Add build system, basic docs and crypto helpers module
Change-Id: I761cde5adac85596c5a3a53ec3e94a9a81fb5416
diff --git a/.jenkins b/.jenkins
new file mode 100755
index 0000000..bc1c847
--- /dev/null
+++ b/.jenkins
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+set -e
+source .jenkins.d/util.sh
+
+export CACHE_DIR=${CACHE_DIR:-/tmp}
+export WAF_JOBS=${WAF_JOBS:-1}
+[[ $JOB_NAME == *"code-coverage" ]] && export DISABLE_ASAN=yes
+
+nanos() {
+ # Cannot use date(1) because macOS does not support %N format specifier
+ python3 -c 'import time; print(int(time.time() * 1e9))'
+}
+
+for file in .jenkins.d/*; do
+ [[ -f $file && -x $file ]] || continue
+
+ if [[ -n $TRAVIS ]]; then
+ label=$(basename "$file" | sed -E 's/[[:digit:]]+-(.*)\..*/\1/')
+ echo -ne "travis_fold:start:${label}\r"
+ echo -ne "travis_time:start:${label}\r"
+ start=$(nanos)
+ fi
+
+ echo "\$ $file"
+ "$file"
+
+ if [[ -n $TRAVIS ]]; then
+ finish=$(nanos)
+ echo -ne "travis_time:end:${label}:start=${start},finish=${finish},duration=$((finish-start)),event=${label}\r"
+ echo -ne "travis_fold:end:${label}\r"
+ fi
+done
diff --git a/.jenkins.d/00-deps.sh b/.jenkins.d/00-deps.sh
new file mode 100755
index 0000000..d4d9c33
--- /dev/null
+++ b/.jenkins.d/00-deps.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+set -ex
+
+if has OSX $NODE_LABELS; then
+ FORMULAE=(boost openssl pkg-config)
+ if has OSX-10.13 $NODE_LABELS || has OSX-10.14 $NODE_LABELS; then
+ FORMULAE+=(python)
+ fi
+
+ if [[ -n $TRAVIS ]]; then
+ # Travis images come with a large number of pre-installed
+ # brew packages, don't waste time upgrading all of them
+ brew list --versions "${FORMULAE[@]}" || brew update
+ for FORMULA in "${FORMULAE[@]}"; do
+ brew list --versions "$FORMULA" || brew install "$FORMULA"
+ done
+ # Ensure /usr/local/opt/openssl exists
+ brew reinstall openssl
+ else
+ brew update
+ brew upgrade
+ brew install "${FORMULAE[@]}"
+ brew cleanup
+ fi
+
+elif has Ubuntu $NODE_LABELS; then
+ sudo apt-get -qq update
+ sudo apt-get -qy install g++ pkg-config python3-minimal \
+ libboost-all-dev libssl-dev libsqlite3-dev
+
+ if [[ $JOB_NAME == *"code-coverage" ]]; then
+ sudo apt-get -qy install gcovr lcov
+ fi
+fi
diff --git a/.jenkins.d/01-ndn-cxx.sh b/.jenkins.d/01-ndn-cxx.sh
new file mode 100755
index 0000000..7bf1cfe
--- /dev/null
+++ b/.jenkins.d/01-ndn-cxx.sh
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+set -ex
+
+pushd "$CACHE_DIR" >/dev/null
+
+INSTALLED_VERSION=
+if has OSX $NODE_LABELS; then
+ BOOST=$(brew ls --versions boost)
+ OLD_BOOST=$(cat boost.txt || :)
+ if [[ $OLD_BOOST != $BOOST ]]; then
+ echo "$BOOST" > boost.txt
+ INSTALLED_VERSION=NONE
+ fi
+fi
+
+if [[ -z $INSTALLED_VERSION ]]; then
+ INSTALLED_VERSION=$(git -C ndn-cxx rev-parse HEAD 2>/dev/null || echo NONE)
+fi
+
+sudo rm -rf ndn-cxx-latest
+git clone --depth 1 https://github.com/named-data/ndn-cxx.git ndn-cxx-latest
+LATEST_VERSION=$(git -C ndn-cxx-latest 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
+ sudo rm -rf ndn-cxx-latest
+fi
+
+sudo rm -f /usr/local/bin/ndnsec*
+sudo rm -fr /usr/local/include/ndn-cxx
+sudo rm -f /usr/local/lib{,64}/libndn-cxx*
+sudo rm -f /usr/local/lib{,64}/pkgconfig/libndn-cxx.pc
+
+pushd ndn-cxx >/dev/null
+
+if has Linux $NODE_LABELS && [[ $CXX != clang* && -z $DISABLE_ASAN ]]; then
+ # https://stackoverflow.com/a/47022141
+ ASAN="--with-sanitizer=address"
+fi
+if has CentOS-8 $NODE_LABELS; then
+ # https://bugzilla.redhat.com/show_bug.cgi?id=1721553
+ PCH="--without-pch"
+fi
+
+./waf --color=yes configure --disable-static --enable-shared --without-osx-keychain $ASAN $PCH
+./waf --color=yes build -j$WAF_JOBS
+sudo_preserve_env PATH -- ./waf --color=yes install
+
+popd >/dev/null
+popd >/dev/null
+
+if has CentOS-8 $NODE_LABELS; then
+ sudo tee /etc/ld.so.conf.d/ndn.conf >/dev/null <<< /usr/local/lib64
+fi
+if has Linux $NODE_LABELS; then
+ sudo ldconfig
+fi
diff --git a/.jenkins.d/10-build.sh b/.jenkins.d/10-build.sh
new file mode 100755
index 0000000..20e6bd1
--- /dev/null
+++ b/.jenkins.d/10-build.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+set -ex
+
+git submodule sync
+git submodule update --init
+
+if [[ -z $DISABLE_ASAN ]]; then
+ ASAN="--with-sanitizer=address"
+fi
+if [[ $JOB_NAME == *"code-coverage" ]]; then
+ COVERAGE="--with-coverage"
+fi
+
+if [[ $JOB_NAME != *"code-coverage" && $JOB_NAME != *"limited-build" ]]; then
+ # Build in release mode with tests
+ ./waf --color=yes configure --with-tests
+ ./waf --color=yes build -j$WAF_JOBS
+
+ # Cleanup
+ ./waf --color=yes distclean
+
+ # Build in release mode without tests
+ ./waf --color=yes configure
+ ./waf --color=yes build -j$WAF_JOBS
+
+ # Cleanup
+ ./waf --color=yes distclean
+fi
+
+# Build in debug mode with tests
+./waf --color=yes configure --debug --with-tests $ASAN $COVERAGE
+./waf --color=yes build -j$WAF_JOBS
+
+# (tests will be run against the debug version)
+
+# Install
+sudo_preserve_env PATH -- ./waf --color=yes install
+
+if has Linux $NODE_LABELS; then
+ sudo ldconfig
+fi
diff --git a/.jenkins.d/20-tests.sh b/.jenkins.d/20-tests.sh
new file mode 100755
index 0000000..226c77d
--- /dev/null
+++ b/.jenkins.d/20-tests.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+set -ex
+
+# Prepare environment
+rm -rf ~/.ndn
+
+BOOST_VERSION=$(python3 -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
+}
+
+# https://github.com/google/sanitizers/wiki/AddressSanitizerFlags
+ASAN_OPTIONS="color=always"
+ASAN_OPTIONS+=":check_initialization_order=1"
+ASAN_OPTIONS+=":detect_stack_use_after_return=1"
+ASAN_OPTIONS+=":strict_init_order=1"
+ASAN_OPTIONS+=":strict_string_checks=1"
+ASAN_OPTIONS+=":detect_invalid_pointer_pairs=2"
+ASAN_OPTIONS+=":strip_path_prefix=${PWD}/"
+export ASAN_OPTIONS
+
+export BOOST_TEST_BUILD_INFO=1
+export BOOST_TEST_COLOR_OUTPUT=1
+
+# Run unit tests
+./build/unit-tests $(ut_log_args)
diff --git a/.jenkins.d/30-coverage.sh b/.jenkins.d/30-coverage.sh
new file mode 100755
index 0000000..4cce87d
--- /dev/null
+++ b/.jenkins.d/30-coverage.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+set -ex
+
+if [[ $JOB_NAME == *"code-coverage" ]]; then
+ gcovr --object-directory=build \
+ --output=build/coverage.xml \
+ --exclude="$PWD/tests" \
+ --root=. \
+ --xml
+
+ # Generate also a detailed HTML output, but using lcov (better results)
+ lcov --quiet \
+ --capture \
+ --directory . \
+ --no-external \
+ --rc lcov_branch_coverage=1 \
+ --output-file build/coverage-with-tests.info
+
+ lcov --quiet \
+ --remove build/coverage-with-tests.info "$PWD/tests/*" \
+ --rc lcov_branch_coverage=1 \
+ --output-file build/coverage.info
+
+ genhtml --branch-coverage \
+ --demangle-cpp \
+ --legend \
+ --output-directory build/coverage \
+ --title "ndncert unit tests" \
+ build/coverage.info
+fi
diff --git a/.jenkins.d/README.md b/.jenkins.d/README.md
new file mode 100644
index 0000000..e8dbf37
--- /dev/null
+++ b/.jenkins.d/README.md
@@ -0,0 +1,28 @@
+# CONTINUOUS INTEGRATION SCRIPTS
+
+## Environment Variables Used in Build Scripts
+
+- `NODE_LABELS`: space-separated list of platform properties. The included values are used by
+ the build scripts to select the proper behavior for different operating systems and versions.
+
+ The list should normally contain `[OS_TYPE]`, `[DISTRO_TYPE]`, and `[DISTRO_VERSION]`.
+
+ Example values:
+
+ - `[OS_TYPE]`: `Linux`, `OSX`
+ - `[DISTRO_TYPE]`: `Ubuntu`, `CentOS`
+ - `[DISTRO_VERSION]`: `Ubuntu-16.04`, `Ubuntu-18.04`, `CentOS-8`, `OSX-10.14`, `OSX-10.15`
+
+- `JOB_NAME`: optional variable that defines the type of build job. Depending on the job type,
+ the build scripts can perform different tasks.
+
+ Possible values:
+
+ - empty: default build task
+ - `code-coverage`: debug build with tests and code coverage analysis (Ubuntu Linux is assumed)
+ - `limited-build`: only a single debug build with tests
+
+- `CACHE_DIR`: directory containing cached files from previous builds, e.g., a compiled version
+ of ndn-cxx. If not set, `/tmp` is used.
+
+- `WAF_JOBS`: number of parallel build threads used by waf, defaults to 1.
diff --git a/.jenkins.d/util.sh b/.jenkins.d/util.sh
new file mode 100644
index 0000000..8077a74
--- /dev/null
+++ b/.jenkins.d/util.sh
@@ -0,0 +1,39 @@
+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}
+}
+export -f has
+
+sudo_preserve_env() {
+ local saved_xtrace
+ [[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x
+ set +x
+
+ local vars=()
+ while [[ $# -gt 0 ]]; do
+ local arg=$1
+ shift
+ case ${arg} in
+ --) break ;;
+ *) vars+=("${arg}=${!arg}") ;;
+ esac
+ done
+
+ set ${saved_xtrace}
+ sudo env "${vars[@]}" "$@"
+}
+export -f sudo_preserve_env
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..8ff6d27
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,105 @@
+version: ~> 1.0
+language: cpp
+os: linux
+dist: bionic
+
+arch:
+ - amd64
+ - arm64
+ - ppc64le
+ - s390x
+
+env:
+ - COMPILER=g++-7
+ - COMPILER=g++-9
+ - COMPILER=clang++-6.0
+ - COMPILER=clang++-9
+
+jobs:
+ include:
+ # Linux
+ - env: COMPILER=g++-8
+ - env: COMPILER=clang++-5.0
+ - env: COMPILER=clang++-7
+ - env: COMPILER=clang++-8
+ - env: COMPILER=clang++-10
+ - env: COMPILER=clang++-11
+ - env: COMPILER=clang++-12
+
+ # macOS
+ - os: osx
+ osx_image: xcode9.4
+ env: # default compiler
+ - os: osx
+ osx_image: xcode10.1
+ env: # default compiler
+ - os: osx
+ osx_image: xcode10.3
+ env: # default compiler
+ - os: osx
+ osx_image: xcode11.3
+ env: # default compiler
+ - os: osx
+ osx_image: xcode11.6
+ env: # default compiler
+ - os: osx
+ osx_image: xcode12
+ env: # default compiler
+
+ allow_failures:
+ - env: COMPILER=clang++-12
+
+ fast_finish: true
+
+before_install:
+ - |
+ : Adding apt repositories
+ case ${COMPILER} in
+ g++-9)
+ # https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test/+packages
+ travis_retry sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
+ travis_retry sudo apt-get -qq update
+ ;;
+ clang++-1?)
+ # https://apt.llvm.org/
+ LLVM_REPO=${COMPILER/clang++/llvm-toolchain-${TRAVIS_DIST}}
+ travis_retry wget -nv -O - "https://apt.llvm.org/llvm-snapshot.gpg.key" | sudo apt-key add -
+ travis_retry sudo add-apt-repository -y "deb http://apt.llvm.org/${TRAVIS_DIST}/ ${LLVM_REPO%-12} main"
+ travis_retry sudo apt-get -qq update
+ ;;
+ esac
+
+install:
+ - |
+ : Installing C++ compiler
+ if [[ -n ${COMPILER} ]]; then
+ travis_retry sudo apt-get -qy install ${COMPILER/clang++/clang}
+ fi
+
+before_script:
+ - |
+ : Setting environment variables
+ if [[ -n ${COMPILER} ]]; then
+ export CXX=${COMPILER}
+ fi
+ case ${TRAVIS_OS_NAME} in
+ linux) export NODE_LABELS="Linux Ubuntu Ubuntu-18.04" ;;
+ osx) export NODE_LABELS="OSX OSX-$(sw_vers -productVersion | cut -d . -f -2)" ;;
+ esac
+ export WAF_JOBS=2
+ - |
+ : Enabling workarounds
+ case "${TRAVIS_CPU_ARCH},${COMPILER}" in
+ ppc64le,g++-7)
+ # AddressSanitizer does not seem to be working
+ export DISABLE_ASAN=yes
+ ;;
+ *,clang++-8)
+ # https://bugs.llvm.org/show_bug.cgi?id=40808
+ export DISABLE_ASAN=yes
+ ;;
+ esac
+ - ${CXX:-c++} --version
+
+script:
+ - ./.jenkins
diff --git a/.waf-tools/boost.py b/.waf-tools/boost.py
new file mode 100644
index 0000000..4b2ede5
--- /dev/null
+++ b/.waf-tools/boost.py
@@ -0,0 +1,533 @@
+#!/usr/bin/env python
+# encoding: utf-8
+#
+# partially based on boost.py written by Gernot Vormayr
+# written by Ruediger Sonderfeld <ruediger@c-plusplus.de>, 2008
+# modified by Bjoern Michaelsen, 2008
+# modified by Luca Fossati, 2008
+# rewritten for waf 1.5.1, Thomas Nagy, 2008
+# rewritten for waf 1.6.2, Sylvain Rouquette, 2011
+
+'''
+
+This is an extra tool, not bundled with the default waf binary.
+To add the boost tool to the waf file:
+$ ./waf-light --tools=compat15,boost
+ or, if you have waf >= 1.6.2
+$ ./waf update --files=boost
+
+When using this tool, the wscript will look like:
+
+ def options(opt):
+ opt.load('compiler_cxx boost')
+
+ def configure(conf):
+ conf.load('compiler_cxx boost')
+ conf.check_boost(lib='system filesystem')
+
+ def build(bld):
+ bld(source='main.cpp', target='app', use='BOOST')
+
+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-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']
+ Errors:
+ - boost might also be compiled with /MT, which links the runtime statically.
+ If you have problems with redefined symbols,
+ self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB']
+ self.env['CXXFLAGS_%s' % var] += ['/MD', '/EHsc']
+Passing `--boost-linkage_autodetect` might help ensuring having a correct linkage in some basic cases.
+
+'''
+
+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']
+BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include']
+
+BOOST_VERSION_FILE = 'boost/version.hpp'
+BOOST_VERSION_CODE = '''
+#include <iostream>
+#include <boost/version.hpp>
+int main() { std::cout << BOOST_LIB_VERSION << ":" << BOOST_VERSION << std::endl; }
+'''
+
+BOOST_ERROR_CODE = '''
+#include <boost/system/error_code.hpp>
+int main() { boost::system::error_code c; }
+'''
+
+PTHREAD_CODE = '''
+#include <pthread.h>
+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 <boost/thread.hpp>
+int main() { boost::thread t; }
+'''
+
+BOOST_LOG_CODE = '''
+#include <boost/log/trivial.hpp>
+int main() { BOOST_LOG_TRIVIAL(info) << "boost_log is working"; }
+'''
+
+BOOST_LOG_SETUP_CODE = '''
+#include <boost/log/trivial.hpp>
+#include <boost/log/utility/setup/console.hpp>
+#include <boost/log/utility/setup/common_attributes.hpp>
+int main() {
+ using namespace boost::log;
+ add_common_attributes();
+ add_console_log(std::clog, keywords::format = "%Message%");
+ BOOST_LOG_TRIVIAL(info) << "boost_log_setup is working";
+}
+'''
+
+# 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'
+detect_clang = lambda env: (PLATFORM == 'darwin') and 'clang-darwin' or 'clang'
+detect_mingw = lambda env: (re.search('MinGW', env.CXX[0])) and 'mgw' or 'gcc'
+BOOST_TOOLSETS = {
+ 'borland': 'bcb',
+ 'clang': detect_clang,
+ 'como': 'como',
+ 'cw': 'cw',
+ 'darwin': 'xgcc',
+ 'edg': 'edg',
+ 'g++': detect_mingw,
+ 'gcc': detect_mingw,
+ 'icpc': detect_intel,
+ 'intel': detect_intel,
+ 'kcc': 'kcc',
+ 'kylix': 'bck',
+ 'mipspro': 'mp',
+ 'mingw': 'mgw',
+ 'msvc': 'vc',
+ 'qcc': 'qcc',
+ 'sun': 'sw',
+ 'sunc++': 'sw',
+ 'tru64cxx': 'tru',
+ 'vacpp': 'xlc'
+}
+
+
+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''')
+ 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-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 (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)')
+ 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)
+
+
+@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)
+ return None
+
+@conf
+def boost_get_version(self, d):
+ """silently retrieve the boost version number"""
+ node = self.__boost_get_version_file(d)
+ if node:
+ try:
+ txt = node.read()
+ 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
+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 self.environ.get('INCLUDE', '').split(';') + BOOST_INCLUDES:
+ if self.__boost_get_version_file(d):
+ return d
+ if includes:
+ self.end_msg('headers not found in %s' % includes, 'YELLOW')
+ self.fatal('The configuration failed')
+ else:
+ self.end_msg('headers not found, please provide a --boost-includes argument (see help)', 'YELLOW')
+ self.fatal('The configuration failed')
+
+
+@conf
+def boost_get_toolset(self, cc):
+ toolset = cc
+ if not cc:
+ build_platform = Utils.unversioned_sys_platform()
+ if build_platform in BOOST_TOOLSETS:
+ cc = build_platform
+ else:
+ cc = self.env.CXX_NAME
+ if cc in BOOST_TOOLSETS:
+ toolset = BOOST_TOOLSETS[cc]
+ return isinstance(toolset, str) and toolset or toolset(self.env)
+
+
+@conf
+def __boost_get_libs_path(self, *k, **kw):
+ ''' return the lib path and all the files in it '''
+ if 'files' in kw:
+ return self.root.find_dir('.'), Utils.to_list(kw['files'])
+ libs = k and k[0] or kw.get('libs', None)
+ if libs:
+ path = self.root.find_dir(libs)
+ files = path.ant_glob('*boost_*')
+ if not libs or not files:
+ 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_*')
+ if files:
+ break
+ path = self.root.find_dir(d + '64')
+ if path:
+ files = path.ant_glob('*boost_*')
+ if files:
+ break
+ if not path:
+ if libs:
+ self.end_msg('libs not found in %s' % libs, 'YELLOW')
+ self.fatal('The configuration failed')
+ else:
+ self.end_msg('libs not found, please provide a --boost-libs argument (see help)', 'YELLOW')
+ self.fatal('The configuration failed')
+
+ self.to_log('Found the boost path in %r with the libraries:' % path)
+ for x in files:
+ self.to_log(' %r' % x)
+ return path, files
+
+@conf
+def boost_get_libs(self, *k, **kw):
+ '''
+ return the lib path and the required libs
+ according to the parameters
+ '''
+ path, files = self.__boost_get_libs_path(**kw)
+ 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
+
+ def find_lib(re_lib, files):
+ for file in files:
+ if re_lib.search(file.name):
+ self.to_log('Found boost lib %s' % file)
+ return file
+ return None
+
+ def format_lib_name(name):
+ if name.startswith('lib') and self.env.CC_NAME != 'msvc':
+ name = name[3:]
+ return name[:name.rfind('.')]
+
+ 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
+
+ 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()), 'YELLOW')
+ 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, quiet=True)
+ 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):
+ """
+ Initialize boost libraries to be used.
+
+ Keywords: you can pass the same parameters as with the command line (without "--boost-").
+ Note that the command line has the priority, and should preferably be used.
+ """
+ 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),
+ 'stlib': kw.get('stlib', None)
+ }
+ for key, value in self.options.__dict__.items():
+ if not key.startswith('boost_'):
+ continue
+ key = key[len('boost_'):]
+ params[key] = value and value or kw.get(key, '')
+
+ var = kw.get('uselib_store', 'BOOST')
+
+ if not self.env.DONE_FIND_BOOST_COMMON:
+ self.find_program('dpkg-architecture', var='DPKG_ARCHITECTURE', mandatory=False)
+ if self.env.DPKG_ARCHITECTURE:
+ deb_host_multiarch = self.cmd_and_log([self.env.DPKG_ARCHITECTURE[0], '-qDEB_HOST_MULTIARCH'])
+ BOOST_LIBS.insert(0, '/usr/lib/%s' % deb_host_multiarch.strip())
+
+ self.start_msg('Checking boost includes')
+ self.env['INCLUDES_%s' % var] = inc = self.boost_get_includes(**params)
+ versions = self.boost_get_version(inc)
+ 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))
+ if Logs.verbose:
+ Logs.pprint('CYAN', ' path : %s' % self.env['INCLUDES_%s' % var])
+
+ self.env.DONE_FIND_BOOST_COMMON = True
+
+ 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')
+ 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(' '.join(libs + stlibs))
+ if Logs.verbose:
+ Logs.pprint('CYAN', ' path : %s' % path)
+ 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 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') or has_lib('log_setup'):
+ if not has_lib('thread'):
+ self.env['DEFINES_%s' % var] += ['BOOST_LOG_NO_THREADS']
+ if has_shlib('log') or has_shlib('log_setup'):
+ self.env['DEFINES_%s' % var] += ['BOOST_LOG_DYN_LINK']
+ if has_lib('log_setup'):
+ self.check_cxx(fragment=BOOST_LOG_SETUP_CODE, use=var, execute=False)
+ else:
+ 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',):
+ # disable auto-linking feature, causing error LNK1181
+ # because the code wants to be linked against
+ self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB']
+
+ # if no dlls are present, we guess the .lib files are not stubs
+ has_dlls = False
+ for x in Utils.listdir(path):
+ if x.endswith(self.env.cxxshlib_PATTERN % ''):
+ has_dlls = True
+ break
+ if not has_dlls:
+ self.env['STLIBPATH_%s' % var] = [path]
+ self.env['STLIB_%s' % var] = libs
+ del self.env['LIB_%s' % var]
+ del self.env['LIBPATH_%s' % var]
+
+ # we attempt to play with some known-to-work CXXFLAGS combinations
+ for cxxflags in (['/MD', '/EHsc'], []):
+ self.env.stash()
+ self.env['CXXFLAGS_%s' % var] += cxxflags
+ try:
+ try_link()
+ self.end_msg('ok: winning cxxflags combination: %s' % (self.env['CXXFLAGS_%s' % var]))
+ exc = None
+ break
+ except Errors.ConfigurationError as e:
+ self.env.revert()
+ exc = 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')
+ self.fatal('The configuration failed')
+ else:
+ self.start_msg('Checking for boost linkage')
+ try:
+ try_link()
+ except Errors.ConfigurationError as e:
+ self.end_msg('Could not link against boost libraries using supplied options', 'YELLOW')
+ 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..cc58165
--- /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
+
+def options(opt):
+ opt.add_option('--with-coverage', action='store_true', default=False,
+ help='Add compiler flags 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
new file mode 100644
index 0000000..9e045c3
--- /dev/null
+++ b/.waf-tools/default-compiler-flags.py
@@ -0,0 +1,216 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+from waflib import Configure, Logs, Utils
+
+def options(opt):
+ opt.add_option('--debug', '--with-debug', action='store_true', default=False,
+ help='Compile in debugging mode with minimal optimizations (-O0 or -Og)')
+
+def configure(conf):
+ conf.start_msg('Checking C++ compiler version')
+
+ cxx = conf.env.CXX_NAME # generic name of the compiler
+ ccver = tuple(int(i) for i in conf.env.CC_VERSION)
+ ccverstr = '.'.join(conf.env.CC_VERSION)
+ errmsg = ''
+ warnmsg = ''
+ if cxx == 'gcc':
+ if ccver < (5, 3, 0):
+ errmsg = ('The version of gcc you are using is too old.\n'
+ 'The minimum supported gcc version is 5.3.0.')
+ conf.flags = GccFlags()
+ elif cxx == 'clang':
+ if ccver < (3, 6, 0):
+ errmsg = ('The version of clang you are using is too old.\n'
+ 'The minimum supported clang version is 3.6.0.')
+ conf.flags = ClangFlags()
+ else:
+ warnmsg = 'Note: %s compiler is unsupported' % cxx
+ conf.flags = CompilerFlags()
+
+ if errmsg:
+ conf.end_msg(ccverstr, color='RED')
+ conf.fatal(errmsg)
+ elif warnmsg:
+ conf.end_msg(ccverstr, color='YELLOW')
+ Logs.warn(warnmsg)
+ else:
+ conf.end_msg(ccverstr)
+
+ conf.areCustomCxxflagsPresent = (len(conf.env.CXXFLAGS) > 0)
+
+ # General flags are always applied (e.g., selecting C++ language standard)
+ generalFlags = conf.flags.getGeneralFlags(conf)
+ conf.add_supported_cxxflags(generalFlags['CXXFLAGS'])
+ conf.add_supported_linkflags(generalFlags['LINKFLAGS'])
+ conf.env.DEFINES += generalFlags['DEFINES']
+
+@Configure.conf
+def check_compiler_flags(conf):
+ # 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:
+ extraFlags = conf.flags.getDebugFlags(conf)
+ if conf.areCustomCxxflagsPresent:
+ missingFlags = [x for x in extraFlags['CXXFLAGS'] if x not in conf.env.CXXFLAGS]
+ if missingFlags:
+ Logs.warn('Selected debug mode, but CXXFLAGS is set to a custom value "%s"'
+ % ' '.join(conf.env.CXXFLAGS))
+ Logs.warn('Default flags "%s" will not be used' % ' '.join(missingFlags))
+ else:
+ extraFlags = conf.flags.getOptimizedFlags(conf)
+
+ if not conf.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 = []
+ for flags in cxxflags:
+ flags = Utils.to_list(flags)
+ if self.check_cxx(cxxflags=['-Werror'] + flags, mandatory=False):
+ supportedFlags += flags
+
+ self.end_msg(' '.join(supportedFlags))
+ 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 = []
+ for flags in linkflags:
+ flags = Utils.to_list(flags)
+ if self.check_cxx(linkflags=['-Werror'] + flags, mandatory=False):
+ supportedFlags += flags
+
+ self.end_msg(' '.join(supportedFlags))
+ self.env.prepend_value('LINKFLAGS', supportedFlags)
+
+
+class CompilerFlags(object):
+ def getCompilerVersion(self, conf):
+ return tuple(int(i) for i in conf.env.CC_VERSION)
+
+ 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 getGeneralFlags(self, conf):
+ flags = super(GccBasicFlags, self).getGeneralFlags(conf)
+ flags['CXXFLAGS'] += ['-std=c++14']
+ if Utils.unversioned_sys_platform() == 'linux':
+ flags['LINKFLAGS'] += ['-fuse-ld=gold']
+ elif Utils.unversioned_sys_platform() == 'freebsd':
+ flags['LINKFLAGS'] += ['-fuse-ld=lld']
+ return flags
+
+ def getDebugFlags(self, conf):
+ flags = super(GccBasicFlags, self).getDebugFlags(conf)
+ flags['CXXFLAGS'] += ['-O0',
+ '-Og', # gcc >= 4.8, clang >= 4.0
+ '-g3',
+ '-pedantic',
+ '-Wall',
+ '-Wextra',
+ '-Werror',
+ '-Wnon-virtual-dtor',
+ '-Wno-error=deprecated-declarations', # Bug #3795
+ '-Wno-error=maybe-uninitialized', # Bug #1615
+ '-Wno-unused-parameter',
+ ]
+ flags['LINKFLAGS'] += ['-Wl,-O1']
+ return flags
+
+ def getOptimizedFlags(self, conf):
+ flags = super(GccBasicFlags, self).getOptimizedFlags(conf)
+ flags['CXXFLAGS'] += ['-O2',
+ '-g',
+ '-pedantic',
+ '-Wall',
+ '-Wextra',
+ '-Wnon-virtual-dtor',
+ '-Wno-unused-parameter',
+ ]
+ flags['LINKFLAGS'] += ['-Wl,-O1']
+ return flags
+
+class GccFlags(GccBasicFlags):
+ def getDebugFlags(self, conf):
+ flags = super(GccFlags, self).getDebugFlags(conf)
+ flags['CXXFLAGS'] += ['-fdiagnostics-color']
+ return flags
+
+ def getOptimizedFlags(self, conf):
+ flags = super(GccFlags, self).getOptimizedFlags(conf)
+ flags['CXXFLAGS'] += ['-fdiagnostics-color']
+ return flags
+
+class ClangFlags(GccBasicFlags):
+ def getGeneralFlags(self, conf):
+ flags = super(ClangFlags, self).getGeneralFlags(conf)
+ if Utils.unversioned_sys_platform() == 'darwin' and self.getCompilerVersion(conf) >= (9, 0, 0):
+ # Bug #4296
+ flags['CXXFLAGS'] += [['-isystem', '/usr/local/include'], # for Homebrew
+ ['-isystem', '/opt/local/include']] # for MacPorts
+ if Utils.unversioned_sys_platform() == 'freebsd':
+ flags['CXXFLAGS'] += [['-isystem', '/usr/local/include']] # Bug #4790
+ return flags
+
+ def getDebugFlags(self, conf):
+ flags = super(ClangFlags, self).getDebugFlags(conf)
+ flags['CXXFLAGS'] += ['-fcolor-diagnostics',
+ '-Wextra-semi',
+ '-Wundefined-func-template',
+ '-Wno-unused-local-typedef', # Bugs #2657 and #3209
+ ]
+ version = self.getCompilerVersion(conf)
+ if version < (3, 9, 0) or (Utils.unversioned_sys_platform() == 'darwin' and version < (8, 1, 0)):
+ flags['CXXFLAGS'] += ['-Wno-unknown-pragmas']
+ if version < (6, 0, 0):
+ flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721
+ return flags
+
+ def getOptimizedFlags(self, conf):
+ flags = super(ClangFlags, self).getOptimizedFlags(conf)
+ flags['CXXFLAGS'] += ['-fcolor-diagnostics',
+ '-Wextra-semi',
+ '-Wundefined-func-template',
+ '-Wno-unused-local-typedef', # Bugs #2657 and #3209
+ ]
+ version = self.getCompilerVersion(conf)
+ if version < (3, 9, 0) or (Utils.unversioned_sys_platform() == 'darwin' and version < (8, 1, 0)):
+ flags['CXXFLAGS'] += ['-Wno-unknown-pragmas']
+ if version < (6, 0, 0):
+ flags['CXXFLAGS'] += ['-Wno-missing-braces'] # Bug #4721
+ return flags
diff --git a/.waf-tools/openssl.py b/.waf-tools/openssl.py
new file mode 100644
index 0000000..b35795f
--- /dev/null
+++ b/.waf-tools/openssl.py
@@ -0,0 +1,102 @@
+#! /usr/bin/env python
+# encoding: utf-8
+# Yingdi Yu (UCLA) 2016
+
+'''
+
+When using this tool, the wscript will look like:
+
+ def options(opt):
+ opt.load('openssl')
+
+ def configure(conf):
+ conf.load('compiler_cxx openssl')
+ conf.check_openssl()
+
+ def build(bld):
+ bld(source='main.cpp', target='app', use='OPENSSL')
+
+'''
+
+import re
+from waflib import Utils
+from waflib.Configure import conf
+
+OPENSSL_DIR_OSX = ['/usr/local', '/opt/local', '/usr/local/opt/openssl']
+OPENSSL_DIR = ['/usr', '/usr/local', '/opt/local', '/sw']
+
+def options(opt):
+ opt.add_option('--with-openssl', type='string', default=None, dest='openssl_dir',
+ help='directory where OpenSSL is installed, e.g., /usr/local')
+
+@conf
+def __openssl_get_version_file(self, dir):
+ try:
+ return self.root.find_dir(dir).find_node('include/openssl/opensslv.h')
+ except:
+ return None
+
+@conf
+def __openssl_find_root_and_version_file(self, *k, **kw):
+ root = k and k[0] or kw.get('path', self.options.openssl_dir)
+
+ file = self.__openssl_get_version_file(root)
+ if root and file:
+ return (root, file)
+
+ openssl_dir = []
+ if Utils.unversioned_sys_platform() == 'darwin':
+ openssl_dir = OPENSSL_DIR_OSX
+ else:
+ openssl_dir = OPENSSL_DIR
+
+ if not root:
+ for dir in openssl_dir:
+ file = self.__openssl_get_version_file(dir)
+ if file:
+ return (dir, file)
+
+ if root:
+ self.fatal('OpenSSL not found in %s' % root)
+ else:
+ self.fatal('OpenSSL not found, please provide a --with-openssl=PATH argument (see help)')
+
+@conf
+def check_openssl(self, *k, **kw):
+ self.start_msg('Checking for OpenSSL version')
+ (root, file) = self.__openssl_find_root_and_version_file(*k, **kw)
+
+ try:
+ txt = file.read()
+ re_version = re.compile('^#\\s*define\\s+OPENSSL_VERSION_NUMBER\\s+(.*)L', re.M)
+ version_number = re_version.search(txt)
+
+ re_version_text = re.compile('^#\\s*define\\s+OPENSSL_VERSION_TEXT\\s+(.*)', re.M)
+ version_text = re_version_text.search(txt)
+
+ if version_number and version_text:
+ version = version_number.group(1)
+ self.end_msg(version_text.group(1))
+ else:
+ self.fatal('OpenSSL version file is present, but is not recognizable')
+ except:
+ self.fatal('OpenSSL version file is not found or is not usable')
+
+ atleast_version = kw.get('atleast_version', 0)
+ if int(version, 16) < atleast_version:
+ self.fatal('The version of OpenSSL is too old\n'
+ 'Please upgrade your distribution or manually install a newer version of OpenSSL')
+
+ if 'msg' not in kw:
+ kw['msg'] = 'Checking if OpenSSL library works'
+ if 'lib' not in kw:
+ kw['lib'] = ['ssl', 'crypto']
+ if 'uselib_store' not in kw:
+ kw['uselib_store'] = 'OPENSSL'
+ if 'define_name' not in kw:
+ kw['define_name'] = 'HAVE_%s' % kw['uselib_store']
+ if root:
+ kw['includes'] = '%s/include' % root
+ kw['libpath'] = '%s/lib' % root
+
+ self.check_cxx(**kw)
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/.waf-tools/sqlite3.py b/.waf-tools/sqlite3.py
new file mode 100644
index 0000000..4f2c016
--- /dev/null
+++ b/.waf-tools/sqlite3.py
@@ -0,0 +1,37 @@
+#! /usr/bin/env python
+# encoding: utf-8
+
+from waflib.Configure import conf
+
+def options(opt):
+ opt.add_option('--with-sqlite3', type='string', default=None, dest='sqlite3_dir',
+ help='directory where SQLite3 is installed, e.g., /usr/local')
+
+@conf
+def check_sqlite3(self, *k, **kw):
+ root = k and k[0] or kw.get('path', self.options.sqlite3_dir)
+ mandatory = kw.get('mandatory', True)
+ var = kw.get('uselib_store', 'SQLITE3')
+
+ if root:
+ self.check_cxx(lib='sqlite3',
+ msg='Checking for SQLite3 library',
+ define_name='HAVE_%s' % var,
+ uselib_store=var,
+ mandatory=mandatory,
+ includes='%s/include' % root,
+ libpath='%s/lib' % root)
+ else:
+ try:
+ self.check_cfg(package='sqlite3',
+ args=['--cflags', '--libs'],
+ global_define=True,
+ define_name='HAVE_%s' % var,
+ uselib_store='SQLITE3',
+ mandatory=True)
+ except:
+ self.check_cxx(lib='sqlite3',
+ msg='Checking for SQLite3 library',
+ define_name='HAVE_%s' % var,
+ uselib_store=var,
+ mandatory=mandatory)
diff --git a/AUTHORS.md b/AUTHORS.md
new file mode 100644
index 0000000..0c40c8d
--- /dev/null
+++ b/AUTHORS.md
@@ -0,0 +1,19 @@
+# ndncert Authors
+
+The following lists maintainers, primary developers, and all much-appreciated contributors to ndncert in alphabetic order.
+The specific contributions of individual authors can be obtained from the git history of the [official ndncert repository](https://github.com/named-data/ndncert).
+If you would like to become a contributor to the official repository, please follow the recommendations in https://github.com/named-data/.github/blob/master/CONTRIBUTING.md.
+
+* Alexander Afanasyev <https://users.cs.fiu.edu/~afanasyev/>
+* Ashlesh Gawande <https://www.linkedin.com/in/agawande>
+* Siqi Liu <https://github.com/tylerliu>
+* Eric Newberry <https://ericnewberry.com>
+* Davide Pesavento <https://github.com/Pesa>
+* Md Ashiqur Rahman <https://ashiqrahman.com>
+* Junxiao Shi <https://cs.arizona.edu/~shijunxiao>
+* Yufeng Zhang <https://yufengzh.io>
+* ***(Maintainer)*** Zhiyi Zhang <https://zhiyi-zhang.com>
+
+# Technical Advisors
+
+* Lixia Zhang <https://web.cs.ucla.edu/~lixia>
diff --git a/COPYING.md b/COPYING.md
new file mode 100644
index 0000000..293b2c4
--- /dev/null
+++ b/COPYING.md
@@ -0,0 +1,697 @@
+ndncert is licensed under the terms of the GNU General Public License,
+version 3 or later.
+
+ndncert relies on third-party software, licensed under the following licenses:
+
+- ndn-cxx is licensed under the terms of the
+ [GNU Lesser General Public License version 3](https://github.com/named-data/ndn-cxx/blob/master/COPYING.md)
+
+- The Boost libraries are licensed under the
+ [Boost Software License 1.0](https://www.boost.org/users/license.html)
+
+- SQLite is in the [public domain](https://www.sqlite.org/copyright.html)
+
+- The waf build system is licensed under the terms of the
+ [BSD license](https://github.com/named-data/ndncert/blob/master/waf)
+
+
+The GPL license is provided below in this file. For more information about
+these licenses, see https://www.gnu.org/licenses/
+
+----------------------------------------------------------------------------------
+
+### GNU GENERAL PUBLIC LICENSE
+
+Version 3, 29 June 2007
+
+Copyright (C) 2007 Free Software Foundation, Inc.
+<https://fsf.org/>
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+
+### Preamble
+
+The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom
+to share and change all versions of a program--to make sure it remains
+free software for all its users. We, the Free Software Foundation, use
+the GNU General Public License for most of our software; it applies
+also to any other work released this way by its authors. You can apply
+it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you
+have certain responsibilities if you distribute copies of the
+software, or if you modify it: responsibilities to respect the freedom
+of others.
+
+For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the
+manufacturer can do so. This is fundamentally incompatible with the
+aim of protecting users' freedom to change the software. The
+systematic pattern of such abuse occurs in the area of products for
+individuals to use, which is precisely where it is most unacceptable.
+Therefore, we have designed this version of the GPL to prohibit the
+practice for those products. If such problems arise substantially in
+other domains, we stand ready to extend this provision to those
+domains in future versions of the GPL, as needed to protect the
+freedom of users.
+
+Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish
+to avoid the special danger that patents applied to a free program
+could make it effectively proprietary. To prevent this, the GPL
+assures that patents cannot be used to render the program non-free.
+
+The precise terms and conditions for copying, distribution and
+modification follow.
+
+### TERMS AND CONDITIONS
+
+#### 0. Definitions.
+
+"This License" refers to version 3 of the GNU General Public License.
+
+"Copyright" also means copyright-like laws that apply to other kinds
+of works, such as semiconductor masks.
+
+"The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of
+an exact copy. The resulting work is called a "modified version" of
+the earlier work or a work "based on" the earlier work.
+
+A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user
+through a computer network, with no transfer of a copy, is not
+conveying.
+
+An interactive user interface displays "Appropriate Legal Notices" to
+the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+#### 1. Source Code.
+
+The "source code" for a work means the preferred form of the work for
+making modifications to it. "Object code" means any non-source form of
+a work.
+
+A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users can
+regenerate automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same
+work.
+
+#### 2. Basic Permissions.
+
+All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not convey,
+without conditions so long as your license otherwise remains in force.
+You may convey covered works to others for the sole purpose of having
+them make modifications exclusively for you, or provide you with
+facilities for running those works, provided that you comply with the
+terms of this License in conveying all material for which you do not
+control copyright. Those thus making or running the covered works for
+you must do so exclusively on your behalf, under your direction and
+control, on terms that prohibit them from making any copies of your
+copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under the
+conditions stated below. Sublicensing is not allowed; section 10 makes
+it unnecessary.
+
+#### 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such
+circumvention is effected by exercising rights under this License with
+respect to the covered work, and you disclaim any intention to limit
+operation or modification of the work as a means of enforcing, against
+the work's users, your or third parties' legal rights to forbid
+circumvention of technological measures.
+
+#### 4. Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+#### 5. Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these
+conditions:
+
+- a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+- b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under
+ section 7. This requirement modifies the requirement in section 4
+ to "keep intact all notices".
+- c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+- d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+#### 6. Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms of
+sections 4 and 5, provided that you also convey the machine-readable
+Corresponding Source under the terms of this License, in one of these
+ways:
+
+- a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+- b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the Corresponding
+ Source from a network server at no charge.
+- c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+- d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+- e) Convey the object code using peer-to-peer transmission,
+ provided you inform other peers where the object code and
+ Corresponding Source of the work are being offered to the general
+ public at no charge under subsection 6d.
+
+A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal,
+family, or household purposes, or (2) anything designed or sold for
+incorporation into a dwelling. In determining whether a product is a
+consumer product, doubtful cases shall be resolved in favor of
+coverage. For a particular product received by a particular user,
+"normally used" refers to a typical or common use of that class of
+product, regardless of the status of the particular user or of the way
+in which the particular user actually uses, or expects or is expected
+to use, the product. A product is a consumer product regardless of
+whether the product has substantial commercial, industrial or
+non-consumer uses, unless such uses represent the only significant
+mode of use of the product.
+
+"Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to
+install and execute modified versions of a covered work in that User
+Product from a modified version of its Corresponding Source. The
+information must suffice to ensure that the continued functioning of
+the modified object code is in no case prevented or interfered with
+solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or
+updates for a work that has been modified or installed by the
+recipient, or for the User Product in which it has been modified or
+installed. Access to a network may be denied when the modification
+itself materially and adversely affects the operation of the network
+or violates the rules and protocols for communication across the
+network.
+
+Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+#### 7. Additional Terms.
+
+"Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders
+of that material) supplement the terms of this License with terms:
+
+- a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+- b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+- c) Prohibiting misrepresentation of the origin of that material,
+ or requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+- d) Limiting the use for publicity purposes of names of licensors
+ or authors of the material; or
+- e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+- f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions
+ of it) with contractual assumptions of liability to the recipient,
+ for any liability that these contractual assumptions directly
+ impose on those licensors and authors.
+
+All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions; the
+above requirements apply either way.
+
+#### 8. Termination.
+
+You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+#### 9. Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or run
+a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+#### 10. Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+#### 11. Patents.
+
+A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+A contributor's "essential patent claims" are all patent claims owned
+or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+A patent license is "discriminatory" if it does not include within the
+scope of its coverage, prohibits the exercise of, or is conditioned on
+the non-exercise of one or more of the rights that are specifically
+granted under this License. You may not convey a covered work if you
+are a party to an arrangement with a third party that is in the
+business of distributing software, under which you make payment to the
+third party based on the extent of your activity of conveying the
+work, and under which the third party grants, to any of the parties
+who would receive the covered work from you, a discriminatory patent
+license (a) in connection with copies of the covered work conveyed by
+you (or copies made from those copies), or (b) primarily for and in
+connection with specific products or compilations that contain the
+covered work, unless you entered into that arrangement, or that patent
+license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+#### 12. No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under
+this License and any other pertinent obligations, then as a
+consequence you may not convey it at all. For example, if you agree to
+terms that obligate you to collect a royalty for further conveying
+from those to whom you convey the Program, the only way you could
+satisfy both those terms and this License would be to refrain entirely
+from conveying the Program.
+
+#### 13. Use with the GNU Affero General Public License.
+
+Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+#### 14. Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions
+of the GNU General Public License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in
+detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies that a certain numbered version of the GNU General Public
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that numbered version or
+of any later version published by the Free Software Foundation. If the
+Program does not specify a version number of the GNU General Public
+License, you may choose any version ever published by the Free
+Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions
+of the GNU General Public License can be used, that proxy's public
+statement of acceptance of a version permanently authorizes you to
+choose that version for the Program.
+
+Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+#### 15. Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT
+WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
+DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+CORRECTION.
+
+#### 16. Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR
+CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
+NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
+LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
+TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
+PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+#### 17. Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+END OF TERMS AND CONDITIONS
+
+### How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+To do so, attach the following notices to the program. It is safest to
+attach them to the start of each source file to most effectively state
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program 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.
+
+ This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper
+mail.
+
+If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands \`show w' and \`show c' should show the
+appropriate parts of the General Public License. Of course, your
+program's commands might be different; for a GUI interface, you would
+use an "about box".
+
+You should also get your employer (if you work as a programmer) or
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. For more information on this, and how to apply and follow
+the GNU GPL, see <https://www.gnu.org/licenses/>.
+
+The GNU General Public License does not permit incorporating your
+program into proprietary programs. If your program is a subroutine
+library, you may consider it more useful to permit linking proprietary
+applications with the library. If this is what you want to do, use the
+GNU Lesser General Public License instead of this License. But first,
+please read <https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a2806e3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,34 @@
+# NDN Certificate Management Protocol (NDNCERT)
+
+![Language](https://img.shields.io/badge/C%2B%2B-14-blue.svg)
+[![Build Status](https://travis-ci.org/named-data/ndncert.svg?branch=master)](https://travis-ci.org/named-data/ndncert)
+
+The NDN certificate management protocol (**NDNCERT**) enables automatic certificate management
+in NDN. In Named Data Networking (NDN), every entity should have a corresponding identity
+(namespace) and the corresponding certificate for this namespace. Moreover, entities need simple
+mechanisms to manage sub-identities and their certificates. NDNCERT provides flexible mechanisms
+to request certificates from a certificate authority (CA) and, as soon as the certificate is
+obtained, mechanisms to issue and manage certificates in the designated namespace. Note that
+NDNCERT does not impose any specific trust model or trust anchors. While the primary use case of
+this protocol is to manage NDN testbed certificates, it can be used with any other set of global
+and local trust anchors.
+
+See [our GitHub wiki](https://github.com/named-data/ndncert/wiki) for more details.
+
+## Reporting bugs
+
+Please submit any bug reports or feature requests to the
+[NDNCERT issue tracker](https://redmine.named-data.net/projects/ndncert/issues).
+
+## Contributing
+
+We greatly appreciate contributions to the NDNCERT code base, provided that they are
+licensed under the GPL 3.0+ or a compatible license (see below).
+If you are new to the NDN software community, please read the
+[Contributor's Guide](https://github.com/named-data/.github/blob/master/CONTRIBUTING.md)
+to get started.
+
+## License
+
+NDNCERT is an open source project licensed under the GPL version 3.
+See [`COPYING.md`](COPYING.md) for more information.
diff --git a/libndn-cert.pc.in b/libndn-cert.pc.in
new file mode 100644
index 0000000..d4221e4
--- /dev/null
+++ b/libndn-cert.pc.in
@@ -0,0 +1,10 @@
+prefix=@PREFIX@
+libdir=@LIBDIR@
+includedir=@INCLUDEDIR@
+
+Name: libndn-cert
+Description: ndncert library
+Version: @VERSION@
+Libs: -L${libdir} -lndn-cert
+Cflags: -I${includedir}
+Requires: libndn-cxx >= 0.7.1
\ No newline at end of file
diff --git a/src/detail/crypto-helpers.cpp b/src/detail/crypto-helpers.cpp
new file mode 100644
index 0000000..3142268
--- /dev/null
+++ b/src/detail/crypto-helpers.cpp
@@ -0,0 +1,386 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#include "detail/crypto-helpers.hpp"
+
+#include <boost/endian/conversion.hpp>
+#include <cstring>
+#include <ndn-cxx/encoding/buffer-stream.hpp>
+#include <ndn-cxx/security/transform/base64-decode.hpp>
+#include <ndn-cxx/security/transform/base64-encode.hpp>
+#include <ndn-cxx/security/transform/buffer-source.hpp>
+#include <ndn-cxx/security/transform/stream-sink.hpp>
+#include <ndn-cxx/util/random.hpp>
+#include <openssl/ec.h>
+#include <openssl/err.h>
+#include <openssl/hmac.h>
+#include <openssl/kdf.h>
+#include <openssl/pem.h>
+
+namespace ndn {
+namespace ndncert {
+
+ECDHState::ECDHState()
+{
+ auto EC_NID = NID_X9_62_prime256v1;
+ // params context
+ EVP_PKEY_CTX* ctx_params = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr);
+ if (ctx_params == nullptr) {
+ NDN_THROW(std::runtime_error("Could not create context"));
+ }
+ if (EVP_PKEY_paramgen_init(ctx_params) != 1) {
+ EVP_PKEY_CTX_free(ctx_params);
+ NDN_THROW(std::runtime_error("Could not initialize parameter generation"));
+ }
+ if (1 != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx_params, EC_NID)) {
+ EVP_PKEY_CTX_free(ctx_params);
+ NDN_THROW(std::runtime_error("Likely unknown elliptical curve ID specified"));
+ }
+ // generate params
+ EVP_PKEY* params = nullptr;
+ if (!EVP_PKEY_paramgen(ctx_params, ¶ms)) {
+ EVP_PKEY_CTX_free(ctx_params);
+ NDN_THROW(std::runtime_error("Could not create parameter object parameters"));
+ }
+ // key generation context
+ EVP_PKEY_CTX* ctx_keygen = EVP_PKEY_CTX_new(params, nullptr);
+ if (ctx_keygen == nullptr) {
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(ctx_params);
+ NDN_THROW(std::runtime_error("Could not create the context for the key generation"));
+ }
+ if (1 != EVP_PKEY_keygen_init(ctx_keygen)) {
+ EVP_PKEY_CTX_free(ctx_keygen);
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(ctx_params);
+ NDN_THROW(std::runtime_error("Could not init context for key generation"));
+ }
+ if (1 != EVP_PKEY_keygen(ctx_keygen, &m_privkey)) {
+ EVP_PKEY_CTX_free(ctx_keygen);
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(ctx_params);
+ NDN_THROW(std::runtime_error("Could not generate DHE keys in final step"));
+ }
+ EVP_PKEY_CTX_free(ctx_keygen);
+ EVP_PKEY_free(params);
+ EVP_PKEY_CTX_free(ctx_params);
+}
+
+ECDHState::~ECDHState()
+{
+ if (m_privkey != nullptr) {
+ EVP_PKEY_free(m_privkey);
+ }
+}
+
+const std::vector<uint8_t>&
+ECDHState::getSelfPubKey()
+{
+ auto privECKey = EVP_PKEY_get1_EC_KEY(m_privkey);
+ if (privECKey == nullptr) {
+ NDN_THROW(std::runtime_error("Could not get key when calling EVP_PKEY_get1_EC_KEY()"));
+ }
+ auto ecPoint = EC_KEY_get0_public_key(privECKey);
+ auto group = EC_KEY_get0_group(privECKey);
+ auto requiredBufLen = EC_POINT_point2oct(group, ecPoint, POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
+ m_pubKey.resize(requiredBufLen);
+ auto rev = EC_POINT_point2oct(group, ecPoint, POINT_CONVERSION_UNCOMPRESSED,
+ m_pubKey.data(), requiredBufLen, nullptr);
+ EC_KEY_free(privECKey);
+ if (rev == 0) {
+ NDN_THROW(std::runtime_error("Could not convert EC_POINTS to octet string when calling EC_POINT_point2oct()"));
+ }
+ return m_pubKey;
+}
+
+const std::vector<uint8_t>&
+ECDHState::deriveSecret(const std::vector<uint8_t>& peerKey)
+{
+ // prepare self private key
+ auto privECKey = EVP_PKEY_get1_EC_KEY(m_privkey);
+ if (privECKey == nullptr) {
+ NDN_THROW(std::runtime_error("Cannot not get key when calling EVP_PKEY_get1_EC_KEY()"));
+ }
+ auto group = EC_KEY_get0_group(privECKey);
+ EC_KEY_free(privECKey);
+ // prepare the peer public key
+ auto peerPoint = EC_POINT_new(group);
+ if (peerPoint == nullptr) {
+ NDN_THROW(std::runtime_error("Cannot create the EC_POINT for peer key when calling EC_POINT_new()"));
+ }
+ if (EC_POINT_oct2point(group, peerPoint, peerKey.data(), peerKey.size(), nullptr) == 0) {
+ EC_POINT_free(peerPoint);
+ NDN_THROW(std::runtime_error("Cannot convert peer's key into a EC point when calling EC_POINT_oct2point()"));
+ }
+ EC_KEY* ecPeerkey = EC_KEY_new();
+ if (ecPeerkey == nullptr) {
+ EC_POINT_free(peerPoint);
+ NDN_THROW(std::runtime_error("Cannot create EC_KEY for peer key when calling EC_KEY_new()"));
+ }
+ if (EC_KEY_set_group(ecPeerkey, group) != 1) {
+ EC_POINT_free(peerPoint);
+ NDN_THROW(std::runtime_error("Cannot set group for peer key's EC_KEY when calling EC_KEY_set_group()"));
+ }
+ if (EC_KEY_set_public_key(ecPeerkey, peerPoint) == 0) {
+ EC_KEY_free(ecPeerkey);
+ EC_POINT_free(peerPoint);
+ NDN_THROW(std::runtime_error("Cannot initialize peer EC_KEY with the EC_POINT when calling EC_KEY_set_public_key()"));
+ }
+ EVP_PKEY* evpPeerkey = EVP_PKEY_new();
+ if (EVP_PKEY_set1_EC_KEY(evpPeerkey, ecPeerkey) == 0) {
+ EC_KEY_free(ecPeerkey);
+ EC_POINT_free(peerPoint);
+ NDN_THROW(std::runtime_error("Cannot create EVP_PKEY for peer key when calling EVP_PKEY_new()"));
+ }
+ EC_KEY_free(ecPeerkey);
+ EC_POINT_free(peerPoint);
+ // ECDH context
+ EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new(m_privkey, nullptr);
+ if (ctx == nullptr) {
+ EVP_PKEY_free(evpPeerkey);
+ NDN_THROW(std::runtime_error("Cannot create context for ECDH when calling EVP_PKEY_CTX_new()"));
+ }
+ // Initialize
+ if (1 != EVP_PKEY_derive_init(ctx)) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(evpPeerkey);
+ NDN_THROW(std::runtime_error("Cannot initialize context for ECDH when calling EVP_PKEY_derive_init()"));
+ }
+ // Provide the peer public key
+ if (1 != EVP_PKEY_derive_set_peer(ctx, evpPeerkey)) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(evpPeerkey);
+ NDN_THROW(std::runtime_error("Cannot set peer key for ECDH when calling EVP_PKEY_derive_set_peer()"));
+ }
+ // Determine buffer length for shared secret
+ size_t secretLen = 0;
+ if (1 != EVP_PKEY_derive(ctx, nullptr, &secretLen)) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(evpPeerkey);
+ NDN_THROW(std::runtime_error("Cannot determine the needed buffer length when calling EVP_PKEY_derive()"));
+ }
+ m_secret.resize(secretLen);
+ // Derive the shared secret
+ if (1 != (EVP_PKEY_derive(ctx, m_secret.data(), &secretLen))) {
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(evpPeerkey);
+ NDN_THROW(std::runtime_error("Cannot derive ECDH secret when calling EVP_PKEY_derive()"));
+ }
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(evpPeerkey);
+ return m_secret;
+}
+
+void
+hmacSha256(const uint8_t* data, size_t dataLen,
+ const uint8_t* key, size_t keyLen,
+ uint8_t* result)
+{
+ auto ret = HMAC(EVP_sha256(), key, keyLen,
+ data, dataLen, result, nullptr);
+ if (ret == nullptr) {
+ NDN_THROW(std::runtime_error("Error computing HMAC when calling HMAC()"));
+ }
+}
+
+size_t
+hkdf(const uint8_t* secret, size_t secretLen, const uint8_t* salt,
+ size_t saltLen, uint8_t* output, size_t outputLen,
+ const uint8_t* info, size_t infoLen)
+{
+ EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, nullptr);
+ if (EVP_PKEY_derive_init(pctx) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ NDN_THROW(std::runtime_error("HKDF: Cannot init ctx when calling EVP_PKEY_derive_init()"));
+ }
+ if (EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ NDN_THROW(std::runtime_error("HKDF: Cannot set md when calling EVP_PKEY_CTX_set_hkdf_md()"));
+ }
+ if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, saltLen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ NDN_THROW(std::runtime_error("HKDF: Cannot set salt when calling EVP_PKEY_CTX_set1_hkdf_salt()"));
+ }
+ if (EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secretLen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ NDN_THROW(std::runtime_error("HKDF: Cannot set secret when calling EVP_PKEY_CTX_set1_hkdf_key()"));
+ }
+ if (EVP_PKEY_CTX_add1_hkdf_info(pctx, info, infoLen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ NDN_THROW(std::runtime_error("HKDF: Cannot set info when calling EVP_PKEY_CTX_add1_hkdf_info()"));
+ }
+ size_t outLen = outputLen;
+ if (EVP_PKEY_derive(pctx, output, &outLen) <= 0) {
+ EVP_PKEY_CTX_free(pctx);
+ NDN_THROW(std::runtime_error("HKDF: Cannot derive result when calling EVP_PKEY_derive()"));
+ }
+ EVP_PKEY_CTX_free(pctx);
+ return outLen;
+}
+
+size_t
+aesGcm128Encrypt(const uint8_t* plaintext, size_t plaintextLen, const uint8_t* associated, size_t associatedLen,
+ const uint8_t* key, const uint8_t* iv, uint8_t* ciphertext, uint8_t* tag)
+{
+ EVP_CIPHER_CTX* ctx;
+ int len;
+ size_t ciphertextLen;
+ if (!(ctx = EVP_CIPHER_CTX_new())) {
+ NDN_THROW(std::runtime_error("Cannot create and initialise the context when calling EVP_CIPHER_CTX_new()"));
+ }
+ if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) {
+ EVP_CIPHER_CTX_free(ctx);
+ NDN_THROW(std::runtime_error("Cannot initialize the encryption operation when calling EVP_EncryptInit_ex()"));
+ }
+ if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, nullptr)) {
+ EVP_CIPHER_CTX_free(ctx);
+ NDN_THROW(std::runtime_error("Cannot set IV length when calling EVP_CIPHER_CTX_ctrl()"));
+ }
+ if (1 != EVP_EncryptInit_ex(ctx, nullptr, nullptr, key, iv)) {
+ EVP_CIPHER_CTX_free(ctx);
+ NDN_THROW(std::runtime_error("Cannot initialize key and IV when calling EVP_EncryptInit_ex()"));
+ }
+ if (1 != EVP_EncryptUpdate(ctx, nullptr, &len, associated, associatedLen)) {
+ EVP_CIPHER_CTX_free(ctx);
+ NDN_THROW(std::runtime_error("Cannot set associated authentication data when calling EVP_EncryptUpdate()"));
+ }
+ if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintextLen)) {
+ EVP_CIPHER_CTX_free(ctx);
+ NDN_THROW(std::runtime_error("Cannot encrypt when calling EVP_EncryptUpdate()"));
+ }
+ ciphertextLen = len;
+ if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) {
+ EVP_CIPHER_CTX_free(ctx);
+ NDN_THROW(std::runtime_error("Cannot finalise the encryption when calling EVP_EncryptFinal_ex()"));
+ }
+ ciphertextLen += len;
+ if (1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) {
+ EVP_CIPHER_CTX_free(ctx);
+ NDN_THROW(std::runtime_error("Cannot get tag when calling EVP_CIPHER_CTX_ctrl()"));
+ }
+ EVP_CIPHER_CTX_free(ctx);
+ return ciphertextLen;
+}
+
+size_t
+aesGcm128Decrypt(const uint8_t* ciphertext, size_t ciphertextLen, const uint8_t* associated, size_t associatedLen,
+ const uint8_t* tag, const uint8_t* key, const uint8_t* iv, uint8_t* plaintext)
+{
+ EVP_CIPHER_CTX* ctx;
+ int len;
+ size_t plaintextLen;
+ if (!(ctx = EVP_CIPHER_CTX_new())) {
+ NDN_THROW(std::runtime_error("Cannot create and initialise the context when calling EVP_CIPHER_CTX_new()"));
+ }
+ if (!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) {
+ EVP_CIPHER_CTX_free(ctx);
+ NDN_THROW(std::runtime_error("Cannot initialise the decryption operation when calling EVP_DecryptInit_ex()"));
+ }
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, nullptr)) {
+ EVP_CIPHER_CTX_free(ctx);
+ NDN_THROW(std::runtime_error("Cannot set IV length when calling EVP_CIPHER_CTX_ctrl"));
+ }
+ if (!EVP_DecryptInit_ex(ctx, nullptr, nullptr, key, iv)) {
+ EVP_CIPHER_CTX_free(ctx);
+ NDN_THROW(std::runtime_error("Cannot initialise key and IV when calling EVP_DecryptInit_ex()"));
+ }
+ if (!EVP_DecryptUpdate(ctx, nullptr, &len, associated, associatedLen)) {
+ EVP_CIPHER_CTX_free(ctx);
+ NDN_THROW(std::runtime_error("Cannot set associated authentication data when calling EVP_EncryptUpdate()"));
+ }
+ if (!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertextLen)) {
+ EVP_CIPHER_CTX_free(ctx);
+ NDN_THROW(std::runtime_error("Cannot decrypt when calling EVP_DecryptUpdate()"));
+ }
+ plaintextLen = len;
+ if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, const_cast<void*>(reinterpret_cast<const void*>(tag)))) {
+ EVP_CIPHER_CTX_free(ctx);
+ NDN_THROW(std::runtime_error("Cannot set tag value when calling EVP_CIPHER_CTX_ctrl()"));
+ }
+ auto ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len);
+ EVP_CIPHER_CTX_free(ctx);
+ if (ret > 0) {
+ plaintextLen += len;
+ return plaintextLen;
+ }
+ else {
+ NDN_THROW(std::runtime_error("Cannot finalize the decryption when calling EVP_DecryptFinal_ex()"));
+ }
+}
+
+Block
+encodeBlockWithAesGcm128(uint32_t tlvType, const uint8_t* key, const uint8_t* payload, size_t payloadSize,
+ const uint8_t* associatedData, size_t associatedDataSize, uint32_t& counter)
+{
+ Buffer iv(12);
+ random::generateSecureBytes(iv.data(), 8);
+ if (tlvType == ndn::tlv::ApplicationParameters) {
+ // requester
+ iv[0] &= ~(1UL << 7);
+ }
+ else {
+ // CA
+ iv[0] |= 1UL << 7;
+ }
+ uint32_t temp = boost::endian::native_to_big(counter);
+ std::memcpy(&iv[8], reinterpret_cast<const uint8_t*>(&temp), 4);
+ uint32_t increment = (payloadSize + 15) / 16;
+ if (std::numeric_limits<uint32_t>::max() - counter < increment) {
+ NDN_THROW(std::runtime_error("Error incrementing the AES block counter: "
+ "too many blocks have been encrypted for the same request instance"));
+ }
+ else {
+ counter += increment;
+ }
+
+ // The spec of AES encrypted payload TLV used in NDNCERT:
+ // https://github.com/named-data/ndncert/wiki/NDNCERT-Protocol-0.3#242-aes-gcm-encryption
+ Buffer encryptedPayload(payloadSize);
+ uint8_t tag[16];
+ size_t encryptedPayloadLen = aesGcm128Encrypt(payload, payloadSize, associatedData, associatedDataSize,
+ key, iv.data(), encryptedPayload.data(), tag);
+ auto content = makeEmptyBlock(tlvType);
+ content.push_back(makeBinaryBlock(tlv::InitializationVector, iv.data(), iv.size()));
+ content.push_back(makeBinaryBlock(tlv::AuthenticationTag, tag, 16));
+ content.push_back(makeBinaryBlock(tlv::EncryptedPayload, encryptedPayload.data(), encryptedPayloadLen));
+ content.encode();
+ return content;
+}
+
+Buffer
+decodeBlockWithAesGcm128(const Block& block, const uint8_t* key, const uint8_t* associatedData, size_t associatedDataSize)
+{
+ // The spec of AES encrypted payload TLV used in NDNCERT:
+ // https://github.com/named-data/ndncert/wiki/NDNCERT-Protocol-0.3#242-aes-gcm-encryption
+ block.parse();
+ const auto& encryptedPayloadBlock = block.get(tlv::EncryptedPayload);
+ Buffer result(encryptedPayloadBlock.value_size());
+ auto resultLen = aesGcm128Decrypt(encryptedPayloadBlock.value(), encryptedPayloadBlock.value_size(),
+ associatedData, associatedDataSize, block.get(tlv::AuthenticationTag).value(),
+ key, block.get(tlv::InitializationVector).value(), result.data());
+ if (resultLen != encryptedPayloadBlock.value_size()) {
+ NDN_THROW(std::runtime_error("Error when decrypting the AES Encrypted Block: "
+ "Decrypted payload is of an unexpected size"));
+ }
+ return result;
+}
+
+} // namespace ndncert
+} // namespace ndn
diff --git a/src/detail/crypto-helpers.hpp b/src/detail/crypto-helpers.hpp
new file mode 100644
index 0000000..56446e4
--- /dev/null
+++ b/src/detail/crypto-helpers.hpp
@@ -0,0 +1,173 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#ifndef NDNCERT_DETAIL_CRYPTO_HELPERS_HPP
+#define NDNCERT_DETAIL_CRYPTO_HELPERS_HPP
+
+#include "detail/ndncert-common.hpp"
+#include <openssl/evp.h>
+
+namespace ndn {
+namespace ndncert {
+
+/**
+ * @brief State for ECDH.
+ *
+ * The ECDH is based on prime256v1.
+ */
+class ECDHState : noncopyable
+{
+public:
+ ECDHState();
+ ~ECDHState();
+
+ /**
+ * @brief Derive ECDH secret from peer's EC public key and self's private key.
+ *
+ * @param peerkey Peer's EC public key in the uncompressed octet string format.
+ * See details in https://www.openssl.org/docs/man1.1.1/man3/EC_POINT_point2oct.html.
+ * @return const std::vector<uint8_t>& the derived secret.
+ */
+ const std::vector<uint8_t>&
+ deriveSecret(const std::vector<uint8_t>& peerkey);
+
+ /**
+ * @brief Get the Self Pub Key object
+ *
+ * @return const std::vector<uint8_t>& the Self public key in the uncompressed oct string format.
+ * See details in https://www.openssl.org/docs/man1.1.1/man3/EC_POINT_point2oct.html.
+ */
+ const std::vector<uint8_t>&
+ getSelfPubKey();
+
+private:
+ EVP_PKEY* m_privkey = nullptr;
+ std::vector<uint8_t> m_pubKey;
+ std::vector<uint8_t> m_secret;
+};
+
+/**
+ * @brief HMAC based key derivation function (HKDF).
+ *
+ * @param secret The input to the HKDF.
+ * @param secretLen The length of the secret.
+ * @param salt The salt used in HKDF.
+ * @param saltLen The length of the salt.
+ * @param output The output of the HKDF.
+ * @param outputLen The length of expected output.
+ * @param info The additional information used in HKDF.
+ * @param infoLen The length of the additional information.
+ * @return size_t The length of the derived key if successful.
+ */
+size_t
+hkdf(const uint8_t* secret, size_t secretLen,
+ const uint8_t* salt, size_t saltLen,
+ uint8_t* output, size_t outputLen,
+ const uint8_t* info = nullptr, size_t infoLen = 0);
+
+/**
+ * @brief HMAC based on SHA-256.
+ *
+ * @param data The intput array to hmac.
+ * @param dataLen The length of the input array.
+ * @param key The HMAC key.
+ * @param keyLen The length of the HMAC key.
+ * @param result The result of the HMAC. Enough memory (32 Bytes) must be allocated beforehands.
+ * @throw runtime_error when an error occurred in the underlying HMAC.
+ */
+void
+hmacSha256(const uint8_t* data, size_t dataLen,
+ const uint8_t* key, size_t keyLen,
+ uint8_t* result);
+
+/**
+ * @brief Authenticated GCM 128 Encryption with associated data.
+ *
+ * @param plaintext The plaintext.
+ * @param plaintextLen The size of plaintext.
+ * @param associated The associated authentication data.
+ * @param associatedLen The size of associated authentication data.
+ * @param key 16 bytes AES key.
+ * @param iv 12 bytes IV.
+ * @param ciphertext The output and enough memory must be allocated beforehands.
+ * @param tag 16 bytes tag.
+ * @return size_t The size of ciphertext.
+ * @throw runtime_error When there is an error in the process of encryption.
+ */
+size_t
+aesGcm128Encrypt(const uint8_t* plaintext, size_t plaintextLen, const uint8_t* associated, size_t associatedLen,
+ const uint8_t* key, const uint8_t* iv, uint8_t* ciphertext, uint8_t* tag);
+
+/**
+ * @brief Authenticated GCM 128 Decryption with associated data.
+ *
+ * @param ciphertext The ciphertext.
+ * @param ciphertextLen The size of ciphertext.
+ * @param associated The associated authentication data.
+ * @param associatedLen The size of associated authentication data.
+ * @param tag 16 bytes tag.
+ * @param key 16 bytes AES key.
+ * @param iv 12 bytes IV.
+ * @param plaintext The output and enough memory must be allocated beforehands.
+ * @return size_t The size of plaintext.
+ * @throw runtime_error When there is an error in the process of decryption.
+ */
+size_t
+aesGcm128Decrypt(const uint8_t* ciphertext, size_t ciphertextLen, const uint8_t* associated, size_t associatedLen,
+ const uint8_t* tag, const uint8_t* key, const uint8_t* iv, uint8_t* plaintext);
+
+/**
+ * @brief Encode the payload into TLV block with Authenticated GCM 128 Encryption.
+ *
+ * The TLV spec: https://github.com/named-data/ndncert/wiki/NDNCERT-Protocol-0.3#242-aes-gcm-encryption.
+ *
+ * @param tlv_type The TLV TYPE of the encoded block, either ApplicationParameters or Content.
+ * @param key The AES key used for encryption.
+ * @param payload The plaintext payload.
+ * @param payloadSize The size of the plaintext payload.
+ * @param associatedData The associated data used for authentication.
+ * @param associatedDataSize The size of associated data.
+ * @param counter An opaque counter that must be passed to subsequent invocations of this function
+ * with the same @p key.
+ * @return Block The TLV block with @p tlv_type TLV TYPE.
+ */
+Block
+encodeBlockWithAesGcm128(uint32_t tlvType, const uint8_t* key, const uint8_t* payload, size_t payloadSize,
+ const uint8_t* associatedData, size_t associatedDataSize, uint32_t& counter);
+
+/**
+ * @brief Decode the payload from TLV block with Authenticated GCM 128 Encryption.
+ *
+ * The TLV spec: https://github.com/named-data/ndncert/wiki/NDNCERT-Protocol-0.3#242-aes-gcm-encryption.
+ *
+ * @param block The TLV block in the format of NDNCERT protocol.
+ * @param key The AES key used for encryption.
+ * @param associatedData The associated data used for authentication.
+ * @param associatedDataSize The size of associated data.
+ * @return Buffer The plaintext buffer.
+ */
+Buffer
+decodeBlockWithAesGcm128(const Block& block, const uint8_t* key,
+ const uint8_t* associatedData, size_t associatedDataSize);
+
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDNCERT_DETAIL_CRYPTO_HELPERS_HPP
diff --git a/src/detail/ndncert-common.cpp b/src/detail/ndncert-common.cpp
new file mode 100644
index 0000000..7c210b7
--- /dev/null
+++ b/src/detail/ndncert-common.cpp
@@ -0,0 +1,59 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#include "detail/ndncert-common.hpp"
+
+namespace ndn {
+namespace ndncert {
+
+std::ostream&
+operator<<(std::ostream& out, ErrorCode code)
+{
+ switch (code) {
+ case ErrorCode::NO_ERROR: out << "NO_ERROR"; break;
+ case ErrorCode::BAD_INTEREST_FORMAT: out << "BAD_INTEREST_FORMAT"; break;
+ case ErrorCode::BAD_PARAMETER_FORMAT: out << "BAD_PARAMETER_FORMAT"; break;
+ case ErrorCode::BAD_SIGNATURE: out << "BAD_SIGNATURE"; break;
+ case ErrorCode::INVALID_PARAMETER: out << "INVALID_PARAMETER"; break;
+ case ErrorCode::NAME_NOT_ALLOWED: out << "NAME_NOT_ALLOWED"; break;
+ case ErrorCode::BAD_VALIDITY_PERIOD: out << "BAD_VALIDITY_PERIOD"; break;
+ case ErrorCode::OUT_OF_TRIES: out << "OUT_OF_TRIES"; break;
+ case ErrorCode::OUT_OF_TIME: out << "OUT_OF_TIME"; break;
+ case ErrorCode::NO_AVAILABLE_NAMES: out << "NO_AVAILABLE_NAMES"; break;
+ default: out << "UNKNOWN_ERROR"; break;
+ }
+ return out;
+}
+
+std::ostream&
+operator<<(std::ostream& out, RequestType type)
+{
+ switch (type) {
+ case RequestType::NEW: out << "New"; break;
+ case RequestType::RENEW: out << "Renew"; break;
+ case RequestType::REVOKE: out << "Revoke"; break;
+ case RequestType::NOTINITIALIZED: out << "Not Initialized"; break;
+ default: out << "UNKNOWN_REQUEST_TYPE"; break;
+ }
+ return out;
+}
+
+} // namespace ndncert
+} // namespace ndn
diff --git a/src/detail/ndncert-common.hpp b/src/detail/ndncert-common.hpp
new file mode 100644
index 0000000..77f6ca2
--- /dev/null
+++ b/src/detail/ndncert-common.hpp
@@ -0,0 +1,131 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#ifndef NDNCERT_DETAIL_NDNCERT_COMMON_HPP
+#define NDNCERT_DETAIL_NDNCERT_COMMON_HPP
+
+#include "detail/ndncert-config.hpp"
+
+#ifdef NDNCERT_HAVE_TESTS
+#define NDNCERT_VIRTUAL_WITH_TESTS virtual
+#define NDNCERT_PUBLIC_WITH_TESTS_ELSE_PROTECTED public
+#define NDNCERT_PUBLIC_WITH_TESTS_ELSE_PRIVATE public
+#define NDNCERT_PROTECTED_WITH_TESTS_ELSE_PRIVATE protected
+#else
+#define NDNCERT_VIRTUAL_WITH_TESTS
+#define NDNCERT_PUBLIC_WITH_TESTS_ELSE_PROTECTED protected
+#define NDNCERT_PUBLIC_WITH_TESTS_ELSE_PRIVATE private
+#define NDNCERT_PROTECTED_WITH_TESTS_ELSE_PRIVATE private
+#endif
+
+#include <cstddef>
+#include <cstdint>
+#include <ndn-cxx/data.hpp>
+#include <ndn-cxx/encoding/block-helpers.hpp>
+#include <ndn-cxx/encoding/block.hpp>
+#include <ndn-cxx/encoding/tlv.hpp>
+#include <ndn-cxx/face.hpp>
+#include <ndn-cxx/interest.hpp>
+#include <ndn-cxx/lp/nack.hpp>
+#include <ndn-cxx/name.hpp>
+#include <ndn-cxx/security/certificate.hpp>
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/util/logger.hpp>
+#include <tuple>
+#include <boost/algorithm/string.hpp>
+#include <boost/assert.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/property_tree/info_parser.hpp>
+#include <boost/property_tree/json_parser.hpp>
+#include <boost/property_tree/ptree.hpp>
+
+namespace ndn {
+namespace ndncert {
+
+namespace tlv {
+
+enum : uint32_t {
+ CaPrefix = 129,
+ CaInfo = 131,
+ ParameterKey = 133,
+ ParameterValue = 135,
+ CaCertificate = 137,
+ MaxValidityPeriod = 139,
+ ProbeResponse = 141,
+ MaxSuffixLength = 143,
+ EcdhPub = 145,
+ CertRequest = 147,
+ Salt = 149,
+ RequestId = 151,
+ Challenge = 153,
+ Status = 155,
+ InitializationVector = 157,
+ EncryptedPayload = 159,
+ SelectedChallenge = 161,
+ ChallengeStatus = 163,
+ RemainingTries = 165,
+ RemainingTime = 167,
+ IssuedCertName = 169,
+ ErrorCode = 171,
+ ErrorInfo = 173,
+ AuthenticationTag = 175,
+ CertToRevoke = 177,
+ ProbeRedirect = 179
+};
+
+} // namespace tlv
+
+using boost::noncopyable;
+typedef boost::property_tree::ptree JsonSection;
+
+// NDNCERT error code
+enum class ErrorCode : uint64_t {
+ NO_ERROR = 0,
+ BAD_INTEREST_FORMAT = 1,
+ BAD_PARAMETER_FORMAT = 2,
+ BAD_SIGNATURE = 3,
+ INVALID_PARAMETER = 4,
+ NAME_NOT_ALLOWED = 5,
+ BAD_VALIDITY_PERIOD = 6,
+ OUT_OF_TRIES = 7,
+ OUT_OF_TIME = 8,
+ NO_AVAILABLE_NAMES = 9
+};
+
+// Convert error code to string
+std::ostream&
+operator<<(std::ostream& os, ErrorCode code);
+
+// NDNCERT request type
+enum class RequestType : uint64_t {
+ NOTINITIALIZED = 0,
+ NEW = 1,
+ RENEW = 2,
+ REVOKE = 3
+};
+
+// Convert request type to string
+std::ostream&
+operator<<(std::ostream& out, RequestType type);
+
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDNCERT_DETAIL_NDNCERT_COMMON_HPP
diff --git a/tests/boost-test.hpp b/tests/boost-test.hpp
new file mode 100644
index 0000000..419b01e
--- /dev/null
+++ b/tests/boost-test.hpp
@@ -0,0 +1,38 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2020, 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, originally written as part of NFD (Named Data Networking Forwarding Daemon),
+ * is a part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#ifndef NDNCERT_TESTS_BOOST_TEST_HPP
+#define NDNCERT_TESTS_BOOST_TEST_HPP
+
+// suppress warnings from Boost.Test
+#pragma GCC system_header
+#pragma clang system_header
+
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+
+#endif // NDNCERT_TESTS_BOOST_TEST_HPP
diff --git a/tests/database-fixture.hpp b/tests/database-fixture.hpp
new file mode 100644
index 0000000..598e304
--- /dev/null
+++ b/tests/database-fixture.hpp
@@ -0,0 +1,63 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2020 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDNCERT_TESTS_DATABASE_FIXTURE_HPP
+#define NDNCERT_TESTS_DATABASE_FIXTURE_HPP
+
+#include "identity-management-fixture.hpp"
+#include "unit-test-time-fixture.hpp"
+#include <boost/filesystem.hpp>
+
+namespace ndn {
+namespace ndncert {
+namespace tests {
+
+class IdentityManagementTimeFixture : public UnitTestTimeFixture
+ , public IdentityManagementFixture
+{
+};
+
+class DatabaseFixture : public IdentityManagementTimeFixture
+{
+public:
+ DatabaseFixture()
+ {
+ boost::filesystem::path parentDir{TMP_TESTS_PATH};
+ dbDir = parentDir / "test-home" / ".ndncert";
+ if (!boost::filesystem::exists(dbDir)) {
+ boost::filesystem::create_directory(dbDir);
+ }
+ }
+
+ ~DatabaseFixture()
+ {
+ boost::filesystem::remove_all(dbDir);
+ }
+
+protected:
+ boost::filesystem::path dbDir;
+};
+
+} // namespace tests
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDNCERT_TESTS_DATABASE_FIXTURE_HPP
diff --git a/tests/global-configuration.cpp b/tests/global-configuration.cpp
new file mode 100644
index 0000000..61d0cbd
--- /dev/null
+++ b/tests/global-configuration.cpp
@@ -0,0 +1,69 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#include "boost-test.hpp"
+#include <boost/filesystem.hpp>
+#include <fstream>
+#include <stdlib.h>
+
+namespace ndn {
+namespace ndncert {
+namespace tests {
+
+class GlobalConfiguration
+{
+public:
+ GlobalConfiguration()
+ {
+ const char* envHome = ::getenv("HOME");
+ if (envHome)
+ m_home = envHome;
+
+ boost::filesystem::path dir{TMP_TESTS_PATH};
+ dir /= "test-home";
+ ::setenv("HOME", dir.c_str(), 1);
+
+ boost::filesystem::create_directories(dir);
+ std::ofstream clientConf((dir / ".ndn" / "client.conf").c_str());
+ clientConf << "pib=pib-sqlite3" << std::endl
+ << "tpm=tpm-file" << std::endl;
+ }
+
+ ~GlobalConfiguration()
+ {
+ if (!m_home.empty())
+ ::setenv("HOME", m_home.data(), 1);
+ }
+
+private:
+ std::string m_home;
+};
+
+#if BOOST_VERSION >= 106500
+BOOST_TEST_GLOBAL_CONFIGURATION(GlobalConfiguration);
+#elif BOOST_VERSION >= 105900
+BOOST_GLOBAL_FIXTURE(GlobalConfiguration);
+#else
+BOOST_GLOBAL_FIXTURE(GlobalConfiguration)
+#endif
+
+} // namespace tests
+} // namespace ndncert
+} // namespace ndn
\ No newline at end of file
diff --git a/tests/identity-management-fixture.cpp b/tests/identity-management-fixture.cpp
new file mode 100644
index 0000000..8ca0545
--- /dev/null
+++ b/tests/identity-management-fixture.cpp
@@ -0,0 +1,131 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2020 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#include "identity-management-fixture.hpp"
+#include <ndn-cxx/security/additional-description.hpp>
+#include <ndn-cxx/util/io.hpp>
+#include <boost/filesystem.hpp>
+
+namespace ndn {
+namespace ndncert {
+namespace tests {
+
+namespace v2 = security::v2;
+
+IdentityManagementBaseFixture::~IdentityManagementBaseFixture()
+{
+ boost::system::error_code ec;
+ for (const auto& certFile : m_certFiles) {
+ boost::filesystem::remove(certFile, ec); // ignore error
+ }
+}
+
+bool
+IdentityManagementBaseFixture::saveCertToFile(const Data& obj, const std::string& filename)
+{
+ m_certFiles.insert(filename);
+ try {
+ io::save(obj, filename);
+ return true;
+ }
+ catch (const io::Error&) {
+ return false;
+ }
+}
+
+IdentityManagementFixture::IdentityManagementFixture()
+ : m_keyChain("pib-memory:", "tpm-memory:")
+{
+}
+
+security::Identity
+IdentityManagementFixture::addIdentity(const Name& identityName, const KeyParams& params)
+{
+ auto identity = m_keyChain.createIdentity(identityName, params);
+ m_identities.insert(identityName);
+ return identity;
+}
+
+bool
+IdentityManagementFixture::saveCertificate(const security::Identity& identity, const std::string& filename)
+{
+ try {
+ auto cert = identity.getDefaultKey().getDefaultCertificate();
+ return saveCertToFile(cert, filename);
+ }
+ catch (const security::Pib::Error&) {
+ return false;
+ }
+}
+
+security::Identity
+IdentityManagementFixture::addSubCertificate(const Name& subIdentityName,
+ const security::Identity& issuer, const KeyParams& params)
+{
+ auto subIdentity = addIdentity(subIdentityName, params);
+
+ v2::Certificate request = subIdentity.getDefaultKey().getDefaultCertificate();
+
+ request.setName(request.getKeyName().append("parent").appendVersion());
+
+ SignatureInfo info;
+ auto now = time::system_clock::now();
+ info.setValidityPeriod(security::ValidityPeriod(now, now + 7300_days));
+
+ v2::AdditionalDescription description;
+ description.set("type", "sub-certificate");
+ info.addCustomTlv(description.wireEncode());
+
+ m_keyChain.sign(request, signingByIdentity(issuer).setSignatureInfo(info));
+ m_keyChain.setDefaultCertificate(subIdentity.getDefaultKey(), request);
+
+ return subIdentity;
+}
+
+v2::Certificate
+IdentityManagementFixture::addCertificate(const security::Key& key, const std::string& issuer)
+{
+ Name certificateName = key.getName();
+ certificateName
+ .append(issuer)
+ .appendVersion();
+ v2::Certificate certificate;
+ certificate.setName(certificateName);
+
+ // set metainfo
+ certificate.setContentType(ndn::tlv::ContentType_Key);
+ certificate.setFreshnessPeriod(1_h);
+
+ // set content
+ certificate.setContent(key.getPublicKey().data(), key.getPublicKey().size());
+
+ // set signature-info
+ SignatureInfo info;
+ auto now = time::system_clock::now();
+ info.setValidityPeriod(security::ValidityPeriod(now, now + 10_days));
+
+ m_keyChain.sign(certificate, signingByKey(key).setSignatureInfo(info));
+ return certificate;
+}
+
+} // namespace tests
+} // namespace ndncert
+} // namespace ndn
diff --git a/tests/identity-management-fixture.hpp b/tests/identity-management-fixture.hpp
new file mode 100644
index 0000000..9b10dbf
--- /dev/null
+++ b/tests/identity-management-fixture.hpp
@@ -0,0 +1,101 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2020 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_TESTS_IDENTITY_MANAGEMENT_FIXTURE_HPP
+#define NDN_TESTS_IDENTITY_MANAGEMENT_FIXTURE_HPP
+
+#include <ndn-cxx/security/key-chain.hpp>
+#include <ndn-cxx/security/signing-helpers.hpp>
+#include <vector>
+
+namespace ndn {
+namespace ndncert {
+namespace tests {
+
+class IdentityManagementBaseFixture
+{
+public:
+ ~IdentityManagementBaseFixture();
+
+ bool
+ saveCertToFile(const Data& obj, const std::string& filename);
+
+protected:
+ std::set<Name> m_identities;
+ std::set<std::string> m_certFiles;
+};
+
+/**
+ * @brief A test suite level fixture to help with identity management
+ *
+ * Test cases in the suite can use this fixture to create identities. Identities,
+ * certificates, and saved certificates are automatically removed during test teardown.
+ */
+class IdentityManagementFixture : public IdentityManagementBaseFixture
+{
+public:
+ IdentityManagementFixture();
+
+ /**
+ * @brief Add identity @p identityName
+ * @return name of the created self-signed certificate
+ */
+ security::Identity
+ addIdentity(const Name& identityName,
+ const KeyParams& params = security::KeyChain::getDefaultKeyParams());
+
+ /**
+ * @brief Save identity certificate to a file
+ * @param identity identity
+ * @param filename file name, should be writable
+ * @return whether successful
+ */
+ bool
+ saveCertificate(const security::Identity& identity, const std::string& filename);
+
+ /**
+ * @brief Issue a certificate for \p subIdentityName signed by \p issuer
+ *
+ * If identity does not exist, it is created.
+ * A new key is generated as the default key for identity.
+ * A default certificate for the key is signed by the issuer using its default certificate.
+ *
+ * @return the sub identity
+ */
+ security::Identity
+ addSubCertificate(const Name& subIdentityName, const security::Identity& issuer,
+ const KeyParams& params = security::KeyChain::getDefaultKeyParams());
+
+ /**
+ * @brief Add a self-signed certificate to @p key with issuer ID @p issuer
+ */
+ security::Certificate
+ addCertificate(const security::Key& key, const std::string& issuer);
+
+protected:
+ KeyChain m_keyChain;
+};
+
+} // namespace tests
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDN_TESTS_IDENTITY_MANAGEMENT_FIXTURE_HPP
diff --git a/tests/main.cpp b/tests/main.cpp
new file mode 100644
index 0000000..779d74a
--- /dev/null
+++ b/tests/main.cpp
@@ -0,0 +1,29 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2014-2020, 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, originally written as part of NFD (Named Data Networking Forwarding Daemon),
+ * is a part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#define BOOST_TEST_MODULE ndncert
+#include "boost-test.hpp"
\ No newline at end of file
diff --git a/tests/test-common.hpp b/tests/test-common.hpp
new file mode 100644
index 0000000..68cccc2
--- /dev/null
+++ b/tests/test-common.hpp
@@ -0,0 +1,38 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2020 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDNCERT_TESTS_TEST_COMMON_HPP
+#define NDNCERT_TESTS_TEST_COMMON_HPP
+
+#include "boost-test.hpp"
+#include "database-fixture.hpp"
+#include "identity-management-fixture.hpp"
+#include "unit-test-time-fixture.hpp"
+#include <ndn-cxx/metadata-object.hpp>
+#include <ndn-cxx/security/signing-helpers.hpp>
+#include <ndn-cxx/security/transform/base64-encode.hpp>
+#include <ndn-cxx/security/transform/buffer-source.hpp>
+#include <ndn-cxx/security/transform/public-key.hpp>
+#include <ndn-cxx/security/transform/stream-sink.hpp>
+#include <ndn-cxx/security/verification-helpers.hpp>
+#include <ndn-cxx/util/dummy-client-face.hpp>
+
+#endif // NDNCERT_TESTS_TEST_COMMON_HPP
diff --git a/tests/unit-test-time-fixture.hpp b/tests/unit-test-time-fixture.hpp
new file mode 100644
index 0000000..cebce38
--- /dev/null
+++ b/tests/unit-test-time-fixture.hpp
@@ -0,0 +1,107 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2013-2020 Regents of the University of California.
+ *
+ * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
+ *
+ * ndn-cxx library is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * ndn-cxx library 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 Lesser General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License and GNU Lesser
+ * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
+ */
+
+#ifndef NDN_TESTS_UNIT_UNIT_TEST_TIME_FIXTURE_HPP
+#define NDN_TESTS_UNIT_UNIT_TEST_TIME_FIXTURE_HPP
+
+#include <ndn-cxx/util/time-unit-test-clock.hpp>
+#include <boost/asio/io_service.hpp>
+
+namespace ndn {
+namespace ndncert {
+namespace tests {
+
+/** \brief a test fixture that overrides steady clock and system clock
+ */
+class UnitTestTimeFixture
+{
+public:
+ UnitTestTimeFixture()
+ : steadyClock(make_shared<time::UnitTestSteadyClock>())
+ , systemClock(make_shared<time::UnitTestSystemClock>())
+ {
+ time::setCustomClocks(steadyClock, systemClock);
+ }
+
+ ~UnitTestTimeFixture()
+ {
+ time::setCustomClocks(nullptr, nullptr);
+ }
+
+ /** \brief advance steady and system clocks
+ *
+ * Clocks are advanced in increments of \p tick for \p nTicks ticks.
+ * After each tick, io_service is polled to process pending I/O events.
+ *
+ * Exceptions thrown during I/O events are propagated to the caller.
+ * Clock advancing would stop in case of an exception.
+ */
+ void
+ advanceClocks(const time::nanoseconds& tick, size_t nTicks = 1)
+ {
+ this->advanceClocks(tick, tick * nTicks);
+ }
+
+ /** \brief advance steady and system clocks
+ *
+ * Clocks are advanced in increments of \p tick for \p total time.
+ * The last increment might be shorter than \p tick.
+ * After each tick, io_service is polled to process pending I/O events.
+ *
+ * Exceptions thrown during I/O events are propagated to the caller.
+ * Clock advancing would stop in case of an exception.
+ */
+ void
+ advanceClocks(const time::nanoseconds& tick, const time::nanoseconds& total)
+ {
+ BOOST_ASSERT(tick > time::nanoseconds::zero());
+ BOOST_ASSERT(total >= time::nanoseconds::zero());
+
+ time::nanoseconds remaining = total;
+ while (remaining > time::nanoseconds::zero()) {
+ if (remaining >= tick) {
+ steadyClock->advance(tick);
+ systemClock->advance(tick);
+ remaining -= tick;
+ }
+ else {
+ steadyClock->advance(remaining);
+ systemClock->advance(remaining);
+ remaining = time::nanoseconds::zero();
+ }
+
+ if (io.stopped())
+ io.reset();
+ io.poll();
+ }
+ }
+
+public:
+ shared_ptr<time::UnitTestSteadyClock> steadyClock;
+ shared_ptr<time::UnitTestSystemClock> systemClock;
+ boost::asio::io_service io;
+};
+
+} // namespace tests
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDN_TESTS_UNIT_UNIT_TEST_TIME_FIXTURE_HPP
diff --git a/tests/unit-tests/crypto-helpers.t.cpp b/tests/unit-tests/crypto-helpers.t.cpp
new file mode 100644
index 0000000..5f29a03
--- /dev/null
+++ b/tests/unit-tests/crypto-helpers.t.cpp
@@ -0,0 +1,334 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2017-2020, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert 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.
+ *
+ * ndncert 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 copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#include "detail/crypto-helpers.hpp"
+#include "test-common.hpp"
+
+namespace ndn {
+namespace ndncert {
+namespace tests {
+
+BOOST_AUTO_TEST_SUITE(TestCryptoHelpers)
+
+BOOST_AUTO_TEST_CASE(EcdhWithRawKey)
+{
+ ECDHState aliceState;
+ auto alicePub = aliceState.getSelfPubKey();
+ BOOST_CHECK(!alicePub.empty());
+
+ ECDHState bobState;
+ auto bobPub = bobState.getSelfPubKey();
+ BOOST_CHECK(!bobPub.empty());
+
+ auto aliceResult = aliceState.deriveSecret(bobPub);
+ BOOST_CHECK(!aliceResult.empty());
+ auto bobResult = bobState.deriveSecret(alicePub);
+ BOOST_CHECK(!bobResult.empty());
+ BOOST_CHECK_EQUAL_COLLECTIONS(aliceResult.begin(), aliceResult.end(), bobResult.begin(), bobResult.end());
+}
+
+BOOST_AUTO_TEST_CASE(EcdhWithRawKeyWrongInput)
+{
+ ECDHState aliceState;
+ auto alicePub = aliceState.getSelfPubKey();
+ BOOST_CHECK(!alicePub.empty());
+ std::vector<uint8_t> fakePub(10, 0x0b);
+ BOOST_CHECK_THROW(aliceState.deriveSecret(fakePub), std::runtime_error);
+}
+
+BOOST_AUTO_TEST_CASE(HmacSha256)
+{
+ const uint8_t input[] = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b};
+ const uint8_t key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c};
+ const uint8_t expected[] = {0x07, 0x77, 0x09, 0x36, 0x2c, 0x2e, 0x32, 0xdf,
+ 0x0d, 0xdc, 0x3f, 0x0d, 0xc4, 0x7b, 0xba, 0x63,
+ 0x90, 0xb6, 0xc7, 0x3b, 0xb5, 0x0f, 0x9c, 0x31,
+ 0x22, 0xec, 0x84, 0x4a, 0xd7, 0xc2, 0xb3, 0xe5};
+ uint8_t result[32];
+ hmacSha256(input, sizeof(input), key, sizeof(key), result);
+ BOOST_CHECK_EQUAL_COLLECTIONS(result, result + sizeof(result), expected,
+ expected + sizeof(expected));
+}
+
+BOOST_AUTO_TEST_CASE(Hkdf1)
+{
+ // RFC5869 appendix A.1
+ const uint8_t ikm[] = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b};
+ const uint8_t salt[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c};
+ const uint8_t info[] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4,
+ 0xf5, 0xf6, 0xf7, 0xf8, 0xf9};
+ const uint8_t expected[] = {
+ 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f,
+ 0x64, 0xd0, 0x36, 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a,
+ 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, 0x34,
+ 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65};
+ uint8_t result[42];
+ auto resultLen = hkdf(ikm, sizeof(ikm), salt, sizeof(salt), result,
+ sizeof(result), info, sizeof(info));
+
+ BOOST_CHECK_EQUAL(resultLen, sizeof(result));
+ BOOST_CHECK_EQUAL_COLLECTIONS(result, result + sizeof(result), expected,
+ expected + sizeof(expected));
+}
+
+BOOST_AUTO_TEST_CASE(Hkdf2)
+{
+ // RFC5869 appendix A.2
+ const uint8_t ikm[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f};
+ const uint8_t salt[] = {
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
+ 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
+ 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
+ 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf};
+ const uint8_t info[] = {
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb,
+ 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3,
+ 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb,
+ 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff};
+ const uint8_t expected[] = {
+ 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c,
+ 0x59, 0x6a, 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8,
+ 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99,
+ 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09,
+ 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, 0x36, 0x77, 0x93, 0xa9,
+ 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87,
+ 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87};
+
+ uint8_t result[82];
+ auto resultLen = hkdf(ikm, sizeof(ikm), salt, sizeof(salt), result,
+ sizeof(result), info, sizeof(info));
+
+ BOOST_CHECK_EQUAL(resultLen, sizeof(result));
+ BOOST_CHECK_EQUAL_COLLECTIONS(result, result + sizeof(result), expected,
+ expected + sizeof(expected));
+}
+
+BOOST_AUTO_TEST_CASE(Hkdf3)
+{
+ // RFC5869 appendix A.3
+ const uint8_t ikm[] = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b};
+ const uint8_t expected[] = {
+ 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, 0x80,
+ 0x2a, 0x06, 0x3c, 0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1,
+ 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, 0x9d,
+ 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8};
+ uint8_t result[42];
+
+ auto resultLen = hkdf(ikm, sizeof(ikm), nullptr, 0, result,
+ sizeof(result), nullptr, 0);
+
+ BOOST_CHECK_EQUAL(resultLen, sizeof(result));
+ BOOST_CHECK_EQUAL_COLLECTIONS(result, result + sizeof(result), expected,
+ expected + sizeof(expected));
+}
+
+BOOST_AUTO_TEST_CASE(AesGcm1)
+{
+ // Test case from NIST Cryptographic Algorithm Validation Program
+ // https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/CAVP-TESTING-BLOCK-CIPHER-MODES
+ // Count = 0
+ // Key = cf063a34d4a9a76c2c86787d3f96db71
+ // IV = 113b9785971864c83b01c787
+ // CT =
+ // AAD =
+ // Tag = 72ac8493e3a5228b5d130a69d2510e42
+ // PT =
+ const uint8_t key[] = {0xcf, 0x06, 0x3a, 0x34, 0xd4, 0xa9, 0xa7, 0x6c,
+ 0x2c, 0x86, 0x78, 0x7d, 0x3f, 0x96, 0xdb, 0x71};
+ const uint8_t iv[] = {0x11, 0x3b, 0x97, 0x85, 0x97, 0x18,
+ 0x64, 0xc8, 0x3b, 0x01, 0xc7, 0x87};
+ const uint8_t expected_tag[] = {0x72, 0xac, 0x84, 0x93, 0xe3, 0xa5,
+ 0x22, 0x8b, 0x5d, 0x13, 0x0a, 0x69,
+ 0xd2, 0x51, 0x0e, 0x42};
+
+ uint8_t ciphertext[256] = {0};
+ uint8_t tag[16] = {0};
+ const uint8_t empty_buffer[1] = {0};
+ int size = aesGcm128Encrypt(empty_buffer, 0, empty_buffer, 0, key, iv, ciphertext, tag);
+ BOOST_CHECK(size == 0);
+ BOOST_CHECK_EQUAL_COLLECTIONS(tag, tag + 16, expected_tag, expected_tag + sizeof(expected_tag));
+
+ uint8_t decrypted[256] = {0};
+ size = aesGcm128Decrypt(ciphertext, size, empty_buffer, 0, tag, key, iv, decrypted);
+ BOOST_CHECK(size == 0);
+}
+
+BOOST_AUTO_TEST_CASE(AesGcm2)
+{
+ // Test case from NIST Cryptographic Algorithm Validation Program
+ // https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/CAVP-TESTING-BLOCK-CIPHER-MODES
+ // Count = 1
+ // Key = 2370e320d4344208e0ff5683f243b213
+ // IV = 04dbb82f044d30831c441228
+ // CT =
+ // AAD = d43a8e5089eea0d026c03a85178b27da
+ // Tag = 2a049c049d25aa95969b451d93c31c6e
+ // PT =
+ const uint8_t key[] = {0x23, 0x70, 0xe3, 0x20, 0xd4, 0x34, 0x42, 0x08,
+ 0xe0, 0xff, 0x56, 0x83, 0xf2, 0x43, 0xb2, 0x13};
+ const uint8_t iv[] = {0x04, 0xdb, 0xb8, 0x2f, 0x04, 0x4d,
+ 0x30, 0x83, 0x1c, 0x44, 0x12, 0x28};
+ const uint8_t aad[] = {0xd4, 0x3a, 0x8e, 0x50, 0x89, 0xee, 0xa0, 0xd0,
+ 0x26, 0xc0, 0x3a, 0x85, 0x17, 0x8b, 0x27, 0xda};
+ const uint8_t expected_tag[] = {0x2a, 0x04, 0x9c, 0x04, 0x9d, 0x25,
+ 0xaa, 0x95, 0x96, 0x9b, 0x45, 0x1d,
+ 0x93, 0xc3, 0x1c, 0x6e};
+
+ uint8_t ciphertext[256] = {0};
+ uint8_t tag[16] = {0};
+ const uint8_t empty_buffer[1] = {0};
+ int size = aesGcm128Encrypt(empty_buffer, 0, aad, sizeof(aad), key, iv, ciphertext, tag);
+ BOOST_CHECK(size == 0);
+ BOOST_CHECK_EQUAL_COLLECTIONS(tag, tag + 16, expected_tag, expected_tag + sizeof(expected_tag));
+
+ uint8_t decrypted[256] = {0};
+ size = aesGcm128Decrypt(ciphertext, size, aad, sizeof(aad), tag, key, iv, decrypted);
+ BOOST_CHECK(size == 0);
+}
+
+BOOST_AUTO_TEST_CASE(AesGcm3)
+{
+ // Test case from NIST Cryptographic Algorithm Validation Program
+ // https://csrc.nist.gov/Projects/cryptographic-algorithm-validation-program/CAVP-TESTING-BLOCK-CIPHER-MODES
+ // Count = 0
+ // Key = bc22f3f05cc40db9311e4192966fee92
+ // IV = 134988e662343c06d3ab83db
+ // CT = 4c0168ab95d3a10ef25e5924108389365c67d97778995892d9fd46897384af61fc559212b3267e90fe4df7bfd1fbed46f4b9ee
+ // AAD = 10087e6ed81049b509c31d12fee88c64
+ // Tag = 771357958a316f166bd0dacc98ea801a
+ // PT = 337c1bc992386cf0f957617fe4d5ec1218ae1cc40369305518eb177e9b15c1646b142ff71237efaa58790080cd82e8848b295c
+ const uint8_t key[] = {0xbc, 0x22, 0xf3, 0xf0, 0x5c, 0xc4, 0x0d, 0xb9,
+ 0x31, 0x1e, 0x41, 0x92, 0x96, 0x6f, 0xee, 0x92};
+ const uint8_t iv[] = {0x13, 0x49, 0x88, 0xe6, 0x62, 0x34,
+ 0x3c, 0x06, 0xd3, 0xab, 0x83, 0xdb};
+ const uint8_t aad[] = {0x10, 0x08, 0x7e, 0x6e, 0xd8, 0x10, 0x49, 0xb5,
+ 0x09, 0xc3, 0x1d, 0x12, 0xfe, 0xe8, 0x8c, 0x64};
+ const uint8_t expected_ciphertext[] = {
+ 0x4c, 0x01, 0x68, 0xab, 0x95, 0xd3, 0xa1, 0x0e, 0xf2, 0x5e, 0x59,
+ 0x24, 0x10, 0x83, 0x89, 0x36, 0x5c, 0x67, 0xd9, 0x77, 0x78, 0x99,
+ 0x58, 0x92, 0xd9, 0xfd, 0x46, 0x89, 0x73, 0x84, 0xaf, 0x61, 0xfc,
+ 0x55, 0x92, 0x12, 0xb3, 0x26, 0x7e, 0x90, 0xfe, 0x4d, 0xf7, 0xbf,
+ 0xd1, 0xfb, 0xed, 0x46, 0xf4, 0xb9, 0xee};
+ const uint8_t expected_tag[] = {0x77, 0x13, 0x57, 0x95, 0x8a, 0x31,
+ 0x6f, 0x16, 0x6b, 0xd0, 0xda, 0xcc,
+ 0x98, 0xea, 0x80, 0x1a};
+ const uint8_t plaintext[] = {
+ 0x33, 0x7c, 0x1b, 0xc9, 0x92, 0x38, 0x6c, 0xf0, 0xf9, 0x57, 0x61,
+ 0x7f, 0xe4, 0xd5, 0xec, 0x12, 0x18, 0xae, 0x1c, 0xc4, 0x03, 0x69,
+ 0x30, 0x55, 0x18, 0xeb, 0x17, 0x7e, 0x9b, 0x15, 0xc1, 0x64, 0x6b,
+ 0x14, 0x2f, 0xf7, 0x12, 0x37, 0xef, 0xaa, 0x58, 0x79, 0x00, 0x80,
+ 0xcd, 0x82, 0xe8, 0x84, 0x8b, 0x29, 0x5c};
+
+ uint8_t ciphertext[256] = {0};
+ uint8_t tag[16] = {0};
+ int size = aesGcm128Encrypt(plaintext, sizeof(plaintext), aad, sizeof(aad), key, iv, ciphertext, tag);
+ BOOST_CHECK_EQUAL_COLLECTIONS(ciphertext, ciphertext + size,
+ expected_ciphertext, expected_ciphertext + sizeof(expected_ciphertext));
+ BOOST_CHECK_EQUAL_COLLECTIONS(tag, tag + 16, expected_tag, expected_tag + sizeof(expected_tag));
+
+ uint8_t decrypted[256] = {0};
+ size = aesGcm128Decrypt(ciphertext, size, aad, sizeof(aad), tag, key, iv, decrypted);
+ BOOST_CHECK_EQUAL_COLLECTIONS(decrypted, decrypted + size,
+ plaintext, plaintext + sizeof(plaintext));
+}
+
+BOOST_AUTO_TEST_CASE(AesIV)
+{
+ const uint8_t key[] = {0xbc, 0x22, 0xf3, 0xf0, 0x5c, 0xc4, 0x0d, 0xb9,
+ 0x31, 0x1e, 0x41, 0x92, 0x96, 0x6f, 0xee, 0x92};
+ const std::string plaintext = "alongstringalongstringalongstringalongstringalongstringalongstringalongstringalongstring";
+ const std::string associatedData = "test";
+ uint32_t counter = 0;
+ auto block = encodeBlockWithAesGcm128(ndn::tlv::Content, key, (uint8_t*)plaintext.c_str(), plaintext.size(),
+ (uint8_t*)associatedData.c_str(), associatedData.size(), counter);
+ block.parse();
+ auto ivBlock = block.get(tlv::InitializationVector);
+ Buffer ivBuf(ivBlock.value(), ivBlock.value_size());
+ BOOST_CHECK_EQUAL(ivBuf.size(), 12);
+ BOOST_CHECK(ivBuf[0] >= 128);
+ BOOST_CHECK_EQUAL(ivBuf[8] + ivBuf[9] + ivBuf[10] + ivBuf[11], 0);
+ BOOST_CHECK_EQUAL(counter, 6);
+ counter = 300;
+ block = encodeBlockWithAesGcm128(ndn::tlv::ApplicationParameters, key, (uint8_t*)plaintext.c_str(), plaintext.size(),
+ (uint8_t*)associatedData.c_str(), associatedData.size(), counter);
+ block.parse();
+ ivBlock = block.get(tlv::InitializationVector);
+ Buffer ivBuf2(ivBlock.value(), ivBlock.value_size());
+ BOOST_CHECK_EQUAL(ivBuf2.size(), 12);
+ BOOST_CHECK(ivBuf2[0] < 128);
+ BOOST_CHECK_EQUAL(ivBuf2[8] + ivBuf2[9], 0);
+ BOOST_CHECK_EQUAL(ivBuf2[10], 1);
+ BOOST_CHECK_EQUAL(ivBuf2[11], 44);
+ BOOST_CHECK_EQUAL(counter, 306);
+}
+
+BOOST_AUTO_TEST_CASE(BlockEncodingDecoding)
+{
+ const uint8_t key[] = {0xbc, 0x22, 0xf3, 0xf0, 0x5c, 0xc4, 0x0d, 0xb9,
+ 0x31, 0x1e, 0x41, 0x92, 0x96, 0x6f, 0xee, 0x92};
+ const std::string plaintext = "alongstringalongstringalongstringalongstringalongstringalongstringalongstringalongstring";
+ const std::string plaintext2 = "shortstring";
+ const std::string associatedData = "right";
+ const std::string wrongAssociatedData = "wrong";
+ uint32_t counter = 0;
+ // long string encryption
+ auto block = encodeBlockWithAesGcm128(ndn::tlv::Content, key, (uint8_t*)plaintext.c_str(), plaintext.size(),
+ (uint8_t*)associatedData.c_str(), associatedData.size(), counter);
+ auto decoded = decodeBlockWithAesGcm128(block, key, (uint8_t*)associatedData.c_str(), associatedData.size());
+ BOOST_CHECK_EQUAL(plaintext, std::string(decoded.get<char>(), decoded.size()));
+
+ // short string encryption
+ block = encodeBlockWithAesGcm128(ndn::tlv::Content, key, (uint8_t*)plaintext2.c_str(), plaintext2.size(),
+ (uint8_t*)associatedData.c_str(), associatedData.size(), counter);
+ decoded = decodeBlockWithAesGcm128(block, key, (uint8_t*)associatedData.c_str(), associatedData.size());
+ BOOST_CHECK_EQUAL(plaintext2, std::string(decoded.get<char>(), decoded.size()));
+
+ // use wrong associated data
+ BOOST_CHECK_THROW(decodeBlockWithAesGcm128(block, key,
+ (uint8_t*)wrongAssociatedData.c_str(),
+ wrongAssociatedData.size()), std::runtime_error);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+} // namespace tests
+} // namespace ndncert
+} // namespace ndn
diff --git a/tests/wscript b/tests/wscript
new file mode 100644
index 0000000..87151bd
--- /dev/null
+++ b/tests/wscript
@@ -0,0 +1,17 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+top = '..'
+
+def build(bld):
+ if not bld.env.WITH_TESTS:
+ return
+
+ tmp_path = 'TMP_TESTS_PATH="%s"' % bld.bldnode.make_node('tmp-tests')
+
+ bld.program(
+ target='../unit-tests',
+ name='unit-tests',
+ source=bld.path.ant_glob(['*.cpp', 'unit-tests/**/*.cpp']),
+ use='ndn-cert BOOST',
+ includes='.',
+ defines=[tmp_path],
+ install_path=None)
diff --git a/waf b/waf
new file mode 100755
index 0000000..a1c5c96
--- /dev/null
+++ b/waf
@@ -0,0 +1,173 @@
+#!/usr/bin/env python3
+# encoding: latin-1
+# Thomas Nagy, 2005-2018
+#
+"""
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+"""
+
+import os, sys, inspect
+
+VERSION="2.0.19"
+REVISION="1f3c580272b15a03d2566843c5fe872a"
+GIT="61ee22b598cf80e260beb64e475966f58b304d0d"
+INSTALL=''
+C1='#6'
+C2='#.'
+C3='#%'
+cwd = os.getcwd()
+join = os.path.join
+
+
+WAF='waf'
+def b(x):
+ return x
+if sys.hexversion>0x300000f:
+ WAF='waf3'
+ def b(x):
+ return x.encode()
+
+def err(m):
+ print(('\033[91mError: %s\033[0m' % m))
+ sys.exit(1)
+
+def unpack_wafdir(dir, src):
+ f = open(src,'rb')
+ c = 'corrupt archive (%d)'
+ while 1:
+ line = f.readline()
+ if not line: err('run waf-light from a folder containing waflib')
+ if line == b('#==>\n'):
+ txt = f.readline()
+ if not txt: err(c % 1)
+ if f.readline() != b('#<==\n'): err(c % 2)
+ break
+ if not txt: err(c % 3)
+ txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r')).replace(b(C3), b('\x00'))
+
+ import shutil, tarfile
+ try: shutil.rmtree(dir)
+ except OSError: pass
+ try:
+ for x in ('Tools', 'extras'):
+ os.makedirs(join(dir, 'waflib', x))
+ except OSError:
+ err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir)
+
+ os.chdir(dir)
+ tmp = 't.bz2'
+ t = open(tmp,'wb')
+ try: t.write(txt)
+ finally: t.close()
+
+ try:
+ t = tarfile.open(tmp)
+ except:
+ try:
+ os.system('bunzip2 t.bz2')
+ t = tarfile.open('t')
+ tmp = 't'
+ except:
+ os.chdir(cwd)
+ try: shutil.rmtree(dir)
+ except OSError: pass
+ err("Waf cannot be unpacked, check that bzip2 support is present")
+
+ try:
+ for x in t: t.extract(x)
+ finally:
+ t.close()
+
+ for x in ('Tools', 'extras'):
+ os.chmod(join('waflib',x), 493)
+
+ if sys.hexversion<0x300000f:
+ sys.path = [join(dir, 'waflib')] + sys.path
+ import fixpy2
+ fixpy2.fixdir(dir)
+
+ os.remove(tmp)
+ os.chdir(cwd)
+
+ try: dir = unicode(dir, 'mbcs')
+ except: pass
+ try:
+ from ctypes import windll
+ windll.kernel32.SetFileAttributesW(dir, 2)
+ except:
+ pass
+
+def test(dir):
+ try:
+ os.stat(join(dir, 'waflib'))
+ return os.path.abspath(dir)
+ except OSError:
+ pass
+
+def find_lib():
+ src = os.path.abspath(inspect.getfile(inspect.getmodule(err)))
+ base, name = os.path.split(src)
+
+ #devs use $WAFDIR
+ w=test(os.environ.get('WAFDIR', ''))
+ if w: return w
+
+ #waf-light
+ if name.endswith('waf-light'):
+ w = test(base)
+ if w: return w
+ for dir in sys.path:
+ if test(dir):
+ return dir
+ err('waf-light requires waflib -> export WAFDIR=/folder')
+
+ dirname = '%s-%s-%s' % (WAF, VERSION, REVISION)
+ for i in (INSTALL,'/usr','/usr/local','/opt'):
+ w = test(i + '/lib/' + dirname)
+ if w: return w
+
+ #waf-local
+ dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname)
+ w = test(dir)
+ if w: return w
+
+ #unpack
+ unpack_wafdir(dir, src)
+ return dir
+
+wafdir = find_lib()
+sys.path.insert(0, wafdir)
+
+if __name__ == '__main__':
+
+ from waflib import Scripting
+ Scripting.waf_entry_point(cwd, VERSION, wafdir)
+
+#==>
+#BZh91AY&SY9 ½´\¥ÿÿÿ³DPÿÿÿÿÿÿÿÿÿÿÿm (¬#%00e(b÷/mÐ#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%#%öÞúzómmkîÖZÞæ²U#.´[iÚ¾îõ¹±µú:¥'kdî7{ÛïoºµÛ¶ÖµK¹]Øvµ'ÛßO¾ö¸gv÷s½÷¶N)#.Q+Ù½íp·µÞ]/{m»<{guÒ@Ýó{§«vo;¾ø;vÎiîáÉî44lºï{ß|ûïëËßÚU9íõÝÝî·¯y½÷½x#%#%@(}ìh#%` ï²=âwfí:4§[aÓ¹½ y©³A¦¸ê»´ö4=¦öìd+Ö¨ª)íf0#6 *¢{Q$#%#6#%YJzÚV½%çÍíîæ}»j½êºaïjÚØá3TTf˦Iv×]s}6óu7¾÷z:#.ÎxûÝW_=³ÛzÖåZ;Û»ÍÝÛ}Þsy¾¯³»ß{¸ûíÖîiÉÔ÷Ëzõ¶§rç>^æû}ñ¾íóÛa zúz{x¹-ìzÍݳֲ4÷³¼ÛÞ÷fÞÏs¬ô`u¡ÒãF°Û"EE7w¼#%(J*OCÀ#%lîè=÷n{Ywº¹½»ÐdÜöï>}Ü[vÇGÐ`>ÛEmk®¥ÑMãW`×LæyÛãÚ^u½#%}÷aît;o¶û}|{mçOvpòǼÎo·*WµíÆܶ2>öí®®òÏwÖõ»]´î;ºjîí9QÚt×·Zt>÷»Ü®¨ÜÙu÷ß|}í«×ܬ&ÞíN«îq\îû½:¾Ã.ñ^ÙéyaC§¶Ó¶Û³®÷Ð¥&nCzî¤|öilöͶíÝîвë[¸÷»³Ûºû5ÖkoX«èqØnöÐlîõÞÞ/`{´ó½wÌ>ïÐê¥PJªPTT´jB¹7uÐv&i¶vÜèº]vúÝ:kÛkÔØëUUÜ{x÷)º¼»HкÚɯfw#%7ZI#%#%;Ü^êåÉÎó²û3ÊF-m½ÜözÔíÝÜì_U.us[¶õv]]ó¸|Hû,ÍqÑ»ÝÁæñ{c;úçvåJº{+¹éÔ²õ§l÷+ªWg¡»`úùÛÙ;{n#î²Ç]÷}çww»{»»xîvÛ#.¾Øú½mÝEfù"s¼ï¯¼ùÚÀ°ËlÐú$/g¬íÑx<ïÜë°VØ6EǵޮÚGxO{×>öø½ïwÞ´#%À*×Û;Fªµíí7¶;g<ÂÀëu´oSk´ÝëÓmï 9.ó®Ú×ݬ»Ý¾çwÅówwtåvë¥Þç:#.[.ëwc ÓàéÕhÁgu½Þ^ïnØu¼ÓÐ
/=ÝÚ4#%c¹éî½Mö{ÜàìJ
U )½{xW»´×`ï{®ñÝÊäÅÖÃV¶U[}÷IzovuÇH*í·u$ëIÒÖªîúãÞncÚ[ÓµÛ× &Æ»»}öøø½óí·³acÜ| ìÁG»îñÌͼÜ&:·»}½í6µîÐíç;ï¹ßvÛRÀîï·w}-âòó[ãnh &#%& £CBa0#.#%äPÏTzÐ#%õ§{SÔõA) B @@©©á$zzIâ é4#%#%#%#%#%#%#%D! M5TÿMoU<ÔôzTý(òÔõ)é¨mG¨#%#%Ñ£@#%#%'ªRD!4dÐODõ$ÙOF¡£õM#.ò@#.Sj#%#%#%#%#%#%$!#%&@bh&M#%M#.4SÓi4 ¢ #%h#%#%#%I¨ L#A&¦=&õmê{SIé h#%d4#%È#%ÿÓ?£Uirê\ÕQWwk¹úµZvhÊ>5Zu!LA³ ,LQ*")æ°Pcõ§óü Zü5OùÓ¦¸ üæJt¦î£Ä8WoT"¢]^SÌÆ´_3ýos2ìÀlDs4;m»qE6®ñÎÊ´ÚMíÖØ`Vd
â]jíâ5o# åñ÷UI7wD¼áÌKUå¦/Ý~«oÔBäE"ªSº»U¦ÖÖ5k3khÈ 7#%H*-E Õ:¥$H& " HåP° !ß#%h¡#%ª$@dPÉ@mªfL
ÍCLÓd@M$Rj6Ñ3525)FSm&Â$ÐJ2ZQ°h[Fi,i¢Z!#.F)iMF¥#.1eM£DRl¨ZSMhYi#. (ÌÌcRF£Qµ&JlBjcI@hÒËHÆRF¦"[M¶³U´iÆfLÈM&²m¦ÛM65%)-5±¦Û3fZL1f´ÄÑd¢lB!Qf´R`4TH!`ؤ©fJb0lB XhdFIR&B4±ClÍ&)BFRÊËf$@ÒYY5ccE#6dK) -)¦ ±%&ED2hhÉIF($@VAME¢fRÒ¦`ÉØ1MÍab6¤ØV$$´PRD%¤Q0EaÆIL# &RJME±£XHÒjHb iM$"H²[bË2F̲3bdE(Í&U4Ä)A³Q`,i¦Æ"5+%6(R"I&¤a³LcI¡ &¤QÔi3HÚ("h¢kP,&YA¤²2%&DÐM2*4f6)1¨6ÄÊA! "1F4,Ë Ù&TÌÕ£l¥±(#.H¦!HØСYM$QF¤É&ÉØÆJF¦h±b2²2³i¬D`¢JM52i!¢)#.1Sb5*R)#.2)´
HÅ(ÊHR"E$M)´i5DFÀh&Ti¦DÚ#.,ÒeDÈY¦ÉJbD!f k6lmd°$4Ld5EPZ XR$Ècc1 Â2RXÔY¤J&E©M(ZhII$2ɲ#)E,Ñ¥15²e"$4M¶¦¶´`Bjf¦F&RLÈ¥6À¥,Å&%TÙ¢-L¬-bCØRD#HJm~Ãk¢¦©aÍ¢lVƶ*6L¥4ÔR¤44´
¨ØFÉ5Y¡¦c(ÉS*H¶D¦[%´QIKQµ
£&D±5±acR#6e¥2eI´*Ò4TÙB+dË"©TÒTÂ63¶,YL¬S,¦ÖJ²ÙJSLlµ)¬±%¤2RÔZ ª!¨Õ£%AEVMd£jÅEHkDÑ$mhÅÔl2ѵ´0°U@iR £F2&¦±Æ¦&±di Õªµ* ÍKY4IR1!M¤lY"¶¥Y¶1Jm*R¦YaZDF¶K"e5MM¶Êk,Xl²k+,
lÓ ¨ÒD
bÃ4!´
-£T%¢KQY&6LJ,&Ël¤#."+,E1ÌJlÓ4AE¢Ó$&Fm6F6ÆÈS¦cE%bHÌÔ#!4LÔQ¢JdRP5BTÀ4Ó J²Bj-#636£)F̤£!HbÊkÃi4F5&Éa$YP
-4)Ä4Y©²d¬a,±jE¨Õ5£4ECF¥)6b¥fQj4 2ÆA¦&Ä%I1Rcd¤Ía)ME`Û0Ù¤²lfECJ2ZfµhTÍ2Hl£0D2hªih¬ÒlÄ,LDÒRBAh´[ Q¨ÔQÆ-ÃIM#6LR#b-fC26*2%,¤©Ñ´k£TI¢Ë5E$Ô£Pdðj¡kA¥4Ë!E$¦Ih5E±JÛ"¥F±¤ÁdÑÌ¡jQHfJ$©±(j#V#.2,Y*6)4¢Ù2V-&)+)¶D¶M¡¢TR¢Âccd£dÑ&#¶HÔRLÁ¬ÉA#6)³6&"ƨ©Y¤)¤¢&RV-ÆÉ£F42JÔÑie£he¨Ñj±£i5²
Q¶5%)ÐÈÌÆLÙ&kDlU%hÔ,«&´LÚ1lj £cc$UE2©¥XÚ6¶1mIÊQ f²±-F+iQµ´©QJVf*B(4X"J&ØÖ,Ê+I[M²+FbbÑIE[l¶¬R&T*&$¢1PÀ"CFi&ÔÃ%XÛØ´Í[F5¬´42ÖÊY6ÔÔÛ!mI¦¬ME26QA°ÖjMI²Ê B¢LI&RLÈÄd"Ù-¢Ñ±þn··ýÔ¥C)þB51jÄÿTqôe+(a(Æh÷!þ§ ûbåÕ LÿL$hÒlùNzí¿Îó±½9¿øºô·¦SUIPª?ë[lÈÎÿ·ÖYLâsÈ ßùë;L(0\:8À¥pÁI äd*Ãß±¢rý*¤çÿ3ÿ³ôZÑÿÊI(R×+½g,$b/Í0ÿ-npz%ZM¼íõâ8ßwB¹Á¨d~ËÕNØÆZþ,3cRR(lrrXþúݳf¤áV
cÈÌ`I¥Û"lÆLhcôzçG]¼îÞ¹w§¥^¥ã\³Ë/âuçåuÍ\LëP¦"W4LªvcK@¥JAF&ÄMê×bÈÒ3(êñç]¨eñnY½74h6m`Ù(c2@sªªzoþÝ( 7pÊc#6Gv
)ì,`¼rÂü®R[R}ßÒëdzçgsÅéÐN×VÄQL0¦Ð¤Y;ùd«Ïô8$ÚÍÏ£ØÐØj¤Ï(%?·râþ°ÃµºÀ¡
JÅxß÷k¶¶cÂx-2KËw%¬C°UyáyÜíÞw^Qrè»esnCQW6éçqllO²ëå5¼Z4EA¯»º?_ÆWò-ȦWÅȶÆåÈIºÕø¼u¨Û?Go*Èyùæ|m<b#4L9cuPEX°«©#.¹t@#6A!´ä#ñÆ#.¯)ÎãÂHÃz^+Ý\Ѩ8ëÞwcrË(Ë®é$s5öøZAÿhÿJrÈ.YÚlCÙ,0!MðÛtÉÈe«#6ýRÁÃ79ô,ýפ¾ìÉþFtÃÏxV¬@Gô¡d%lþ «p<kìÄ9 c£ðÐÃ|¶Ç#tE]HP0îT[æÈØÙ_#¨½zírH ȦwâÔÍW7mxþVYê?)Ärvj³oQwE¦me#.¿ÂdÔç׶b²àþN!ïe §&¢øuû/ÑÏKà`ö§nínùT)"*¤#6d9#c*w&ébÛÉðfR6z®:'ï.àûì¥k,YL#6N*}±ÆyÞ>ÇãUË"õÖUO«pi)8ªâ+ñ §Ó¬,±Èj[þv¼lQôÇôa1Kèë¯Ç×FÌ÷¿SªÄ7ÍmZ½*£N¼Pâ-#6¬AË@*{iX<ÙZøW÷»(Éðâ»EEE¼nY5ÆÕ͵þìw>ÇS6½ß«¦öøÿMfhF¨%2+zmýW!bSQIðîÜ®÷uVé(i%"÷@X'+¬¥&D§)J²å¢¶/]öï^¯"R¬k¹bÑ_·-×»±öõÆ*|ý{ü=o÷îèëØÔl|ÏÀÞ1¨4ü>õÝ>¬ýóLÖȲ"4£~"Uä¨ræPaLÖ¶jϹ$Â![ÙùzÛ²F²lWßî«âøùÑÊW=ì¼4DÁa«lAHÒPŤ'Ò'mBµ§
C×G¶éE2R]U¥"»wÕ¬ü*ÔðХ߲²ôî²Á¨ÀSE#6lÃQMZH"JuëJ»*Ã#6I¢L²íãe¥ÂS²$+b¨¬N¬<ÙkH](©É#6<*oÐçAJõÂü/;q°óap×^Ro^XjÅÄ"_gñË<TCª¼s×y¬Xq&ýqK\:05aáeF1PXäiMö÷3g{O4ÝurgúkßÙóôoÄï3Ã)#åªiÔö¢'־ʣôwr³éº8;+¹+oìÑ®Há m^L¯q#.1¼öÊIr%ÉnCMÏ}×ì6q¸v~ØÆ5.|båÙåAÅ#S<*Jtªð¡áô\äáDäÑö%*Éú9ß<}/²Á"#.L3¦ÙúÀýv½ëå+ù§T-±·,»í¶g)õïD!;SñŵaÊà=±3ÏDKA´](´¸åHvÈÍRß#v/6P½E#Ç
8qêΰâKè(q<åÅð¹ý>¼ê÷:+#%ñ²(\HÎpÊ6ç´zmï*'Ü©×1Ù»á?_k#.êV£ÊFyûeoÐæ$ê?ßjfAvß¾ÚNü£z
$
!¨.fä³Ü¡Ï\iÌ©Ê#.#¥ÉE0F:E&©¯}Ù
µAîg]°éÃp?X7d1á\NB=}ÙILÆ#6P#6íç;¢gäý=«»"<ú¹áïïRî:I2Éð\õq.V)gÉ
,Õ8`¬=jPûíÞèqëZ®#.þø¯,nM´B8÷8»è¸×µÛºä1il÷õm±Ï׺|5Ì=Zí鵦üLuÙ $(w0©WX uÒBdN>ù¢Ü¸I¸ì¾½iíEéËÒêwë+Õ^{å5ÁZU{)ãÉÂé¨c¼Tìí§ @^Ç¡=4´îç ÊÂZÛoý4^Û1¶Ã±öíªÆË ò-îûâû§õoÉÜn¬æU>õéºiúK|e˨J/±ßåÇ}m}w*IeQ92e@êÛíhQAA9¼CrºõÝO¡¸Ëðuu5¤&÷JÃF}w/Å¡j©jÿ}
(© +þ«¯½û¿éºÚ|~þëÇTöµö°ù¥±GR{¨«E ¢úªS>,õ÷öæß»åj»çíjܱ¿Yõ¿¯õâú·+$þ.hÚ>n·ªôj£]Pê©¨Æ ×¶{âÝûïgå mk4µO§k{ÑÇÛEË£õ;ndm¥AyÑQ#6ÚäúÓ«fͲãX8T¾NL\ðôPè1 ø63Yî y²úUM3¦ùÝ#.X|è¤TWù7ìÍÇÎD^jÀER,)9Õß¹ÊÈ·)óÜÑûúuO³~¾$_¶Ï ÊsãÆ4?Zu>ì]1yÅøÚükÓEµÛX)>óOÖâm8s´ÌëéÞOz\àÚÄÚ¸;â¦R¸Á1~FS_tíÂRn(ØPñ¼b¤RfWYüÊ¡êôcì×ùúù«ÜËÎP¼B´ úY×
é¤DQQe0¨x~Û{*©nf £ªwiXT¯)6-Ï;Ë£êw³$3Ê¡¶Ö}TÛÉ|-ºz²8ï5`BüéÝââêÖh¢
Ò¡¸É~¦JΤZ+¯¦9r¬èlÿV´xð¨#6h6ÀêD¶x0¥Ë)AX³£*0²¹ë¯_#.Ç·È÷zìe¥HÙÓ,¿µñïñ²5AòõÁÞ{eÔË7Súþ¡&yÖYñ¯¥³LÅS¹¾Ù?¾ÙÊ-y¯69^è}¦pàBIiK&±nÎǨþ³
éÝs»Î¹ße²ð,¼&2:LäßÏå[«¸óxHÇ®*Ø×ÒU9åé1äDL5;þ²ÏiîÐåQT nUÙ`Ò#ÍoJò41Sºëïv馫ÚÕéa離Mô4O|®I${U½órà¼0;0©*ÃzG/½7+#%Qb ]öÙK\.ª¸ÌÖ÷) I9q×ëa¾¡¼òó#.ÑýýïÞ5оä¬×w*8ÙA'<ß:¥bÊï¬2×ÂxÕQn:ú,öTl8:<ôáyï9ëCÛ¢M\¡"#.JvX¢=Êóðw¹Ô%g±CÍP´GhaÑû£ªºÅH
ö)¬¾U.ÎõÛÂîA=sÈ«ÔsH]#.¤ú$¢8.\Ó³Mìòõò³Þ TÑTaÓM}ªP «½È¥>?¿½¨èØkÕborR#Rñ/Ìç*3ÔÆѦøÚ4u©ð±ocÈÞéñÇ#.vnV»pÁáã)r³Z,ª£.OêÀ·}zwîÝlnª¥.LQøy×@EHiwýÐçç=Qq§"%V2&0+Vq¬¨w=Pë¦uÁ7ºV^-Eu©QQ'çU0D}ÏéÞNi×ôñ$¤úÊ'1ÎK¯U=_lS#6´í0ã×D1zßÆǾ+âdpÚô±æZ?wéx½\`<+½fJøã×~WKËÕ¸îáÝ8n©$z«G»à<c½Ì/Yá÷Ó vfz3ó¹L´cz7kù%ûÚEÎY¥ñ¹-J`]ÞBvP\ÃÚïHm2LMßwðrÈ÷4:ðŵ¼`¡¯\Ô½u}<(ñf`¨Å³÷ôͽUQ9c:ªO+%öPiP/º°<H¬§`±È6,I<Ye"4ECØ@fzÝ«ÉbFõG¡B>q¡z<À®÷±¢Ù èì#á?}ûI¡ÓL»_KÃ'ëB¶Øÿ#É+ù¢ËÖò|Ñúåµöm±×ª©ü°áÇ7û"ònþ½bô#sh¡¶¢~¥?~´V]6k)0úô£ ¦ÙUBÕñ °U¢,õ'«@5ûÜ+ÏÕl±X6µÉ n.ö{pùèü}´:ÑÚðy¥ªbsf19%¢ØñZ³æ#Ô#6 ê,&Ñ3|#6y"ú.$#.#.æuµÅ.÷ éÙ×»*{gd¾evKfûQοí¶ÒÌð7N hÃe hP"1b±êL`ÅMm¬"ã-ÅX]#6=©Õ)«Î#.äÓ2¿+]øºtÉg:Ô00Y½UDàÆÛHIå#LÇÍ6\j¾}Þ#.Û»Æ6Ñ=U S¿ÑÏÞtÌ4såÙº"ïg³.¾t(ÄÉ:qþ²c1û¦³^¹ÙÈÕýÉn*fb¢fÛã;èXhêöÛ÷Ç1£a¼s>¬=N#.ä÷Áý(ûqÃÙfT`ÒalÚÞ~2å8Àr¥¦!:Y@àe¨Öj¡Á¥N¬Íec±;8`ij%ÉÓcW?äDM¶@0L¸¤\Þ'kK«®NºËϧcV*±FÖÒßãñð³Ô9OäÇ»éìåôÁõ*5,<:Ø|EI$¹$G4¡Õ{âS§#%beÙTö¯äìÚÈQ·Ø!ûPveòóêÞ6^ø\F´÷fX=*´nïú>Q/ãnNQ#64
¯¦E¼×^Æ~ú`GÈ'0õÍ\PDØLÍÕ7ØKuÑohsyÛÝQ¼ã*Sçs;5XvPÍf8uÁ®[ÂÝÒS¬ÝϳÔÍ4¹²s?
'ÚÝiÎ;¾n)tYG.å¯K|íMÆ×6AâÖuü×8'¶¿UÊÒ»*se¦ÜL)e8«|ãý×W#%}O`×|AÊ>bmfò\sIÑO##y3£Bé#.â }ÏÕ¡n«r£CDb+ÂÛ`ìúÛn¨>O½Õqòh¼×59·b¢ f~~V#+bç±^Ug:^ó×ÿxºTq(Ū¿1y{TáâzÒÔ²?[좧sÔ5YÿÆgkqjûWXvã_WmMÆñuÍZ3¥Q_{=ì㳦(5#<IÛD9Ü÷3Ï^y%0IjÂÉ[J3NMíT¦nPÿG4_oñï=BÚÓK¤JÍ¿ï¹¹oÕa^ݶxe@eëªã8GHºê½ÙGÄÆÀú"ûÞ° £wñý~Sa¢v®4L§Uz°ÎÞÛß²+fy´Þ¿#./wWdË«^úPÄ´¤áYKAq:;åG2jT wÌC{¿ÚC¥k5PuÝrª0àÒs¢l+«3Û¬#Û8]ÅTò»Ó:úûâ$KÈr0Êâ(\ñ>Âæ©CÞØ ¥Î]«m9¹ÙãH X1ºÈ½7¸ÙdÉ-KOèÜû¿qÛDËâíÜ×s²ó#%$ÌØ@²%"£ÏiñÁGn¦·ÿ¦ågsáºÖÉÑosã¢Ñ+-¯m%b"¹mofÁfm{pYpÐØoÃZ̸Â4¸b³Øúxì^SÎuÜÛzVþîlbݵ Ï°POæÀ:»¾Zn(Ô#{7)×¹LùÏãÕñÁ÷YÓ¡áõ"6zXø£°ébcGë-þ7J-YSÕ#.[òw_#6}P$RFÂ/þª:üó²§HèCþCo:Të=49yz¿ÃÃÊræÄ{´R4IÖÌom¨3 ]Fm;Àuc£tÇlozÁ`(]ô¿5¨å¥÷!.º¿»ZUǤe(®¯ùÊ<V+Î3¾ÒÿÓ²uèæ:»bà-¯°F|¦WìºS·§µ]ëÑöá« Ø·M(Wù¯:ýuÊ:jÝÚÌ£H¹EÑ£8`ñÅتá¨à³ýk £Ã7c¤ü¶<ÎW=ëS¼qé4§5#.-Úß¾öÝE3ÂcÈär¨Äù§L¢^3ýÞ®§r"ßM¼}1(gËDôÑ%¯PÄI¶ôÄ`³CȲ-G%nG5lV°À(#6QEcærÚéͬ١C8z³`Cß½u.7ªY`ÞD,UGÊRÌÑvp«Oøg[\þ]EÅ@Bcvß8èÕñ]Ñ·7Bov?Uëì?ëo;2ëðÿ
¾>^R÷ FÖ\«ÈÞ¬Ãô²Ct½F«X 8,Ò;hXj¾$8ÍûYùüxpå»È6püà ·Ý¤$ÀA7ýc%#%%"A/üÕê¢cå9Xãßá]5GóÚY"E5É#ÁÛ/*9/QÉ?BuîjÑm-Ã&é;ýz|¯££Õ¨l@'ñ(¢¹*öúi|GÀS«êÓ©ÝKð!7ÕmVÐÒ×>ø³9&u È#% ûÿÕ»Ñþ-¢îÕáøÇîäévÞ»¥ #.cc¢¼¢ ÎD×Ì@?Ç4#6¡o轶j0ê**¸ÙsóîÅÃ#.¾º"M\îª"¤ò©¹#%gíÞá4yRb(Ñ>@òtÆ¡R¿Ò]eÑ·äsvÓ Én(+VpäÿE®+ü'6¹ðN°¢3¤Ä[(ZaÉ»I{Þa½x=9"1[ëJ¯lê1H#.ªñ%OÃ#%ì#%ÄcÏm¾ÿ¶çaùã¤þÑIç³ñåú#.5ðׯ_ó~µ?èÌOHÅGTUÙÀM¿ðý¶y´»õ¨5Ñ6¥Ãcjb²ø§¹$|_Cºu0^~c_ñd°"w#%°>×j>ðõER=Sþñ¶s|º5ÛåÃm¶fÕ¿.Õ4|åÝj]³¨:;£ún>ñ:ÿn@ é)ª×fËw#.·l¾¡ßþ0}÷îâ£(WÏÎüoNßÛès{G4ÆÞ|ö0t9×bbÎ?GÝ÷k_ÁÉfª "@îkòX/E÷;¥fL¡¦¿qößÕ5¼8±d¢*¡â{/Ìë¿D4áÅtÉûàûoötgS³wÓ>¬XB§<ÈIÁMmGýùu
9£>¿zsáþ¸'^Í¡c®¶7Bª+Ã
À3ïr\«poª_PÜâÛô=TÁÖæõ§º»¶4ZMI:îäÙ³[Ê+YòÈ{QÓho³
`#67]±áÄRd1ÌU
²[d"b$#6Jk!¬gÛªLk $,¸ûÌ£Ö[ËúP&¶Ï¢U´ð¼U1#ÅË;§¿&b±A
1dy%*üüóî¨"/Z7cûÿuËBsr§¿-$ýþ~
mLÀ:z®X»U ÄDq#6Ïß©s <=U¨~L
¯R5¸}ÛVIé³íLgï ¦aóÓáåvºÿ_EF -áG8?ûmRGÒ=bSfqÖ7¶ÆAi+sèü"Ê|;O¦$÷#I±aiñÓíÁº×®[Hå[#.ºuÆƲX[È¡J×<óÙT¢ ÞºÆÕQjª@Jßü.Å#%
W&û9o
èîD@¾Àß#.âë
cû§A,BCG:l¡úkLuÐ#6Õž?; éõæk¬©÷#.qÌvÊÐ3:^LUÈk4#6`#.~H5ðÏÙ>Ãõ÷þ}¾Ó¯[hyѺBJ2\¡~¬dâe#/¯ÿa7·§4ãYUáCÇMs÷þ{¿ÍcB'$Å;Ç©·8¦ø¦#.{,µjweß#.røâ^˾<0fxþîÍÎ5&Ī¦6P·cQÇ"5Uô÷êE7¥ãyl)pÚ7úµ!$Ó8>{K2®rãyòUçD#¯lüw¯åzã=wÊÝ#6Dn
¸}^æ¡}ªé«)D¥Ð]âuq·à¿çÛ³2±³
®\ÚS{ûìSXãÅY%qßÀn©ÇA#°óÑUá]=@tÔ³Åj&»Æ5&fîðpK ¶Sd&vEÚ}´zGYÌ*B#6 ìÃQ>Gêp¬vþÛ
m}Mææï¤É*Ý0ÞþÓpì÷Æûè|A²vB0;½k[Èé#6¦h"#_ ßzéòøÍ3ã 2&BÑ
5Â6
ܦ2,,»¹Ç|زØR¢"ÈQæY¼° ÆÒÇLkG>'ôj1* ÈéôuüiS1ëu\SdIiÆT°²O¨6ÆÚ±Ôᢻµázl_gêÿ8hxMöX0-ôî ê#ôésüKòÿ5ö¨»?#%Ýyx®)À7 y#%í2òw ÐPc± Æ#%tÀ`=!#.fîÁN¯%Ò[^v
'k³Q÷Þ´Ŗ`ÆzÆ) û¼nuí¶#ÎÃí?.ÒIpJ[¥iB¡×*,ÂÒÅ =ÕÕ`ìQ×pgc¼Iâèez«ôC,Áf{Ê2ѪRuÆú ë¹7©Óyå_æ>£vöt
µÆ|ú9´VKâR;#6(<äwãC)ª((FÏv0ñ2hÊÐDÊ#0+C9°z¼]>ÄlÑJYb¦ÒT-¨¦Å¾bàèÁFrÐpõ*(~¨Ñäû£sÐÌêÊ4 u»y!jÐ#8±sy#.bn=>tzËÌhÁ¡ÈÌ\åê¦å
bPõYÄËþ:¹ÂnTÝÐ`¨éÕñí±Ö½nz1»DRÅ+GèobÊØÛÑ£U$2Öå#tóëñØó^¸émÖî²½¹ªO8«,}YEÏ{^ÜIfxOÐpLÂÅG#.pßú¿¸ÊYE³>vKUÓç¼çû}gا©Ú§^ÏÜøÌÍ+#%®[a:9Þ9ÉÃd×+àB~e.wµ¼qalñwE#%{j,dº*1®íwyæ]®îëOÀFnsnZ*4xm1|F¢ ªÝ4s¡ÊýÖ{ι,äl D {#%ÓDhM´ÔD)$CTÅVƨʣ}íÁ14LT.%"¸ã#%l@'D188Ö÷#.A³èòñ®$Õ^¾0Ʊ³\´h${Þ®#.NUzJ);I?×$è±ØíJö»? v#.êÙöT«T¾î°¦ãaÆ»EÀø5vÈbãlyA}·É¹»Rò¢C÷)K.Ç(
ösN\0p¨¨S"Ðo*ñ!WTðCyp2b2è/mû¬kÙÓY¢Kn9¦µJ:¸Ü³\ü{oMh]¥ÂfXn#6àÛ¯d ÓÂ/QèØ
E®KNÀá®WöÙ=þ=^u¶Ã?×íÆÊ5çã+8~Ñ
ZF0oÑ48Ã@òð_¾*Çc0Z4ÛþþJ°q
áFÃ=tÌÐÔ%Îln¶bæ¦ÀéJÞ(BwyÉ.ÅBjÜxHÃQTÊ8¦4c#6Å|mñd@ñ#%Òå¥c6PºËÈaFÄ`]ÿw&ÅççqÕ2ü2GµÐQ˯Û1R^+¦¯LZ¾yïÛn@m2(Å£-eFK`²(euDÕ8IwN`;ª4,:$VbV66ÄPEBD 2ÙNßYö;üó6é}rÛ=ùk²#6_³S0¢³*¸B¬¥yÔy¥,ôS°X¾.9¶¤Ëuªë@+ë#%)|ðÆÔÔ@zæX"% F#%Às´õ&Á;Æzüiûç|ú¶&íïöí0t 65à1L Þ=Ùôãõ¹H9ív ¥RÜð¿4Þ{mÇnpíÔ+ãÍ=Sº!tî#6oÅgcìtn
©t,ÜluVFƱ#.Ù%Æ·©_NÃÕsËÏù*\¶µ8r&Aö²ÕÚ¨N6÷KY¾#¥öZÔÌì:w¬9§Uf Þj Íñ0ÀF+Iu,<H¿ý
ÍF;ù]õ½ =ci?kÓ]w©XNÚÃC$#."oáo+wÖÓý6Ì<ärÿg·²ln{²ïé£ú/ä#%Ưۡ¬ÏªÜåô¥ázY].Lè®k¥èÐk#.Ï·
g/!¡5ªJ ±R%KA¾Ç³8Ávk#.î#ßxÄEûÈ¿÷þÎÈÚìv`ÁÕåEjÜ¡øØ¢Öö%#d¶{äs1ÜQãËðÓøÉÏe·&¸r¦¶Äj¡ýÓ;¤5wÙ1#.Ä)rÁ·÷íÌiò/:'D\ÿlÌm#.¦2!1Mäñ&¬¬F)èdXUK¤@md2,ÈtëE4'ÖFÁ°5F:Ep[ÌÙRMÔ0õoïº5"HJ)#.í¤#6)$Õ¤o.Ø
)Ú"0Ñ¥bÈèQѸ&bÄÌ´cu·^Øj5 ÔF=3#.MC]o/Õïâ÷~ÞaÆDbÃ'¢Yé±ÍCB&g×LF[o×QLiÂ4òìÏËGdÛ78¬Hý]Ñãg(q5ÆL¯;ÆÎEêRiü\©Dyb9iȦa<µL£Õö½w±Í£ÅBM"1¸È¥Yi]Ã\¶
Ýb»/Ì]NçúséÇp#fâzÜòëÑFßÄå .¡IÛµË#.oQævyÙxq=L°¤XÁMÀ7E+_î9x:ãOF#äøT`¡Ü³µqùCåÊjm·}#6±;¤½dJHµ!MSxLÍÁÁàé#6\³*"ÿ©©eãÂ;ßÏxý#.q#Ö§i¸>NcUGEæÿÏ^Û¤Éà4ó$Á;>)Ín$"Ëýȵ7æÍÑ ÷ÈÙf1¡ýê(v h«éC5×`ò ã{Ô R#7(HTZ'ÖcJ:7Zf6NGÌQä8@ªsIÊÛ¤ÜjìÚ#%;qÂnwjÙQ±¡3¿Áaªê©i·(Vj¡(bõëVðÖ\ÓâM´0kD>§¶UzpNzb#.ý:ë8áâJï}CñOv(ÀäO˦Ãÿ¡68H^&ì×¥±Ó³?òtÇyë°#%#ûý¶¼·6é³]Vâ¡3éeÁ×GY`IÁ´ÚÎ%® ¼ï|HsϺÛEH:uÅ) ²,Fj0ËsVºY#W6éÑ(4ÐÅ"´4YadtªÙ#6#}´Ü¶`Ø5Mõøf¤ëÀºfmjÎ(#.árµ¯V¢¿í;'\ãS´)=ǸöòÒ#%'Ü#%½zÜ\n@|ʼîmÛ¿6ôÙ ²êö¶¾7Ç¿ eÊçó)vaÒ¡ÃHFÁ XÏÛwêÖ?!¿òÑ©ÂâýjÌxOuÖwð4r }ðÛãæá7>ñ§Æ(8Ñ_Ì]`#÷úv#%HÑ=©U°Q0
þrm¾H%x; Öõý¹
.?½VI|gxûq¨[$î}PT=]#6Lk+ì Ïãý¯²K»d9r_ ¹bD³åAÍÝðü(òìù· #6#føåðÝÿ¯c»ì²BÜÖÝÕÏtê~jðêêçßlúü3~i»Ónn>ûy¾{çñ~ùë] Þn¨`"1Ø{ô°õ¯©Y.HGs$å<Æë½\G<Dºáëߧ=~ÏÕþÓCrqy!áã^H³U$ÅÕ2Änà cèúÔb3AÙîù½ùa.ÁGc@õ¼#6\Q\RÒ9¼ôUäÎ)uÛ¯ëqVÂRVÜ°¶·úûJ#%Gh¡ïÿÒ#%f÷,ÛQ¾ß·èøvKx#% è¡#6»wE·B¸cÖáÄîâ§Ï¹øj<}Åz¤4:CíÖï÷7¥dBb3Ôíh"µ%DÍ,J/Îã14i±WöÑÛv¢e»véRIKûR
IXñ¥·õjý_È^ÖÒVÅ&.Ìýü²Ü2SQui¶ø]!Cû^~7²^4snë«u*ä©ó«º±5øuåw?çÔÕû%`¢åÑ©ÉãüjRD>=>ÿòu>i>ÊÊ:##69dc|Vþénmü/®~çú´J:3#Þ'$!éþÝPY]oR®m½$òZ¯&Ö¯SQUQF@ö#Ûá aøè}ÎÙCui±b)f¢y&¨D é*þn&NSìÓ°%ö$¨áTò¹^%\
ýÖwbIlI{VTeùä§îjÅçÞ¥Ô:±
Ø1µ&óWR÷ñþÑùùÜ>2
ÿ#.#ú6q4¿~¿ù·X30~>êí{P?ëF(¢,Ö>_#6à3~Ú#6 ï0\îrfÁ«#6CõÃü j1T,j¥q¾#6Û6Od'@h'Á¤¢$Kð²åª¯1¶ ½ô±ùË=rÿ2·æðWÕPÅùw©1P°æ(óÚùP´îÎVåRh!0ÁVñJ@-I[ú¤\T(#6N=>$o¿ï-#ëüþoÌ}÷~?©¿SÄ>áçú}+ãäSÖyà-[O¯?8Ñ[úF©î»ÏDÐÏcÒÿ½tz/º~ùÓïá7|çé6`¶¹ðÍVúö«Ãñ˹G8©ç°híýqpä"#.ó$`{zEÂêVsãbÆG¹ÄL¯<OeпõIGá=}}ô,k±Þá<öv}²#.¹iÒåýº{ã¶+¦p±ß³0éý¹@ÒÍîÎÃ{¶uÁ#uwDa n'ª@ÆpTÏÝc#æPOR1ß@y÷^¥ïPÊí8jßeÖÑnvµåô¸aËA¸cüU&dã#6V]#ÛêG²S "Í÷ÙKÎw-ÃÑ4¾Pdé9ïÏåp.Q¯~9ra#.xR^öseH»q(â>ýºë9ÕÜ{Ϭý°±øï½áäÞQEV§ì±p2/Xu|¶]æ¢c=!U%äi?Cù
CØcX¦ËìÆýýøPRv²Ä
¥24q`Þam;ÿÕÛ¾×Î_\P Wë¾ëÝ2ÒÓÄ«>îþë¤îº~¤>¶=TM@òjj*©¢³ÒB''%=-uûûHkû8ܪpÿXËؼ¡&>]°CÒp}!é8BvþZ>Ö-øÛê¶*äÄǸ$M®p9@øIHg2q#.SýuFfÑýÿ3ñyXx{Pî-ô2Ñ°oõIöO¶$¬'Ñ¿Æâ4ÊÑÅ ÂCcíÔÓ×å óí5±y¿oü|zÚ1QÈøÎóK,,$o_»Cd ÌbWά¯¥éÕáZ¿V3XÀÓÐôü¹CE.}<åÔtÖv¹W:ìN#K»aÝÙ<ïíáËXÿZ0þ:4°4n'ô)¿©cç£*(ÑZ1F ©ûÍIp[Å ]E}¹ýææzï ½ÔÈ@x#Muaͧøô÷{»þyú¾oÓé6låÕTÏG7°èôÓ6Õò}Y]ûü¤~zú)ùí`¯]$Æ×=ù\¹µYÖïS"Ëàîýßê#õoÛ}¶?=º;~ÎícvÏ\·X!kÊôCÍ~8ED´Õí«ù¿]mRáã>^Õçá&÷_#68êpbo×;ëvدµZSq§iûöÇ÷oöjíôgËÈmysrËG÷t{vÇh²à¢á`×æÒúôÏG7
m óSÜpa»£:H~ êþRöÄj9\RAï·î~^ÌîéçÇ]%="Ëùé»íxâ¦É hæ^LGëe#.·s-ëÝÑ3Ú÷ÙÌêÏæ|Û%n³¬|ðjãWuzµ}F×péÌ°çþS¶1¶¯ãLSèyµìÑ}í{ù`-¼-§z9Ðó%[¶5¡v»º½2Î;§'D?/Ã?ÀØ}öÛfª]wT¸(9=E)#.]ÙYYxôpaòÆÁ¿E3Æ£Ü0¹ÏѼF%Ì.lAÀ>2.sºUÍ?¯Öç½F6e2w?.ì·Å¿=ÛüÇn¢n;å"^¯Nù]¦ëûi=Ü[ºó´<JsCÆÉÝác!»
-9ý6G£M\RD8½;ä¬Dèà¨Xhÿk¬1ÛÝîöj|G#àef®zu?|{?b죩]÷<qáóØ2óyúW»î4öùüãØìsfö_IÄdaÀíÔ2²#í·Ù#.ªú«¾û+ôçñé¾ÎïÒ-«alÙÞ¿(ô/£#.l<tìß+{t¤3.üÂó/°Ú 2´@ÎôcL|>y8bºwc|{a²rÜÞÁÐ#gwùv[
qýª$R¿Sú>]ÚwæÿÔtf¶³×ÖOåð{£<î¾ßÇKjØtcú ®ê]·yïìDZ¡¯Úÿ°Ëà F«àËÕ¤pøzì¡Aó:Ð}Ù"¼p+QÕß_«ÐÃ^/±m&îù<7;(|]oÎÇO%~Wûß2lS7µ|r¯ýæï»,èávENJÞá^[#=6{}¶uým`óùÌ~ÃýîÑÛ]nåÌ)ÖÿîËÕè¯m¶ÿ£Ïª£ò©#6ù¿GFqÂ^FÌÒìò7ðü4µ?w·ö¡(?1½è®ßçõ`¶úO·¯¯Ûï)ÍÓ["ïÆH#%õ"ÕËÆÐ2Æ P~kZ#%RE¦)#%é:³»ÿ£O2ìôý½£<Ý~¯Ïî·üs?·åõuåÚ%÷WwPì»4ô¿IÛø×~÷%IôiÓtêüÚoæòº³¢qüµiA£ªÇçÃ@ïîøgÕÓùj¸aõv{À>ÑÀu.Þ?üB
Í´t¶¿®gºç*¯õhÛDAþóSöäyGÇbeÎ>Í_ÝøþÌ)Ón¢¹8h¾>#.[¿g®øÔjý ¿º;¾0v½=áÑÉñ¯ìá¡>1û4ðx÷ gP#÷h÷óñÙÀpý_Yõ¥©Ü;ü|PåVQóñ=ê?~u±ßåmAì#6`¿Ç«+¿÷¶ÔºÇ%ð#.ýìóS³÷wt÷/vÎná#Ͷ?!b¿pv ùlîâ¹ù;òêÌ/Ð|S¶9¢ ãþ?»"(H;G¾÷*t<&/»éÖûçëGK÷Dj`àõç9K#%#61ÜT'&D¯ñª¤½[-2è+`IBfH&ùÚ~;AÎwù´Åð8,È¿{#Y^ýÙátÁôMÏý®7Ü}·»,°§EÜÜpà
#.±JÔÁÐúìR#ÕÃîá4¶LÜhâ+µw».©ÀXê%äqh !ô¦ÏÇ~Ièù}A7®«wèüº!À²h;ÐÁà·->ðÐB)ؼ³»¥JÒ®Ç>;ÚëZÁZ;|%9µdCPSx½ósZËËgDås£wr×+)°±¶1/1B+SéÏkÍÞ<k«ïQ}=:ÕѧBxóÃ&ýÇï"÷´¹8KÎ.óÉÞiYÉê¤kÍÍê BI×eWRÍ ÷z4åµ%fj|x¥¹êÎ0Ϩ]¸RÃbo£<±Ã<âñrgóa^ç£Ç¼;y-¾çYð&aÈI$¤í"
:¶¾ 8wÔu²æ\ËÆv³i¯oM°Õ¥|Yïæ1xÑÀ{]°2Çã×^þa»Pëø-z×ã¾4-]»l¥_3T¿*|õ)8óÌõ:aÎÉ>·_!(£«F+~4sgì¶W×M«°ìÆç/Ïö´©Ý߶£Ní3¡hl3ûÝ-ÌØm=O£Ûóp>Ø#&þQ¬½0â/Sß3 þ>mM©ñw÷ì\î¢ý\}ÿ$Ùwü÷y¡ÔR$ìØú|¡ô_ÓIØÈDí'¶1ulu³L×ãÏú[=8á'x¿ôúè3úA¼#%Éé/SØC¡I%yb1ÖFÉ¥Góü*åbGѺüCª öIO4|ÿHï½cÀøò»ÚcY|u·>Sþÿæ#`ó²{ÑÊÌáþBÔfeÌ©cv²Á¨9G
?G¥F5¨4iTlT Ô¢¥nØÐæ7#6ªÒÀ¢¢,tþÍÚHÁ¶¸}=3´Ö¤On`a´Å-À¦°Aȱ¬a¦ILA«"hhn)"4±[VWcì'Ë#.Ss¬6ÐÚ]&6)":ýº[ÅÖ¡É \6öB{qZ8dÚuýÿ¶ø[Ñã"?9ÌgBPP}¨üÖÊS<¦³ =a5þrÐÍAÉ]E··cXw\1´ac0]WëøoýOSø\ýVæ#¯#±E4DCÄHèé@Öbï¡i7¨1lXT¥Q&FÈCV ±6ÆfJ¤ÿj*P´Y¶Oà9þ¬éq·ßåñãrÌÓÜïëûpìA¾öFþÞi|-'Ôl³D±çj·UuwåËu¾_
ãÉfºòöWV¯Ùãõlò:ëôeñÖ1ýèæÕ»ê(¦áLS·ñþ>ܬù±ý9Hþÿ<·jÄU±Ýmù}ZbçvùU²«&¸ê²·ü³×íú¡[GmC
fj#6#Ò$pçwÔ]uGÜ<Ý~ßÓø¯Ó§Ù£O«¸¢Zxûþ#%8g#65U6ü;ܶ>®aL~ØY¿w?VPèÁwÙu~Uwö¹\ç3Ü®ÀÂÐÃÉÑkøÿ.¬&5)n|?±½¿>¯&¿án®nàM>äM¹¬ýûôwL[%û"ûBßæ<ëά#6)_@è¸à\S¼|8¿ÁéÎØÄÑ^F+rEµh[J%c§lõX*5¢gtõu¼^´yçÛÆ9ÍfRÉ¢((©[\0°Ä£#6 ÙiéÈ¢ Ôch¥b
È£°µÂÂ44W VR²ÙÿÒ£FÁ÷R\æmFAKTQeBÑlB#.°QtêMæîy3wä%r(*`¥2shÙÀX;Ýg6®¶JhÇTChÆ%8Ì+:ª-!ñiÜtu,¥µÌà#.óÅ!ÚÐ@AFþ§YÙ¬uD³mé¾#.äQ¡±$I8ì~UÒI#ü,D¢Ö%\ȪrF(3*®ÔÊp#®²R1l°b¹ÓòJ®x3¸ø!U$IsJCÙõCID&é½ôAô;/ôôÆNô}Ë ´íäë-ûLH ¬^Þ@ u3ÇD>Õ÷z´ö#.QùUôhÉz°÷ýOT=¾÷góxá$g±SóPü-ÎÃáÉj»#6ý£×£LPL*øý§f¶£Ô§ü!½ëÉ3§F9û§ùj~¸îîh¨xÊìÍcÔºåøËãïÏ""'NõOU87«6«üVûúÖY´¹ÄÞÏÇñ}NO#ûjÒõ@Tõ¹â9ØsûÊvA#%_ï${Ó«ÔVì6TÖÙõ¯=óø~ç{àäm·l_/ÊÙµÇÒBÐÄ'pâqCó9Ëèæ÷¯!üyI£×<³ì©«.V|¾ÇÕ!檣#6u¬êyÄC¸î'·>Åþ¹õüܯ±öÝAe;6LèǨ4«9ÎCH¡QH2t2wT9"+1r_uLUv¹ähì¯F¬ÿÂÅêwf\F±>[î÷QâZ%T»
#6ÏÕ¬ªÿM[hÅe£$#ܱ#.D¿ºÅlÅ˦ómòØÊBYQYCFF¶Ï7®_ËäÇÝã³áê_{HUuí;wùüÿ§OÉAó¬º!BAT1saèsÊ,¿] WÚh&6p¦41-6·nÑHÚ)¬1=j ±o\ËAy©Y¦=ZﶰÌ#6Ô«ÉgAèpE30ËBH¨ÁV¢À*ø¹¢hâÒñ/mM}RdCÝ7Ìy#6Ú´s¶jdßå$ 8ÛAmb{&ãìͬo*©H¥·86AU³àrYbÍZ¨¬ÛÕ§hCZ¸ÆÛ
2SSDÍ#.H#6J lXdL1a4KDã#.Gí3³u#.Ðá1¶¡×l°lôÝXÊ-m(Uz§ûÿñhÉäø1µ(UX¬0âØ©DlópÈ#.Ìi@¢OlÂÕ·åtS¼'Þ30<sÁlPt⢲o»ø¿Õæ#6 !B#6-ê»o.O6öÚº<AÿlqgºØÏwìèõfñf4ÙËÆbýÖ}æSuT044V\áÿwáîÞ:ÙìÛé{yзc(~Qïɨ<Þ O û¹ñÓÍ«ÑJtzAíÜ'ku#%ùÇ"#,,6űaiUSõÒª4ã÷]áv,ÄDjGH¸¸ÂðâÒi§O®|´°UdN¤G#"DÔÂfýV5[ÒDê*#.m4&Wç§(¡ßÅÆ_t5³
¥3MéСÅA!ðy½ÀÐÑK¥¢#.T£¡·ÆóÌU:¼]*«EPTå·ôùdì×k»¤kmó0¦T¨J5Ël$2~ßØ?sÏêê¿g¯Ì:?.\`<<øâï«@»6ñ>\G¯øøJ½µ`CT<ʤ2+ri÷M -+A¸·Tc£´øìz^ǶòÅG=Úæ4Rë«Ùî65ÚatHǵ0 óFÞG[q·º¨ÊN𮳠þü¥Å¶<ª¢¨6Ó®Ç!#6^¹"XÞ<(²ÀÐk]o3ÆÌÀãH5KK¸´pLÊ,°¡+&°,Êp#.#Za¿*V>#%ÐÎýhÂ8pÍK§9æe¼õ².lm¬8ÁV6>d4#±C§à¶ÔAܺÉ&Fèé ᦦ¬ÒKbíV4Î Ø=ÕÝ ¸Døn$DN÷»A£PÓ+gbXÌ®çFPá2-îc¶+P¥ò)2ÉÂ2+ç*³v»öw?Ãzwò_Ûü9ô[ߣo×ûiþnþAý èyÔÆÓýb'j¼ç3Xtß1ám¦,¼3êtäzÉù~îìa#.6uqöMÛó¦q9°gì,ªÄÊ;÷ ÁÍS¹(v-ª ù`kbô»6ßV۾ϱ£)`åÈf=NÜRäòAUHtF¨ÚEë1ÕOSxWxe¶ãjh¨ô©Siyiºf6äÜR®©n1v6«DE¼ qìT'wÜÏ.gÊh#i£^ÞM¼h½óé¶3`ìQ±q&Úri3haÔ9ÙÆbX±AO}`PwÍUí«3Û¡~ÕoÒ_ÇúFÅ°¤<N=¦,Ü9}Ð'pøF_smÕA#6#.¬:M³±¸-µÉ°àzÌ! 1IË(Dâ8ìMpî@Τ2ìl+ñ"V½Üq·*t;$î§i¨Åo;n3Ù-Ïu#.põQ
boyN×?u°L
#.¹}#.IM¤$Á x¶ï)Ï®v¼îѱnú¼
Ë@:kï¯#.K¨iccndëÔªÞAåj«[ÉP]ÃK©)pU7UØ"wW;´ÇÁßÛÄ!ÜÔr7 JQoùŲmÛZé\¨ÂIAÆàQÞ#6:26#.]î;ñ´ïC®â¶£¨ë³º ¬ÌK%c¸Tnq°QÍ峺mñÙºâã!X ÷Ðk¶Ö·ÚåÇF=ˤV¬vNSuÕÑÆs'&vl©4µrÍb< vjN19ÆbÉÃ"°Ë0NrcZ6ßW$ãdB\ÜÖëwl#6Ó¨cÇ.Ûldå¤É6µ&Dm<Íc/³Ür±±5ß ÕoÓ:ÙD$âoµ}ä«ÅÇy溽<¸üþY·íhÕ@óμKaNâÒWGiÝ/_³ym§,qGr0÷GÂÜFDdªõçV×¾¿òÜdIÄäF6$«,©
5·\m4üb-ßöÐTM^í¶"R§".få½ÿ¾ºáwu
¹RM|an¸ê!Ô¥ÄAl©·KÆ<F°´¼)ÁF§P6ø¤,½¬-®eß4ð¡RàoNYyÉ\#6wæïÆ·¶¨ÅÎîn,ÿ
ÒÛ§GtïJLL kÞ8!ÉLº÷m?oõxtîåöÅa^øñ×4@üÃe¥nÓ8¹búÇUÖµÕim;'Âyhz7,íÎ+¿öÉ«þÇyDCá÷TToÁ89I°Y¾ç´<ß\±`%dn½;,ù²BÂå68ãu6«7'}ÆôÛ^÷YtNÃWdÓ;=ä/fRͲºòc p®FiùUóísk[áü3¦¯²77Ð{¬1F.LÍÔ4éç¤<³§n#%·SáGFÓ9fài©CÓzÒ¯,6õbi#6aÝì®îÊómàò7ù¾ÅÚOf#.5Í`ùfz×¥qaôËÊǵ¦ô»u×[A(g×zÿdÅGߨrt5:Ú'à®üc´vP¢¨$ÞìÛ³FáàtxÃù]L@¢Ùù¨öVA¬^yw17sGqìAÙÉdfÒÒ_Ä£¯Ãó7n·hÓ'²8u,Ü.¤ñy¿0t¾óO`D
Tò#63ɤ@ºÃjúP3<#.þFRØ/(?7óGá:ix¤ú{¹Dç#%²yþ¼#âôØ¢8=lè{ý}å¥r¸¸éñ¾áç\Íï>ïø2Ýä¹ÐiߥþCÒKíWnר>áüpbx_9³å¬×WÎ@TÛBðÑZ·¼Bìb>ß_§çcOVz|ymx#6fǼYJ
²-Ê 0#6@wßwvOóÓ®ËÒëÎ!ÞöxnpF°Q¨#%²Ýj«ÀÎÇ·e#1T´ËRV¡Ö1(3È40° cpç¯Tô沪ÎAϨ9zâ"3áÅNÇíí<·¹ycÐrv>óZªQà:¹ýí%ÖÐ~ND|²EÊÉ´à÷Ô%¸< &ÙÚq4öÁ
)UyøèÌùÿ_óÆu«޼?ßàzg nõ¼;qËô;åÞÒ&LÅSå1ºúeÃyg²)IVì\.Bm0J°þ[qkdÅ°ó#´-©`®Rb]8ð3ÏcÝÇÊûO¥]ÝB$ÄKÁÇ|\ÀÈ|jÌÅg}'ò$ja±áêȵ¿<4Æ=6=&¹|§ð»®6
]ºÔOvé¸pX»Ü=ôTÖV*yumì
+¾â1e¼#µöÚgDt,DãFQiwqlÞäÀþµ#.س^O¢àô.é¤îÝϪ-ÇIÐ÷]ÔAõõ
îÆQ72I8ïxLjoLk.Ë¢MDz=ýtï&½ó:o$48;!Cªpóa}j bÝ94gÖ|«¯3ß½µ4#.ÒOè%èÛÔØ¡ñÓÞ:Î<4ÅôE#.54òì3R¬úTW-Çðk¥³øyçÈcUéN-<#.'çiké;!:-D¤§ 7)%#.M;î·$®Â÷h.ØCpíJi5Ðéï¬Zñ9þ®ß#%ÿ7±CðÉêpC Ï#òÁ´ð ü¹ßrÞÓ¬Grɧå¶9¶EJ¥ÍaÕ
ë¶ú`xf¤-0è´%ùkö2#¼üx#.|^:+Ð ÒÉùÌÛS9lVoazâ3!m²<
¦y©CÞo{vþ|eûüÿdQè¶F÷T½Ä½Ïá~;¬wÚjl.r<0XîÍ1`à1ß¹iê1æйºKj¶Ó§\¾¯å;ådý|:ó»OeÑ¡ÌìÉâcs§ãò²ÍcâZøô<«LÁQÖE-¿Æa Hàòµ0·Nõ3\JÜrSs t UýÒ>\}[ìäåúÞcríàXZ.ê,¥¯Ô#Îfi?ú'î¤èDÁµÊ©æÔ÷½`£Ñ@¨úã´#6oÍÇ~ÏhÊ0*Ü×ã:Ö hïÿKC¼i´Î|½_ðÍÓÃ_.¼71¼§½Âu"¹rFxôâ ç#LþÒ¹Ækyóé>Q9¬Àȳ÷#%hÍÊÈ(²
¨+fLmìßãh}ãÄuÚBN[ëR fJé{ 2ñªA·Pjפ/ñté£YÚÚ$ùyPñÖøêúë¢@
)Õ§)O~U$BO3âud¾Û1/5¿<k«æU«xdí¬½ìu¶ø¦ta>y6¡û5ÍNîQápNHèºeò¸è>·D.÷*EdÌn2,Y(è¿fñ/¥sµÒñDµÒÓôÌØЦwN¯®ÖIóíîç#.¤PBbÛV¦u]íUn=Elã·ï¿>JªE·":ÇÌ[~ÊÚÄ&ÂO¨ÁÄ)%&UrfIJNgq¾aCF¦pzPvß·SC
:l#:=ɪ/¢6<ç0DU¼F9¦îÅR3}m¡ð6£y)¤8Õáà7Õ¿QúÜñeìî#$ã\¦Æ§ò^q1®J=f3£ÕÍkÆÝ$·LùÎã{¦Ö=Jìm&@×vµÑ|^m÷"Xî<ºãcèQÕ¨RHyrÕòá#6̪\hlæÏ#6Qɺ*h9·¹52g(eG=¦!B-½FäÈ= *\¨½[=Ù4³Ê
ܧIm¯Ðã¹Fo%ë*¡açgþsé7s¾ð¤ß>üç:¶è$qCñntl ûÜÂ=³DOåùÅ@à}Äýó;Â_+'ç» EFÍÇD_½@Ê´Î/HÌ(¹%üñãÖÛ~!ÞʨÁõsÉMªG4E8yKåÒØÚ¾ôc6Ãä´ÜàÎû6vâv¥l½Ë#.gt>";¢ïm¼Ùu¼,ÉvõutÁ=;2hä!0ßH¿(âÞ}´s^G ap%N=¬c¥çµQ»<dZfÛêïÞWå=¾ïy±[g|̥ÿi¼å¤2ÖÉüLøÅ7¯#.¿nßF0r ðI8TÝÌ·6µD$M/#6oñ@üÑHÜ¡ÈYeV×ÛrÁD¨ïDÔ_MºpàütC¯y°ý:Ç1_G ¦h.:üzÑÓ«&~ÐbªÒqëMN6kÕmcí99º×ļkgX3sS§¶ûtc¼/+ÍìF!ä÷ø2xìåX?]¤BM#%èìùRÔöÁ3. s®)©³ù3F~~!Äi9þ×8ÁIütgHC©B³Ê @éFº×E¸éÆÉÔtÎxêýbT{ÈIZkÎérÎ[J(7ÕZÇפÒé½¥°ô4%ngW³U¡pÂzÜÆ.D
c·Fó\Ïå¢ê ÑsT»f«øW#6/á9=jÑ´S¹eEØàö¹ÑãÈB#%ÈX±uÏÊÖ¬N,&6#6Bõ=p]Ù#6f§|:×D¹aêF/þ¿©+6Í|Õ,2Ø'7;5mÌ©ÙÂû]Ü`x¿2°²k\U_v¬X)æûêëò°,àµ{wï
ñYÞ%åq\jµ|ßxèªÌÕ,`RWn²Æ°øÙÍËM0º <X5
UÛo6<-¨Ç)d^÷Ýb#%ûðçÚ°ò®[£±õ¾·>Iz]¸lð«°S·#6eh´³$'°´¬çíHf#6^Uî
Ðt..k¤ö#.п4âî6zÛXÛPÅ¥½\9Û1mðR´t}yUQ¯}[;î¨Æûáos-÷À<¤¦TvZ§H¤sÄéïã寻Ë&?ÁßÆf}ôèÁ>WÞ³ÅøÕOÙwbe'½øëåÆqçtÕÑ_I&5q¶"æ¹Öçgõj2àE°©£½"*[WÕn¬2¾ëAá¦ÐM*aFkmö0*áe"ë²°I@.µq|%hy±gt>ûõGÌ0ÍxQ¨ZQ]~¹
LfÏ9ÖÑhjÀ®'»YtX?PØçÜôTðQäj?¬½Èo]YQµfÐ[DÔ³áGçtP?ÒóèþØÎeϤ;ûmð÷\ã4§áx§5¨íÍKèÒ@¥ÛY ü°¡³([¥uã`£"ñ%K ¢%b5j!®#TRé,Ы©ªö`A¬5w,åu1
¶K#6¯uÌÍ+;¼òzÜÇEºâko¡.¦ùÕÏVÍßÇ>ëä(úXòV÷9Cg ôuª<²w]ÇÞ7ÆðÛþë+Þ#6~J¢ÖÞo8Ð#!õþ³PJ#%)W&8Ø9¢/ï®Îo7v°Ðv¸-õ 6âm¾æ¤C+«WAz)zÄêéVµ{Ñuå|NÉK¦Ò¥tßËòܹÆ"½E¦/séÑWaƺ\T:Ü©ÝÆðñ#%̹ÖovJ±$o¨e@¦ëtLE#.õHáÐæxizÎ@pßy¦M>úgV0P´¡ã/ïÚWFê ªÆê°ÊgR0y¹ö\÷Ü+nS×GJÊÕ^I¸ºY©}ªëÜè½BÎYC;-|CÄDfVsÖ#%Û5·\a?Æ ÖÖvs>×_Òë5Fó¨÷ypfÝuÓÊ#-/Í\¿Tz>#»¸dqÄËÍKÎ{e¿"ϽFòæÁ³Áµ@}#6#6pÂi1Ic¯1¡òª¯ÇÃ|èIm'T\&IËlgï´µp/jº~?5óÎvÝ ææܲÓ5b7fÓnºN3[al@}sÙ
_XFÉÆÛß'mÂ6)k4ïÞ',Ö#6ÖKdÒUÅCÞî
£¬ô#6F6¡HDp¢JÊ÷ÖÚWSä²R²sýÙí~¥axÆ«aázß5Ä7¾m.mí*E¨$CAlæ¦BIm*øÒ¡ò˳5®Ø45ÖJ·jºï9}æÖÏxôHü5Z¸Q<W÷¾»N³VDÕhU¡|ãf+ÏÆ<é¹v^-~]ðBäA`Äænð¬W
éÒô>·W«¯êñB¢(P%¶ÃD7K#..mØÎÇئ+Ô,#e3m{wl4º/}úî}¼ÎYðsEÞC9H2¶±tflkA²´ÕM1C,áî
`âlرëkù´OIiN}¥áù#6nÆ#%ààÍA^³(ÆÀl!Ê.±o7Bù[8fX»HíÚWzò2ÔÕså@ç¬É¯ËjÎc¯oN=,qkóPxÙ¡ÀË·qÊX8~ =Þ¡O½íÏÓ¯tÌqÁ8=þø´¼ÂûxÔE@é#%ÅmpÀONгÏaj¬ôe³ÊÈTI*xzÊÔ¢4äãlûGüGþÞtÐqͯ5K¯ìëâì·VÉxdÔÊ*W6XËSm³¾$ðH/᦯°Fì¤øSÙà<?zÌGP-;yZæOµD5Ë·gºë«iTÖêÏéÄ2 Á¿ryº~NKûôøÌGâkgÑêv|¿Wç¿êþÆú~xøLη²1«¨\8û}ÑÓ®ÌW¯Î6¼jS
;TǯOmæÜuW<ß±©38z%~çrý·ÙÄ¢3̦ۤïàåq^úðN¥gÑ'u±k//u65>Q²{Æhe!wº(¦±Ï]ºÈc!ïÂëOZÏ_
ÍÓy©1L6ðéP¾·«>ºÃezÑa¦ö_j¸ï©~Z^¢iJáÝtQaè[Â9ò-QÍïäzí$o±ýL÷æsaÕHR1ÒTÕ ×¡Áâè*aæu®|b¶µïææyÌ
Ä{Sê-p5cÞ§wsÕ_LÜÂGËÖôöû©å¿¦àc}± «ûû5I³©jJ#fع¾ÎM$rÂKLîg¡sß9a--JÉ,°ã¾õ½`¤Ç|ír]xä+n/ÑÖÕELm¹Èb3ÍO]aÓ(£ì!^\CὦÕ-(r"ÇFgRÒ¸nXÙ
꣥ü1½+/!ÆÃ6d#6P ÕdØIáÇTÁHS{ÚÔbÿ31æ£
N¬ù\¤ë`- xf<3·¡Ù#6 gî®Þ|Ûc$âSâ¹@ág"Ä ÀÝ:9Òà»Ý.mÚ¾|×[6âjg5sÍ¢ðºàÙ½KÚ=WæÐ#%U)Aµý³MU7/Îà³E³V¶û³õb>|ÔÔsDD°#6T2À¦yÁq¢Ð²#6èü¥Òk1~6ñ,Ñå%ØâèûgûK°¶"hÔi2Kú;e#6é f¼¬T¡ÅX]Ó¦hvÍÖ°NZPqîWP¦õáÐä²I¼|Æág¬í÷i ã¢\ÒªÊaîa·Øé8ºibP» Jr¬ÑÑkLØ0óöÖë¢vÝ\ê£q!öytØ :÷Ôܵoû<£gÏ=Éo6¼IÞbì·låHÜCZýn±ù¯Ö7Fn²d»Ê¿_¦ÖVMü£cî:v¹+F;³Ü¬)&#.M'ÁÂ#.˯£¶b»ÀYÊw:$±å½À=ëZ×û°' &hhmZñX\Ë,ÊÙ9CÆçò¤!9¹0rÊÜ=Þµm©3¾¶[
¿èZÁW©T·ÈÞÝ+(a19ÅÌáë<¥Ñéæ¡ÜvÅF³Ôè©xñè~ÅGÁB UU(;}ný½º¯àÞ¹Áµzoô]4B:Ð=.®atÏ$³ôÒeJûäí` r=q`ÉiCÂJ¿ç¼øD¡ùâÓÁ#.BY`åfYB¢òó¿Ay ±U /v¶ /C3¯¿±òÔ$¬sék:!ßr=®.ê«Y8=}«[SdÐ*¼¡÷M¹õ(ö´¯RÔxÁ5&¾GÔ¢¨)´èÉÄp¼Ió{ ã.xGtÆ¡ÿ',©iAxdÙt½×ôY»7ÓFs<dçWÙÕÈߣlõúÅ`)N}ÊèÍfK¸H}öC¡ó"qÝQ/Dq×hÞ%YNuðùËûaØÓüf6¦O}_+Ës$õÞ;öçzìm$$L·LÑáz¯bòþøË*'%$i:tÙc£yªâsQi':-'·(Þ`b6<-ã8¨ó.£uÐé¶ïËmòÚ]{¿ÜÞg·j9 ¨ ^æJª'ÎæÀo}Ò¬ÑÐñD-W8g{Èm´qnáêkÏZ9æË9òïùÖ, Cü`ÅN`[£½Ây#6Z=Ôs'´WïÏ'dë¤\¬ù¦¯ÇUÖ|MÛµÃÑé{ùËzürE÷õntwæi0²J:Ìñímã¢û åOäzã-¹|o)#XÔW·>ÅÓÐs=o¼[DØÐunÄ2¨æû`Ü1ÛNAö;ñoó$³¶¸x<¡³EüqÊíêK/¬ÙßbÐK¬/aÑt÷h$&c%n×çl#«'¬s¹â(éT¿·iاۤªËò¡^v*ø1Ö.)òFÅ<eZÝØxA)³NTÿ(ÃöAÐ?>?Ná_§X#6ãûbo1QìÐb¼DzÞÒ¸Û¾nB¬htRßM~Þ¹¼çhæ>(â= 6º6Mº1@ì|]½fÏ.×ösÛ(õ::l¬züø³jîOÁk)¾pVzקk÷û±jÔ3pV×>IÎf¥$Jý?LV2e*¤Xpå¹³nÈ(#2òY¸zk0Ö9ê<õ-w¨õ°u¡Í¶lÂnIv("`îTaÙߦ:b×däB®zíGmÚå»#6õÈyh3å³#.¡æóvÏ=ýB´Ùîïj¸+8;å>N¼Ù8dÃøݺÌu]:D£~·/Ò®*©z½pIs>ӾĶ7¢ð¾ìæ|¡Ð.ÝC×oü<©Oz¬Û5*ôÚÐ}&E§xãÑ»ó!½SbGeFI-ÉU#%¦$Ô³I ÙlM,01*Fe`÷ S~S G>»2@×ã¾~ï3¬ZÂË/ÒsÛ¤¸zµkÓÆ.xï|~ñÍD¤#%¼Ûé®u¯ÍÐ*±§Z#.ßËn¾P>¡
uxi¬ëÍÔ¨&'a¼S92)igkHÏíð|·¯`çÛÜ¡àiÖÉÛS{Æ`'+æU<:êI,öæÙ7¿_ÇVñ5îO/Iú~!®ìàZ§ºÜÁáÈR¸÷pùqyàì^Km$?«ÿr¢uà;46CR;,VÒ¤èøu'/0Î?í5¯{íÀiÎÚÞÜsü"Vîu¾ jOð3ýKÉOäýNw³ª¯ÂÛ¦/½6¨ .¡#6×XrpÑoHì~!ÑRKz¹£%dn(è)!ëßnÈrlÔ£§GÜ#DθN5çþwP$È~åtÔNBeåkµîM ÏÙènæ²1Â7_êÝóÞ¹¾?5õü;{Óº'àãÕøÏ¥¡{ùq(#%`@)ïõ(õ§áôáÔç°Ö9Mv#Õ(JL+G;I@Àðèz¼xÔ¾(H)ægëxTWÆ®òØ]÷ào»ýEkù©\ë¹lIi?K¶Wò¨ØRmcÚ-«®¯ñþ5ù³L
>(2ÍÊþbFmpßgË~:×ô@ß4>$Ë_#p¼$Å"AY ä&©×z½:Û¬-&OÈÌySµgÎ]ÜlÈþÔÃfÁõ¤^¥«Û¾÷ÊAo¼?ñxüG5ý7B÷ØHÓ\ü¯íN91¤IY[Gtþ#%²©¨qHTi*7+¡þÜõÿËò?¯YCxþöaÏ(¾zÿ~[Ûá_ÚÏ]>Nt©"rNK(ö·ËçzÔöKíd¿»æïðù´!ÚEá¹tîV}ëªÚÃÞíèÝnCiü]÷ùY??Îý
ªz¯nÇN¶:*F`6$´t%5®Ææó³\ª#%±|´ãÓ¹þ1ì?£¾í/ÒÊY¡°ê8KË,H|ñ"~¯Ð©¡ýj!#.K©wk|Y²äèYû=v&Sú7åí}f¥h¯P#6ªÌ· Ϩ:ý_Bý>¼s<7Ea§VNKÎõú](ú¶ÅÆQØ/ð~¶w+E@âõL0½Æ\üª"XÉBÌÜ!?_þG7LzßçmßÂÇ>¯+e§m¿Á÷¡Øf c(QÆ#6"ýu9¡Ñ#.P?KóO¹ êL¥09]#%n?øí®@¡/T¨#%½t xÎè"RµK Tg¹L°ÇJæhZ\j ¨µ+r¼ Lt#Èæ"#%o®¡òËÒ(~ª#%¾± ´é§ëãcßÁmÃfÿU#%èõ@ÝEôÿR ðºØÄxi¯ÐþëôBañ¾`Ù8ú&ØH¨Ù6óòP¿XøcÚi®àí´ÇK÷$qý4¹aß-)Á>ÏN99¨ÕÂ5v8ñ:je`a"ÅeOXï2~ZhCq yÏWiƺ(T¾¦Û¿ol|ïøH,ézþë(`L$¼{ 9gÕWR|1¿{Õ¹Ýø@Äyi<×Þÿ$ïèÇòS(òýäOgÏIëÕ¥OSIïôõ#Ñzüco*(B¢Êvæý?Ít,¡xë©TÏ[]3«X(~¤©R#6¥`UMKõ·;ã6Á¢(Ü£Øy·½?=ÆÝаì>©aI\öñ}V$øÁ4º2qÇm¿Êe#.fqpÚiÌkZÔ·ü(b§RfÌ%ݵEÔR1#µ¤Ûp2\4SywE9g+ìôÐmÒü!ô¯#Àè (&ë]Ì#%¹Öië
uQºâý:vêÙ®¨ÙJË5Ií4ôýn½2×mpè«¡ön³DAñ|],Ê[#6Øy`ïÄ#6PIµoßÕwÊî,ßlN¹¬ç·Ü"c;þúY³:=±Z&W¨å#6Çf½Y¦ÈÈ`¢ÃÏÅ3×8È7K±´-T"EÃvÉFQ`¹\ÏP.Dp1C¯f¶Öoe¹_}g¶âúà«âc'K³T¢©Ö¨`¢XD$¡\æ#6P8ÌüøÀ·Ì£¾ýtbÓÎOIan0aÓÖL bBç#.° ¶ö]\ñ²òBET dØÇ(°so¾)g®Ñà#.4FÌ·e¦`1ÜL`òyJIÅG§³Â¥ô ï#?øYÖzKéÄ2÷#.ÍÔþ:·Ü7ÃßüÕaÖNQżÿiË2}}Jo£Èú¯.þ³ÊÍýÇÐïL_fs@vô#6Ä¥Í7;Î_{ÉFy"]yXºmý~,@yÆNr+(kîØ®ñ3zL;,"ì¼BN3$ü÷>åq6׿yðö]|'<@¶HZ°¦ Ýè[ï*¹süÚÍæðX¤ßï@¤U-0àe{¶Ú3ÀÂÓíTÆií7q¢I¼y»Î
'íýVç?rÕëHõ!d=1#3tÿe®ÎÝ~AN{º4N¡úÓ× I5Ù(åtD# ø uÕÜ`ÔQP+&Öá`KH³Zhð!É î¾ÉA ê(e<ýd¼þ½eý÷ímÊ5^äÞ¢)?̸Úþñç6`éØÂàäâ{î£Æák¼dVÔ2SÄ;¬7ÊN¤@`wdÃ@à¢`s¤á59_E·OR« _ªzq
Ks^GlÞ<й\¡±BóBdF&!Úë\[S®~zÞd'¼¢$6ÒÙ¢½É6NX |¼¡AÀ(åøïÃrã;XËq-î¨ùöÎrI{@Î{"{íLÕźÞ5y\JEã%9×!}ÞCøI(ès=>§X.~Xp^éó{ì¨k±âøa§Ë%&âÑþWw,/òmì¥z¹Nãõ5Ç/mK¦$jìá +ÓK6L²8ª~í1o'\8¸`À- #!C<×® lá2ô×8ëõÍÙXÃN¾eÌü®R«b/!ö¥E7Â5pdp«¬BÜqÖ;»8]c5Ù½= L=«ô7#%í¾XïÃ%3#6¥,4«ã¤"»¹¼±¦ÿòuo8KÔ<׬(¸§E¤;UZÙÃoXÍ:I¬ßMejyyBþBT¥îú#6=q¨<ô,;¢ qÌ·¡Lá-á¨rjß~Ä=%³¿uû:Rcx+#.ÃVe(Jź¨C°×¦m"¯1IÃÉ2*ܼùÎÔFÆ2
?Ù0¨k˳ßïÚ?Éðý\ðßCc£{ ±¥õ>Ôå¯p/UMóè<g;e#6,Û¡¬
(àÆz¶bâJ ü¼¢®:
Öò7ã lG1Ñát¸ù|±<XÛ'M1çIñà/T½])Ïo9ìð_Urb,ÝOèL{Sá_mTܶ§ã³ZY:Tú9°Ïo¿¥ÁƳ(ul;g}m@óß¿²YµCfMjdÕó<#.x³:O)ºm÷/·ú4@[Zô;÷hÙhhP¯;wìÁÒVñ¸¥_Fm¥?ºø2_P|M9Ü©|r]¼½ko{<xrÎdLf¡,z7±¿ßg>îPxÝ,lû5=¹ËJÔé{CTjÇh÷ñbìãc°«¾DiÊî:L$eRI¦ÆÚtî×ãÄtç)¬ëÈß·ÜÑ~tÔÆãÃç£#.p²}wÍ)@))ë 2d¨
t`!.3ØYbô(%D®#%ûtdb#Ð7BÊ©'Ø«ÁYúcþõCµgïîé¬ÔMRaÿ2[þ4¤ ]gbÒ»woÕNÝ«Ï,.1D¦XËûØö¾ÛTÓ<5ÿ'Ë.¸¿¢ª×?Øä*£b¯iöÅW-«cµ@UTÙ #%AýJÌ#%î?øó>ÝÚô¯á[íê{}¾¤aªô·ï«éE aûÄEÃû(ÈõÍüÏðÝøÉöýÁä?²ÔðNxè`ß·¥"lÆPÞ·G?`lû=Úø ®j¹ËÂ\ॣ4ʤAàP(AÍ&
à¾Ê0Ax2E¼«¸Mór¹Ù2I#6Q0D%9èÀ÷¯0(^Cg~ÁÛRT:F¯gw÷Ù}}v®ÄT$/d*>Q¾4C´ãÝÞ¨¦ÙÇVÍT«ÅKv#.ïÙÊ[Tú_üúl6q½Ì:ÑAéé-¾ìE.ôñ x4àÎ2²#.±ñÞ|Â¥ÀÿóääqÚ¡K¥Èj#Åìðý3© 2r·2¢ «êÈ#6Óù¬<7ÐêYÖ1Ö$âÍh>GÛTÌx~2ããéÊô@î*%Ô39hþZ[ÃÏù`tgø·Øj«Úcü© Àïð÷Ãz¾ô! °,¹f°ÇÙèd"Ô@2 v¨0é³k(!ïh[YÙR|"h/ #.(³(00Ýú¸
Mm°¶>+dʦ²ÆDTK¥ÊGE´@Å2.¨&c¯u
ù8#aj¥6MIFEÜ.3+;bÁ$K*Ù³THBn|4D3¿Á#6Ù½3¡ç$ú{OôÙ«ÂÿHô³i"Q`UKÈ
s;$>ª¾5ñÌP({èlpùÈ?)ã¨,ý¾rb"Zô§KA±Æ;5WÚøO´~Ë~ËýOîNâ¡{Zc#1¼¦ÌÅ
P'Oä)Ï·±Î£¼M!+½E>÷TöÃßô9¶s¨ÎÞ?ä#%`cnh?½öÝ+BGG%om_}þ ¤M¼Q'ÀwG«ÏwE&h¢æÝnï%óªpmÜ"&ñõëw&©$·)¢rÛu©í³Ùí«ûÉíööñp)\uÆUüdá{KãqÚÛãE¦é]RÎ*8#.ñ6lTxÌ2i§DéÃL©Ýåj22JËïuPݹ3Tj²©ÿ:§Å¦%tCAç0Û³ô=f[ª®Û/0MksvLoTõwe1ð C¹{
ÉRâ_qýZkác>Õaü¬ûìfоáÜlJéæBBér'·;<[KåîñÛuïºä±fÈ«%3Ja1b{Ûì=G\ULj#ERXåncsÁÜrsVÓm;ÃX;MÆV ]±#.Z²·mÔ2$ g-$FÄÆñ L%ð.ª_L©§Ç6íßQSÔxÝ#.I»!¨M#.F×ϪMCêvB¶ð#%æ!qI*Øt§må´Æ¡t:CÖ\$×@0!ª#6%ÀBeV7vdÀ°ò®cÀAÖ©Fvt×FýeÐm6Û¨ëô_^qöÀ©3_éävjá:¤ö7T%â#.aû È3ÅÀã#Dõ<d!'=Ws=Ñá"{Üð±ür3»xXããÑèL#Ì{ëFÅ0ñ¹<ït²'ö(v²¢Uº¥\±ªÞËs[%k·ÁÖUÖÅZåµslUÊ®@ÁK¢¼ªÆ!E T$UhÁ^³¢eeÍq0Qj¹»6x©$ëÛAICt×M4iÁ@\!£{í!Êxt®á,ØècÄß³¡x ltH±h<ûyî̯wy£¥|®3¼¥ðìp§Õ+4ð)ÒIÍ HÂE@;Ð4['H!³¡ljÁQÎ^58uä9^çSi|£E_¬PEÜ4æÃixjRdF[ÏI)-|ÝE#.ÉBÿJÖ¢}÷Ø ÊS0+Zc8VêrØQ5TQ¨[u-¶*£guï«^2÷4¯yt£K»kvË_\h¼G}þ÷{ÇÎNÍߨV I tU¯Ìb*ÂäÚ§VKðfá,#lìÇs·©¿®üwB1óQ"¬ÝØÊN¿]S}|x×?¿ç=,%xo:!ÀI*såÑoÉ1¬J:ò¤´¡eÒB Û#.#%,þ$÷ü9g»nòyϨ7#%&êuÆ$3â6;7ØR71)¥Tð$¸¤¶§#6ø¹!ÅHTZaH$´"%;úQÒ¬ß(Z©"²(MPB0ÛËw@NÕeóñÙ{]=Üd[»ÁrÈnÀÇVoÃR@<$D DÉG׶·-"+joaÖà eSUXò'ÒòB«ÐÆ,ÚºKÔ¸g¯/7vj»ºRK]#.Ìeâ+µÿ|½xzªp®ÞERÇPig>á,üPCªÄ{Æò½½«XÜ©¦_=Þq¤¡A g6ÐO¢¦_*P!6E3Ë87Xd]ä#6æmó±2M#%áF³k#U@T¢yÂý3Ø÷o#ÖÉÐÁfÞî,Ü ;èÎm0T&â&4÷5I$Âpº~¶4Æ1rÍ/ë#6íÙj¼wüXëËh:nxfø|ñÇgXC§ÒPt/yÒ¿áìÍør#6°\ÈÆØÍ(< UTȵ\[#%^H#.}q¨ÛVFX+1á÷D¨ûºÕÓBà#..rªüm¾È½Í¡½Y]Z I¸8ÓLÓA5À×ÏN·Ó0$ÑmÅ#6æ#.Xõæa÷îÙâ.êôå\ºHÜ9T¥w_¥v¢EF`0HÊ¡E%xÜÂ+º¸öî2<õç<-#.áê}ϤÛy£¶ÙÜT[§Ï%)Ý7°40¶ãòâæÙO:§dXoY£t¢«º{{»õÆU;ªR%£D PÈÌ0ì¼Y3#%Û*VÃØq@iãAF®L`àîë´'©!ç#´ ÏAVì#º(®RÐBVcÙ3±EÊí a ¶)ÙXª`_ôÉ X¸h£Dì;£Ûe¼ô'¡4QÁJ#6Q`¹(T"@ çK¨ ®¬`²ÇînÆ´ÝïZ:uY¹í©ÆtFýðìÂ-¢RTÐfµsK>÷Bo¾Hç¼~YÅuúýsPÓÊÑ¿±ï 9:ôY&Û:öcU:çÙëBûrÎ0º>È^i
[d6p;÷6¡Oð#.¿c>ëU o*&L:ÜÁÀ.$ó³ôLx㤴»§Õ~àÂïÉ9Àë'tldæ
!¤1#.@Ìäu*n&H÷QT*ÖËCî.ì¡=9"E.Ô+ue×̪¤HÈA$}á{;~æJ²\¨MâÔDF`aÝGnJBPÁ=Ù#.ݱâcL¸¡B"Yáî¢ýYÏÒj@=½Ï<èq¾í!ÉùÆÞfl¹c\ü1GVø¦l.o6ÈêûlinDµÄ®ÌCÆD¬ïÁKøµÃÖ)Uf[(8?ìBª± §^fÀ] tJëM/BóC]é¯
è×»i¡^|ÇE7u[d¥g¥ÊZ;KÚ`¤ÆóÈ3;óæï`n
ç¯qi8ö×OB!2ÌØCP;Èä{]¡GÊ¢¼È0QvDÝ9¼¥ºËY=s³¤íEÃBî4¶:vAèC2.û\|ÓioÝv®ZFQ4ZOí²i2e67î1kÓkð/#.§]6@³4xÊ3töÕÑøelGͲÍÑ@R ])NýþüueVL5Ú)·é.´É©ü sà7§@4/:UÛË]uC<äR\wÂ'UWÞ:çQvbª§FHRÉS©Ð,wÀ×ß=uÃYV\<wWa"ä¢wÕ÷Èߤ#ö®q¿£å.#8%vÏÏíÏIúu-?µ÷ð·8>ë2RªMÄ£8{ôíåíxÍ]z¨Bì<bc«öz:yÿfáÃçGËhäbV
©÷b ÒÖéZÙÙUð%¯óèQ>V'׿_ÝSÈ2È6½_g¸ñ¢Öåä#%Æð§:¬É©£_ÑÆxÖyßÔ#%ÒéDÙ¯~ªJó$?Ù~~é8f>îÑ=G/
Þe%A7Üüq,[Y§â¿o¹b΢oªd¡Ýãà¶4CÄÀ?Æaûý?ËÉoôÝÝãèßþ$Ý6aH*2AHe,-3ôWðþ>|ðoÃpûgrñßãjËntKç;ÓøÂß%ÂòJMY¨TßzÊüúQ÷óÌ<u`ÔáXXCWKq_æA?ÛÇoMW*ôˤ,«éý£õÿ/7ö0oöÿÛöþ±/Ý8üq¤¬I&Éêe
UÕÏkôR2XIlW+YsÎC?Û äÚ¡GþeÝYg ÜÕ|ÆÚ#%$Ç¡µ¨Ãhý[<cOgöNÚk¼Mbf"\ 0íÝ{PÖõÏ?oÈGðª¡)©>p?îüy÷?=BVüsɼcýNG8(´5YyPYú¾ÎÞξ½¢jö«vÚÙÜ1¸ýË}+sk
6édص2½yÛù¯$Ü¡i)_?ï_3÷ÓÇíüûàüéC6ª?·LG÷³û_Àȯ«ï5Mu¹=!£~*+LOú¤k2¨bÄ2ðÏVÞ 7üDÏDa{ª';âû (#jº£ª%3t»¬i×¥¦AQÇ®¬2ÕYhqß´w/ùøã¦Z7¤Åö#6uÑiM«ZÎ0XL¡ë!
9¼zóüª ²zYÏ¿hnÎHr`§fá5©¯N$fá"ßæßV Þ±Æeî>¥?ë.3/«ð>KÔ6½M(Â9OÊK#6=mcÒï¾´'ª¬§J¦1Eæw³g¶ËO
õR¿Õó°"ûå m"À@¦D¡È_ßØ_éú«ÕÈqè4é|`òßRì+´j`Q(âL&ÂÐK#.FM=3ÿ§úñ3£I¢Sø¦Ø¥cÒ ÈȹÄþ~î>ÜþËqU×-Ã^ËuèàH19ôêaY?¸NN·Ñ¯¨]ó#.y·Ûßù `2É/ÃDÏàê> #6m*ÕHç<\2ê=|.mcÅw~÷w§`PòMêÆ9^Þj¼=ÐXÂfulDRÀç,±þBpRHúÐÝîµ)_Å®ðߦ.üîÏÏôúýà|Iõü¸ò»ãMJîëáEO×ñ"aÚOA$ÉFï5ýéúxqçÐû¦Fwd;zçСËÓ².'gòêç©äâ|9Êlråó×ê¯l¢:vGÐi2] ³ @ñ¦®3×#M»½.À;Gâ¿9BG8ý¯ý\ý»D=®h¯^þòÖØøÉýò=kâ<RÂÐäõ©DD`_êåî"xKyy+·75¼â]*ß:Îp#%"t-8¹j°ä ®Ä»ÓëRiö4úi÷>áú¿ÀØñ<ÎzüãËçò%LÑQû>\ÿ3pÓ°êvÇ1gío¡¨ÓcjÛÚï^ÿø½\¯:³Hr!i ~ZT×°-î(ÿL½þrø'@Ù·Uì:k¶+cJ©Òò]ô8<Ãr¾É¹Ð#6ÈÔ²¤ìüØõ^cÕgqÁoTÔL#6$8=Ìò<Ë1c4+?G£âòó¿x#.âÎ\ÝZs ÜÀàF)¡Ehs.²`.z´ñòÙ0öªÞÒʹQR~m+í»0Ç._¯ÛËÑåÇC«nè5 ÏutßWv#60èªZ.0òë𷵬ËðSF§NOµN®#.ÐûEÁ¤eûøÑ3¦2J¦|;ìïMmQ³ ïºvjx¼rïJ¹¾Ý~Ðpr)c§~¢;wo«j£ïïÎö1sÑõñTh#0Ò!ãóR³UW×}Úh¥bÍ exËá"æ|PH[ǧ:àJäô/°qDC×I¦uÃGµ_z§ó8XzgüÏN×È:ÎÝÓ¿¿x£aF÷Ó¤ïÅø̺["·½ò½ejøM§ÛAéA&¶²¶®6)BÐ;XGê§('ꢵ¬IB¬×(~ a{Õpß5×.êµ55½.>#b·´Þç=ÿ©]oðÃG§Tmü#%AÁP1@zsÍnál?]ÞªzxkÝ@2 eó*+hÛ:¬¿wìÝ©ÎÜ~ TJ^9¿ Í4hB&¨ï¿#.xbðPýÀ;Ô¢^Æýú}¡¥ØKÚ}´!I+ê@=ªçÏ@-êá)"-±ñ³êaå7&#.J+Ç¢ñåÏL½pæ#.uÚ
ýÏó,fò¼5à(ÌTMB³î9ál¡0á5Õ:¦sV6z=oÝür¼úÙ,åƯ÷~\Ý¿£m½ñW#úLvÅÙÏ#.{£PP·6Ú).zEËÃÂ{ï»ýÜan!Ì@ï\Nø絛*}Wÿ±þÉ3ÄÒS+ÏPhÅu·¯cãßmÙÓÚ]<ÑÒõyÅÕ'ëïztW{ÛÚ³êøÞ`Ì«í-XLm#¸Fu¢ÓZ±ä¾µïÿ9S9í¶}È8ß+äªnæÓ^ßn$ÊdE[Ó'}ìt¯íøѵK¥Q´Ûmï·ms³ñVhïU¹á _@6½oÞíöO¢êCUsªVÃú«:ÇJM,²tnOäÛä¼r'Jh±ÏªÁ¬Wè* IJTy`¸ñ´,xÂÆPèL*3(#.ÛàsÇÍ(Ç5Ã.wà~>>j;A^ZÕÂ0MÆÇ¿*vaF¸7Ï#%÷Ðg}lÌÒÌÁì-aÔz3urî#.÷?̶#6!î8P¹ò-ã¡lÕ]EïÇ®ÎZØð[¥ðRÓºÝâH53û5qµÓÝ¥¡(¨*SvAkë«Ü´iXE¦ë%qaÅn_#%ÑEò¸ÙeÑ.g}H#lkÓ>§.¿ÙÔ¯-º(2}T|pðÔ=æ ÊÓm.C:)]úÝ«ËÛyï§ÌåÝÖÇð
0«¥7§aÝçYÑóÉî®úÁÛEg'>±E®LNïzûë1Åè§âßÒ(íÓ\x¬ëµÎ©êwõÆiYئóãÊe0wóÔ%<Gz¦÷Z¿±aúÝÊéFK^Ô%zd¿M½5:îRª®cw×{Wô©hØOú¨o¯¾½löyâÍ$®¨¯zÀ0§mCÓgÀpP®¥hîÒöUA|ÊÀÝ!=yy©DzäsÎ9UI#ºêI¹#6ÉWeý¯gÍóz8V)tÇáFö®úBÜXöãfñÎþG|Âøoí.lì&)ÄpæôëøMSÓô5#.2sQ"Þw"×ju÷5ªNþº7Îåí}uKfs=}éØzÚ_C¿dlO¶¹²ªrú%§Øçß#¤¿|*¦góßsg~®ÉD\Ízw¼Ö~h鬻{xHgPî6ßÂ÷¬8¹ãß³Þt[iÖ(N
ÒIÝôпÅÜSm©ÁwtîsÄ:·'³?¬g6ã ÉÄz)÷=nçЯ[JDqDQJhµ<Â^·gPáñ%mÝäú»·n·=3¼ítd2ïäËÉAíTdýúÌù^sÙoR×j=µì\å,c¾-#%¯Ã³x©©; WÍxÙzëX\µÜéó3Õ] ΰ»«K^ûÕGª1Õª÷Ä¡k{¦1Bϧñ êY±£]é~·<ëí¬«%HºîmÆ2¡´¸U\ E\¨¥D#6Ö©ýè¥=ÿEÌã¶ÛËrëïÇYòûáã%»¾f=ÞéMÞ³KÚtZÓÈ'l8¿8{ß6TF=Eò|"#.ßßUGÙVmÏiûY'.þ÷Æ ´n¤(¦Ôh³ä\jdäW¹MØ£Ç×G¦XÒ|^uS&Æ ú]^Ñ]s}§GPWé½ÉµùÛ]¹>íîæ~çÚã¯+}ß Ùî"6ÃõµÁU=c¥Ú8j~>Ï?sÓ×Òs
Å"Cqv
?·åN=3 ÏDüÆs\ùÿ¤õ¤=§¤y-&*JýöãÃ[ÔÛwbÄØñéûDfNÖHZZÛóJQù«¿¯bÑÔ|¥¨Áv¼ê±¤z(ó±VÖÁtAµêq¶#.èÄø6ÔÔrÑþú#¸\ØÇÖgÞü},#6ÛNjBÅp®~ÃBYÅ7àÅË;æßO¶ïÃß«
Ä* Â=µ³\Fv©êÌÁRÚMܯ©øeàE\G)×ÈLÅ<ý];8iÉúÆ££í]Ä ËĺÏY\6Çg#%U¤{Ø[»¦.I<:Øg#6¨Q.AQÁ´7漯#üá#.¬h;û!]X0ÇÏçò¸mgÝ19ÍÿèmúH¾_HGYÓ¼Ï?N××wíQ:)þ$ø/KyÎi6¡+vJ¢ÕEB¹@¸ÊÆðP¢úz
¢,¡ªÙm¿¢ÛiK»eïAxý1_®ùS4`÷³
¿wÙ»N¶{PÔôÖ÷ÅTXPD]Î*çDïCEüYc¤ô¤ãð^FO¸ëz]ÕÏéæcpÈÚUÊUÐ@,#%ÂpHmUWùa±µ®*|ÛH¦Î}Úu÷'Ø2Ô¤æ¼
ìGC9BSu&3æÖ5ñh÷=3m"±|Ø\!XP.{ØyÝH¸¹[¹BJ+ÅGPÍS#.O2,,<Ó¿f;r÷ú½M`ª)
®¢Ñ@9b\m@ü @@]¶ÐئD #_K®cR(ä?µ#QQÄpFñ#%¨ªêªÄÄ:UÙ#%¨"ñÓmݲ#.·4맯É(¾Î^¬(üEJBë
23º ¬W¾\îp®4«ÎJê#.¬ËqÂ&zÐB/ò!<Ë9#.ølc´Àw£ôMzME×®#.CÁEEÁEà#%<så£ñhõyp³R¸øðá#6ÌÞO}¢åE§=ï½ï8Å»ðàÙø{q! ¯ÑÅ=ÜÆ¢Û©)êCöà?Ës_îì]#6êT?@-!öðó÷ÎÌ/¾¥Mþ¢Jk覱{Z-@?÷U§Õë¹üGê-Ç·Õ@{ª¼cnÎL§Q-ðÿúöòÎÿÛeÐFçÛAùk9ý3xÇx/À4¾ÔPÅHDÀÒ¯ §¼z@ìÓüUÿ¼x´#%o22iíé
¶z® kÒ$~ÇÙcÒ5õ«oÕöü}ù°RH1è¹çèÚ4£}çKêçÎL¥vJjþ©J%ÿñ ìøÐ}ÝAbArðQ1«o£Ú·X#66ÅH.>qÈ|ñ$T½"~ßÀ$ééí#.YqrA@f#%ûW°@Cë:ÑÐi&s7Ïôì¾&BOCüf+uÙòj Ù$ߺ×Ïíz³¾EêOæÚ$>ùhÕn¡át÷Hú§¸!#*1"Ú.Nç¸Û;]\xVÙöùú¤d^ wÏ|gO6ÃϺí;Jæ0&é5Ó#%}¡8Ur/$ß
3ì>Üx¿,Cq¨;@v/#%å@]¹C9P¤grÏþ¸(9Á Èvk$§9T¬Æ4h ÷~ÿm*ñ8ê»È`#%X}¹lJ^¾ü. #.JCVg5t^7!ß÷ eøÆe#%~zT)AY`ʼNµÂùíUö)>Sæ×rYXP\¨¢!Å&N0#6±zY*¥MtÛ ìtÊl,tgÎçg2jbOåN@Âq7´ñ&¿F)¶¦=(({;P'+ª×ÃwV_ðÀëá?tf¸@¢ÛnóX.3Q%x]]Ïv[ÒÉk¥×¡TÔ4¢¦ª%
e^ROkl(FX8g&øwå!£?géâÊ#.#íYÍïj~âieÄ×u'³Ýe;gÂTüLìq1Ý ¯#¨(òáá#É,pçtAè5+ÙldèwäÕÒ{øÞvåÆ;ÚõmP'@î}ço=pÊ2H#6OGê_0P&ÚJ#%íËTO¦\ýæÀ¢jhDp¿ÉꡧÐy©9Sr³xêÚ-ÇhvÔd#.Y|ÓãÃPmSÀ_¶V?L_"'(PvÖR«6ã$¾Z'xõ×=÷#.A='áTP)þ%¦}ýjW¿Íþ\èô´Ò¨õÑ3Ê¡â̸|ÅZ~c¡ÞFÊ0V(·ÙÛiúÿ+Þíôüt|~!s#.Ë@Å¥ÑZÃñxä·a
%»©±ªþ½GK1à*ÒpÁþ'Â=6qK½¶±/öþ®x ©®óÒ½±dRl/U¬ôdÂAÆr³#6+óÁ
GÌ&IòênçôBs\g"ìé_Kâé?§èMað{4ÃCɸü¤ý³þ~öÜ
ÚázNö}Ëê9)Jë³ÒïIÆf¸<Êw²Á»¤Æ=,µ¶&M!.üpVí±ðNtÞe°Ø²Ó¦p1ÐàøôzrżùXwÇ+8So£°y1Ï,ð#.0#йò½ÇÈB9:-{~Ã1[rµã[öÁå/{Ã" V«Ñ*&dÛëqì¶Y-Ï.õâÒÝpO5Æw;-¹¸ò ¦JÅff Ç»¼Á¤à°ÕçH|WÉ¡!I¥Æý1eEÖ¿Ö9AtP_ªÈåÐêkWHV#6%±¥ìå¬1^´#0Ó)åªùº°Eóg*ímŲÜëèûßÁVBo^Eæñ4ûyÖ°.éÄF±¾z4÷ö`¡(Ù§¢W'¨f鶹Jb®òÑ;¥:ZÑ;n»Íçe¤°,5÷¿_¡==:©8¼á*èçñ_ozâ|qä5v]QsÚö.2ß#6ïÓÓ~ýá*ÜEÛ"c¬|T=ù<³##6àÆ`Ñ-¶P¦#.
ÀLï6 ÏÜѺ Gà¨ëÔTt6k®^m¾×¡Îu¾ír%ÄD>ÚòQMã~pÝ, ¬&»_Ag¨²Naæ{¼'##6ØÊ°àYÈ#søýø²\¿ú-´Ø~mÞÂɱ*6i¨I@¡¯PUG¶/G$YYzÑÎR0úgÏüîå¯Cæô~6·ÌSPÔ^ÎÓ¤é#.Ózý¯kHmiÛm.3ÌxK¦ÜÈÿ~®%Ä"Þ+G;L¡ïncï53áõ>¬pxq¸dê}¬=ÓÓ·UýöA¶vrv¤94>üL¸½p¯´°©gL{Ùþµt6É{<]^ÒÞÓXÈÁ\ ¸ALäo¢Ïóü¢Ôð8ºÜP6;Ak
Ù#.njú«xõm©ÁäXµEÕ-">/Ñ£§5ô¦`åä[R÷6qì./Ó#%®Prö9¤¡ÏTXù8H^ôѬPòÖ~Zª¨S~§!¡<פýUîO'Uú¤0°*û¡Â!5Éåúõ
`ØY³¿ÂÁà$µD£#%¡<ç A8¤y¦ç½â±F*$PIåeÉ#%úZ;d>ý{/ón\ö»A8*#vw3
*ü5`,rØ5¦#./¾ºËÜ 4WiZ¢Gé!uá&(ÒÇ_qDå®g·3$g²a:¬ï,ÕM{ÂkÌû!ÚR [#.Mßâi a½6`3"»½§ïØÈNÐ+Ùbv§êëdëZO9ª$-]»°Ûü"üfÕÃõ¸pELÂçìîiUHE¹é±e.ÂC¼âgA¬6y¢gÃë]±éwÁ÷Uîåã½}¿)¯#.A²ÌëðÀ`lAºÁ×dí9Èãjá*ÙÝ渻²§°ñ,«hïÜ£dwÌ.°»dåyr %(sãeäFzeÚXí¼#.Kó¿iCÜÚ'~Z6´#±sYJÉaLJ¦#%39F¸¨Q" ^Då6{PSS3yÝLÝ'n'´sûõ*ãz¶«cT¸#.2!r(PhPÚë37nPáF;E6#%ò-®}]
âRkß ×ø°ç>Ðt©[â¾Ú²Ù¯kYëõÉ×,oÅѲZf°Øâ'Ìü¼üFæ"_êßv8í<[8¢XæË«É;ýÚru06fåÚ¹$£ìH½_¿ÅÌÖ_ÈB'ÑsÁ¾Wì$³m#6E]}Ñ#.~j4aÙ£ Mfù À\ö=°¶²ÔJqåÎ{ôÅOª÷Üþ§ÒjAéTPº¦Êæ}Ëã1¨ò%¦ÿ£Ì÷"ÛÍ¢1#6HsMÇ¡±Q¯5óßâ¬Ì½9ÆÂ>uRÂ#}ì3va¤gìvm¹ZUÀ#ª³qÆîëVØX®H2ÚÏßÙ#.ÁÖ@¨$7°íc<!"·ô2¯È.îöö!Ò5ÐÀ¡L÷³á±Ú¶æ
`ÆVØäºÑb#6#6õϧë(¢Ýa'9ú#6«`4Z¢ >P4i á~q\KAÔ!nAÌ)ÁÑYÅɼLèÈÉ6Þ¼44m§3r !±ééZ-*5Þ/!*kâÔVäDK¸ù°;"Ön[z2bèé}ÚÖ½ÖJ"ÃX¢Ìvh{X£è¹Øf¬b¡Zëóè¾´ò+Au~üâOÚ°Éqm©Þ:¤·C®aïÄ,«&q\ÈA̶¿n<l4(ÉÙÛÄWÎ"oí?w©zg\.Äf¾]%kÙ¢t<æÐ#.cÊá tgßr#%s-¤ ÷çmhÅ»]§N4(ãZs´cÎ.ßx*sgi5ÃÌJI@íod/(&_ÊX·éåøC¥¿ZO¹V?0Ìd<Ö¼ÌÄË0æ;bù¶ëðzàUöKd3³ Êáh@ÙQm´c`ñíYÀíÌÀNò1ª8Ø´+n5µ#ðF¼]²"RO]WQ5#.ê/Ùªß~aêÔàí#%飵âÓê(-+GcÒÐÝ`|^D]ÿ¤¿³ÄÁ#6El\q´`!zI¡¼<)MG~©oÖxEß¿øÍF'Qn#%xTL9ó¸- 4ÜÜÜÝOÂxp8Yx¶@Øo\D÷Níu§WL7COÀ»îZ¨#6iY|ÊäVúAÓ]&[óêæ¥À_5·i>sE/#6¸¹%5ÿ/ÃN¿ÃÝìï(öþlâò9Ðs7Îåú§óh£ógTHðYg}ç_Aò0¢VÅSNÄHQ'Äá×õÀ£UGJÙB3qØ÷dZÞgÅÒÐq÷q¥¢×_aÜ8#%Iü~JÚ79ÀëÒ6ò`á|û6¯/ YÚr´hÄú§]Ù3óþKÕ⻳«Ä|3ü|cÈuyb3fïíÃøÝCx-®X3ÐPXút?QÃL#6Ô28~±s;{þ|%UVvþ,¿Æpgºÿ
ÀY²Tì*Br)S0eÇûï¯Éþp>VÇù¸îü¡ü_ábÖ?©BÈrøð½C9%_ý¹$TÅIÿUP©þ·÷êYE»üZÕôAêa#°^ØXá©81#%hÿ]¡0;5gûYý¼³Ö÷vØà|ávçv
ßëûîÖáþйÞcË«±_wNóx©©A3CaÚ ï:Æ]Û¸
xn4©ã×Ìê{3 ®íH¸éÍßYTBºâüT£Ca²lÀºª<ý¼;ª§`xµÍG°{ÚÀÞõ{¯aô{ý.Aô¯³í4A#.PÈû=¨íÚ+þªYÄ; ]ÃäNÁ5%Ñ
î\þK¿ÞÍ59Í=¶Ïâ} F²¡®B Ötüû§ }ËÔ:Ð$A7ýß¾ºÏîû]MéÎÉã D|_÷*ØUÙý./ó,Õ!nÿP=`dÄ_¼çâÜ&\B7dªõ{ ²Aåý qÈP#%)Xu¬¯# #\>Ïæþ¯G¿å+÷[q7¡çb<*Ïw÷ý=OâGÔûôH|ï=áãøN®A ÊLª´RÅßzáóHò?yCÔàVøþí¼
ò>!0нÈ^ûÆÁ.4ñ6×å#.ý?ipvóÙ7ìj¢Ñ X
%.S7pÂMÞbÀò6£4¡ÖyÂCaÎ#.Ì·¨¬Qv ´&ËPÿ<#6ÃvT«±}ûXðÒ¥WÒ`_Ýä }ÝâÄì9Åwû[wmZ?¼C`ðã tÌ{àsõÛ?OqÂöVÆȨ7RÁ°Æ.¸È(H0µp½#%o{íx-)F,=ÂÙ²"ÃÌä°íÀÚæ9Níw.i
cvL0ìòÆÐ*ÚÃz}pAZsmy^®ROÅö
îNÿïòðYGÔT%X|ËBáá5¦ý4¨TÎ(ÔXÐ#ýeµeþô=]Hê#%ºwZÁÀH_6£áúl¯ïwç£èÃ0%ï»=¡iìÁ'åÇ`w%#{ì;r6,#.øÖ,Ĥzdx`¿ý9p©CYÐÒTe*ÞiD¢-&¶Ö H<>Rg#65Y$î?.ÔäxRR°Áîú=T²U}ø@ú1ME~ kmmÙGåô¨ó&FØèÃefæj²~G³M¬2ëôêYAÁwYÃâÖ÷ #%yM©o®#ÌôlBÉÕ@"Ð$eæ Ä|³5:IF~¸"Ì-¨É>¤÷x¸º"#.?â#6ª[pÆñ·æ4ï* *D¨ uåsØmos¬!ÖÃfMð*fÀo5йdãÆ¿ç=1
V·ñÚÀÓömçÊkû8
6úl£\ðgbÝK!UU;¤I#6ðïlJüý¸f¶Çí86#îuï¸öoz©àÖó×Éà<è:YhÜðyfÊçñÎSlK6ÉÆd.ÕåèSøÌöü½Aô~Ã!#6ü§ù|N3ôÿ»òï;§ÔOÚy K~ô¡
×Ä°´SêúfÄ=ºÔ#.óévdÖõò?IÆÉõáUê6üôû[~@ð@X#6Ä`ÈÃ/õ{ü>¨ #6èQÚ@Äöl²Î¦§\Ã)%±·P7À`«³¹ð×
÷C.Ðup È`güûV}¹Î|¥F1°bcC2æ²Ëæ0}"£A°o#. '#%ØÐhü÷ìÚ¹&F÷7yGÃÌ2M:ÖúD(3ü_ý}Hlû·§qE#.2+ÏM¦äûøæÖ039!×ÚFå9-Eö V#6`dêxïk #%ÔOÁ-=fq/¾Êõ¥*`k|X}yÅ^Eí!l<FDYºÓA ±¨TD â)#¢3S:i°q`wr$îï+à±">,òq$D©L#63ÎÏõkNðÍÔkÄ^!rÈÌC¹éi Ñ93C<µ½Ø2.¦#.Y$à ¸ûÙÓñoXÿËw^º#%rÿúõUvAýù+RWáóÆVoë¸q®½v¤ÞzíÛ$cÁú»eXjÿÇý1-.õXÊf]dmffµ¨Tä!Ô}§§Å´5N*näl³+¤CE×I$ª5LTËMIikm§«²Öjãzef׺:õ'«^kA«ÐÖ·¢féuG¼ÇV:ÒÄeA)2¬gøY(Î:ü¾Ù#6X#6ª4YH¹²¨éô0 AP~_bÑjTmå»2sxqnaÑXî;Ú%³ïöÞÙýµ£tGí^^ÈÂÆÛýÁ éó˼ÉI~}~ÝÕ¼QRü¾ÔúÑ÷}q§#%è!À´>Ò^¶Cwl9¨; 6ðIÝ·;¶¯¬ó·Þd]¶d>aØZjH M)ßQlЪïVY¬$ r¶PRm82d?ðÛc;ÆxézZªÎÀ«àU¶#AIE5º&W¾f^%àù§S«-5RkÓ¾]ZÍÌ¿Â19l=1IAJ~ËöêuEð4+Õ.^¿%6èßرfÆó£æg§-Ô¦ÝɽI"H±~Å÷WN3v¥7()sp*Kûû;®Î϶þÒÀû´Ûï3£ßødc_dDôvö´»~¢µQý![~Æ1mؾñ!túíÈÿ©©¿)èlHÅ3ê+ì:öK<¾¢ªQRR"äÙLÙ°LÔËsMw¶`¡º îÍieBñ@0bRòK:R¢d|~n|âWnGô ݽ}8_¨à<'¯aòV¼Qîó5¯·o\W÷Û^0'h7 2u%¸Fmîòf±0/ÍÊÀ·ió¸ò@£P.£ùbúÈ+?NÎTáõPäDs#%>!ø½Þ@Y68þçxÉ\ż.Ü?ú-¸QÙþ*°DjIôßç½a-êzÄRÏ¢*%öQ<ìr0}y,ýÂz ú>Ç[ävãò`õ#.²Â½ú&Ì2(Abã:6¿ô9v¾ðû`ç¾É±9ßÙú_¨ì>ʧ8»ÀþÉùö»6x'ã7u'{Å;H©A5twµñíPIÉ(Ö?xyX"DNþ}+»ÅÞysF±èæÆÀY3m;0#6JÊÌ#%âaAö÷D<
ÉY(Ìò ¯À.pW÷Îapõ÷lòÕs½8¾?~ç3PGÌpC© :¨3yC³ÐÕ?P«¯»/id+ä?ÇGÞÙúÉõõɬ÷V7LUQX®4=áù2»Ý£¯ëø|áçð*úÄêkCÔ¦j£I'±â©æ>·Ò »ø5UÈA°4d>/ЯãH¤Wb)ÙZ]CÝZ{_\£ßö¨0G±LùrupÖÖÆZÿG}6\ÒT
Éá åõú÷£°20®UöÊ°8MAÕñ#.7û;³¬{¯Ïàtc$:FÞ,!î:ìÎ:`âÁbqe¨s꾸äædQÒPÁNêËJCì2UÕZ*>RQÀÑЩüèeLæHãc;väáÁbNTm÷TÍ&tK£Pññø©tóUHª%HYÇW¯>nÛC-mur6ÑêE±½¹Þô+n}|=i³'2)E^úÏS<a$Ed@¡$´ZЫFþÎ)Ìí76,BĤJ(~¾'QvVôbJÁøN|À=ɯ»ß<OZ'Iâh<Þ°ö#%`íßÂs#.dòUî6ûcÁ-£È3#%§Mª¥¹ãïù¼_Øû«óåïè/_Çk/qcu¨²{¤·´?×?#%#49'öJ<ªJÿ¡ÄÃ5má¥8`«:m _\¸Í©RJJQ¸kúºu÷OIÝ'lòµ°~3áGbâ=hòäÒøj=ußËã$½!°ÔÃïLý®äwò!³Ý(TöCÇÙDåÄã÷~CÏ¡\ÈৠT £T¦!Sä§r>Ð2üY"æC}ÀíiòJ;).Ù¹½ð h_éç±¾üåw¼!,#6|õ»ùN}Cà=åË)BB¡háô"þã3ì kEµ,ãe'?`vðßù\à£öíç¶>ã(}M|)kì`éþ¹áaª]Ëàa½E½h#ãòF%LæV #%ÚI0%¾ Z\Baнìh%RÀ2` øÐlHvE6(¤\D½dó¸HÅH"8ERG5Ö ½Áù²AC DÖ55-~£¿Àú}ý#.>(#.ØÈðòÅÓ<³1Z*¦°°'Qb¨r#%*ãIé}¨kOH~)Û´ÑLAG§QbY()9gb4 ÁGô~×ôs¢×3Ü×fHz3J³íü`V߶PÁý+_>q°Ù#64XÌ¢3|»Í¯r«Ò¸n[]0ÙP²ÙmÝyæ]<(©hïôWóúý?fþÐ3MãʳìóAì};`%õñºéîfú#%½'¼YÍõù½HÃ[±#hqÃkóÔ6CôH&·j ªY1#(#.DB2`ëJhLé·E(Ò*XZÌO/' ;+óxBJ<ò9/;3§¨^-ûi^Cµ#6@Õ£wëÜ¢}RN5Â7ön9ÐõD#%ØpHo(ë u}J6öÄ+pòi:ºØç¡<½s¶Üíö[cÛ.Ó à49°¶¨<ïªÊ<Ïgã³ÙÛ;Âä=Åa¨]lùúÇ#.ÒÒá)#6(£ß½d©ý`~¯YíIæIRJìóî9\§ÃÞúî8ÿ#6Ù6zC¬÷|ý>4Ò~Á1Ø¡ð&IlLatɼ,#ZÅò4|kf_ѽ ´¸¹K\UÔ0½¼$
´UO°ßÈùq¢úHhG®¬:#Y9!|úÿró=HÍ@p2¡ «B#Øë·×îüèt*KHÍÁÙ·Z<°ïC$"4ëêëç?}z¢3Ôx'îM'oÝé#%ø÷ÿ´;)âB0®ôo%dL,6f(·Öߤ¯J¼u.î¯[<r±!J´Sâ_í#6Ïíªãø ùßïÅ#%¯PC2?¢?½öýfYÌ1?I#6¯Úz³:ÃÀÉåÖh¢"V£Ìwg#6þ¬)ʲüöTÜ0¯Á=iÚ Ï
Bi0ÖÂ%ö§gpõ c%ÌU!1¤1*D\?S:PzÎ ®þçæËÉHJM´RÁd¸¸1?;ÁcÀÌÝ°.<Îb§ Ö;nçÎN[»Ñê Ýõ{Cíz!RسãõÙ. S#6 ê=,è>½¾zDZN°ëÀàô·NV2KÀ.*Ð~ àGX5º!¶Å/K¬Û
Ø©ÓyâzK¨*üÌ`
êAnßlä¦ï/g«*|[B³¿âUBP £âÍù·4¸Åá8'Pf,Í¥dÄ1éÿkü;Ô¾Ö#ÕQÒRQñ{ùmzIIJ
0êÄ´ÃÅ
ãd
å1*ç0%v_η?nTÖtÎ#l1绸UgP=`*IùI²8¢º'ʨ´§F¥ëPØA¶_NáAJ`µ}ÿ¨|ýÅÓÚ/O>9X<ü|z`î7Éíö¤»ÍýVèt¹ úd¨HÁ^mQÔЯÒkKÖH¾ºëÓ.pâìDéGb\3>:ZA*à¡=^Wû<eÀ|ä 9 âp]û-³¦hêØy¡¥ÌÁÐðN£{q¤bB:8jð´AKF#6#}ë¸O`y½JÝüÑ<÷ à]ÈÈJ¬Êª%¤[9_Ôöì;#.HÂ.ÒPó÷áùOܶÕÜÌúQóμ8*eåàx_Xú(ÉA=ÐIÓíÉ\½èÖÈ,Råí <nÝÔn3Ûò'ÙÙéóøö_gùUJè â¯Wô(X¨7>àý<?ÔÕ =>Âcp`¾ÆøÏðAv}Ï°¦òO"¾<ªR{˦8r?Oësðo¶S·à~4Îj·¹£0gþð¢¢+dã(Z@·A}îlí
rÔåØÞ̤]×Ý®¥éÎ#%5I#%M$ee5hPmØØ5o¢àLÝpxûÂoJ#.0I Ò,6©BÈXõZªPýÑ÷w*÷o6`>Ϲ#.¨,~è¬ð!"Æ"?» Þ`]Q{jòNo.ä˾0,bd% ¯pA°kó:Î.îz³h*;¾Ï»kõê'©uÑÔ9V/N|¢½%bªdÏ¡?*=
ym+Pw!Ýd#.[*p
½ÈÁa°ln7â^öÂ9íLÀйp´4#6ú}>¿|{Vuï-¯M«¼ô©)mï¥Ývó·n°EÿQõ½Ä3t6ËnáññõÙºÈÀ®Þn]¯C9Qpë]q¾#.ãvË´[ÒQ¦ßôßõ
ÌD÷F§-hja°»^¹BVͶlØÅ#%PX°V0PPÓ®¹ø:ä nî¡zgxDeñÝÚb³ÇÐ>yÊék¦ô>z{h}Ás1óAdÑäH>Ôî£éf X}Ô¾îÍÌ#¼ð8&`ÛwÐ6pÑF¾ý
BBM¬#6I#6çá~Èë H7V%íü/Äÿxên=@çE¶¡ï=jÛQQEV$[jUUD:üzâ¤^*eVØ!ªú¿¨Ì&&r¶l|ôD\Üç´XÖi¡?«Xiê%x¯<íæ®ézîÒfSo[Ö¨ ¬s4üåú¿ä'÷åcyÜÕÕáPÐvSÓú0Ñ"#òÈðÍ~éº{ç´×Dª_*9äÕ¸S^t §(MÉg#ärö=§ßÆò}²)NVú¿A>?Òe ³èÎýPã/#.Yl{d+×V=µpø£µ0têÔ¹2ý0â{Qnwvï÷ê8KÎÛ¨àzÊk0Ó2¡#%óØéüú»#.qÉTÕK£ë±+WUÑù÷ÜxÉ°ý*(D¾Ý!Q4ãHÀ¢¤çæT,P@X$àY´5eHrëþ;lýÐèllWTKw{ºZĬû?ü£øN=ªg±\ļ3à1ê¢Il¸ùÝã'0´`°+Ãm÷@#.ÉYÇî½Éc÷µóy§#êúéàã/ê#%B§ôëé._0þjà%Æ/ò9Q»ür#6Wúÿ=
rý¥âÀ¡(#6`1M3-ÊS¼ómÛÛËÄï)sª[!÷DTL¡Y¬ß¨èhq9"ºT"Õ#6+èAá©
¤©¥q¬©æøÚàúY¡
ûfgñ ²¤(kf:ñ£ðåØÅCù¬#. çXÑa¤Å¨klmYçqÎ3Ö~73®Ô.¦Æ%½Q²: v-°r· ê0#6ÄlÖ¯H`³}gÏ¡t¼¨Lýïä|~GôÿìÛnîv<ÁÌ!ìÊù#.ÓÕwÊ,ýðõ*U0BA_Üá÷KÒ¡(æI:§*þM?µÍ®ßÅÁ5ä=½ÖN}¼NÍ\ë׳&í?z Ф´Y-
¤*¨õÃ~#%·öµ¦ÚSõ Qk#%Z
z³#%åÝÈW;Àϧm`ðÝ%#%&âUêï1ó~{ýq×ÙúùT{,eÃMÙ"bª!ÖÍÌ"qùzNº|úw¿1ÔeÉ»D@åÀy#6#°2;×â¾÷%þ÷2zTXAÄ#%28Æð*5@åï'»nÊlV#6~\bHQ^ÿ½è¿,[>G;H=iêPÈJÞ§b¨$ ¦ð¯ñLÒú.½ÕÎ`ð4Ñm°É(4^?bS*èdðpéÿ7f§Mó ÜÖñ?A£7DË$ËtÆûëÌdÞ>o#%d*6<¾Þ<Î= ͸_èyËa°aúðLfë9ßmÚíãÆxjt3û±]]î~N.5¿U4K.w¤Í
ÒG
Qëæìøæ°Þi}kCeúÉî.§ZÆ8=6t¸Yr#6%Ý7"sPDÖL1ܱ þ^'y·=ë;â*Slb¬l{¼*þR{\2î@¯çk·¨ªØPîá¬
âðDçG½#6@<0GzÂò£|~Hø¤þzN ØûcGÿÍý]bïÓcy×÷Ò
Ø!éÅ!ùÆ?í·oÙÜÙ?ÉåTQÜ)ÞQñ6ÓÒáÞú_7Ûàòà#.èðüª½ÚpÉê7?v¿~óAÞJîîç'bû,íÜz@®^í@q(M¶9T*²õÃ.Évm¶Âº9ÏY t Æ"ñÌ&÷Ä;:×ì<ÝLò0âÃñ{ü×R¬þ/$úý3Ò#6?¿>þ_Óu,6æsl»sÄlË©Å0âÕ躨sæG#ä.ñuÁgg¹mPÿk¼§l$XóüEævQ?â[òÏÞßÆIGGHNåwÒSîýçâ-¹³\Áxµ9ù¯s£{©¤`öù¤J÷ªÕ:^¶B4Ë?ÕzfêÞÿ§¥¢®¿)#.!£aû1¬KÚëõÌóê2_ã[¬{lAnµLL#6#.µ qÍ¡S'[o½ÂÓGf¬(`{JÂñwóç¦$ÛÇRu:g<®ÏðÛ]3êød¼çCpêÖ4¦8óe2övÏw]Lâ0W½k³8h[¡åÁ,¶ {ö}/l\_GH½£¤á¦#6ù^'
òlæ¢å®#6ÊÙ.rw ë0Þáü~-¼ï>]¸ãÉÀswsÜ&
ÑÜÝÛeìü§]È]2ý3Ë4Ù£UtÏ[mjpª¤9-ÐÁ@Ab#6£AkãÕÓlÔùúøoTq4°gÒ3,Îw<vâ/£Ã±ü3#6¤39ß \ëa7gÖâ¸<«I
º×$ #%!¼|_á1wç£6ôt3kì'6¥e¶>É1~¯&#Ùî+ïUÜ¿îÌ×}.µðƳӦ³K7wMïTD_UÒr{RniÐU!Üñȸ>mòi?]Ðúsyü®ç:áéõ#6õ3Pÿ[~´ìù¯§¹OÏ.pìà?h^UÚfÞ|ð 7ä¨ DN&¥6iQ-9z-¶bêwþ{£KÝ4d@òuL:ØÝrËç}ÖÓ¶æ8\à4Ý&dOËxtð£Õ1ÕoêïSßþþt¾þßã}¿FZ÷|iwïòÃ\EÂ^ÃÑq¼.Îúyµß³Ì#F×cró°Ê1J?yU`< zôê9=(ÇV#%Û»#%øÓY]¦ÆÉNIör+Í0Õ#%)aN^/X#÷$ 2ÂOaA~eoa#%aÓÃÅNÍ¿GõðãηÁ8ÝóÎ$÷ÍKs{ütJä^ôeìQú¤ê(LÌ#.!~=.gm iijÞ]¨¦b¸MÐ6Eî@ý´Þv`waY<<ëà;% Ó3!.áé»IÕ35Ç3å·®NúÇÓ(¯§ëù6c9vòD[µ4;ÈQT4¢ÆR.²aV&¤BÓÕ¯Nh¬Fz *åQH¼Õj´$fU"Â67U<yb×b® »T#.ZdK©¨å9Ì?¼TRëøq©û߯:ÌÑÜYEzhÀO¥òúÑ'Â}ßϯú¶´ã´!hRéÿgÉ8_ú+vá4¼þxÓËDçèûý]g#.ZgùPô}ý;ñlÈ°± IôKû«ôlpýHN#öþ?bpà~á¹#%$!!ûß#%ÜUl?ÚzSøól]¸~·a¶ÄÛÉkä öjk#6vè¼]ý#.çÓHIHÿ{µ?¢ËÀ;uMÎYMQÃÈÓ[qÉ[N¹´&ÚôunµÝWx¾0óÉç±×p4-çPÖ\IÁ¸7\¶Öò¨ªñô¦Ü Béǽÿ9Á¸t<#%<3§ê#. 2¿ÛÐs½k!(Ú*]𪨰©A+hXÂÆ?Úvÿ)Èi0h~~ë[v[¹a,îÍìw ÚÌÖMN0Ï|¼Ùª<ÝÐ'Qä{jWÛö[¾¿9`±Mà®P³(yÝ9qõEXós!GWQ®Ú-ñg4'io/R á«®Pï¡ØùØk¬ÈBé;"k£s_¤}5fcfS.ê²ëÃ2 `D §ÂSI0&b1"áJ5ih¤>fRàH¢Í«N¶s8¬ Fe
qWäz§d¾5àÖ
!;xÀÞ>ïçeÕeB-!Øïm§0M.Î"Éô¤à7ñ¡NõbÈ>}¾X3ýä
:²íäÖNÅÍ÷ü7º[Sòaéߦ#HáòÇéwo¦¢Ì³ÙÛ´!;Z-"¡øèzbS Á#6ª
°ÐÕ²A±¨ÛAp¥i²e¢TA Ð@h=BµËº¿ f?´5û»q&}Ûrd^Wð?üßk{K5 Ú,_Öï{¬/+Yüt1Q!%¥*d`ü¿Ú@R¾Ä9AäF"ÕÝ·fÛPàw£|}¯ôh {·g=×·½¬HER!AÓË´Ößè,?»ßØ=ËȪÄDy_7xÿ<íî,ö+ɲ.eñÖàÈÔhXØ+VBG=«ÝÛV =¼R7Áý.ÎùrõT'(f¡Úh»V7ʤsW´Ð¦À&áõQN!ëMpqZ%·då²n¶;±'Ú%1LhUQú#6l}i à ó"e¿¦<BÈ|½3®Ü<<t¹Rð`6¸Ç&ÀvîÛvyÂ8Û`«pBº¶DÆdkOVR\:¤+;ï#¡s°îÝÈãLºÅxórÇúÝkå.ÌxÔ©¸ë4Úgu"0úË!we*ñt5æ:ÝÎ&e%ßãD¬sì·.¬é5Ĭ^r)Ãg[Äb.;a3¤ðX8:^Ó·¿¡Û&ÉëÏs^½ÛÃõwG$f>Wâw}wλw̸áŶòÕY$6ÎÖa7Åç4E#v8¹omæf¸À¯C'am²H|MÜ4!vkÿ!VBÞðÙ:Æ Å]å&@Éî[ÝÈù1àô#.sµ3/MC4XÅ#6ÅE)ënØáã´'aÚ[\£Àº½fÖ@¬næ¨|?¢©£_w³Ý¨Ï¦ÐàYÎÀlô2K?*#%a8xIéç×¾=¾øs¿AÜrøfA#6¤±á·GÃM§o#.F¾Üϵ*wQ¥íè¥Tñ`Ñö7õF4kÈAËð#.2ìª0hXøT¬ZÔß´åb µØ=H<àXoA#.!rqíg#%[:yléTËs©ÓT#q¿`Z×Í^!|´Bl¶Ç¸ò´©Ê=1#ÖÑ8ÆÎ$'`äQ.º%ì+¶&À÷{¡èzy
5 °ÔmyÁ,Tí6¾$pdø(Q13(%&ŤÂBß²°Ôla¥²HrÏ#.æcÎ<BÙɤôÏÔÞ»«[°ËZPX·wouMÁÈ̪÷LÎi]©C£0=°X¨îuà]ñ»$8dï;u!ÉÒ@0äPT®a¬xoàfvfåWl× G¿àªQp@©Öö¡MÇqG{tØ&ðºSl* z½39Ã=NùÌÌÈðØy"¥w'ÐUÒq5¶Æé¹v/¡Ëà24@·øl'âlȳ§w@'©gyÂvkÌùµÒ¢¬d¤Í4ôÎ¥ë|í#6£Ðà«5t¶õMÚ]î<#6i5À{WÓêB<á¤16;¤ ²D`ª#6ÍÉN^DYuQX¥ÚhgLm¤»2îxNKaÊ£R+q õ(Xø8LÎÎoE¤hÂ.JhÚBHN_C]àYÑÉ.Åuá-,\à@ Ø+ǯ53¢,UæeÇ2æffXÛ1¬«2ÌÉ%Xì<õcûªjñl$0nÆ&z¸íü'qÚÌQ¶*WÕÜFÞz>7³w&¥éÖû½CÂ9Û#%!zlP?V[¸·=¾Û»ÊÄsÍÑÖÒ&w·áÁ"TK¯=k9çÓäôzp¼m)ðièÖÜæÄÙ3=êFC¾hYCS8G+}9ÇÏ5®ÍGÞsÔÁÐi·d%(ô#6×nÜÉBiÄháIw°P¨¡%Õ,±h¨¢^4{ûw+Ñ#6Æ]Án³ÍÊÔJ,!25.!bÌÎ[úsHƶg6|këPå¥èÐÐɪ×eìëÁéë#.dÓC¸ÌG)¢AkotcC~[^²Ù#%D¹ÞìÎBI(×¼®Ò´U6U;â´øÀ¸}=»Ï|#%Ö«Õ¬´ÑÂ7:ðäUC#6S¥Áµ;ÈèáÎ\6Fj«U*F7Û`r¹át¯äXÈë@¾v
^µG1)ã^ï4¡N)LvàYÎò`']ÑLª5m²Ý3ã}´Y¼5ÞB@-º·¦ü¦ÏFµ&¶á®) lÐÑÛµm,¹r,±aòãH }3V%O2(öÐà£J(ÐâHk2fdçqªºDôòÚy"èN5«Û¹]Æ#.¡¬Ï7Á£0¡:þÿç06î쪻BÌÙµRÉÊ$ÇcHÃáÂûJ$ètU&WD9æÏ*Ë!çÈÜåÞb<BÑ#.#.¤E¡Fy ha½¶E· 38aú-á'/JZ*V¨i4`hRq!]#6ÐΡ«0Q¢e.ÿ_B"ûÉ¥#:+R*Fä¨ãºq=r@õ¾_ 9Û!ß/¦MHYLÓÓgq.Ôt=vü7]Xu&I¯Ù(Cy¨¼°jÏ4±K¨d;Ä¢¥Ú
©#.üJ$E1ΦÚ1dk±×´³[&ᨡÁÄrGÌXÐ!"|&4ÑIr`ô<4ÒËMkWgÅ7&»Ó6ínS./ÌçÇÚÖÞ°F2õN;@ÕDf¹â»ãUëÐûÀ%NÐn_~LÀ DH²Óf©¤ß|oR½oªó æ85IF+:5_`d{ÎuȦ¾¿\·\g#_-7èõì{èìî"æ³#YCi#.×ØÊW¬¹7R¹ÉØÎ!±E¹*.I¦#6Éw×¢½³áp$Ç$#.Îxy|FÀPLZ#.°(ÌnÛm&C¶#.F´"뼡%Ï·z9¼ÒjÄ6¦Þ0ð¾oHCøÇÇ¥7L!3 0qÄ#%Æ;{[þ@o $ÜÙVI6-Ãp%A<åO××'P£ÿ¯¹Mu#%I|E>½Êõ
8q¼D¨-ê½0ÒÆ»²ô:¢äåê=¦&-Oé¥éÏÛgÆ úîí²]+<GHk%Ù¢*>ñ¬K¿·M>i#.$×ûwã_ÜóÐѸ$ëÌgñ\W«§Ñ3nWVGM§OUªy#.ñÜY7#.ï·»·=h=BÐR´gÌß»´_t=V[(@²2N. c !áHôØ>((Q6ÿÅ7Ý*
=°eHÐÿoµéÅr.#6ë\HîÚæzyðCÿ?²e³ýBÔVKÓÝò<`PA>B¢*£!>y5©÷Tõ.¥(¶fÉ(ε<Uvöú|G¼z¨lô!á×gï"ûN`´é~aõúCäD#6F [Ûº7÷«nÓ6R[êP!½ÊPE.xù®5#.+i}2AAûwR@H¡A)Ò¢+4Õ#6ÚÊ fkÙ:·oNqï$$$¥¯b¸ÎôyØöpÕ$µ@© Ò(øì¡Þ§pm`<lr°#.ú¯±òÁY±W,ï$Íø àô]CP÷À;?8¤Dv#6#bBÙ-hÐ I÷ì{ÄB"@æ|§®\¦ú¢Æ*X4GZA#.ÊÃx{i#.¤Pd ##%=ÀA`|x_äCR³¥éó4èÔ£`$kB1KºíÁ#6Xƨ1tIÅÊ»{m|®Õé¶#%¬Pº580.HÜÌö¶D[¡·¯¸ê{-Ïþ0~ðî6#.ÐÀÛuHKÓÁȬ;Æè+ù(ª°0#6AÍ£3¬%_²\$Í>&@!åÌh!7#%Ü#.[Ó]ì¸F/5û"µöi^øUÍÔdwéÖn\¶qü/ êÌpá<`bé·¤Éê5e6Û}åcj墩i,ÚAE`d;á;`þèè«UÛ4ÖÖéW¼ªÙ¬àcòz9$»u[}ÌnS(îÁG¦"uÆäMö#%²¶×/lM²`Î3 IBÅ
ÆêÜ£ÉPbî0*z*RIz»·M·7©½MÍv%»´^uå»ùÞy·¦;¹ÕÍË%ewhä½#.ºEhÒÐ% Ô¦¯>6õ|,µÁ}l@$~×Ú#%Üà=Ó$.4¡°eÏEY $$gñ¸|o'¯Øÿ&_xr¤¹ße{Ú²qõøç#Øéêô/Í9xóÏsLXËüðDoÃ7æzF%A\Gvíg}¡õ¨ÄhKmBx#6I!yb°hÚùëí*×Oé¦Ïî§{hVø¶¹[sU>þ³Ö2f00$Y§ÓÄÎ+?ßó÷ãì#%OPÐ?ÂUHïjÍgy诨·«f#.¼çr£k¸,CÇs(lÈd×XT¡
#.-¡¦êTÞè`¦`0¹þf( äC.¸hïâÜ_<rµXzèý¦.[÷9WlÑþDÝÇ~++yKÜDÝèó5Û=ÇÝåóÝæ°_uZ¬ÎûÛItï½ìßi!,òîh~aÑCåð#.ïv±ß!@»#.W8Gµä´®M[q³ó'ôÿ5çcyÎèóó\sÚUÁ´ü³1,;næ)È£D£lè¢{Â#6üýEªRNÞϤ:oNEµbz©5RöónJ¯\E k}ðGp0³5+"¾N¤z¥|JNq±z©$MÅkÔÃâÁ/H
çx8Sø{Qy´¶"ØØ}¹ú+<·1#k²*âªhü·ÖÐñÓãïí()de1*#úå¢#Ñ{<¤©#6B~´0úÑPPa¶ÉVd¢6jÆl¢JV++-«M²ZI[Ò[YQ¦ÌÐ @AdDõü8üúÒZ§U¾¹G]WHsÞ"zådHª2#%È õúÐú à×ùuÜßÄgõ¯"ÝV7Õ6?e¹¡ðÐØë£5hXdi½ú#.«,_Â*éiâ{ÒWÍíïBI*@<&k(}¼Ht¯MÍ#.%hkI/¤Ò²fI¯©ÓrÝw§º*(»w*R Z(íxÇÕN{Òup£&ݨ$[j]8l JÄ*ʽmî°uA}Cˬ ê##%©QM¢:ö捻*$g¸À½3ÂtBE ÁP'H¤!-EjæÜÙ+ܦl)S(ªf#.EI¤)¨¢ç÷O°h!ØÜÓ&²Ð8@#% HAdANÔUÔ£Êúø>|Çí½÷z»Õr¦7ËHdaÅÂ&ïfA=/Q
ywßv) ß#%ÖH}0!ÂÓã!ì?çîÿðûoçôü6*9Ã}âHß$Áßég/b¬5B^!Õ i >ÐüÝhFD"°¢#誨d|M×½÷ÇNV2]Q5J
:4¡x¡²¢(.QÒHMn]E>¶,xC6th/×áÉ»²Ô{hÍDhËþ8_£÷ùóÄõÒ+µA#.¬Zb¡ÿiÞ0"$qÝ»1ñ;£n²èÓxIx5S²ù2ûõ#.Ou *}À©9,Ê1üKûEåè')®Á²#% ÈB £Hì¶0º=IÐøõþÚ;B³q@li8"d3¿!û±Üx#.ARúì:ýØp´xÔ
$¶¯SÓÖû·¿'Cµ¥ß£sì¡ßlQñ»aúpð:rS²^uÍzë³ÃéÊdT$Ö`ý²À >·D=ÕN3%c£xIîÝøµÏʼiÄ=ÏI#.-3}ûüÉr¯ÏõÉÀÃÄ#%ÿ4vvu#%ÍNvº÷n¼BqY¼ê
(lÊSiLúÚ¥Äcí&b3ãOx±»#.k#6P2C+´ãLjAçXô9¢pªq¯ïf÷³®zçíblS¡-§Úá&+íXRka\¹ÙrÇ`X#% ⢡ë ò£À;x¦h}§6uò:«1[w~ÿòÑ ³?Ä7¯(iHPjÊj¨¨4£QPuQöt?_ïbɱù*îíw(QaDçéýM ªEbyf:öõ¯ìôeÕË8C8èPX{il[ÍI~#6!OLcì¾@#9OÓçVvÐøX79° #¡@úA¢V/5MP40#.»Bgð¸k7ÿß^×ο}Ò¯Êùñ(=côôþÁ~'¢!ÈD£v^ÿ#6îóÊ@²²ZÐXzñÍ}fT°Þ.Rá>çæÞ¤SÚ¶8ècs(:óÁ¿>z ,>cº¸½¾1Þt*U¶¼G¡ÔLc3úZo¥î«ÂÁÞµÑáè㥷;WeÓÇc¶¹åpçqF;jÌt,½ÇÙ¤mÖÙ*a\£·¶|kµÐ/ç¦ÅоÍh¯ËDP$S¡x7ãm£"ä[lmp`¯h8xÁÁ}7:Ù×líA¦ÕÃÃ|v#6õw;60ný1ljmß>øµ;QcµnÊ$[9µÚ5)ÜQaH$ì£h8âæfÏ{xÅlÔÝ.£Á°_+À£ÐÑðøbsaצóëÇ#%YbdSÎdÆ#.pûs{¼Il0ÜûÙR&ÌêAÇ#6ñÿBHjëP¹A골)HTøL3#%!+R¨Ï¢VAH©JÙêÄcv>8}¥hà÷·2Ö|ÊöçÛ!¿#%ùì÷;vÀ+
Ã"x%õéÑ×Ûc@¤«x@¥Ñ ºï¡8`Ŷoê¡ùÁS'+ä9Ùýâ6*êvòñ¹lØ6×ÆÛywPõ¤/ÊfïWÇ ¬ï¡ëµ#.W#Ãòú¾ ædôn;vêÝFl[Ú ÷w6%9ªMÛpZód½òK[?i`ë¿WúXAÔÓ}{n#.˹ÏeAÇ=ÎB:£ îÎhá#¯$ïR¥"Ã!ÙÙã>|÷É8f#.(¤SôܾöÒcC|¸á6RGdõLÅõý}ô=H )G¯÷&r 0Áôzs:ñwdêßË-㡧"Ö$3!~I$ß¿Ð4!#(í¿ Ó]àôöklÑü1v.ÂsϺ&®]Cj¤Jöm7ÊöÚ´õúAôöh)(r¡ÊVTu©£Ý55#hý~=Yäk©"N(Dï·Ká%OÔLzJ"À^q\øëÑX0¸°&ÃaÅ?Õ³hFE5|øeëëܼó¨_ ë'_·&µîP5' ;ûè`õVSªS¼ª*·Us²43d¶º\ÙIÝ]MÆÚ[]¾TR5 ²0¹`¨ÈX¬%JB¡i)¹d¥ÖpìnæDp¹f²áݳ ²XÒÄé½Vùµôh´55f¬ÊE$M¯ê ï!åÄ£c#6låÑ1¥gkÏ~ÓcíÝèginÿu[ÇPüúᤠ×#6Ê´é+¥dÖm¿JâÐÂO}gº#%¨#%ÆÙCÜ#6tü¥È|lûäðv+ªÁÂ"®Ý ÙS)D¨ìr«4óI£#gm±°æ´Sà¨P©Í×pã²µma·Ø¢ÏÎumwñ`W¹ ¤vëC0Ù_·«#%b n*F¢[föUÃÛ¦¸í<¶ÞNHONù'ùîHÙ¥#6¬
#.¬meQFªd°QB$J`ÈÓD©*X²R A¡iPbB>&í'5mÌSÀaõP#.3¼ù«¯Uõ_\ÊÆnëµXÚIét÷ÄAÓ¹jrir%§Ã^[õpÉ!1ßй×ÑXZÚ§TÙóYüÕfǦ³¶Kò`^üBþ:â"^%GPß:D×-nóD¿\iKÛ6ªª§£Ú!ÚE$H#%;±Ä+¦ûãÛþ:ÁÙ(gëw'`v2OA¸ºÚ¡bb$(cÕ¨Bô6HÐçªõ&:åÁ[ýBðn6LÙY¢&oáoÃa gZæ4ÅS$.vøü}^Gwxù?LD(:íÔlÚ£Ø|û»^ys*½ oèoè¡ýþ{o´Ò)4±"EÖ"ÎgÑf¯:ºJåM.î8gÕô8è$ÍI¬´e¨Ùò7Ú!ôäþF9Îòué¬ÌV°WT
vg÷ÙîN^»Þ×·t) Õc=#j7®çkÏgÔKm&ðßÌåܹÁ5.SêÔÆɸk4JApN:l§eÏÛÆm2LÆ?¯]°ËYØ¡¶¯Áª¤úCÝÂûªC<sLTCvêÃA ´»Ê/>!!hl5ç©\¬ÐJ\¯×¥ dHÂdê43d=BÂÁH#¢¸pK5Qz 5ÑZt%Î^EA@@È_àæ÷e{>ñ¢ ³<Ô ²Æw+¸s, "õ5#%B «Piuô+55ÁÚ4ÍÖo.Æ#*H) BFõ®¦`È`¡âÏY¥Âz¢ØÃÉj8MË!KI} A#.``(3UÀõ¶Ô&¢M·ÊêëlUj0À%Ô¥-Ù_áç;^Q=õ\¿)I#6w¬©H¹`Íöò¨Åïå|ÙF×mÐA;8ck³èÚ{Î{44 JàÉÜÕÏ}LPCæyBM±dY¾«²ábyOÄýäµý~ɹúØàÕ#.¼C"¶I<Û;úÏÕ{FÊinlü~}|ßáñBûÅÉ{øºF¾ dìàÉ#6çîà±!!1134ã¹c÷t³Ê'HC
-&Å#6°ªhvÏWqþDÈAèªt@QÙÃÇD¹Ö [!äåRÉÒs'tÃ-T#%g£èé*ªÒYKt¥ÅF"(«UV#6Ñ0&(÷&T¼Ç0}zO²Qj#Æ%
N¼±¤n²(VMBòÑsýì¬ãb¨LcC@! .¤ð¥t1'?]& Õã¶ØÀÀ¨i®(D÷¨æçÌâõy¤Z¬Ý*BèÀ½ej·Mdø¨Fí¢FtHFØÑ}ÃZ0À"'¦?ÑâÊõhØÒ;ðdYC*Ï;C¿ P
Ct_ À#%2Nÿµª©°¢dÔÔH<ü%ÝqHMÝI\uª´ßßÎ äLĦæêpÚMÒ<ëç#.ÚÊ8ôã%fLQÇ&ÑÅ\*
å01ñxaj ;ùª{è<(
pÑ®=¬¢ÿHy!wD0íµÞÇÔAc&´²b£¤Ø.5sSIý1ôj2¶EH¢¥·ÆÏ,k¬Õ=ÍñÚÍÍ2äÁE¸¨(ʽ :¡9Zkµ©´öO<שMFØÚË!Lc`0Ò3s@ï}Y÷N#6late<pÖ0÷J"DzØØÓßyCr6±Ë#%=l+§j¹0jÒOþ¯|×f>-=q¦ûÊß:Û¿עó1Èø¹¨õ ^¼P\aa£Oö¶³r@^õéu4¨ãº} xÚc4uÆÙàâ×Xgds°;îæ"ÆÖ,_ãMþºláÇtï¡ÛKV¬7LÅ¡8 9À²T(5TH ¨p_;K¦ùeÉYJ9-Uà AìXÛIò.#.áï#bìlÃIm£õU±ØdáA´Ã)jѹ ÒMF
Ý4m¦¤j!6I&ͳ¦&1>ì!áÞ¦°ãm.[¼R>Ø]Ã]+ÙÒí.ì]¥ñéx·´®jñaJ¥-#.ÐÑÇ#6%±dAafÂÈ[&fVî£ãøIå.Û¹ðÇ9ÝMLÍ5#Ô#|¼[AÚæèu_kØAÆ:QB3³eÀÔ/ð°ÎÊF ws+¡-+¬pä.QS&h%mKOÖ¨fö¬¾Ò·ñßÝä:yGÈ`ÓÂ$F
½"»|hÙàP;#.aHêÅ4¦K_kà@Çip[66y3÷óxpBÿFýfÔLâ[6ãknk׫®TãÝ¥¹ÊÊÎúNº¬Ó 2I+FÂmáØÙkå>)4+.b$馬ú¨Ë¶?m
ÃS>^O¹ðã³*0üÉÍhæ'£~;j0æÕº5-Nîe¶F¯Á³9HßGIÚÉr,=ä°4!{nî8nØýÐëÙë ~Æí:gg¿Ð`È-@Tùÿ/¯Þ?D/«¹ÕíاÁB °!D±¡DÐEÏ% #.&3í÷RÖâ6æ¦÷0Ü Éu*:hë$ÌM4h@I&
M/WX(,¹§fh#6l°#%ÌSÎ`°£X n¦yÓzÚ¹©i¥RJùkïVr2L7käÜrE¤¼Ö¦EÇRJðÉ·ÂwXU:½c7ãweûÚ(AÓ×Lo®ÜXçû¡¸×-=®1&òXËÙL9É! Ù}Á¹IǾä\y$þÉW¦G~ÃE4ªm©ëS_ÉþßÌ G®#%£sºvYBog?~ËA%*j×Ú¹âÛ,#6ѵ¨¶¼TjæÕ¶5¨ÖÕÍmͶ-V6«¥¥ÖévCÙç.'Q÷¸ÁE5bõG9;#.¶ïY4¥(ö±Ô÷u;k®Û+¦¤ùï4Ö¿D4$S&e3JÓ,É)I¦)5E¤ÍAúΤÂZÒ1Q4Ô¡"P¢´±¯~Ü¡ZLY%[4)4ÌhEQCM½ÝDFÒY)¤PÃT%¢Ò£EL¦FhÆL¦)¬TÊ&%!MA¨ÌA¦LÚcH` 4ÑÜS¹&óg¶§äe/è#6b|[|X&Aï~lU_SBÝ×ÇøfÌþ¢;708ëY!,Ìm¯ÒfvòúsÁ©Ù9`ÄÞ¬ü8Î#.©4czKÖãj\ 0¬Î]iÙ¼¼Ú(5÷ÐzàmÚn.Ö¨,mDñs0³¥xÂxâN;Z-_ßK¡# ý}úYJÒ»0te^ÎÝfw~âÅçãîùA{*ÂïÃñbm°Çªd©
ïúûZø^Ûo³_bc5 £#f²V*(i`!Faå³><9ôí0ݽò¬X #6"tXaÛô3³ÙyèNUMæçaëÔYbÂ+ÏNbC4®}û0_ê®[ç/c´yOÀôW¿¼}#êk#6xn4ëOåûÒ3Ï=GQáíPê+|ÎàÉ ÒV_£ãfåÄw&}z^Ë p{"r>Mõ£ÓG]eUY´#.q¨ E)¢AT$/rdÇ¥oKý}eÂGÝ2û¶ÛùåßXÇÆiKôô£¬Ê%x4ûmÁ÷cÇ$I*#1â8-¹¬-ߣ¼8ó#+ígÇö£dÎCìÖ÷µ« ªIm¦úõöÃ{N¹`g"âPR¨EΨ¸)µxãcB?+ç#6cguVÖˬ!çE®PÓ#6Ú+G0Âè'#66[ïG8 ápI5ö,nm_&·ÉÔè2
òí¶£·WÂc.[õ"^7L³§<1YCu-Í4î'¼Ñ¯$º41²Úîg ®Ä©OSååä½ðæ^R°öAèO?M"
CòqôÂdìNIÈDBª´ÊxK'²Ùª ÕµÞ¢gd6Eõ)×FÛÀ¹m¹¼2ÙIb=OiÑ·,(Õ5X@ý\µê{w÷7g FÊHCï:ڷשÔ'®½]Æðëì±õz¼ Ãíúëïúv¢B¤xà÷Ç}IÁ\³Âw¢âvÏ·§ÓæÖ_¯¥ø? ç§ÐªX@w Üóß5Ìííá#6áí)~¿.wðzàDà ¢nGkBkjl8ògâm»]%};àf.äIG^fPså3 jÓ5'B;Cq¬ #6;ë<rÝ &\?#EC8(p+x#.jÝ_âN®ú9pÜh>?/æåüÛ>é5ú³0ù²Yþ¥7Q6È£ö0¦Ä¦aiªF»ÔÎEL¢Ö¡Âu§÷5Ú30ÞW>ØÙÓ©ê<Ô4̵¶Í<¼ØÍ3©t,Åq4hÔQSRJbã5¬D(E
Æð¶ÒçVLÂWUÞŵ¬ æß´¥(%©ñ?ÕKľ$.¥âÃ1^{¶S{ÛeóL:Ø"a*cóuo\ a\MLËhz²IÆ´lÆV#6¶Â'¿S³;Ùï¬îç;WGÚv Òá8acgµ9t!éî^Ñ´åd»Ìê5+6É5#.ÂÉ,0&àbÛNJÒ:¤é°~g]øì`ɽ/Ü,7#6ÁR[Ì&*_¨ÊÐõ¡êìí§4ÍTo#.ª?02!ðnÐ6#.ÂΩª²æÑóÄï4Á&:ÏJFìÀ9]Ѥ]Ò¬ua®y:0jæó2w67¶LªL¹$ôgç}õ´n£ð@ußpBí
´ñÖ=,æYí?9@ôÓRP±áɬ@ºZßlAsø;oNñ©¦«¬qbÐ×gÉÙã6ô¯fl-&¢<ºF!ÏOB|VvÌïDDÆÇr¯/,¸Úz"VnöÍfrg£ÑñSëqHÎ:Óº¶6´=V_è-³eßÇ®ÚƱãæ·mO¸è¢õ¸t¤÷)0eÔj§=1åÎØÐàF§1ÜWVÕ£i7îæ)¬Rãw¾_<ã0Ý®È^ÏPÜd>ÃÜllg:ûà5Úã%¬GQÄî²a
3§¦è:Ó;1¢dÆ9°Ç¡n5´£Í']ºßÊßQt×\PÄ##.'yJX5Ñ\FÖ¸2L/Fò.ZX]ÔG¡(¸jS}5#6jåVͶã]*ïXTäðóqdßûªÚöFSBcÕ\llÏ^sÇ9*Në¡Ü,ß]ÌöO,ºK+çThu¿(vÎ[=e´Æ¹CAibuS"q0V^£ Zk¿kO+gX]°ÎNe6¼_y#nuÁÕÎk¦©Éct9)¯Y6ª9àZnl8\e¢±¿#¿A#M|fS®±*CP7ðvB¦EVöU;"áÖX.\[DY\('¹Ä>;Öï8óghh:yYzä×&YNÚ0,¶iQ!³é¥ØXlhÍÍÌpÑÓNVNÚ]#. ºÑH.q¼Å:¦ÌRIFÈ¡bÓ<P¹ÔÂÀµ)>Û4=¸ÍÃ#6Y¬ÛëEÎ&)Ä+æaõÆ0[3A@¡®bXßQÝëí*1¤X1qIN~.2ߩݨÛháÛá£Ô7á) ¬neïpOVêÑÙRQ9B&PÆ7ÊsiõncºÍ7Ûu³U·6vublâÂçìwÛsðüa½evâæfcy5Ù9ݬe|[Èu`z§ÛL>8¦²·¹O/¦ÅR=:%)Ç:Ó{¸ÜÖZÍQëF72Ìf2û"t[¸LLLb|¾ZÏÔáFcêEæðó8S7G´ÖQ²´ÓgórâÊܨ;ç¿©Ç1£W· i©#\Z%±pð²ÌÝUX6嵡s2úBº9H4qÆ:jn¬21ÉO)&PmVÌâë\[lÖfõ5,yULbÇ0vB ¢&¨©ÒªC¤r# SH^éi!°Ó×ÆÊ»I>ívÃ8YÙªüµWa²EZN©ØÏ+aì'gj0²ÕUÎâìrÓÖ*L¾#6$§Ê 3vðä{Á¨·É"aNû+â(0àe#6Bu öóRô`h©µÃpPI©,#. fFèã#6ëÚ°äÚ¸c¸M©_{RÆ£eé\½1åf2åR;ÎZ©a®f%ñÂb"âzÿºïÍ·9V¶ßé2#.¾¦¡#º@DE»ÎuBI@aàÞÔs¯#]Öhè Ph}èuz1Uõç tÍ®NzzOQ(¶Twqh÷Ä঴üÄõRù` »pZPLÒ;Ì7CN]"ÌÍäü#6.s׫ZÃ4ý½Ø'»õâÎ Ñä^île,Tm®t ìSR3@±0îÃt¬y\)&#.:b8ô!ËK@õ´]NÍc4ÜÓ@rÖà²e53Al2ÈbiA-µRrîvÖºS%#6#¥ÍÜ ¶ói"2ÐÀ
°õ3SdÂÅtvNI-"ÚS#.ó['£2ä`éRqfàd5eëRª#.XsL%q®i¶L§¤n2éÍc*±<.Gâ(N¶çc²¥i¶m£¦TéÂ&pL*[#%X*tvmÀåÈB$I3¥/ObYÚD³»w\ñ#.»dÃíxå/ºï#.Ó\lÜêÎ#6eÊ47Uç3}Ç/ÒÙlpNZÖ)£¢Ájx#u±¡öMXNRÎÒ¬³Î ÔÁ|`5`pËî¸è²3Pòàf8¬&7PÐÖÆn°Öj;Ã'CS
_¿&ÓPiIÛ+]#%ODö®÷Â,zÜÎùèe̲¤9i 7R#6tÈðS0@e°usÇùM×#6KÕ5BE¥!UAIHX.Ëb004ÚÏêÀób;àG±.NâÑÔGIF1T*©ÒNï_»;QwWm3oüòÊA8ÐTX$GaJt®ÞÁ`g£é®á N ¡}[aY¢¹I°êÒB5RÙÂ[#%l8Øq+CûÈ¡¢#.F+2fisÄØÜ l³3YÅÖ¸©Hu#.ÍîÌIawmw#6nòaæqÁÊWÃ;ÂeUô88JD61C#%CGfú1ÃgÆ$±ÆNØÃɵ#.fåî äi q¥º£ Ã0é#.(à hLÉåJII4dpjìËrÁ·i3fÕ̺ÇEÐÙ9Fm0²jJG8ÒgtÓ^Rg~V@.·uXiØl4I%ÝlK9Ã00¡Ü[Xn&uA#%0IF ÄúÈ%#6¯qCÿ$R5Á@w³;ÀiSh¦²
Ê#â1Aÿ6¾*?g|z( íW¹ *I"H#$d#%|jÇØ?´È3$ä@q:áÔ:7H¤ýhuF¤@&È4¨±TC8Ì î#%»-=Ùk<÷º~¸X$*vʪL>ô ÷ó¼JÓhiÁ×/Ô'س7®RÆM߬·YEr,;Bó®_}®P«4ó¸ëá&A±´Æ\©s'M.áiR¸k5
ÜÖBh7nÂ20+aÀ7èu%¶exnX!ÑÕöõ#%c=¤×Àæ^çõµ§4pu\0RÈpBÿev#6h"J¨ÔËkñ¦[m&òRjµ*ÕáPÙR² q¶X¡1H_§D#.o=#6JAµµÍBp5ã¡\¡íö÷¬C$;×á8·SoWÇ4íUú*#%nùnR6._¡SWwUÙn»³.nºn¨-sd¯å¯5<¿Fîȵ¾*ä}î³ÓÁAáÖ<`P¡ý÷©¬ÙLv*ôrð8«#6#%|(u/¼qz0g-Z"½(à{̸°'ìò@7>GÔ»ìo?6©2.þ0Vè<²¾Ü?Ø|~rÚ=¹ÈFÙÙwE¹µÈM44¨ÈÀ,;Si#67 P¼oÆnF¿½µ°bhÐ1D)¦ õªS@£¦n0.ÖÒ.eÆùA2Ac¿´z¸äf$YÞÐQ#.cG÷±3þ!¬:?+xø
Ë%êá¹A.¦9FòKPí?Vþ?_¶×äUi´&RkF±£Q[FÔIDL`Í3-lXÅ|ÿZ0Pì´Oïö¸ñÒ´TîRºÔ᳧zäK¼º:Øk5vz4D+ZÂ"kÂÑÄDFÓI0#%¬D¨í #E¶V-ÄÞ âêxÝïf§PD`@Ë[ÎIß3_Ùk̹<æÑÛÕ~«Qb*H²j}J²a_x;wÙ$l[^ÖAõ4ÑLÔdÂËpçb7úN(ÒcKi"ÈF'¸Üf5jå]*¾M½KÓoB5LâÕÙ1fR@l@ÓE`+K³D#0QÆR&lc8®åB+ Ö×ËHyÂ˱JEHÐq ²@Q¶Uú©o#.ê;eK¾ü'ô(ïéz#.sddÞí¨»¼è%Ï$¡ïÏë&ðÙ»#.PÔ
HåïT¥Èõ¢®î°]Æc(i°·Ej#.^&²ÐåZHp0
8Wª.¢cc#%mÆLN¨L
uÈÍY^sŲñüÞaÅ#%ò=§wKbm´lc+A)aLDHÀÆ-°5Iq0]i>â k
@ /_¢Àm!* I,Ëñ ݼ;âdç¬D©_&,ŠúMõÊ6Áý{8QÌ`o¨¹U¹¾NJÚ## qöe]²gÞRrE0;>Ç/¼Ú#Ú:í¦Æ>µîÅÇmcz"4ïU#.è§2]õÈl0ÒjøáiiZµ}køw3FC®zª¶i!KábÇgØÌ:'5bCèVmÓc{^ZÖH8 ÉË¿+#%Ó¾æÖZøAËIÃ4Áùz¶^ym£Á¬ÂÉ'Gi±êØá9E$åP«%* ÀUeYNÜBº1B)#6×6¦Ô9sypYµ.ÝUfylM¥çx¸kÈDÔëi¦lïÊ]ôÁúÑ ¡C|ÐÁÅF1#6hÊ7n®ÆbC#%ktE.J ÔDbTJ¨ Q$Ø£J#.L@Àc¤#%-P$PRÄ[¼ t`luqlg¨LÍ#6Ð?Æ@ ®åB<5í¨;+Æ>ER+ýÜÉz¹M8¤Qb{(=Gø+t Ãï ~L>±ÿWTª/¢ÒkºÓÏó<1G¦A¢|A]fsÕ10#!ëGú"dFHÅ"½«bƨÚɶ¬ZÚM« "BCÒ÷©5Ï?=xT\½KJåÈû ó[ʾ§ôÀikE/³âk|t¶u+W
þ n.¬
¨ê¬ÞÔrØr$®E#.{:iÃYÞ%leäʵS0:2¥KYk8ißjÓm&ìÙ&èdñv5-zÔbºSc³AÎ##6pHÒ.KÄÓƶð¤¶Ê>-ÌÞIS1d¼ÔèËÍ<»SâKÛ¦3Û$iÈ3̸jMÙsyô@#Dmãü¼ÕÁ(Ñíju¾N&Hmr¦=fÎþWÑÇàËNÔë5ÀÈå˵ÝÀÆi>Sæ)1jnÀI®$ÌÜC#:¨y>ÖÞ*¨i½ðyXÛzMp\ÎJù}e)ãï3Ã&=¾¢¸É&B°âðÇ"í75¬´ÝÎ+c¤ØàdÌrpQ©»M=íW0arr1Æ@Æõ«t¥XEDLXÄ%ѵeÌôö²ÒBÌ´¼ËôÖkUã\§©ê^y^¦¶¼¼âƺÜÛiÖíª ,ÜÔsK¡B4ªä!_ÁhRM¢:«#ÿRDõìͤDkm^|ÝÅUÚì"hI°1<¥jÆY*dÂK èí0]#6»jí&°nÝuÝÅ&ñ\µëµÉ§®ó*òlLi[©Ãc]¦£hÒT¼e?äÐÉHÃ
(¦Ñ³R¤me-¦U$
f±¶5¦¤S5ÔµÒ´²5¥SUF6¾^xMEª*fVÐlÒT7öy¼túccQÕ©£â`IPÀ¡Q6@bQQP´X!º+çÚD='qí°z³Äõ.kÓWéaKÞ9S@Ð×î6ýy´O;Øngq ¾ Oz³,§EÀËÂqhöëÏKS-Àº#%DFßÝOXÅ¥*jXÃɪÓm'ÓO#»;ÎLÀMÉÞ¦l1JSí"[ÕKR¥U(ÑJ01!¤Uý¨¦Ða#%¨Çj#%¨)"ìØn¢¶Í¸eµsÆòèéf´Í:ð²ÿfÂs©÷ pÝ#%H
5¦µ.Gf`#6 ò®µ2ñÞ eRD£T5ïÓ×ûûyk#.æñ#.ãÀÇ=AõÕê4\¸Twíé©Øm?2s¦O^ßnõU\«#%rãÑâuJÿo¢Æé%òÅ´AS¶(L!¯$yB`w?6Èl¨íx3Ýb
ÍÁL8o\årEÎD¹S¤,`&Q¶7ühÄ´t{Î+Áon/1~»bµxÙ#%à.jßÞ¡ö ~É0Tªþ¯æƹ¾óíèlodð8YGçÙ|fQ¯ãûô0*mùʨ< h%µj6¢ùýÕ²Eâì(eQMÍmr,¡¬ÞûµkM¥c)m&Ê6-")¦Y,¦JUÅ,µgå]aM«)lÚ1&ÑFÚ¦µMÓ+"µ+ºéµ }í®Öí^Ý»*b(2#6em¥)IkjhÆ¥Wµó¹Æ¯~íl-cd¶¶ÙHen]ihÒeRMKmçáM´Úl¡3#6°ÛilÚMìêKlcãnÍó«¯;R2hkêÍRWë5x®ØĪÂFÛÂk±Ë[L7ô®ßõLUq¼ó¾TÔÇîRÈ´,£^?/Ëá>Ïw>Bmôs'`ÆèOeÅ3$SF¯<XqIFÎzTX@÷Äñ
ª×æmã÷_NñW{<{1MEC=#%.b¤3ª#E À$T B 6Ø£Ç^S² ¤"-³JÙ¦Ú÷mªé¶±o²³KÍÚå5soº×ª¢#6²QdFAôR*fSJl)«iJ)Ô,¢
EÖÍFÌRÓ3ÚE E¥&©Kmi¶iY5°Ò)R|Vå(-EeQ-%£(ÓJHQ¡´Û)M"jLÑ°Ó1bÄa£+eØÙ2IdhXÔ±jª#6ÙRÉT¢©Y#jQ#.¨µM!BJLX)2 ¦I¦Jj¦Øƨ²$mE,LÚ$6Ö¥ÉFÒl²¶¤Z÷Õk»VÒ²ÛM¤²ÔÞòÚ×M6µ)ª²V¯f¯6{*¹zÍV-¶RÁmFÕ¤J*mm£ZúáÖÞcí³^ù6g]! n5Æx§{á·ç5ª÷è`fþÆpbÉzì7ùWkN-ÝðÞW ¸îmE<³¤!à#%¤yFäoDz¥ª$>Xqå×⢵åE÷Äô^éèøì\$1gÁÚa>®ìk£g]7bÙ 3meÌz4º:¶.L@ݤ¡áÈ"¥+´Ä»/ö7ñ_K3ü½©=Úßn9=½C#6?q°Å@P \cha!¼ )Ìæ]28ÐÆࡪ (ÁW_@pÄ$ûŽ -θ>õÒlÕsuæ°ÙåÈ)P;+ôø :ólPùÀ.3ôÑ¿I÷¾×ÅLFz%;8ã»m§f¸ñ¼õЫ´Ô¬ovÄÅ.yËg ØPÝM±"Ê~¤}þ
b\åö2eÏàØ¥WCó|såÇéл\Lu#68TóT>µKîªtJZ~ÙVêøPvÙÂíͳÏHdÖ°éè#ÅÄØÚ =õ øs«~OØõl£qGFù¬Öû#6¤Èƺjµ¤7Ò6Wi0½«#._Èé}/[onÓ @òî#%#%lj¨Ê²N"Q@R+¥rÔ'8#6Èo(Õà "2! ÖDëê¥Ñxíb¹Õu^¬U°=³¾_vóÒ
Xdé[&ya&\TCA¸!$*¨c#.ª SLÖ`O¼I.!&*x³VÏz§@â]7ù=ý«¨á×èv#.çWµ±ç]{|)LcÜÃPó fÛÊÖs²D\OúÙÀ«Îx
#6((S)øbî#úÛËRdA]%Ù@ÿgìºùaZÞåe±F6ÐÊÊHFæª&cD2L#l#6Ðh{ÄC5U.mÈÁ¶ÄH)fáu'6ÑÆ¡±ÅXVFA4^Z®¨ÆÎjv©g6& b S´·»RÅF[¢ÃK#6ª@Q®IL*cð¨Râ¿JT#.t#%6:^ôtqsèÕ(ñQ jÔÎQ§×hXÔz´A;Pl|߶¨4"ÑJÔL©ªhJ¸XÌîÁò`8ŤMýà5çñæk±°÷§ÁÜæ" k;CXxj/zø/#£Pì|
4ÉL`ZhÚ-AXAKëíÚÛ[EìÔ×9b$>#%ý0¸ Ìèª=V.ná·kmÿ>sê ý¹gźÆS®i{HÔ·t0Jc*ßÁ$çL¼·Z«ùß$!þ$ëÚwËI;àtnl øÇ-i¥!I¡#.njßRY²VTÊÁ[õððl
c0¶õ«ìXlA4(Fë¹ËÈ/n÷OdçèÊô½teú&YùA16ºa2e8 ÔÁõQv!h+åËbêÅó¿r@Ã
/¥)Æ®)iQÒÆâO±¹9&íBø>ÿ|Ép©*ÚYKmji!´:I$mDVCCpP±Èc&P1èó´âÚs½s¯gÙ².Û!H #6áPªR3ÂxQȵßxÇ¥cQ¢Á:÷Tshiß5¶JÆKF¤ÉÃ'3ÔGÃyÍãsKMûé:]û`ª§ ÃÂ2UKÕJâòÌ«ÏZ§N7~R±î(: @"¡ÌȡⶶQfíf´ÄÒiDÓ´ThA´~ù~ÿNè>èëTPåúÇQpº¢óGÇpó ¥CaFE<Q#%,2ªä°®Gíâ&±û¼á9Ťð;õ1A¾¼uÈh)¹¢`ÛkNÑD=ó§#.ùüq ¹[tcv¦¢â#.iÉÆLjÆD.Ã1ìÆVí¡¶&q±"J5Òë`Ì/¸:¯lF#6¾R¯OQz#%ñ=;NÝÖo+fy*wйçF|û Å"TX¥BSM4
DB ¥×*¯rïJZÀeE¤É@òrÎf§PÜ\/èÆQø#%»¶(tWx.ǨÚP QÕ¤BÉUN#("»ðX¨2#%LâFM`'°fT(#.à2pâ§.=ZpË×v3{×raY &&´Ú²4î¤G]:\clç¹¾,u/Ëß xµî¹anGÇå¬$46×PÁDùkIt¼îÂ2v¹ÍÄÀ+¹,Òçu ñ<xϹ½eäm "#%$lá`Ü1R ü{n×z¨¢3D¦ë2Ó#.äÅêí¤¯dòêß¹nh/!Ý]ñåîî¶Øné-ü:»+~A8uëÈN35åP«Ãp¼Cmí$/R«4²¦ÆîÁ,Ã1=;ÓPp¥'#.¾>ú UGLc0õâu{2=AÑ+½ëÜ('_¹HCX=DàmÆqzEnÆÅ$ONÃ-¥¯Ë¡e¤È#6¤ÍSY}¹YîêúÑ#6I£åíª¸%Ý£HÐÍ?]$E/]jôåå˼n¤ÛìnÈHNõæ½Z½jé%»mj©RC¤@
àmQc°^:wn) «1KÙ)y#6QÒ4lß·ºw7¥´D9;¢¾âênïÕ¢ìÑê§ëÛÄtN(Àºü5îIåÖïãrBÌ©[æq_S¾®¦Rg¿s%_Æ¥àM~%Db+)'æhwJM¬0
«ö5¯YFqtªÁÏé "ïª:ʽÕ4Ñ´L¢Z®QM4jW]6èrbK$ج[FßVäbÄVkãJ*¯KÒõ-kÆ嬳oßýþñ¶Éki¶[V½*ÝrttÊ7ĸeÀ ®h'kåг)ôãK ]¬Îe´"¶JJPÉB7&®r°2ý(-Øo)<( û7Îu¡¬²h%,3al!â ¦±hv>¹3Ù]´l4}»ÒX(¸ÐÞì½qOtT5(¿åiÀ¤(º#8+!iH@ÛaSòÕ*µVzPT*édWfTp9°ÌPð5 ëÖàtïôQìêª
¨
E#5ÝvÆÓ"£I´Ul#%&°ÝíÝ+Èt00p²Fù`Åì&á,Ü}C
pÀ×t,Våp¨CA2¬ ÛÑo¢|¸¾ÀÞï'´Pg=b,q¤ B=cik=A~x#6gLüqöÿË.×HÂà\h]IÕíø1
#%¨%æ¨&?¿dÒI¡ÏÊçÕ~¶ÔØ;Îáâ¨Ë#.ÃÀa aQúùhFÍpA24»Mjÿ-F?=+áÿûRâl~C~$4Kç^n«&ßByï(íê`=4ñ
x(«C~¿´A@TTвÏa81#6êå{ êÒB|<Luß»¤/6ìÙýðéÙÔ;Âûîpt6øSTSbGz¿Cé¿Êw.;=#%d#%RIí #6J¥*#6¡DYX@¨©PPfôlY!x¥EdBD b[3\0ù_a»ÌË÷¡ôq¸Á+£bÓIbÁNQ²Õ~«0GqÍ9e±ìSQù~ý£Ëj±DPõ$SÒÔ£C N/P¼läV_Òþ íUAd: Câ[!Üak%ªEIH®^E¿Wcâ|s¼R¨ÄÅgßêóåÅàX!`â«r'ÈàPë;OyÜbPWGçÄ>'¯¯ï`Ãæy~6×Üß=a§,»rÞtï£ÔHÄTÌI9¨¦¤¯V¾TªSRÙÍTþËÁI¦úËúPÑj,TU#6©3û®ÜSE,#6@¼I#6e,%ìZe¡Cð@ÃQ>9yñþ_¼ïÕ-6#ÆDca]ªñË<>ÙZcm¦É\ïg:F0¶ 0#BÌ £&D®¤ÍeµÄ±¡Gf4'ÔF4ÆÒqIlb-ªÍåLQX(J¶*Ef°-H#.Ôa4J@fµ@¤ ±I2ÈPµ´Ùbb$]ÌÐLïR`MS$µZLibm-äB1ç+=B`HVZM¨F`L%¥ª¤mV>Lä±¼xa¶EXVâÄÞª²¬ ÕÖAÉF¶áÃ4gJZ¢,j¨j¥0¤
'6Ñ´®è±\·6Årܾ#.ãc^»½.4<ºí¾-¹1ç4\3¨lêApÌjÓ´K&D`:3±ók0Ó,$i¾Kµbc,P¸yA®5&Ψ hÕQ.Hº5@ák[R²°ðÕ5O<#.C:Q¨6%Üe{îË]úÓN×Ò!£ Ñ uP2Ëñ»h|úim²O:4MiãÁÖÆïØøÈxÕ,#>¸Òc!I¬ÆñÛmwºòeºÍ7YºÐ«áùqüôÂ1Ó ÍÍÓ+p8ñö¼þ#.áߣ .H(ôMTØØ?9ø Ñ0À«¢¯`1 «þ8÷A%Q#FååljT²j,ªê£TIñnª0±¬QrÕ]JƬQ¶ÜÝmÓDbd@b-eAÔn*¬Z$A$TɸúÓøC )È°íDÔ@QHXÄHE¤Ç¼ð?ÙÔX#.Gê¤@ÆYÁáõ×g¿Â¬{S(±kÙæf¹!¡çò«W²®]¦Ûnºë[ÎerZOºÂ¡.TP¤IËúìÀ&#é¹ÍuÕñVã1 Ng°þ["ALàlBêPoÕTBDWáU¼ZPø¯4²mdÛÎÝJT²«æ·¯¥VòÌ¢Ù+Xl
TzÅ껪-zjö»×/]nË\Õ|×ZƯ7uY
$¶¤Õ©3Jö÷í¶ØA¦@¨¢G¶2<㥩Xý|º!ÔÑòkkE{\±È5¨p¯ÊE.I#%}3@¡ËÁ±,erIcÇQ4×´Õ0NK2#.É#%½çìè¤0#qÒòMÇnXq[l'µ}Ò@a%Ç¿¯3ËÂ74Â&iGÊ<Ø!DWbUTUðËÂ[åH=TvU Äh¸¨Z7aqP×ñ0»¹aÌ°oËuÍ>¨½ ¥ECObÈ(¿|³Mî®d=` T6qÓr.À;Q$!îa^Ò¥#.-TiKJTÕcj´×¼®ØÓUk)êWQ´E%D/åÐñ9çÙê°Ä@º5]°;c{nÑ÷µJ*ÎdBdñaöü6µñ³'¤.ÿ¤ý¾víFqp£FC²êNº3ìBKQé£4Ó]®#6¤Óý#.ËÌg8¨¼±bCÖ°¡ :ëÃPó¨êÎÉ&&42i´PËZÇ0Û#%G{ª"M18=ÉÝGÜ`Â+h}ñ¡È*Mbð]þáñOC×ÝXdI"BMçQýQ¹ì<ÏÖônå¦F^Ϻú¹!}zæ±Ë`ÉûdWß#"%54I7L0µ
°3'øþ|@å¹ÉY¶çA#6?KämÉ:®MÓûlp(¡©ÐÌÒ¸×V¹ "ÄëÔ§VlÃ@,×j°nÅF@$+ûRM6SHDÀB0 D¢¥Ø#P³N5X©Õ4O4D1öÍá=ü'§1ÀÁ55Ò¤{Û:ðeQÃýi`êñ×Kã;4Ï×ú´1$ÐÑеÊc£çF^Ó#¼ô=¥ØΤú¡©§A>iéTSíMZʸk2Pù|Tà¨ðÛÂ5¶PajJLi¶¦¶¤ØÖe5ù¥tA&2ÒÏØjܶ¦e©²-,Í`³LKlÛl6³Lµm$µJ"©µ3f«4M5M±UQli$1H³$#.GäiGåL"±£æÙ8î¸lƸÈéáü)D M´VµÔåV¢ÚÅ®¦µ®kvo^aQoѴצÕû»ËA'"vC¿¯#%#%ÛFÈD*TK[R]Kí´·µUøm~B²#ùKÐ=Q_fÚÈHEQ ÆGúZ#>ÕaõóØøá¼ådzApQÙ¸»h¥âB9¨!áOGk§!' %J¾ØÞ!¡ìNHlá`G´>ÒB zAm¨#%û¢Ü%íKtD©ìByìçxÆqä;ÏÓ×8Ï<Iµ#%CÁÕPÌżÐyzÔ´àµ!¶7$¹=É6Ý*ax2^³30xãèpþ#6XXPµÈ
p>W·ÑëU8;¡¤gê&LxÑ;QÄ7V«ZÖKè6x#6ÅéØ¡¼¸p[1v*®@â7̨·Ý£Bò8#. Ò\Ð;¤:háÜz°p!¬a#.DV#mbL¿ê¯(Ó4tì!#6°I£±
Oú;N¦ÏRbå.¡÷Ã-+?£VF0¥Vªêãì~}мáömFÂiîAÁÆQ:ïÄ#%>°Ñ#&!¦-cöðtL!/Ù¯9ãvþWà¼è¥æÔörÍù[ë9+ÁS:~râúýt&ø-tõw¼¤¦åÆåÒñL ,SÝðð4Ç]«Pø¦äºC#6(,HQXPíÇéÓ9Àóx§ï¥½#%2Oùæ&ѬHø8ÕY!D14P)#.h¤4ÉÓL*v#6HÛLMûþ¯éIJB#.üX11¾"lN9anTG§d#6ì6«Æ% `6ØÄ´wc&µi︷l¼C#.@6dÏZ«Hfh
ãëU)%E`Òc JO´'ñT¨â*cm¬hæF&(}q#%çDB ;sR; SÎTyzg?~<s/T #.\/lëã:Þo\qF(P¹¨µîâð8' ¬Jô*Æ%S ×õ-ªl;w£DÃ@äàP@4ÆB¤PEÐBÈÅPe'Î#6zx¨vi=>~¼® QÐu}Þ&`]|Ñ÷N^@ÃÕUBÅfÔUЪ`EZó}MI¢#ðGðGù$=èÞ;}%¡&ZiÁ]ä4¸¸fÇfÙ«ECn¢ÉBvP§`¾Cqh\5&+&ÉWsLjFà|Ûùfwâ{àrTPÙ#6`R#.Õ!æÊ%r)(#6a<,<Ï[ÞK:MåÊd¤.óÏ!Y;0UQT»¸Y¡õñ²"½®$D0øBR0!ÔÜD½.ØboìÀ#]Ì T`ÁѱÉ".)¢èÉdrf5Âó"^¬¿îihòÝÝ%|Á#6ÓeOuB¥´àÈ©PÚW.T²¹[#.½i?îÍL#%Ez¤#6©36¶~ôâüÞ*(Âý4Ƕ¿Í»CVnÙ=è¾»VâHfmÚ¨·aYeÖje 5VWE·[Ñ$F¥¤ÂB°NÄy3ó, /¼X¼½p 8¬§gdp¨:©´>j"ìO=H£EëeäÎh ï˧ÊgؤHÞ%?^uÝF§·ÙéV§mTS±ÄºÕ+njÜBðôÕ#6´×9ÍâBröÓ,à¾81rÂsÚU:âæìbúékÿgÖË:¼µÜ|ÖƲ:#6K%$,è`#%*¨#%ADPÐÈÒ¥h#ͨ¨In1l+p<;TÈ)í ©Ù¿Ó:þ°UyónêïæÔe³#6ÔeëÇ·VÜÞQöº1ÈßÌÕ×ë2Q#%dd!CÇBbuðE!¤G³v#6Ð($«U`ѽÀsqKòÙï Ñ£Äv\5Ê ÎÐHÒ%A#%Î|É:LòOB§¯ÆSÌN¦#64 / LdM´¼íÍr¼ó¦ëÏ5wÚëm¦ÖJI¶ÒËÇBHT*F2ÀD#6üÿ_¸÷J(-!þÚnêÖwÁrPl ´ W1¢ª`Gñúnî¿«Âb£ b´Fϸ:Ä6Ö4kR&'Ó&{_¿´)·w¶õÚV7t\-2áÖ5bB<* \KlH2Ym@¡&©ª"Ó-PÒËf{½nçØé¦{ÚG.®ÊÅz¢ç±¦&#.¼zPÕ1`W¨¬PÙ²2¸ÛO!-Ý0éàÈfÙF¢D$ #fKÀ0#.`ömZhmmèØáͳX"bͲ9PÃ(¼XmÌG0Õ.à£MËì¿Ëâ§iÅLüI!1²Éb;EP DüÀSqS¿c²vwñÄä'Ñ祥ÎUñ<þÞzªßòNuØ'úû¤ÓIáÂfÊbWGq'NÄöP!×#%ÄI¾åmøÛ^efÊdÒjØÕ)}ʾÖÚL®»U?OÇkÆÛÊæ°µ0}½ÃÞ^xÇëaÎ6<îXJ.mèÚ¦Òv¨"«Om¬Õ¨}Pr)N=\wü²Ë«(ײ|J+±±òT-ªä`UíèvÙïIð{¨óÎ!WâÛoUx$§áUýÇêYÐYy¾áa©<·ØÍn6I6=Î q.ê`Â÷ývÇ]tú¦øo¹+M`sZõQ4$n@âtÂpÅ&/m
ÇãîHF1×wë߸Æ,bÅè¬ÞBðì&Ù3°kÕ&72^A#% ·4ß¹çLÌÑL´K3Jj í>E/»ÛêÛçÌÚA!~ï,v7ÞÛ¯é#sµzø%ªì2t·Æ¶Bõ-úð*¨ð ¹FÇò,¬ðç" s^ÓÅC^´GÌñUGÝ!p6m=ßmÃÝ#6NÓ0¨^b!d%]±-Ê.ÛJZÊ0O¾^!¡ÖÂ0×bí-s¦µyäÕe´SZ·°òüXKï¾fsMÖï%ç8Tb»üè\²?}{Þ>%ËÂça8ðøqgêd;1Cð)æÁ
ªT'çd%íBnpêá·>¡¼»f>¥óèÄyKp#ÃææG³´ÕsmGyç
cQ®»·¦Û%¶Ì\U#.¡$HH0Q·KACo·UïУç»R*·µsà$.?çûõà¶KªbÓ\µ
ÅaÇY2J2ÄTX (·VyÛ¹ÖîuÞªZÛ¦Û#.1A¼A(ð ¬ ^3@¤dâÑnÀÕÁ£òðt£àyÅù¿r=÷·EI&þö01ü$Õ¥³º[Ðö"û·'Ã4|·låËMÓGÎòçQÝOgC_ù´4èÓwA0Cf±eÂEÃpÑIå¨GGè öà$ëªUèt§ÝÅÈòZ¿0óhäk>1"°Õ,W%ëFþä;ùq56z{þÎ@ @qôÙ(yCScpô_{J!0£:tª4QZ$¸ê×\×v庺ͩ¦¬¦ÛNݵu&ÄÚÛ4¶«ªØÑ\¦^.^]ÚVòµ¾l²@ Å#%C@US_BÄ«ËÚ5ê)ALjºr·S9¬¹ 5öTXlzïÀÊMu>#.3ïk¤ÁÖøûí#ÂÈÉ j÷â¿«Gí#.Ã0¾Ãnº·JYUiKí:ÍËaÛp¶<h6Ú`g5!5È0°ØzùpÕH¥²!ÍíÀuþÁë¾pS-VÞM¹dmÐL¯Üá¸6uð|#.ÊäÊÉÜ@à{&ÿ}vuÄE'sj>¦þZ2nÇË׬-å®Wâæ#%ß`+ÂÞɬí'm'·õ#.|¹_úuØÑTF#6Ì5å*oµµX~ÍóÂ\èÄgi[á4Gëk®]ä9*éitQ0#6ñ'êwÉúgúÿ§îoÛ`§ñ!(RÄæY}_bû.»áÁ5Å(,DÙéPºRð¹ßSX§%DAÀµ¶&¤?3Y{ÀZ$*Áömk_ªèzÔ.¹#mäÐl¨AAì[v,aÈ$ºvÀ¥+ã'C-®H4(an~#.ÐÅ¡´ÁëX> 7¼PÅ£ãFs¼ðEÓ£pè&¦K¨ü~iÿKn<£ª{6±gTSE_çõð¾ÌÏRI'EÔ,Ìï#.ümQºC^[ò#6Èì<¶èÝPi¥ÀûqL
ñ=Lo³#%{BhÙë Ҭܿ¶lÁs-
¯¢jgÎ0xAËÓ¥¶ßgLeXd¬b
û`Y)0(ÏQ3I!
áô®ÔùaÃý¡ø̽:ТIÅÔeÁÙ)ýÕÔ<=±®áÐÁác),·[I_òÀ3r^B8iý5³V-êWBÆCGµ÷cHgMardæ7ÝÍO1U;æf,Ý1!Èkq.ìaì£P0ëO¯võѤÈgõá§NJ±ÐèO5Ĩw¿yr²þÊçõm|µåê#%ĨÂ#%p+ÓUC'ÕG Ìñä¦j&¨ªßË ¡!ÞÀ[©#%¦B½OE«¨¶Ö+Q´Z5mdÆ©5£Y,mb¶@¢²*TEM2
Èì5WÙn¹\ê4"Ô* ARæÀá¹Uz,.ã`!i ÅòìÚp:6ßvýøg7nYÁÞúËÝ;«Üd(])5«=:C÷«7ã-\õûn}ªcâÀuÓWCÈ2ùmFmCEli î°2dS ~Õê(åíOyÖ!¤ØwF¿?´"5jùíÌ<ÁCi²RÚPl.@ä#6ê%ºéçÓ5ÊU¨ü=¹Ñ®%O×?#6\¢p`vãÇÉ@;$Ðs]_2BªPôÐöVâ¢ßÌ0`Cm¶¬×7¶Ú9FD·7|Y´&©ªVÍ,[þ}¯]tÁ(L:"W. {§¶@,ϬGüÛoÖͽ(TÐJÀÕsª¤ ó£äI/#6½y³ªîfx²&qK¨*.qß<¡¥¥LÒ®%Å#6eq}Kw4(#ÔæH ò*EZ#66°Ö-5¸éW¾`[É@DêFq#.á ̪MZ¡Pwgåõ{ö²7>Gcúìcò0Ä5µÕÔâ»×võo1kpÄ&Á|ÙôO«Y
ñ¦ãQèî>#.zÞ®ùÅ'èkj©a¨²ÐÈTÊ¥ÈläÏ$ÍíB
mÊ=·e×àY bø¿]ع`±#% ª£.êLãÅÓ?ɧtÐnòu#%NÐêØL8»1²üÁð¢zÏpÝ#.½
ÔêônêÌÇʪKq·t/Bª+5ÖkYf
2ÉUBÆÐÀù¾C®YIô ÙMIÀǵÜ$Á¨Ø:¤Â*ËuÖηL«w]¥#jff±PÑh×]uôÕ<®óõ§½æèQfðÀÆÀnBhT¬ci0xÈ`hpTZÔJÄ0`Ä28Ü«hãÕJ!ÁÑS£ ÉLkLD²üaÐ6Þ(ÚßpHìÃWÖû%°Dûo!H¤HI¬j¬¦ºUÍôMÌ6J´¥\é23Í×Y2¤
r»àd¨Å ¢#6&Û¤ 3PEÐî÷ZH ¨ÌÝZ@ë²Ä0ÂíV52 ¥l¥fSµ$e6,Û3$ÈÛe-/]Û˵riÝËrAfë®[sNݽåÍy¼ï"h¡RÔ3ùýw³Ùf¡å輸÷íï¼öÕæ"¢FJ°ë¦2Ù¬ËAÁ\µh@Ò4EÙcÄôõf1ºÔ6î#.j*Ócq¡¨ÑÈ0À×ÙUkH°[yÐ÷´IòãÁ¤óßQÆM¦Òp&äbÓ\3PÍÖúÀ4Õ½1ÎóEåêÞnÕ zÚéEF¾ÊËIµð[¤ö#6<qêTU¶ÓuÛ5!(£dbå´±#k7+®6½ª\®¦øµ]ï\÷¾¥Yâ²"°£i1yic$IÙi%ehCÑVc"sz(¤ÝT&0ÝÜD1§~/êÔaáenÃ)±²ái©Ä3aCwc®<¥j[J\Mb0s.#.ç¶ÖÆÖ¤2Eõ5ß`il(A£§£G½MÙ·¥2ATÍn¦©Ü]ÏDOµ3JiAÓ«Ê_¬Ý»8+ɳskhÁÇgjFV4Ò.#%ÖcKlÆöõTMX
,A(SæXôçzGí ºó2Ìÿ#FÜ4úf#.ndÇÕ|PÇí÷k#zLö1ÂfÝÖd6róo?v:WGÆ.5Fcmäå
tÈWÓÇ°
1¯ÝqÆM!j´M¶Vo¥Øz¦øã5 ¤§dvÎUjhÙµ#.\"ª9lT¡µ=³C#-ÃqÓéîó}&°Æ0#.7B¬¡û÷ Bì¤]¬&Áê$åÜ,eeU»cõ ¹¸GãO8a¤)¡ ä¥P4/ººëtÖ{¯5E]5fT@Ã& Â6:é `"0lU,P]§DÂQ %Ħÿ¸ tàtë=A×n¸Ø nìÁìüô³,8¤è×æ¤EþÕiqu#%T#.Pæûqb¾e4~¹(ÄHægÞ·f='³¦ÓO¾ï×q6ø¿yÃ&ÒVý?²çª+lMHÜúõCÔÞ±\öÍ#.hÅ#3ÚÚmáîÝÔÉK#{{ºNÅËÖåyºjð=y½\ÖM\l¹ÙK*̵ðòJpð÷uÐôÐïÛjØÍ-¿kÙ»£qFb!$-ÌÌۨټ讹ãÌÛF6qÇ8hPhÂ,CöºÂ7ÌÕãµCdÌqÎám#±M¥ÙBº¯¹yÐà½ë|÷3¿y!È7稺(4Q®ÛX0wù¾,h#6?äè!¸\£Êo/£÷õgg^i¹ãíÓj#.M,=6ͪë·ê³xFpSÑ4¦ì¨FÛ,~¦JôÖ±ÝrðÓ+°iá³Ýdý_>÷ÖéM¨#6îkf©l#6Ìë¡Å)êýá{Á=óùû£{ vÜé R$T@Ð# *Ì
°´%Ôl#%ú H*GåB XtL,³:jU(älFÒª®Õ`][ÖéµIµwb×r髵·6îÜÈrêñµðË%H´T©«wUÝÚ±Z¦¾+Uã[É[Iº@%rØ¡#6BKI`W(0ú6nün°££aI}ø«Jì¹X½9*ae(¡Q#P1EZÀôÉ.p»RÕ·ÓÍÆ×ZïrÐÕâ¢%&±XÑ%¨OsË}2±PBTBeEªR¤_ÂëQMZÅf&i¥E±¶5E¨¶6³+Ó5I²YLÉTÑDmLɲlklÕçjº7à¥9?ÉïÐÐ>ߺDEOjÚóÔMª+ RRËð9ì¿âÆýÝ^lxêþeËÝåEÓ¸°zÃÅ8ÓÕÝóaT9ùhì !¥ÖüíM6´ÊѾ7ѽ]Bͨûf·äV·#6µâ×OÜêêFæî¢6Ó»³®µÝ¤¥¹«Knk5]¥+ZV²½vìÖj(ÄJE¦®ÏøHf;ÙYÈIb2_l(Ñ$D@ Ä:o',ÀÕPBMÈ4p#6¡a#.§gW¶¤¡Pm+Ä4ÚÁ NκkfñÖ¶!4õ
>ûµ>ÖùñkÑ6wÄäÁí0Ϻ¼è¨
Ì]hÊ°,Ó`ûO]ÿ3]¸·7µLÌf7?,lc]ÌMBbA1H¬µ4Ýid8w&ßNÓ)Äv»Æ#.Áàu?²æñçãµì! 5éá1°<¦t2b²tÙðVþ²ðæ8ÀU;¬"ǶC}åtÈÏë|w½µ^]3aÌ8fùã=ù6´ì§Í%µ ~¹åѶ»zÊW\=ÙXÛÔZh¸Ïa°Ó(±Æmå÷<H°UýÒvЬbEÈ#6NÁÛ±=ôL~+"õÈeÛ)·È~ÏðV<0T&*ž2ÊuJÚ©X¡à÷BxQG`
×Øh -TѪKo/©ZºB2$"cü\¯IÛ\â£rh¶·{:²Ulm¨Ú¹U#U#%iy?Ò3vµÇ$eù»#%b Zü¬ßàTy/o\½Õ.@Úº[%´×]§·-lfmBÑl@Eá1Á¢#DBùRÈ8$j©À\0z¦Fü¡¸ á[oZµ¾[[fIlm\ÓX¾>Ù*¼î«Ë¼UÚDFÒæ»É×>µ¹éwWÙãKÁhã*7j*A#6´¶³V¥(1Ä*ÛAÍXU¬!R#. aS#6$DQ#6#6Æ,ÊXI
vUïDdÐÂ%¢¤äÄã0õázâhÌ RLcAA¬T#.9?³¿Ïïç*®·(øhyÒ]aöàsÖÐa`ªsêpÄ%X¬gÕ3n#.Ç#.³ÈÂêH9F1ÖKQ·níùîÑÛÌmµ¶¾©kU~[Â` #.Ä;@¸â@HnüÝ¡ã¦Qð!¼*ï'æ£[£Cõmþè¡/C ;¡ø&©òƽqj¯ù#%AD^G9ÐÀÓz*J#.¬¤,XcÍ#6Ç+Ìf¡z#%fθåC8>yóvoÖ¢J¹ÛïFØØé8ê¦bCDÐ#%ÅE7áÃGÐ*¨á%ÎÞÇ¢tºÄ÷Å4Èn#6½¡1*ÃM63âqMí!ý!ȵ¥ð¨W¬|TaøµX#»#hLCZ¢«xbi(6³±t\°èYl
EX#%$p4b9&K`È°y~5D¼_¼ #%¡ô^3Äê;HÓ× XïYU[ï"zGEMpùCݶÍêÑ|J§NqÂIß.k6#.éï?XC߶ óð&©UMÛWJ(Õ]Ûeº»±¿ºÄB¬%ò\;é(B¢ÔÈîLgÇõÙüÞôÛWÎôNÝWu\v¶Âegd!QòBt?g>YAh7vgyÝ\º2å«uÝâòÜËÍÅfË"i$l&Ê£ÆÛ´Û&S60xÜMæÜ®UÍÜw^vo.Üu×l£ÝÛ¤W/ñäª9¦Ëy<Ëurîk2ÆnójhÈó¶Úæå®VKhԥη)³,'ÝÝݧ5wft×$RÑáÊ»eγQhÑÊÔX¥"µDh´m ¹¸#6XTbzàvAØCH#%ömõoÊ´;TÄ< 8#%îGû;¾#P ¡A;XalExýª*oN¨xþÉÂ{S´pAÀúJA¸!áE ±#%ãêw'¬+Ó}Ïu¯¥hÂ%öz3ï
#6ËïÜ´æm:Ïr#%r"1 ÌÒùíêæÛVükZæ+kº¬ÿ¤¹gú£ #6Æ#%Îî6S!5²jÅjÐ¥¡·½5{Ì|1À P÷A!µ%AbÄBVçjuÝÔ²±c#.ݵêZðc^úªli¤#.÷5w!,8*àNßD l&PtI¨ÅiéÓ&I#.½Ö|ý·\{úµ¯UÑæÝÛ½(ÒDH"^b#6#.)k`ETb¤"M(0'ñn\ÄÈ)OVuç#6'÷ð=øØ 1HAcQAûj=Ôáa3¼D#%;" TÒÍÖiµJ¢¶fËMô¡!·/¤¸Y@sÑV2#Í©ZdÍQ¶Ú
DüÏ&1½#.@ §ËHH"Zf0ÚÿmFkB¦km
Ë7ÉLÍv¦vÓÆk±_T,£T ÂÊ$6#%þDûOPp%*¼CrW¿ªúÖó6óô÷}w~¢|ïd`B2¿¦gËñê´Cå#%aaÌHôÿ¹X4)RkU»M¶ ÈfÈOÆÑv`iñÎlDHI'2's¤Ñõ¡²y?Àáýb@cÈoSÑ5·câX¢^ü-ëpqûZÇ#%ÄÄ#.IÇY%¢iQ8ð$MÊ$4ªB£Q!.pK#.dÔþÕâòºmsWI*å^ï&ÅÄ*6VjBTBW@#6Ö#.c0LK½à1åËBá-$ok#%´Â "JM!hKEÌ©#~Nͪð»/8Áo:¶f¾$öû^à쪰pÐÖ 331(Ä`m¥ÁØx]âO,½).àdË0L\Ò²u"Áb
0«ÔÁh BXT°²+"¢7*© H4uÍit52LòêUÖRnݸ6Âhüt#ùÓw2¢H×`ôÂò*ù{Ntp~m£fE
DAÙ`=aPP¬&i»PE±*Ð#6E#KT-ѺZÆ^v0ù lûa£ïÄ$µb ÉS¯t·\ªvݪÊ[§.ê¾»mµõR¶¿¶×ºØ+ìfMı f#.¨-RHE9À³ÐÂѹÑxOd#.Áyþg2Å>?åDÚñçì[Ýa3FÖAÊR±1m6¥ÒqÏ#.¾r¯©×PäqPì4`!ÄFÁDm6¬¶òÉc$¦ÖcÁ¨ñ©ÛvHEJèG+ú2LÌRØ&Ç.-S9;7¶£´3P´¹-2µ}¦ÓòxPëצè!àDûOË[m4;CìAÓA?{@~¨ìFêøÊ;gèª#. #°êÞ#6&àÍdT#%¤O]#.0UXû%Hð+Qè¨÷#6'dÑg"æØ;¾#%âßh§#%6ÕáüÓ#.¶ö!þ]ßzLÉ¿¿¯¥$ÑHX*fO'Æ"°[>PAÍ#%GÉQMAû={}á§vY¬¯ÑõÖ)Ñu©A_°d FÛϲ½¿c[Ü%oEÓ,y÷¢J2&óotÜÖ;¤¼6^o´uçA(77ü) µ¶÷Y
ÄLxl+Û¨SÃù5ä4wòò$;8SVâT:<t(ñHȪ',ð³RÚÒâRgpo¤ÂÉ2"ZBÇË0/xã~æŸÇTCîûÖþIõh&"´#6béC;¾¯3¯«ÚÉÖÙ>úWûc~ÓÊqÖ'lcØÆö·0´U>L#»²8US3H¸¨wâ® B?ïkzþú&)¸Em[p´!oqÎJÐYÅ{ÙL7£LÁA¸¦ÓV0>²BG.#ÄDDJª® )æM+I¦Ík¥¦=i4b¦sì'4³>é}2ksá²HÎó|DaXéwkÎú}e°&f´RÚyiÚÎóKÛù=iæÙ°y/âu+`Çxö$ÝÀû0}]ÐJ3ñdáË-^Ýø϶Û9@Ѽ#.3]7üºÊê@óÀ¶ñXTÕ¬Fôõ{¹ë²Q
2fqLd¦ñ!»o³! ÄtÞ8<µçÂôÈ6c8Cg¥B~óQMãøÙKºËù®ÇCmª¹"9n¨¢H´<J#Öر#%×1Mn ¥ÊéÝÔxaöOÚÖNÿuQá´ÿb¨Ìñz` 74*¨9N¾tÌ Sõz¡Ö
Ë8 zJãì;EøxW´±3Cd¦6JöHå¼Òa¯`&C! íó<µ,]IZðÇáÒß:}P#6f27¢ TÍ6Eún§m¯FØØáOum×êoÙºSV#6ÌÔýìÞ×éÀÔ¶I&³#ø}3 lýCÖå¿YãµÏ]Ú6·©d·jsÝ
M)gV\ÕÛÒÕÞ,¯ßë'õr8ÃÒPòC5
U4v!yc:Îpôk¼¶ÿd^קÃD~»÷??[TôðE¶»wª;Àk½WÆÎÊ]!Aùp£Îrm°d+Û #L`± ´|P Hƹç_®gXo,¹i¹ªË\ XyËú)ò¦á4·§`8ÏkÆïgBC¹HÎçÕåNw3Uv0/ÏnñÑ8ª¡3'»=·1MwÉ1Ù}ûÒ2xÃER
¦§±PL¿@ã×¢LQRI5=û¼x_ZC#.eÒG§ïüØke(¤ÞàÒ F@½Ù¹uôWnqÈËÙþ/£ò貧Ù(oÒ`ÄH¿I/#% $;ÁðH|ëü!ôÿ8¬¾$DYDvâõtFþX*G²»ÏÅ^ÒÌÝ@E8*mì81P}°f>ÃÞ²âôs#.Anã"Ý3-½GCÔtä.9#¿å¼:ö´Ô>ÄÇpwÇÉÄP+m&#%f¶FÖ´ÑÛd92hÅ$ÑEy#6,:@ä¡í(:xÔwu#6©6Ïì¯T®Î®£Æ>ÞH{:¨óÚrz¨öY5zº¹[(úù³¨ågõ8Àu¢ÚO
±Ú¨¦ ¢0ôV#% FB$¯°Þå<jØÀOfçD¡Ð+ö8ÍÆ#%àA)hBÀÆ+ Ä®qk_g?ë?¯à̬¤ÝOÞS/P@JFÒQ?µªù±À2:ß·gdªH5R#£Ê;ãMç¾Á#%óëxN_¼n1¬ÙlX+¤g¹·ù_4k3>÷Vgl6éÎ×Ó©ñCq×ÐEúW9³v@ÓѨa´Nø¥7ìâ²ñvVù¦
éì?ÔTÆ'»e¿Ü»Ù;}`£9úì=§¦ò
A+©/þnw®Bv>û¶çU;QUΤRtÐ:`#A'BÑ1«¾ùa+Ð1 MpAH!þO«mmCPç¢6îÐ*Á#ñÈr=ñ?£?ùûKÑTHØ?ÚáU¦7ÊIÈÛXÇrxiÞ7ÎåÆ:tà^³Í£Á!Kòó©,8AüÏzßóÄw(I ìäh·ÑQúöùw,ù.1øµZw®íb!&t4!Ç.üú2E)OkR¶Ä4³¬?eBF1³öeÑ$í8xnÕnùx-PúÉé^û,ÇãXFKPÍ<Ç+wOÞ×j¤Ñ¬E¶Ëf³MRÍbZRµMR(gfísʵ$Èu.kOU;ÏïHÝEUõÔ«@È¥~Ïíýש?£ú~dmeI£0h m¨LBLhb#M*FJ&
!&Ía#6±ü$åÅögxɳ'«:û7Üo'6úÝyRMvÌ ÜÆ0Øh4MÌÝ4¢¤aKæÞ7t¶zh%*éMð·åÆ^&y}Gå1ÑÔ¦×M6`¥·m8@¨
{*E#R«5sQíøøÞ¨Ã&D¡+fCÐÄÆÛxÎ&cz\/ÓÀ[]4ª>n¨¤ôÜh#.ØL ïÖ9obkMNËÒuÕ.Âjõ!2̺ju^ëØÖ8ì3Ûë¨fèÎ[G ç_¸3ýO8°Õ Úm𦶰9ãT/èá3°ûç#6Ri¾m#%F÷"¢Ö[©¥m¦iG#%0NPÈ©-D#61u2HâëQUË;®JnVÝ®ésuu®ÈïkÎòYÛ×·7®«+lÆ4hÆ@î1A *º%*»@Âë&Mæ˪#%¦_å¬2H¢ÈAB,$ÖW¸rérÎësk$¢3ï¶*çF×2 ËLEø:UÊA-H¡K29ÇXarR×eFÉ?6¢teÌeÃÑs4Ñø©
~÷ð/c
òhâÓX!Ë#6Tr!SÑ©/Þ:ãkÃz)\QÑ!TÁ`U«¢7*âÍÒll«/c\(!¡6BÒ¼«³5A«¥¨;Í·rÊ.»xÖúÇ®î×uQõíQ°i
¢I¥Âħ%4Ъ!h¨&M9Q%²ÛSM©·LÆ<DÓÄÜ$AVeCbzŪ×*:R\£³Û+µ(mUÅ¡:ÂWT7"B¡\+-£u´66RÊó Uj
¦<«5C`À5·&Á¼éånãÀnU.à»*.ÔÝTZ%ÚÔ&#.*A±Ñ©§¼Å¶eÕÞøÁÆ1'3²9Da[#.iHH7SlYe «UÆ«A@¬;)ucÔN}fÍ=,$î|ùWoÃAR<®Ó&ÂQAgÛ#©Â\\CÑz!¦©¦GK1dR0q¨²yܦ8BÙ¼1EâMjJ#.ÁBmÌKH'
p¬J¼á*8Àpì#0oàÅ-ZN5FA4¨·Bæ 2+±Ðj!B SR1F/4Ìâ0Ê#.býßR ÷ØsȱTnͯ7nnø÷Xµä¢ÉʾNLâ!ILsC#&DVE¶Fi¨(a S#6Hƺ-¡2@aZM'"1AÆî<j¨í˧¥ÁlUòÃÃÛæM8K¤A³¡Ø¡)"ÞZ9fñJ6Þ ºÐÑê äd'Í4Ǹj¨ºN0üfâÆiûi©²°°(0ÓbÉQÑHD5qîeéån#.nèÀO\m Õà*%oC#.«ÊMïìu¦÷Â
wÀjïT¯¿&Cr@Þ±¨¨Äp6Êäøz$×&p²±@V[i¡YDæË(F )96pÒ¡&4©J¸(©0Ö\±
0¸(æ!BÐQ!bJ£"¤Á4Õ´ÈÂÓGâMI)Ǹ9pd!U!Ì[¼;îíâ+ÎòéQ×bQÁHµCTEÍIÀ;¤Úm¦Í¦l²"µj
Cñ`§ë.ÿ3#6ä4êJðüû¯Ì("Å#6H°=ùÀ=Rc·.£÷e}·ª>üRÕDôÑF¿YÚ>REB#%!T£AÜBåµé{T}µ*Àì=Uí&æë§ÎÎ00Ò °W!P'Û:D¯µg<¼ÕF rO#.4P÷¨ì¬p£þÛ2FÄÙÝÛn®®[{k®;¸[ºU0Ir
Y
vÊk^(¦µR¡LdÁ RËuB¦æ»³qP Ù(f3Т#omB7û¾¥°·°ø\¼ÌÚÒãL6-Öý"ò»-ëÛ¹Vçt$YÐIÛâóÝkXä$Y¬Ùæj±tª/vA»>#.¬½HíÓÒ1ø¶GÛ«ÃD¯PVÑõ(þ¯à© N½¤L¯ÈÏar×($ìÝÉгàw ïRb4w^×»C¾/
ìX,^¨bK\«Ù½-!®ÓlßMvª|ºõö!üȦ7@Ï_]ßÌØuåÜ(7Ñúþ©ØÁ#%Ë·I#ú;}+¾?}n*>Û±ÏÒ[ì×{oѤvÒBÅÛ³É~¹¼È?Èùc(ñG© ÔU#6+¿æd礼콦ÐðÉßzRÊ'j[br¬#.v#%ôηUûʸT71wVfºËmEÃÒXJ§^v×# ïEC°yƱ, ìA2±AETù°áòNÊR¨QeTÎÞrá\ö9Ú5jªË#.&t0ßácZb8z¤0ÀmEþf³ÈßçH°Mq4¤9 #.þ ÃUHr¢\ªévÜV^ßÈò¼QkÚr¶Kh·²ÖìKrîêÛôK\6¼UÆnVéµ·MY#.cnm&Úæ²k-µÍÞír,mjQª+;«î-Ã#.âw²Ë»$çv÷07ü<¢Í}Zk¾zÓo´=H^Êî"Øκ!7@A"ä#6´Þ=¯íÂäD´»¿vú®_oª¾ªýQy>ð)Gä#6çøÑá"É4ÖÂ=$±òSè2w@d#%Gßèq¢1¤(IBHå%J*¨Nîòá^T#6Z\# x Ùb¡*©""(¤[u#.mt¦µø~{oF®Ü¨Rd%ÛÝäT]Ñ *½Q@Q¤ÖHѶÛ%[¿~k÷!D,#6 éB?õ@Ô#%ÿ$CÏ¥'¾ûHjÆMöFÒ¶FñÇÙ{ZPuðPç¼P#%;²f_î@O÷A$;ý&Ô¬¡Ôu`¯ª¤ª£Ù¨3`Ð: H#"&Q)òT(uqe-LÍIJ1id´i66hmIEbÆÊRRJdÚ4)µ´Eª*ØÖÔkjZVjZ52¥bÖci5³[ϺÏn·$cu¬È²#.Ç"6W"Dûne6ÛaPÊAÇ$r®tëÓ£Ò®Ï=tªò®<ìiq¨ò¤©¥D£O c!&$Ü*+hlc ¬HÉ-a"#6@£`èÁi#.H
4ECJ¤P*( B*Zë0$(¾B¡ Ô#6Y2?Íü5°Á#%ô©DØ%%¦îéÝÜ:ÓõÚô·W®ìÛVÀ(@d$f2Óȸ@M°%Ä^û³B3ã`ûÇNÙ"vÔôôm÷wc¾²³Ù
QRN {ABH,O½¸VÆÈÜÐö5OÈ¡äØf2vp®§W_[,1Z%ê/-l@Ò¨±±Ü¨Mâ xFߤj¯§1pV!TÌH!PáJu0UR8Gõa£ÜµõN¦µFénãɼÖòË©R/Ú]êµsQµ±hÕZê®Á¥±ìóp9ávº?®HEÊoz¤ÑïpÛ2#6e_ìÓjÎ`»8C®+dßX{ApÂ!ê>ÿï(ü±YD©Ë³eJ[LTz÷F"Ë`ç`ÎÕRúÕ ÿùiÏJê%áMY¢ªS|²|®#6u¡àÖ½usFpÙ"}rC¼"Él³Êª<Âo×øÏMÏr§ýæØè#Æ X}¨vµºt¡;?;#'ËRùi@Ü¡ÍM¸Ôã|]?ÙÒί^¡ÔB}¨#.#%ù`ø¨ÖîAåÍã°Ï/Ñÿ|hÒl\1º**;»3Ú*¥âTþÈñÅ4¢ØìçÓ~ö3a¦)¸÷GZ³*¥zÁÑÇUƶÜ` ÂpÞ]ÎÚ£]u\ÊJãQ¢ëòUÓ3÷ðÁÆ&Òe¥ÌI#ÆåÛJ{ií'[lüÇ¿Üo5ÕÛÄîÙ¥º'Q#%ä3!O¨"e¨BG½V×ÒH#´'53×ÕîZ×#.ÃPñçRn tÈCñxm÷¦¾Ù¶Uúûïy/ãV°A<(}ZÒÙ81K²$=·E4¢Bl:EæÊSlµÉÆW_û×¹/#.ÑÛQuÔîí®:väì³G¸\§µí{KXî{îV¾¬#%¤LÒ#6Bk¬¨7â¶(/%ÀèÃà÷Ô¦Çb-¬Ä¢õÂÕÄÀÂFÅÆixå$Z³F®;ûó©vÂqÙÔ!Äg ÷7tVBZÇS¼/yÀo#ß«½Þ%&s©X½*77/²cM±ÁrøW^3Ý$"Q?:yÛ6"£éÅƺ{åøÉÐ#.ô¡¡ÌVË~ügÉgsmm9)¸®jWMöÓÃmf± è·â®8kÃÓ[éþ]»±6årXöNVRTâÌYÍZª¥;¢øùgrª³s BÄyo
,pѾa& q<£jf)ÐÙnÆÛÐÓE¥Åf5w©±ÑÄâV\º)2Æl`qÑáDë¾x¶Åf^aTûåkÄWnëh6³m<pæyßý_ZÝ>Ø[ÑÆçhNI/$ËÆf7)¤ÖôöÍGb$C¥×ÃêCC:ÚÒs/}Ñw§Êò¶DÉJnÛTóQíjP÷xÍ÷bëZ:>ì¶Êü¹9õÌW_J×°¦éyiÄÆx»uw}²×:üç´ç¼î'÷u{õõa*½^WW0ïoèÌÐâò¹ô³8ÎÜVx«¶®§|ÅtªCVo
#6åUvga*Fñêòªéïlg¢/Ç=Ã5ÅéüÔÂln÷.úþöb¢</Deìóիô<¥sï>NÎ lr²¶AÅ׬Æ<EúûcÛÔÑìôþÝ! "D^æy¾8Ü£ËB6KÛ8£,g :d©D÷ÓìLíoY°¼0PÚ/iÈÚyÔsdÛ)
7°²TîÃ÷ä&ªhdrå#6%#.-í/×Cð&d«©.]ê'O8çmÃ7£UãIð,¦`W£2êçµ8ÏNÀÅî$`.èXÌ@ð=Z¢Ãì÷mRm³³£f3g#RcÀÞQä¼b3x0óð½0_$gBÈ0íÚº9¥#6¨ÜÑ)¯±Ò'¬ÏÇ keØ yc0À)Õt±
(ßÛíÖ ÙdJݧÍ-®¯®AåÖǯ0É<¼^G¨&ê@1[õ c®UNÃcAÈn>Ð o#.°(ÐÈ#×LC÷ªó#%@:ó#6`FãaÀPa»ô:£L6ñÕýxõ»Æ`v¥¤`qG=æ26ð9èÖkSAC«#%6ªsÊ^æz±¿v Z3K3.ªÞ&ËsxÃ\ã#6?#6«_Dd\¨¡PʸG`{»u½§D¯OÆ.þîO'6÷ûÞ[°ìkÅÖÈ,½ÓÀý* GÄÂg ¾T©"Vsïδ##ËlºNÁƹÓkFÒéaùC·úÏòghæz¢:§çç>ýcETÚQSSNFüb((±SöÛMÄe²Ú{Að]Ák]zVÔ4o{#.Uû»ð*#%Å9ÇGÖôÚÏ6(¯Û#.oÏ϶;3\4¡³G>FÎD(ÖѽòçÇÑp²9fª7 Zæ0ÙºÞÝCë¡ãÖNÚ21Dª!.e-lZ'ÚUbÕõQÃØ¡ç~%@½vÝiVkQ-29¾ysæ83DñÅì^[)X×ÕÚÉ"Dv:e£;F#6Ç~Ù¸°ëíÓÓwÃãWoÕqÜ̲¿';¢Cs:ö#.aº:ë¶Y¹Tûè¯[ãÔÇ4v4n s©»x÷ÑÏ;èÝ2÷~öçsw~/´j¦<£\Wt·åómåG^5&Éoä wª7AÍÄ%å#¾Þ0Må8pqäñ<³~7SÛ»åßLóÎ¥mZ¡\dõQÐ{x09hRÄ¥µ¥«#%}¥ëôD4·bÍ
è3¨ç®E=¸¼ó ;Hðà>.Ãx[CUZØ=íô7,Èh¨·tz=<7~O ífBñEo7ê9q À°ïLBõ«³üñ6°§«YܱY
;W¸Îå\¹Þq.ï6
)sf\=®Ë#ÕV4(êvµÐ<³Ê@Ç,,¸g ¢(Ôyzw-HÕ]B¡¡¯E´öq3¤:f,öÒ'!Ñð ì@â1HóFÔó vM\;© É3@Úõì.Úg$$VtIm-äSLÛ0w0ÈÁ'#%ÕY"aÃßôèU×]õûC#.`fá+u¸mæò?N®°Cw"³0ñ²)qOn"xX í¸NÛ&Äy~å(ä·°ÇèpÅ`\r P <ßð(;ïÍVßáL{U#.>¿ãxKf°ÂwÀõüå'y;`kàýpÃhST«CÙç2°gÏ¥_V«GªG±8v'$ODMáÀÖN}®;O[Tb,ÈÃäÒ¡E~ ¯Á°e
Daì»Íml
sÔ¸ª#I#6±KºÌ0ªm&@<Æ
(Ó`YF91!²²"¨DÈ¢EXB!$JÆÕ½+F·5¨nZÊèZ©"(ØÁci¬¢ÅFPTÒ¢aQFR¥0ø!\Þg¬âþ&xØ
µ±Î@LñÜî#
# ¹vÐ
á¤é$c9ÍbÕé¼mãnEɱ*µ¯¹m¶V®UQUUé¹UײóÇÐÜÍýÐçP:þ~µÑøC5÷]cÇ-§AKxæ*Æ1K+ud×/¨ÒÁí¸i¶í®oÜ#.hÇHiþc£f-+°£W ¾ù¥SáîÀkN4bJ³ÄòÖ:¸`@¥,×cÉ (2tHqbePDiòãOR;Æ]ÓxÖa%dH°!V7VÁ·Ù(&ÓicRE,%ÝEcbi¦4C®Z*=Ê[ÌgA§ÂuwL¤td½>ùlÀöL!P9lª#6@Y0ÂfL7zUàÅ3R·XQÆ6ëØËÖ¥4ÊÑÛv²ÍîFjh£MÔU¬zmkZ¦A¸Lk.<µµcÔèç9«eoLÑ$DMqP\`SZ¨X³LÐ*±cñcix12ëBÕC$Î¥¯Õ¾5©Ï9;·hÓaYÎS¼JÎ!ª#6A,ØTP2ÇcLhÇ»*ëµs½µPAôãn²U"^Ck*êæVú%+XIwÜ&]J&0ghnÀotÇßhsiH°N'a§ïiÏ]P\ªR8ÙFö0Tj?ªãÞºÓÖcSò£µ.¨CZFLàèd¬q¨Ô"Ú7*ª#6*à ѸÐá¤0m0m15+FÞn-¼,²»zça[ ¹tùÐC 2´CdT¨£]&09ÜEZÙ*å#.hFe¡±mÝF?Sã5@LãRùg%¥¶È|4k ¸Ô Úh¦ª~¬¶Æä$¼*7Ä®é@ìzi¤<D¨°]8&è .ï®r#.VFÚqÉ#B¡ZYm rm2LäÊlbWfJÌæÚ¢&n\c§F±V=¼§^1Q¼ÁèÞi®m·X9¢VßãÞßÞ= GÕyúe}#611(÷"Ñ·e0Qsâz±Xr8cMAø¹¢@=6ñalÊS!vH#.0ÕÏ ¶û0\d#3ÉÜ$d9ö¥:é¨WbTF¡£MP1#BÌðCV#6æe´Î-ͳZ"ÛhDF¤¨b0fµ8Ҹ±¶FxØ7¨Ô{ÔË ¦A¡6Á&'"Ë9#.+µU°ÍNß!UíÏ*ªÛ2s£Û1óM`ÁC!0çrc$Ûã½n翦Ì+¾îÝiL5MÓõ6¯ÚÙH$ä´¤$zO®;ÅÝóèºbCóHwÀ©ÚªwUØÖÀ4*SmÙüç U+ {}E*ûXSÔÓ^#.ñqº²±eÓ¦3~sÈ+?2CÁûàÿÐ9¯¥Ag*Î*JAFä#.o³·Ä³Bx«ÇzQ#È»û<*±¿®væA§ öÁK?~Cóyßì¨×\UbeªÁåó>\f÷={p1¼$a¦î»¹0¿{w@y9;bƪ¦['º0ÇotÜòä<×Ñ(õÈø¦k´àµÕ÷¤qÁÎHû®øü!¬í£Q:ǧ å@Hµðç©!Í5i WjKV\Õm]7hlPPH¯Ð¬»öÐÖiä#ÔD~èì9ߥ}~vý"°R(±H#%VZÛ#61´Æ&1¤D©(Z¦Uil[%¤¶¬RQ¶$¬4(¦Ê£Í¡M5#JMQ³JHIQÓhD¤KFHS4T¦È¥SFa¶lÂ%(I1«X!#%øÞ:úxôÌÔg´ê9ÉSÛº¬î¹[Ç4UyÜÐ~ðWæòs5þW$$g1$8)×ÃÂÚµâW#o®å$îVÐElO"¨>#.¶4~ ¼Hga¡hf6ؽØLKn£R&¾~§Ûzk³pCõ%ßÚ(2ÆH\Àù9q]=½haѹS(ÂBYèâ°ª¦$ã
ß´ùû½ÂùïâsþCJFÃÅqy§üÚµù¯×ÑÖÇ{!Ãë: ûo?WÝjßµ¨Û&ÑXªKXÑ÷Ösi±©BQ£±õÝ«C!bR©bXK2ïÈ0'uàE$fPÉ#6>ÿ£"Ù)í¬÷ó.#.>+¡Q
¡¦b0ÜürèÕcD>n.5ª(àÉX¦¤Rb"©¢ªD.éÊf¡+@6lxËRXÐV,I.¾Þ1Ó{¯.íгöó«ÌѦ»6öå&ñsD¬ÊÜ·/׳PQÀº.a#%ÅÝÞ!`СGLÄĽG¾ôÓIà{è5OEÉ'&u1p6e¤J'LHQb`àËVAd¦¢ b¤
(ó©#.LáGô`6 kgìμÞ6ór1J¤N2,=¤4,°p¦| d<ÀÂÛ«6ìjHÚÛElm#6#%ÚÔ("3@pBh_²*ÁUYU¦#6!ìßÕºL@ ¦@¥+Å-= #%½]ô¿~7c¿#´
`>ϾÈ÷÷ò3þ¨Cft½B$#!¿ö?"dê
|êÙ¾~h%¡Ð{Ñæ#.,(`ä塤|ÈØn2¦LÓÈ3ÏÐ@>ã7ïØVÆiy¼Â°÷ýÞ=ßµöR|ª2Zûf5ïðñÆUo¿[52UQJm¯ZÔÆÊJýKï*G;ó&¦¥uÊqµm¢òêg*ñ4-o^
°n2nF-tiªD§7C5Æ6Ó&TS`Ò&!*Q±A÷Ärê]uâ+NA«B/¯Ô{,¢tòOئÊúÓrµÉF¯Aï J+«)è(° Éë;øNsê>«íó]ÊMË°#.L|ÊÛéRæ!Á)Bª9£^¤ÿjfÅ<Ì;¬#6Aî0xw;ÞõHA)4gfzúqòFõcÏ áØE¡kõ|¦!»°uªMG&~逸²#%Q;ú¿Üt@d"È*¦#.>¸ô/}Râb_cóÖìT#D¥:ΣʱrÖîõý'5>ç|â²âè}.àý_Tl×=ÎÜÔ²]4X`C$0ÇVêã9'HØv'F³ñIÚj&¥gõ@>3¹Ðí#%pàJrê`{ä7s@òq{ÊA/UÒ\zge)^±²=sDþXÜÆ1×Æ£Ôå°nd[wof²X²¾çg)P6B·Þ\+ÉÚEµÜ,3âÍJS»uUtDÀý19W53ÂpTlÐÈÓ#.¤ch` ñ0pP#.@ÐnªÁ`È%ÿV TU*2ìÈ/&YÛr-Þ¨»5!PÔÊ0E#Q¤Ha¸6P";^-@âYÇ1Ìnì5Í¡#%1,½!sYÚñ¾¤flzÙ¹Ôé¥ÁciDã&Ho?/3²Ð½X2(uÇÌ°´ÃdÝzYg$äÝ&Á5åDEPÚ¥HA±è~3#% LªÀC}Yf-"¼¤}q¥£ÌàIQ%¼Ø^FZTz³µHÅKÅ"@Sp¤u^<o.ÈB3@Dmï½àâ
×jta¦lrÞX@zQfkQÁ¨À½A(Ö÷óò¯n7ÛW üï¬"ù:ÈÏÓ7Ò`ÀR7{¦BdXg&ðS¨f%¤ É0ð»,íýî¶ÜD¶uS2ºcre38ºt#%aÁ%ç»#6Lp²O§pßX9¤à»WD¢vkbÔ+LÄ#.ÜË#.»³BñC7<èD©#6H2#%ë¸ïµ!£!PÅ X#6ÉH ºÄy-_F¨é<´öÝañ¿n«ÍÛµ±So1ï[ÍVWÁ¦e 2äptc¯,ã2®i²ís¤°ð4F!ÇöR¨±AV,ñ³á$Eïæm;ÖcHo!Ó@3k9Ã_'LÁYÓB¯iè1@'*kM.³Æ£66 A»m¶ÒÁL\RE΢Fe¥%oÝ*,u`Á´¾Ñ9¥É1260ìo)¯i#.&÷Ã@V«¦Ä$ltÊvÛck¦rF)ÀKE ÙM,vLí.\º{Õ[>!m´Áiå¬Þc#4Î!äkû}avÚߤljW¸ä'7qÖ$[¬vÚÜßLU»ÆD<´ÑjlìïôH=fUÌL3aè'£>4O¬ÈÐ!ZõS5{ÓX¦¹CÎ&;±8k¦î\@r¯2n&='I©Zã¤êBÅ FÕ,¹\¬*ÍV׳p`\ñ©HfJY#%êëã¨"ßkkÌ%ñO+vv&º?grà{Þºç(äUÐä×I¤ X¬E#65³6É!ÅdhmÌóÀé^]04©qs:ÙÁÇ0@ëæE}h·¨nLeÁÃ}8 Ü^-1³ñ|2£Ãµ÷@¸p´V×;"'塱X%ôºí#%í5`+IB27©t§#.NZÐÅ©ºB¸°Aø±b+m:+¤BN\¯
mgY¬ñ[6LÎÀVælåa²DgÑ@iµDбP<ýÿB㱧4ülÔ?nMÖÎðàM$ÕY'¯BÐòtoi´\Ûñ¥Ø+~8ᥢ]-YÃ[Ôtͤp?UÿÂQm2áLØqEÍ#.qíñØåÓ<<4x¨1 (3HrÞ<9²óëktò ¦Æ r³òëz]YÒ1Íñ,ÌsÕ¦)³åÈFµ.ÉzÂy|²ÂÒ+d׳ÛFó~BÀaud¤Ö lÅÇ-Å
µ¾ù3XSC´=±ùq«óëth:j=iu]p3BÀt§¯_ m}i¢2HÛ bvvÏxâ«$3@ä½Ì·gnªÕ ³ PJPÍHÆÜq!¦YÛ%j®`Þ"#I¢#P/¿=¹fgØMÁC´;,LMµM4Yp'Ò*Úúµ·ÉSìÎxÔEë¹Y¦§vMY@ôðSäÌèåå#6ݹpf#%ÊÏÚ;tíyA&w©b¥OLìO#.&Âé?8L89ÞÝM7ã%89Ê¡Ø-u#. ³/L]¯\Õ¿%Ú.cx¨b4&µ!Ò`,fÄlLMá#6Ó£p:5ÒHÄÄÌü¤dA¶¢Hø0ÌÁö4EqT¡ªk&§xÝÛ3ÅÖè)ïe£(Ã1YÃ`¢Ç6!Ý]ÛÑ.$#. àT0%DH!¹±Z¸å9Ç´ÒQ PP4wÈi8,ÑHê%Fl!6aeÈ0à\*hÛiD5Üè8hé*¢P K#6¦æÃ@ÀÀALCÄD6DáS*¸èwB]èÊ4,¨6"wA³½ò3bà"¨)ØÙÒi½ûøU«Hªå¶ÎMlEÜ 1 ÃØ#66v4#60gSP#.F¸H¶WU%0MEó& 83ÐíÄ3mÂtëÉHrºâÄ¢ BB¢ê¯3[Ò^6¼¯_#.ó±c%%¾²yyôCk£U@Ê(¨°×¦½Èn£¤±°f÷ò C°5#6,"B@MbªPê á¿öôl½Èë:½uyÑ\²íeX§ëïk°Õy+'J#.?Ö>£MÃÜ)üøx¨âÙàm&-£×B¸kMµ7âIfsQfE°ë»ºf$$#6DXÍf¿Y¯§·#%ó×W%U®ÔEüðMÑÎ^hÂò¨I#%ê¯JS°x|k0ÂJh(¨GfuaÐÆzíf?nôÓ'àÒ«¨¹*3#¼¹R'W((q#HªÕÝeiè3³%<ªÙìªJÅrØãz#ÈÄ6¹7oSñkJêF9ÌTÍ@Z¿0TV(NAqKìÍËVè+ÈämÎÜa·4}o{«;Ù¬å¦66µ²¶[[:ÁÖ®¿¢>¡DHª{hËà}*s9e¾Dʳ:¯«d{÷ÅT°3ñD#.¶CvN]GÃL@SÞ¡#%4©C»¶Çá^Wf·DîÎZ²º÷áâÔRñ7p#6ªVÚX"kÕáË»[Í$2%ñ5;Îéo7vÈ®òï^vÉåÒ¹Å×RÉ#6AÜ0@4Ð5*F ´8iQ¡øé3 iöGZK(4]-ÌUDÖ7v)<´MF¢¡ÇgV#34u*ÌÙbQ GFùèë쯷»È!ð<ýZ÷H|ÁpDäA#%¦Ï¡¦3õj¬¼dú.ÖÚ1<#P$xîam
ÁVÄ®ÉÉL+ÃàÀØÁ$p ¶((7'§¨&µ9w²#6nc±ì³êlæ!ÜúìçÙ#.:ª&ª§LYUåùû¦÷×!G´È(|#%ÉÂmr,A-Ùa
NKÎMN8ÓR0;»n[5'Ã)Lª×³¨^b>%¹C3é8]6±uLDÔ`X B!:©O¬iæç³n%Ú"öa\ÐØq¥ÑÃK×è£ñLôQ#.i1Ç¿0ÚÉ0µö~tm6V,V"$ú¬ásÈkÐÒʸ öò
0'º)HH2DO¢"öµZÍiHJÔߪXDVBEGEìE0cUÆe5@Àm©n\0P`M`¯8#%ì#%IîËÑ
*Béøah<2½Æ¦Z\ÜìȤ°² H:¯äßbX1¿8Íõ#6 #%H*¾ß[·|4ÅO4oÕå}#9Ñth¼g#.`±Þ»´Å¸3©Õñ*\žY9)h¢#65½P4a£ePM£2Xl+%Ê«EE¨íD·LNAGUÕÂë×yåmÊ^¶²VÌÝv¬V`%QV@IÅNýWPË3:È$#.EG^2S4#%Ü¥
¤M2,Às4µ§âPNÞ0:=G§Í,0!&*Ç·§ä=ÔÌÃaÂÖ
з;sHc²iÞfÍtê1ëa°SàßÚ½&ñØÒ 7!,HÈ#%5ëÃ@ä%驾EsRÏr¢Íýï_kWÏ:ó¶¶*'õÍn¥H[ïh4×·¢`wAuuÚá#.,q89 JþÏáÃ;«¯³3¯ÅO8~kÔ1 Ü$9Ê%¯«y£6ZhI¥EG!+]£fvßæoíÕ8`±Òùn¸¿¾¶^ÓötY[ÕôãBa»ÖiAà~_X>ÈH&³ìÔXb#.4Ñ©î5ë%ïë!rKïl}9úÓì='p>ýÉÔ(^7/$¤´jYiVIJ#6«bÖa´&Ä*kLmµ&ߺÑZ¸Îk¡£Y³ks¼ßÛ<ÕXªåûµ£aÞ¢þsÔæ: ÇÅ#.#.¾®¾+±;öòÃMI@\Ùô²z°/aÙ°nâ#%ÕNÑ=ǾêäKÁFzùÂFC?6ëñ(ukµÃ
XE{J9&ärÔP|üi¶öÔä4Ø-J[hyªÃ´me;;ð´#.MÓIÓqAq«)\»ÄùÑe®qÄAäÒåCD8:ß 7$l·}uf¶Û6c6ZAI¡%!pj[´-ÑÅ[åÍü¬+cTdëÔçL¨Í¶§fܤ#%PYl±Ú!VYCrhM#.ÑÞîôÅN¡êÐ0LoäÅ£JÔ1ÊȲnÅF´ýJÖbÕk#.¥ø?{5²b]%OZZl}Æ0 ¸äE!òó÷ÎÙ,"÷Ég4 )@w}* uAÔ ²$ALpIF wIÏ/©tÊð¨A°O!##Æ jU6¼ãÕt±ð<4O ¢+ÙÚt÷ aÛL;ÏX#6ɨF §ßæý#%oÙ1d@Ç! Tñ{õWnÿWòmî'yüµÍó6@gö8A°ÄZ´³0?yüä<vuøl¼ôªÄfPx"%7³0Ü'´ws7uÿê"çð¾ÞöÝfÇÓ500.=Ôl×Àþê:;Xæ¾·ÞQPñã@?LSa#%G1×#6ÜÕAf˧f¡Xùè£C&3#ÅÔlDhÒKºº #.¦WÑÞaû]Û\«õæóÏ]ųÉSd5Qy7s]¼&ÆѶñs\·Æ+»·yåv¤å[yoÑ[¶Ís!ÅSõ$S`6mÙó÷þ#6*¾%|}¶<L³=AÞIYªa<Í>é#%Å<Ô®Êû>Ê,U!¬Ûf,ÚÍ´õµ¿5÷øµj÷û"Ñ-62)E4²©³jü¿tj7ßÕ~îú#. £D1SQ¶*¥)JÚüz§hµ¼'Ìx"#%Z"göBRÖÃÖ1ȸ0ÄÐ0HrHNT$è>ä#.D1¦î¹²)±¬-f¬Q¬lÈÅc+E²ÁëÎò*(@'](]ê4{qM_îòýé©çÜOsèùfa×$ðWÀ õ#%£'¸}ËeL|ó*j¹#6ý{.³æÉxv÷,!Ú°3
óÈIÀôªyæ8öÑUãoË{Ø,EE'Fñßt &ny¤ÀÞB Q¶ÄbpüÈtî"Û@ÖôTÖ¡ódHE9§¹Z¡ ½B!JSÚjh("jKNíÒkTÛRiIª[RTl@njm¯a0¨ ÿNR(+Ô\/*SÞR¬e¬Ë/n£.ÃgUPû£ãÓdtÎ=v£9é.k¯Ni`MÄÇhú([;³RÑÖ*È5õXV²Oµ8Ð"Å
k°ÞÚ4ì#.y@^K?ÞÑïW-ï%ë¼lcúé#nìzK!ö¦ ¸X÷¢Ð§øþàêüûoçãvMÅ)¦%I²5¶1R`ÔFÕ&Û#6Z7æm¿+W°ÑZ(FAUdQ$ïî9ú»,ìi!`¡P*
û¤6+°0rBF"EHÒ(ÄÉ
)¢hlÚQ¬,#%ýhÆ}qÏzíÙ/uÝJQþÀ!"kW±mF- Ú5F«6XX«QZÊßÓ[¯3:zºüYݽ´ªË%$ÜkìÇègÍ#6Ñü5#ê1KL5VÊåF·ÓLðкùÀÆàIô÷$È«miGlý/$²ÙÛ3"*hc<jÖÓý90(8AK"
Ð2Ú·Én³I©¢-ë6ÛNìµÝÙ^5æòµÕ6&·¥\ówY³2«®nÚ¹ÚKdYµywcMk»«»¤ÙRTÈØÖóº·kΨ¬$ISa!H6Ôb£cÞMi^×jÒÙMIUéZêÞuuçj¼lm(Êe¬¶R×Ü·k»tYc)&A¢a£ÑN¡àÎ#%É#6ÛÐqVm3ø{äè5H±dÜ>²øQ¶EF*dÈÇ#%ª@ S㡬þ¤Ê[Fh¥È(1P¹{äÁ5×\É&§4)DÚ7Õ¥GôØ46àYêÓäö¢ìþ3OêÁ `>¸¯pÏ?~ðøfEº#6ݧ¾÷#R÷fìfKËÇXZ¦#.Yë9¾îã~07"ß^GÏõ¤M#.UJmG/¤lír$a®îB1ßèSJë@ë#³o($QGÊ)ļ.#.õêLo.Eä`%Áæ1¢GP5¦Õñóç/ml·pB#%|²$xk(#6(iι8>J¦ç¸iß>ÔÒ9åÈt(a
-Q¢Þ3oÐÕùUbÙõ`|¢B hÚ)I¨i¦×£|#.âöA¯qØÔùK5Ó"÷gëtód±BKûòVµw¬¢ö|jëP¤Ot~ÃìJ'`O8)¹A°.F´'RK`¨¤,n#¨f4äÈlƽQÁÑÔÂ!³n¶`¢úC#ØÇwƽ!ȱ|*éDÅaM ¶FÕÕWáuzC<óËû²kGG ÄêîéÕ]Üãjþ?70ÚEy£ÉZ$£Y¨Ï¨ÑÐǽÁäuMmÐ/÷Ð
ÄZè8@¾?jã8ùç¯fYÁêF4dý-DEC=µvNÅ|ªÖÞm¨:´Pi\Xì"ð#.%t¢#̸ÝѨU×1Qߪ
@ã[8AÀÓ Êö;÷çK¤B4Db:[nX#.édRS(´@Ír:ä|Xr×c'pdlA±ï47mà¶Ô~¤
f1ÞBG¸Ô_h½GCô"W¾s;/~D#.îfYÚÛÊÚ{aµÝ×oÊ÷}þëiäk×í¸*>ÜD-(?LþdÓ*z©Q£fÜ@ ݨþQD¢¸ß³Ñ2Tm`ô=åWì#%ÇßwïØÁ²>uLäÿl#%#%b#%?Ùÿs¿ñõÿ¿ü¿éýôÿ¹íÿóÿûýíÿóîÿ/óÿëþ_òÿHþ]º>_¿ýÙ|¾ß÷Oþÿëëÿþ?ðøÿãáÿ~#ü¿ãÿ/óþïü?ùÙÿú|åÿ/ôÿ=¸G£üúÿÓËæùGô_ôêüß_Õ¥P÷SÿLBÄ?iþ,ϳüêÈDÊy;"e\?·ûäE7¨;©sÁþ±L@ZüÄm4 þË#%öªÂ)40)*ÿþþǹÝÔI IF·ÊÙVôh #%âQ³ßÌôjB»M¢Ï¡ESY8Û,×gØ+,þûö¦C¦Òæ¨x¶æñ#.Öâ×ýÀä÷² ¢îÇ^A:Õó»0ÉæfØÝ@#Ì%*ãþUÊléÎüiÙ\¾ÅÙ»Æøyö¡ÃÉvǧ¿eÔ«jÿÝë
¥&P"ƾrÿïUËr#.ð7Ï_û«ua:XÈs+u#6Ùýþ.ÀÀ7µ*jHþ¦xiiQ]d*ieaËTÁ0ÙÿeTñhÞ¶ñïÕ¥pvîm©TYn44¼BÒÙl`
ÕÁËsO6e7ª¨5mÚ8øqíMmƶ9T¨¨ëÌFdMmTIqxÝ,ØY.ä5¨mõyõx*ŧ7FÎîs¢kCºFêâ¬#y{¢ï4êÈh2ùÃáf´Øäì¹a²
qS1a ïH²F#¸yíÈd¸ÐH?F:oÌÌü4ÃÃ)×Цë^EúîÞK¨ëN±£\-ÑNàS4'>:`«éßw´ÿJ±·ý4#.póÀ@ÄGßF;tk5SÞæ Ñë gà w#6Hp,#6¹^>`L³¬5¬R Eò "IEq¸Ov].fB¦æ<õÙ3PEATV*AB9wt¸¦cß·YÌÊ2 ¯kº\69¤U¥ >È!<NÁ(¿K61$@ 0P2îHqw;ó\¨xH1Mï}lı38bÿûKuÊɬÆ\¬îÙ ,F#6"`ºT70]#.úwóbs $LjÄÔJlkY¥3[FÔm¨ÌÒDÅ
S_EÛWZªø|:Ö¾¸:?àE3ÿt#%¿]Tµi¸#I(¼co¦üÛªözÜíSlÖÕïéñ#%Mþ}OÒÂFA~©o;|mq>§^²æF4?ícS9öɬצåU1"ü«Ç»'_û6Ä+W] æ8uîKºxteæ߶}C3¿¾zg,r.;À}²½©½Ç0À×fÜT9P^]*zgâ_§Æ³ò8ÎQHÔ¼= #6@C&9Ò#.³QÁOª#.D'ÒáG½\áUò»µP®CGݼòö²á¾¦ÕÍ-ø¾v챯¤[êkØ´|nmcãm½(ÕìµoSEªMAj½óZåUìÞÝy»¶ë]#6.æäQ#. ©| P?ç!xnãdN2Apã'PQ±Ôí±s¼p]º¡f!OVݤ¿7áUÁbÇá*J9
¨H{ÿî°÷cÍÔ¼(5É@$fáÌR¿æû'wØÊ=<ÑܧÛÈ_.EúØqPôÇX¡ÿ#"(]¨î;µ#D)Qb(ÁmLÍtÖêÕÙjûËf¤ÅÍh é! H¤ £þßÃ3ÏëÿÏئ¨¤"þ~áã(ø{fYr0ÛmCòNÀ.!xN¦ çå,A<?àáÿ¨ ýþ&^â|YY?÷ùB-Þ6áÍtçü¤ÿÿ&EÐý hNí'»ÿcÿ`[Óúl¿·@³¼%ËAú¼Oìÿ»æÿÜíe÷øCâ.ÃGéʽ1ÍÀê'¼waÕBÏ+Üã!Éä,yý>^#y;³9ø¾ÿѵú½gþs(?l-A!ñÿÔ¥ÝóG#%#%(ö#6CÛ¢ OùI[¥BY=+¨4ÃÔkéýÕsø]¯üB_F*ÀN#.ÿ6pñäÑÎJíâqTE3o¦«
ÆYÌwÈâfÓ§m3 ÊÊÇðç,Má/-±¿Ñ8¨¼§0aw<}8fJÃ$É o§ì]aðx`H$Y@zõnÒ=®Ù iÿ~é1éÿµ^#.Jz(ÎLPÛæcèªÆ"ÿâ|xãügê?I¼Ëò~ÿð"ÿü]ÉáB@ä&öÐ
+#<==
+#-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEivIt5aBoIuNHTzxwSbTGfAUneqoFAl3aW3cACgkQSbTGfAUn\neqruqA//Y9oJ46ZR8W7YB/e45bfrYxGbN7NnkvkwSPNziObYur+n1QpQEOaPTn/U\n5kFtPWHXRJzaG/A9poKn7pl1Xd7Edcu1aalfoEazZbuD37VOxIp9lnrefCAeICqj\nGv0SD96Zac91CbA+b20Q4xnqxKMi3LSI4NPjfFGy62FkSk3MS4p6Rdp0/WAKwwNj\nw7WEjQCNmLb37z+FGSzXg28aljYeteBZEthsVmGJ5QqVwMBwgj2+y5FOTzFfxmqB\nrWgjFYS0l85kgYRZv9yzdNmFs5SScwafwpT8Xmdr49tFn/+0LxXyRxX+rdODgrpV\nY4EOiQz0fd6mMMnaTDXlLSXls3JyVYmbTjeNL/9gcHmnStzJ851CJQfyQg7A+JoC\nc7nz0HbiFyTgB+PUZr1OhGj3A7287o8XQ0tqR3oa7jXIOX0OynrGplMQKr++0jE1\nBgKzjLoE9CTbjkQfICLG+aUy3S1ZyDk/BcO+5+Ytbru+qXuDsIgAdVosMfNSv9jJ\nXvOINsbRMekdejYMZv8fIkn5OEjCFHVhNpobEsCb768bjB3p7alQGECBvjHCm6dy\nXZPzl9cBMWIXcBjPTS+GZj+PIXGcu76pbsx6HBHWf+uJ+4xgOsUCVu//0AV09jvA\n0MjtLWwQ8mdRH6Wt4hsp4HKtSvQrhmljf2OnuYBgaFmcdJkN1zI=\n=C0oT\n-----END PGP SIGNATURE-----\n
diff --git a/wscript b/wscript
new file mode 100644
index 0000000..286c28a
--- /dev/null
+++ b/wscript
@@ -0,0 +1,88 @@
+# -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+
+from waflib import Utils
+import os
+
+VERSION = '0.1.0'
+APPNAME = 'ndncert'
+GIT_TAG_PREFIX = 'ndncert-'
+
+def options(opt):
+ opt.load(['compiler_cxx', 'gnu_dirs'])
+ opt.load(['default-compiler-flags', 'coverage', 'sanitizers',
+ 'boost', 'openssl', 'sqlite3'],
+ tooldir=['.waf-tools'])
+
+ optgrp = opt.add_option_group('ndncert Options')
+ optgrp.add_option('--with-tests', action='store_true', default=False,
+ help='Build unit tests')
+
+def configure(conf):
+ conf.load(['compiler_cxx', 'gnu_dirs',
+ 'default-compiler-flags', 'boost', 'openssl', 'sqlite3'])
+
+ conf.env.WITH_TESTS = conf.options.with_tests
+
+ conf.check_cfg(package='libndn-cxx', args=['--cflags', '--libs'], uselib_store='NDN_CXX',
+ pkg_config_path=os.environ.get('PKG_CONFIG_PATH', '%s/pkgconfig' % conf.env.LIBDIR))
+
+ conf.check_sqlite3()
+ conf.check_openssl(lib='crypto', atleast_version=0x1010100f) # 1.1.1
+
+ boost_libs = ['system', 'program_options', 'filesystem']
+ if conf.env.WITH_TESTS:
+ boost_libs.append('unit_test_framework')
+
+ conf.check_boost(lib=boost_libs, mt=True)
+ if conf.env.BOOST_VERSION_NUMBER < 105800:
+ conf.fatal('Minimum required Boost version is 1.58.0\n'
+ 'Please upgrade your distribution or manually install a newer version of Boost'
+ ' (https://redmine.named-data.net/projects/nfd/wiki/Boost_FAQ)')
+
+ conf.check_compiler_flags()
+
+ # Loading "late" to prevent tests from being compiled with profiling flags
+ conf.load('coverage')
+ conf.load('sanitizers')
+
+ # 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 ndncert library installed.
+ conf.env.prepend_value('STLIBPATH', ['.'])
+
+ conf.define_cond('HAVE_TESTS', conf.env.WITH_TESTS)
+ conf.define('SYSCONFDIR', conf.env.SYSCONFDIR)
+ # The config header will contain all defines that were added using conf.define()
+ # or conf.define_cond(). Everything that was added directly to conf.env.DEFINES
+ # will not appear in the config header, but will instead be passed directly to the
+ # compiler on the command line.
+ conf.write_config_header('src/detail/ndncert-config.hpp', define_prefix='NDNCERT_')
+
+def build(bld):
+ bld.shlib(target='ndn-cert',
+ vnum=VERSION,
+ cnum=VERSION,
+ source=bld.path.ant_glob('src/**/*.cpp'),
+ use='NDN_CXX BOOST OPENSSL SQLITE3',
+ includes='src',
+ export_includes='src')
+
+ bld(features='subst',
+ source='libndn-cert.pc.in',
+ target='libndn-cert.pc',
+ install_path='${LIBDIR}/pkgconfig',
+ VERSION=VERSION)
+
+ bld.recurse('tests')
+
+ bld.install_files(
+ dest='${INCLUDEDIR}/ndncert',
+ files=bld.path.ant_glob('src/**/*.hpp'),
+ cwd=bld.path.find_dir('src'),
+ relative_trick=True)
+
+ bld.install_files(
+ dest='${INCLUDEDIR}/ndncert',
+ files=bld.path.get_bld().ant_glob('src/**/*.hpp'),
+ cwd=bld.path.get_bld().find_dir('src'),
+ relative_trick=False)
\ No newline at end of file