diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5b91145..df65944 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,27 +6,25 @@ name: CI # Triggers the workflow on push or pull request events but only for the master branch on: push: - branches: [ master ] pull_request: - branches: [ master ] jobs: # Job: Unit test suite - unit-tests: - name: "Unit Tests" + unit-tests-linux-gcc-ceedling: + name: "Unit Tests (Linux/GCC/Ceedling)" runs-on: ubuntu-latest steps: # Checks out repository under $GITHUB_WORKSPACE - name: Checkout Latest Repo - uses: actions/checkout@v4 + uses: actions/checkout@v7 with: submodules: recursive - - # Set up Ruby - - name: Set Up Ruby + + - name: Setup Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '3.2' + ruby-version: "3.1" + bundler-cache: true # Install Ceedling - name: Install Ceedling @@ -37,3 +35,163 @@ jobs: - name: Run All Self Tests run: | ceedling clobber test:all + + unit-tests-linux-gcc-bare: + name: "Unit Tests (Linux/GCC/Bare)" + runs-on: ubuntu-latest + steps: + - name: Checkout Latest Repo + uses: actions/checkout@v7 + + - name: Install Python 3 + uses: actions/setup-python@v7 + with: + python-version: "3.x" + + - name: Cache pip packages + uses: actions/cache@v6 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Create virtual environment + run: | + python3 -m venv .venv + source .venv/bin/activate + pip install --upgrade pip + pip install -r requirements.txt + + - name: Run build and test + run: | + source .venv/bin/activate + python waf configure build -v + + unit-tests-linux-clang-bare: + name: "Unit Tests (Linux/Clang/Bare)" + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: Install Python 3 + uses: actions/setup-python@v7 + with: + python-version: "3.x" + + - name: Cache pip packages + uses: actions/cache@v6 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Create virtual environment + run: | + python3 -m venv .venv + source .venv/bin/activate + pip install --upgrade pip + pip install -r requirements.txt + + - name: Install clang + llvm-cov + run: | + sudo apt-get update + sudo apt-get install -y clang llvm + + - name: Check clang + run: clang --version + + - name: Build with clang + run: | + source .venv/bin/activate + python waf configure build -v --check-c-compiler clang + + unit-tests-windows-gcc-bare: + name: "Unit Tests (Windows/GCC/Bare)" + runs-on: windows-latest + + steps: + - name: Checkout Latest Repo + uses: actions/checkout@v7 + + - name: Install MSYS2 + uses: msys2/setup-msys2@v2 + with: + update: true + install: >- + mingw-w64-x86_64-gcc + mingw-w64-x86_64-make + mingw-w64-x86_64-binutils + + - name: Add MSYS2 MinGW64 to PATH + shell: pwsh + run: | + echo "C:\msys64\mingw64\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + - name: Check GCC + shell: pwsh + run: gcc --version + + - name: Install Python 3 (native Windows) + uses: actions/setup-python@v7 + with: + python-version: "3.x" + + - name: Cache pip packages + uses: actions/cache@v6 + with: + path: ~\AppData\Local\pip\Cache + key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Create virtual environment + shell: pwsh + run: | + python -m venv .venv + .\.venv\Scripts\activate + pip install --upgrade pip + pip install -r requirements.txt + + - name: Run waf build with MSYS2 GCC + shell: pwsh + run: | + .\.venv\Scripts\activate + python waf configure build -v --check-c-compiler gcc + + + unit-tests-windows-msvc-bare: + name: "Unit Tests (Windows/MSVC/Bare)" + runs-on: windows-latest + + steps: + - name: Checkout Latest Repo + uses: actions/checkout@v7 + + - name: Install Python 3 + uses: actions/setup-python@v7 + with: + python-version: "3.x" + + - name: Cache pip packages + uses: actions/cache@v6 + with: + path: ~\AppData\Local\pip\Cache + key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Create virtual environment + run: | + python3 -m venv .venv + .\.venv\Scripts\activate + pip install --upgrade pip + pip install -r requirements.txt + + - name: Run build and test (MSVC) + run: | + .\.venv\Scripts\activate + python waf configure build -v --check-c-compiler msvc \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1cfa3c8..b65265b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ build -*.sublime-* \ No newline at end of file +*.sublime-* +waf*-*-*/ +.lock-waf_* \ No newline at end of file diff --git a/README.md b/README.md index 3b05f24..64d650f 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Mostly error handling. Passing errors down a long chain of function calls gets u So what if you could just specify certain places where you want to handle errors, and all your errors were transferred there? Let's try a lame example: -CException uses C standard library functions setjmp and longjmp to operate. As long as the target system +CException uses C standard library functions `setjmp` and `longjmp` to operate. As long as the target system has these two functions defined, this library should be useable with very little configuration. It even supports environments where multiple program flows are in use, such as real-time operating systems... we started this project for use in embedded systems... but it obviously can be used for larger systems too. @@ -42,7 +42,7 @@ void functionC(void) { } ``` -There are about a gajillion exception frameworks using a similar setjmp/longjmp method out there... and there +There are about a gajillion exception frameworks using a similar `setjmp`/`longjmp` method out there... and there will probably be more in the future. Unfortunately, when we started our last embedded project, all those that existed either (a) did not support multiple tasks (therefore multiple stacks) or (b) were way more complex than we really wanted. CException was born. @@ -63,7 +63,7 @@ in passing objects or structs or strings... just simple error codes. Fast. Easy ### Performance... CException can be configured for single tasking or multitasking. In single tasking, there is -very little overhead past the setjmp/longjmp calls (which are already fast). In multitasking, your only additional +very little overhead past the `setjmp`/`longjmp` calls (which are already fast). In multitasking, your only additional overhead is the time it takes you to determine a unique task id (0 to num_tasks). How? @@ -82,7 +82,7 @@ function calls (nested as deeply as you like). There can be as many Throws as yo execution of the guts of your Try block ends as soon as the first Throw is triggered. Once you throw, you're transferred to the Catch block. A silly example: -``` +```c void SillyExampleWhichPrintsZeroThroughFive(void) { volatile CEXCEPTION_T e; int i; @@ -109,7 +109,7 @@ successfully utilize this library: Do not directly `return` from within a `Try` block, nor `goto` into or out of a `Try` block. The `Try` macro allocates some local memory and alters a global pointer. These are cleaned up at the -top of the `Catch` macro. Gotos and returns would bypass some of these steps, resulting in memory leaks +top of the `Catch` macro. `goto`s and returns would bypass some of these steps, resulting in memory leaks or unpredictable behavior. ### Local Variables @@ -174,7 +174,7 @@ Configuration CException is a mostly portable library. It has one universal dependency, plus some macros which are required if working in a multi-tasking environment. -The standard C library setjmp must be available. Since this is part of the standard library, it's all good. +The standard C library `setjmp` must be available. Since this is part of the standard library, it's all good. If working in a multitasking environment, you need a stack frame for each task. Therefore, you must define methods for obtaining an index into an array of frames and to get the overall number of id's are required. If @@ -232,5 +232,11 @@ Testing If you want to validate that CException works with your tools or that it works with your custom configuration, you may want to run the included test suite. This is the test suite (along with real projects we've used it on) that we use to make sure that things actually work the way we claim. -The test suite makes use of Ceedling, which uses the Unity Test Framework. It will require a native C compiler. -The example makefile and rakefile both use gcc. + +There are two ways of testing CException, using the unit testing frame work `Ceedling` or bare metal. +- `Ceedling`: The test suite makes use of `Ceedling`, which uses the Unity Test Framework. It will require a native C compiler. + The example makefile and `rakefile` both use gcc. +- Bare metal: The test suite makes use of `waf`, which is used as build an test framework. + It will require a native C compiler (GCC/Clang on Linux or GCC/MSVC on Windows). + Usage: `python waf configure build` + A coverage report is created if GCC or Clang are used and GCOVR is available. diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..3383960 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +gcovr==8.6 diff --git a/test/TestException.c b/test/TestException.c index ff8b936..2566812 100644 --- a/test/TestException.c +++ b/test/TestException.c @@ -5,9 +5,35 @@ SPDX-License-Identifier: MIT ========================================================================= */ +#ifndef BARE_TEST #include "unity.h" +#endif // BARE_TEST #include "CException.h" +#ifdef BARE_TEST +#include +#include +#include +#endif // BARE_TEST + +#ifdef BARE_TEST + +#ifndef TEST_FAIL_MESSAGE +#define TEST_FAIL_MESSAGE(x) fprintf(stderr, "%s", x) +#endif // TEST_FAIL_MESSAGE + +// Due to 'test/support/CExceptionConfig.h' CEXCEPTION_T is defined as int. +void TEST_ASSERT_EQUAL(int a, CEXCEPTION_T b) { + assert(a == b); +} + +void TEST_ASSERT_FALSE(unsigned int a) { + if (a != false) { + assert(false); + } +} +#endif // BARE_TEST + volatile int TestingTheFallback; volatile int TestingTheFallbackId; @@ -313,6 +339,9 @@ void test_CanHaveNestedTryBlocksInASingleFunction_ThrowOutside(void) TEST_ASSERT_EQUAL(2, i); } +#ifdef CEXCEPTION_USE_CONFIG_FILE +// This test only makes sense to run when CException was built using the +// customized configuration test/support/CExceptionConfig.h void test_AThrowWithoutATryCatchWillUseDefaultHandlerIfSpecified(void) { //Let the fallback handler know we're expecting it to get called this time, so don't fail @@ -324,7 +353,11 @@ void test_AThrowWithoutATryCatchWillUseDefaultHandlerIfSpecified(void) TEST_ASSERT_FALSE(TestingTheFallback); TEST_ASSERT_EQUAL(0xBE, TestingTheFallbackId); } +#endif // CEXCEPTION_USE_CONFIG_FILE +#ifdef CEXCEPTION_USE_CONFIG_FILE +// This test only makes sense to run when CException was built using the +// customized configuration test/support/CExceptionConfig.h void test_AThrowWithoutOutsideATryCatchWillUseDefaultHandlerEvenAfterTryCatch(void) { CEXCEPTION_T e; @@ -347,6 +380,7 @@ void test_AThrowWithoutOutsideATryCatchWillUseDefaultHandlerEvenAfterTryCatch(vo TEST_ASSERT_FALSE(TestingTheFallback); TEST_ASSERT_EQUAL(0xBE, TestingTheFallbackId); } +#endif // CEXCEPTION_USE_CONFIG_FILE void test_AbilityToExitTryWithoutThrowingAnError(void) { @@ -396,3 +430,44 @@ void test_AbilityToExitTryWillOnlyExitOneLevel(void) // verify that we picked up and ran after first Try TEST_ASSERT_EQUAL(1, i); } + +#ifdef BARE_TEST +int main() { + printf("SetUp\n"); + setUp(); + printf("test_BasicTryDoesNothingIfNoThrow\n"); + test_BasicTryDoesNothingIfNoThrow(); + printf("test_BasicThrowAndCatch\n"); + test_BasicThrowAndCatch(); + printf("test_BasicThrowAndCatch_WithMiniSyntax\n"); + test_BasicThrowAndCatch_WithMiniSyntax(); + printf("test_VerifyVolatilesSurviveThrowAndCatch\n"); + test_VerifyVolatilesSurviveThrowAndCatch(); + printf("test_ThrowFromASubFunctionAndCatchInRootFunc\n"); + test_ThrowFromASubFunctionAndCatchInRootFunc(); + printf("test_ThrowAndCatchFromASubFunctionAndRethrowToCatchInRootFunc\n"); + test_ThrowAndCatchFromASubFunctionAndRethrowToCatchInRootFunc(); + printf("test_ThrowAndCatchFromASubFunctionAndNoRethrowToCatchInRootFunc\n"); + test_ThrowAndCatchFromASubFunctionAndNoRethrowToCatchInRootFunc(); + printf("test_ThrowAnErrorThenEnterATryBlockFromWithinCatch_VerifyThisDoesntCorruptExceptionId\n"); + test_ThrowAnErrorThenEnterATryBlockFromWithinCatch_VerifyThisDoesntCorruptExceptionId(); + printf("test_ThrowAnErrorThenEnterATryBlockFromWithinCatch_VerifyThatEachExceptionIdIndependent\n"); + test_ThrowAnErrorThenEnterATryBlockFromWithinCatch_VerifyThatEachExceptionIdIndependent(); + printf("test_CanHaveMultipleTryBlocksInASingleFunction\n"); + test_CanHaveMultipleTryBlocksInASingleFunction(); + printf("test_CanHaveNestedTryBlocksInASingleFunction_ThrowInside\n"); + test_CanHaveNestedTryBlocksInASingleFunction_ThrowInside(); + printf("test_CanHaveNestedTryBlocksInASingleFunction_ThrowOutside\n"); + test_CanHaveNestedTryBlocksInASingleFunction_ThrowOutside(); + printf("test_AThrowWithoutATryCatchWillUseDefaultHandlerIfSpecified\n"); + test_AThrowWithoutATryCatchWillUseDefaultHandlerIfSpecified(); + printf("test_AThrowWithoutOutsideATryCatchWillUseDefaultHandlerEvenAfterTryCatch\n"); + test_AThrowWithoutOutsideATryCatchWillUseDefaultHandlerEvenAfterTryCatch(); + printf("test_AbilityToExitTryWithoutThrowingAnError\n"); + test_AbilityToExitTryWithoutThrowingAnError(); + printf("test_AbilityToExitTryWillOnlyExitOneLevel\n"); + test_AbilityToExitTryWillOnlyExitOneLevel(); + printf("tearDown\n"); + tearDown(); +} +#endif // BARE_TEST \ No newline at end of file diff --git a/test/support/CExceptionConfig.h b/test/support/CExceptionConfig.h index 6c57faf..ed1232a 100644 --- a/test/support/CExceptionConfig.h +++ b/test/support/CExceptionConfig.h @@ -8,7 +8,23 @@ #ifndef _EXCEPTION_H #define _EXCEPTION_H +#ifndef BARE_TEST #include "unity.h" +#endif // BARE_TEST + +#ifdef BARE_TEST +#include +#include +#include +#define TEST_ASSERT_GREATER_THAN_INT_MESSAGE(x, y, msg) \ +{ \ + bool violation = x > y; \ + if (violation) { \ + fprintf(stderr, "%s", msg); \ + assert(0);\ + } \ +} +#endif // BARE_TEST extern volatile int TestingTheFallback; extern volatile int TestingTheFallbackId; diff --git a/waf b/waf new file mode 100644 index 0000000..29349fa --- /dev/null +++ b/waf @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +# encoding: latin-1 +# Thomas Nagy, 2005-2018 +# SPDX-License-Identifier: BSD-3-Clause +""" +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.1.9" +REVISION="beba77c244731800bf15a003232e7040" +GIT="f59b4af3d1a4715e8fc8b5bb43e8acbfa390c9b2" +INSTALL='' +C1='#2' +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: + if hasattr(tarfile, 'data_filter'): + t.extract(x, filter='data') + else: + 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&SY:d`RM 8#,4u#,b3y}#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,#,Ԋi6݁vؖ¾7sN&VdF֗vsO:uՕ^_.p-繯{={JS].vmʕt hVPϡުwqӮ̓MѠѭ^v݇<=se;#,#,#,A7#,#G'}f=Qg/:vi6zd+@#,5\ww9zz@P#.#,z)]-#,#,P#,/w)E*I #,(]#,#2WKn@֗}hv{=^)EFشĔ}=^Gۨnw|x =^=u=I{ݽ{o{|i\<{V;nwzKnPz.[`**DPi{s]y/rm#.4]ۜa[2"Tvޔ#,UT ٢!@@[wBջ6]u.|O#2:$ZѭOwq@Usހ{^_x>޾/.zw4z/p_MQS":{mV=gCfn.K74sۍfokto2L [.IUץy{o:{`s=|rAPmwaof;mj#,^AZdl)#,:h(t:\g6uGuI7n6tW [kwkj1EzܳzbFO6ٯϕX3oG#2 ѽ}pJ9[o1w,uNvEshϝ/e[nh #,@#,ɦ14Mdd@#,O(%4A#,4&jO&T6y&oTڛhѐ#,#,#,#,#, !#,$&L4)LFʀz2#,#,#,#,#,#,)"#&5=j~OPeCAbh#,#,#,#,#,#,D#,@ !4=A2bCCA#,#,#,#,Q@@ATDSQژ7=O55<O&@@P#,>W-VZܭߵjiUa`P@D O}QiHx7teO7zkRa>_w$B(< |yq$և#2mTҧEEXLbgKod?>#$f͜jV̵Y6hƭ[i! @@ri!P1&KQR>`Pcm^˪جUj6}mZCI&"d$%F&fR(64IL Fjj+f)4Z!#2dQM4#,KbʛF-QFZi4Q bFPZ SbC,ƙ@,iRѩȚҵX ,fd̀AMJI63S-&&d U4h)#h@٤m,),640`؄!E#$D I2#$2ٖ$$H҄fE,34BcIdd ɶM(IdjHdiM0MJLb#.&M#2fLH-%D#BEfRHcEdlBb$X$d"I!&A6F$BHlH`J I)a0RhY-%IbID%(&-$Y- 1eE#fID٦EC $Q#0L4Đ)JZ4Y 1шJK$lhR"I&a hP‘PeF4SMMjBX1LfJI$!CQbQ+(Rc`#H$&)20"ŀC,%L̵J+DLȦZbQP4lLli54Lbff`2kd`K%4̂QjTd,"HQdR"(TRII4ѤlD4DcDLFXe"fQ&CL%6JS! 4Jjjl&1Y1***4)d(H0h5%EFM#LQ!ML)f)!BlHU0L53FS#HI4Ȉ6,&B6lL ɊBlD)DM"4jb 1Q1ƪ*6L4B$ѤVBl#dk,e"a RF1be+2ٚF%%-FR0abH)L eZFM[&YJ)c1cEi+ 6MejFmEk,Ii ڊRVUEIb(։%$U&4El2ѵ0-cP`%`2d+HFѴĬb" M[fBe3YVD#Md&ԵlbU,,JԳMRȚSTbєk6,4-CEYf,Pcd1"Ɔi(!1*(dC&I2dZD")DB+6`%(S%f#26LL`cdFYJ HhƌPЉ$ɨ*HĆIh(I$AeJJF0IBj-"ͨhٔhCHQe-a4jMa#(EbIEJI4daCbc3TlJRl4Kb "P La&Œ% jS1A!3XJSQ fɱhf"i#.#.L1LclF-M%$$I&RL-(QZ36I Сf61MFQK6,e$)œJRTbQhF-D# j I5F)HR)ILh5EMU"dIM)Jd d؈R-"MmDZEL&+i4EXJ)6"V`4eIRBcbIK$Hm& iMLE6ld$i M$RE+I,l4P2JԈFMF6ɨQBmIEE4&BLȈ͑5221QZMF5&6[DR-Dlld)CKlTmZLєeEcX٦#iR[(T#M&&P,Q-KlQTd)2i-ihƋHPC#, IJ6Ѷ-ikYi*hemBړDFQDFhCLPl5%76Y6$4B6l)/'j_Mܢθ˜DSܿb-3m!T4`:T?uaG_ XI5cq/U6ߙR8h Nq(# B1aU&P(Q.C~mm`?ZOv6URXպ%jWt3N-k0Gӻ5caD#.NG]cz޻6 #Y,O܈4Ֆ2+D&VlTƗ21TJ16LM9;\ JF;o_*]ܩ74H#.ZA(pLUA%wW󖯓|2>Nkג,/Ub?Qn^,zf;[E0Ŵ)U!%^潚ҁE7"r#2ptX]ж ̷}7s}N֗*qAu!ݩm(U{͎t.̮mҤ^;6*3]|EBT1_7u2~9&+EKW^.h>};D&Cnj,fُM;*IA, $ P0T\&ɐwe|-rth5ת#U^?zf9:G#2y&$&/z3(fV9wj˳ިSG=/s;wktPhU!#2Hsc*wέLHM(R#AW<,e)!Iե`xQJ+=1kbUrIj0)ChH*i~Ǎ&{A__ޔcs](ΊHCV1C|)|}'Kۡ=tF=8 fE/;|Z{gzCMFôTj17&77v] $=_:0 |Z2kAC~ݺ,M$jRbO^(5ʛq PI`3lfyPHk1i&w,Zݯ-׻QxwG\Ѳk|ﭼcPi-X,uNC5#.Iթ2SL UHT9s(0cfY$ A?[vPȭ]4o/.Gy˵.h tIC6;<*QLZR+}KZ.嗧u REF#2(SfZjASzw>U)vڵ 1}'YՅTV'VlG:*uB'~\>WMBG0m%6!B/w/Uw9171aěcAF4k( &aHқfcjY#E@׆])|襁S,U5#2j(Ywb>}%̋y}(pC#.i&lM2II.@10Cm}-lqC\^:dknFtf5aSdy:XD+w`aI-z>%8+uB;90_BE`y@CXlNZUjcFz ]o/SG p:a#Kv ./}̗0`vC#.ta#O&6;a~n07^n^[ApcRߌv\6ZڊQ#Υ%%6ʢܸI*@P7Y fq6X7!L^z1 1a֧m{a־x6C7c\OW]lߧB$"]ؼ31Dbu>/@&R"a>8Z`‘QDtckvmsWDR#2,e3Pov}V})>zk3+>_JGa$MvJըlWmJaચ#2sGlG#.m)y)ACҙ{\!~nєEĶ~nߥiP@^Tgmmr|5eZ'Xjt81q| \ c9ŞT&[߳]cAݠ?Gњ23lQHBF R0W~Z\ֆl6GH+<A4?Zu>tvvtot[]p>^OD+\fAu'Pi1 _ev'^̉|0<+re2Tfz3XR;6a>(V5(Ig^L")CJ m쪤<VKEZiҮRh䔤Ҏ`;f9դDU {q"kG⊳M(W- 5E(DdFJʀ\O'P#2}9s}T?0~9%^zVqIX-báߔv^+u+\o2A /l9|U"< \Ck3e 3hxBtRo>@64WޕcwD B$Ɵ4yAFoT-V/t"Y8RwC[n\V.ߥvyGLF/]b!B9+JMP19JaK7pG$mc_Ưi߷;֍3rb-8Ox]lPmt~NZʡ|?)wGXtK5RW{e` /yUpPOҎayzq+\Gkvki E U4ULh7ZzDS\cلR?#.k6zN7)!y}6D$.-:f>;K>ޥ68Ǣ"vĞ^lR| #,5Y1H#&q={Ob\+<Áx}ms0fxA+)1M"4[z>J0\or_U@hn1Ű{vQ-ܫP#5㶨0mj"ᇼ*1VoKHM-J1Х|e^MwS'2hdL:~~<<#3yώc_嘔d ^? TJҭNƯN7ݮ\CF#2 yB/$F |NR[iUWӦ׮~4S9qTjs[NL)\)YVoVCBJ-T^9(:S> QziRQn>څWh(Ʉ5C^҄i4W#,AB;}uYNHcX+yϷr74wM&`~s!uT>-3.do~=mz<8&mH%@ŊĘXE0{sSL^q՜K`WO\E46&Z+icm"&H18(бw"-x1pbG8bQ 6*hx~<>:Ar-Kۛb'ѥkoMױղNz3vxQC!遜ة4l1PG26g;&gWT$3YB7ldiɻW6|YdotAa?Ů9eF Rw##2Q˹k:ơTd9/`X*ZQD8)e9+|WW#,}o`w*`觙'B4.^(\zV=`b+^#. [6p|{Gvv PNd my#Q{=q GX ȯb(?=ā#&B<\&7Zmݮ$bŴ9."mMU=}J{THNuGӋgWO]OD2͘Y+c9TڃnļC43-,km W9EϾS;y񠁡;~$׽r6MS4Xt.jT⡥JVciJyBdtxaGFK¢Cݟ :!C'[ܪ'&jıT1O{d5S <82 :="6tGaǙG-M҄`N2݆OKF$93h$.'Uw|=M=/xm?FDݫt}3=]G#,Z&i5#\&<"x(h#2p{#2@GMe7Q;A|'(eb&DH3#8H$jκ}Jz9]p.4s©xְKy5a;t\PD풋,DqsnMcM=!;-b9 ꛄb/w GiNϤҜ4zCE4Ji8b碔,i|sf*%- &(uc!&7S m#,,Q[[8Lǒ{~gmG~nD<싼O ީmX,nv=l{UHW߻P/~~h8''~/>0 EG 9+0l˨ jC`dnD«qÖBl &߆q0&$A%z@rܤf8xy+K$H$xmG0(E'XszmEGWTtЈ~JA"f_VtZbvT)G"%r#.A:;n׼!^t4#,Y{#,Udh}_(Hm6@C(bs`jnjgP#,#,aGzI܈5CDRIt12|EQӡF埳ߍ":+h.ƽ]em`#,AtXGtmo"Y8NP (U.>\\bK3( :}$@@$(#.郭0 V^|=#.uß @3F1찓0*΃1|661p-~IV@׏Mr#.u#.sfFQn=/(4_ 7]fC7{ޢ|oL4Un$|im7o8]nw8ta~\9a6׻A$k_!d#Oz,`XTD&}*smg!\~g叩7-ɲQRV6%lN'RLza-ȥA%Y̰XBa*`I+!0PPi!x%ٽ4$K@#2X=ٸ7k A<0Rꆘ0*#!D RSYND,̣0xԫX&G&q8:<~n#.9F)]%Bsv&ioO;2qP&^ fĆP# %—s!#.Aё006C7᥵5|,-}uyݤ.hݬvfxQ&'5H_R4Aؤڜ퀱ZJȲ=ɋJ|?`k-rmX #.aa(%^f}NW\;RPk(Y )tc @ #2 zR$XwP,!"u7oa-Xc]Qx/vɓYAh8,@;#,8OlK܇;/>]]AFAzDh=v&rͤ&<2f,yV,tF%TR)/_]ބߺrT=1ML6s,.A^¾|0roK0,:x}(I% e|ۍ׶~{^8]BGW_r3Z!IBAh`9on̽Xv2%X!7`[*t8ξM_hZ#.ZuL &L '>L7DTzsvt9) wp}ov\xEpCꦆiCflOn71&"Gaׯ}^bŁ;Ig4ϔȒ 0&XEhQ3*ZuT TDY 3K0(0\tֱqۊ?d<Xt+F2E $f/=ͫ(N?6;#,ku̐"87fOOq`>tO0wv`#tk #A+e+PG`PB@@@(#,x#2).)q45d76Ə /xyp=P(çQ~h!U)nCQ-0BhkuGu ixxC7;a:2 2{Uk#2x DŽ3;YCǴ^ك52NLX_hmXxIE #2zd `֖; WH(%lL(R5:GɀcWge$J*v":K˰`vEjL;.c[mTAbJ ,x#o?vɷ.\K6;G 8ORj}#.4#ږ0FKg8'οsO_$n>WBÂwTL"RlV_#.&\pmi/*'D\l6`D0.wVDVb.L@2,* 62cyNXCR@pdm#.ъR(HF=R*#25a}и @m"sf8@b1-ZFv)HP BV,I! fC4LҬ#,+;FU4H0Hb.q˘{ߋDX,p`(cPjr55c@Εl4f#.kn3Ä gw0Dtal5ƛ6]6r%"IA\NE3CmFdRˬF7#.CFsS3xo>p1ݱHcG^6,X(\GgQ#,'Sp#.ÑJ9f˜>O48NwIO>\,>M+#2lhؼ51[n.,4=(v~0ϗM5FeS7iFY|8I 6y@`싷E?a@mJaʍ(v5V#.:衋WLģU<8Ќw){ln!^ +#+g#(UHnnsRH~#2nxj٘VƄ#.WeɕHQC-(bqxk.i >nnG1|%U±F"~8cc0m0pM8lů/Lq`#.#,Bh5ٶíiHtpm|o]7#2=6!_Sjf OkFĖ&[Ҥ\MhUin=z++4W(ղ,&@, 2PkIہu2x:@\ >J(>y=< o·٘N^#,}!ʼ;sr@ч5WCz#./HY]PcA`h3]v8{PTPy UwZ=W 9F05#^5@&lIV*E3kaCy W+4)_<Ή-cSEH/^pjQ>+C3>[v8RHBgE3jK&1*X_bhb^۵-H!%J>jg #,]G,u,0zv͠b(pg}2!*$HS#2X5ϖt+(NO:?O/~4::##29bn,#,SG#,XQ"HTvN{4mklIc2Pc$.jC،?_󟢏;nm6#E,OD!o2/=*[D|h޽֟y0TׄTثn77{V2?u?/CK @FdB\zlY}>3 YpsN$ [CDIۛJ^θSce<he#>-vYi4A_?jZAD,jqr~UH~rC`vz"eέ~!CE\3!µсbE/!؀gqux&cHrx&V*P #2!' #,K!yPz)/AFُ>7ڿ?W# }_W,zΙS=0-OgH)#.``_ʃZۊutVx~Zor:\j퇏tl7uhm^KnO z"28U@ϖI*/Ƙ1@ydfE/V%kS6y/yĐB"|e6RisUn'Vy l'ߎ|!#2Bc1nDTJ<#2d}ô6,?xǯOt _Z^d2Ls=;E7@w#.EgL}3c(Ui}0:{=#.F/STb+#Qv#.R5xwm5X*}EiiU&uw]>a5izWi#Z_{ so}Lr;/b=vZv}hĕT'y5]obfPH! #.x4AM܏w_&_ǷCz#.  0jV%w(#LiPL$och TQ_#,);F3trJ!=#.7-H:fa;OWC">@7I@AH$%EE2B.N鿻GQq?M$k@#2)\ ~A1}u-#.3/(!EEϗ6:;xkjy*m뒪gջ]e~6e/1ɴ̓z5?%[]8isvxzE4<^etm={w`+=G `vAv=?BF-#,#2r%.gM?Wl8{uzOT7-m#2.7gV鞞m[x!ӚD~Hr AlϾ+ۛώΛ E_}M}OT!,d9#uq2׾Qǝ}ۧ7VkF7[ӒsJ;ƩrJ-{3>V[tyb/`n^ϘLxvNo\skpk6YfQ= #.SežZx0#.49~1.`sssK9Q >nͷwMW;uNJwYM4<tCåc!E-:=vG\RE%b$h|4ضu:\oc*X^ivl9ѶN#3<]GC.Fߒr*ffbpNqyFi}duL:>2]O/ H g郴YS~~o_`+l#2(H~j6+k՘6Ӈڞ_Fzwvg9g ǻ-;|)ӸJLEG#U{ڷ#2փ#,b.L5grkGW|LOL|M-t+Ygua*ssoWG 2*s(?#.#,:7F}ʶv[GF}g>h^8}=,~g2y[?(kZ^plu?! {E@\]].#2z4郗#2$T!|lϛb#.EPv.^V?8AEQ[QϷS#.,Tw'9߿N˯Gp37ᷰw]c[~[we ffɲIBԉAx_4{?vEw{Phhv:iTA+Hpџ85zWhp8|95n޻QTm&{6}^_.I!y29>)|x{*ÿj iKxA?B&x_P#.0 ~9aXsț'#.dWy-b; }<մ=Չ2h\5xj f)R":0> :A*$5q@w({v @?&پ<5Z67@o&a==n;›ߎ Ok8:A/N|ZZdf|&"7w-uYMy[Lto3Y}u}ʍ>u҃`_]l~fKֲSZRvoTm=)3'^4%fHKTKuhOٍ; e*6x>qG\S]}/S/0#2s 3}wm]y,N黚Eގ0=NԒnubM'g)q=ҐA#7#2 %{s$1OÂ|-K:/?xǬ~@tGmZci|u2gxᡓww-Ff\ږ7a+,qG mR8"<RIb4CCX1UPqh,BCj̳5IFv@-AȱaHH5dM#.#.Ѕ$IVzc Tu0N #2J噣n͊ $О G N?WoG|t#X~E3dCx_ CMWUSԅaȣI㠔L~LM0(v(m#3Yވ1 6J0SC+a[*Cc4e$I#ց0\cJg(eԊ&`IF)lZ>36YZ8!ZW~M<.E[m9W^lZ_զ]!>_l×-+ f#,-g$9oC8KbҖf!d6<6)w[F#.AIeCN"G;F͐I7L>Z܃b֪I%UUQ8$ExhM`=-I[j?ӯ"N)mcM9+b,Nm X>Queo:Zm4k6 Fأ,-*~UQ`ۼ[]"#R:Ed%|tUdNG#"DLdcu"t{M$;pﴱdqDf52;S4haSF7q!76sRIBuޖwziH#.ʈw=]~OPy@y}8H-^$1/y%^ڰ(C ob}&aɠrҵ2:`GI#2s,d=4R?wˑ9Nj0 FimgN?6a$ifU`E#p#i+c\0A:7)vaDžF23Bxֺjk"pj8Z8%1ଋJ,{wy&"1!`#2THRST4X*0EX>d4#C3|%c7&.Y׮-4ν(>qs "Vl۞wCdA(᧲1^n#,7#.nyxXdѮ ,x}#2b1!w6o$#2-7mГ$$1mmRlю#Zy tũt#.,lp[&4:i*yZeTP3#x8\F Ta8VC N4ݻw9i˧Nʈbr!Gcw0]jK;븣}:K%^d/Nƛ.wE.ظV}Ň#,@jftWuų"x1MKNLeNƦY!cP6Yr謲aSa͉$g%sY+ݰ,+N6ml4|QXZC" f%dgb X靷ݛbRq78=!(n?tؼPRZۥ=*!ȸZ}' zzmL-ȞTφC`FJ8זm[t?˝6{Tq9 wki#2b-PTM_]ۦf#04,ŝz-vE]{r"c\iih1frU.:XZKdN). 6g:bsZ4|_0:p7vB8¸[%X xstQg9脕m9,L k7!(o//q`R8Jɣ<0Yעv;L.AkUS@0cKi{X%`3Ƥ}jݷwJUjh艤4UM4tekkoÁvb$Ћ8ҤtX.8f<w!z3pϺiiw&fW6:4l귉ŭj"7Bt)Ô&L+#,BrE;ȰiDz3\ޔkYn1AUeĮ7[PDNvUf#,=]=UUp+F#.]kh1YB}LQ}'HsS޼xF=#2<+>? > {.3U(}5naШ ÙeGOa~Gwߵڵk7 <~;5@eF5hԋA,G0'+T ,W<ٗSOx#2$H`eP ";EΟ7+w|ݚ 2瀹i߱sIy2᠖#,$r3,f1Cuק>s))^P ]hRٹC 8'?R]qL09G},3|$#.Ğ ѭ}~bqq`!bL\e)+P$ϱxgs7OlCw "pG@934]s0s̛|%ُjИh:9~b)Ju%">:"dT-nLfi=@"GIUyiy>+ ^A\@vٺ8`20e?#.E)*ٖS˗!B#26%X~[vkdŰ#-fRb\!Qys-˪VlLDHwJmBDDLupk0RhziUHiaM8V-&0={Jk$$.2I.QDq[.&A钒cwańm꘎&`qF}'쮼η~Y[H(φ%~UȡO.5)+JM[hy j)ͧ&uGfq_pZI240f|9c%{{h.ؖCp 5Ǻ:Go{P00A\dI-:bp,~WĎm&6NJ 6UՅ`xf-0%u{^~MEBkxaS9o3'm^B[X{xlOR1Ch~ݘ6:&"X0^^'!pjx~SP@錨;"}:#g|8F_w.zٚO;NtLEEJ,Irmʹh, !T~h==5P`O?F$Dm9>|ya`ti>PVc.9jA1yΧ>dY# sRC"l4$]B+\h`91p= ;j4y xZ6p_BOio)XR"S~sM$BO7^UK蝳P;!V>huZI̾\3)Ә}79rN/O#.tڈ}ALWg}m<0/ƹxy=)~q0;_>]D6Lm4gK Z~|T\-^$6V[ᰓķ+'g4N1#.czt/u.W.3 nF#tl(PhqlM6'9U1w%H>^ҭr'<3M!ƯPg;-=WBhUzFE(#2%mǞ!ʖN'癊K6%#%wٳ+evvd$Gd].4dԫh#ޛIz#ï;ui7vtH{pKuɘL"駉n"||͊; $ÿi4Z>NvQzd`2Fj eE F!Xf:E1dfFIhu]S[Y^IA]9]ޢz?D2:X_oр p3X1DZeAv #2*3˅Kf9qU.h^#Z< z_UƻcUtB<鈯lXK|0P003wz+{)J=m2dIn[LWy~*Q*VM&=./pZFAi+2ɦy3Ͱt8] VfcⒻ8V8zޅxszwώϫvLs^5[+{!B;D_٣,͈W>Nͼ0=MRGx`:6Vf&:%_AԽN$dbGTg KenʐBKYdh.P0v~#.>2\]swi{#.1BlF')xyq{>cI'¶lg]5vu] !hQu#.eph&I01}XYGPkc'H?ָC³ 1( \ϻNŚBb]`7#,#.C(?fL)^s#,n!t&юY9#283^]*K:71@xg;2gh.aS;PB쭂^$tDHtI;@5N۩}ѣq3|ҳz\1_ն`igIGUx_J#2o%oVaY売?8= 0~2Sfgu#,V"j1^lh#.f1ݬpa-K¸`bEѺ)C䆝_ʤN~g oXuObX[8<,}u^v>]"ut9Qa_S|𑷲h}Ez}2v. ICsvA:#c2Z;VWGdhJtݾ:o*es} ˧]GEho:-YhMKW^E$#2ot.ΑDVJV#2E#.aÁXCvQC9;^o+׭b]B,G-oi1\UX2#.Ens?Dp:.^>/rYg@zD*]#iQI;r:qUUxtG$#2sedeUgO/\)R@@#tQ5@Gcsŭg );qb#.yDo6(݄-R|n0+JɠIpV B#2=+PD΢8Q%#2[uaIY) Y9{_X^1S6vw]N\1#.{*^#JN\[cd]n) g{$~\%<_ӌqbvYCFV#.t%±w9OrwE#2Ys7hsn®Z/,#e2ūng.|n'xʸT*{9`tz!q6BLN T⴬-0S0<9k3l#E- ugMNjvڤr~\nT{Mtw͇w;/d;xaYQ[>J0 ]AeDoۤ2wsP j3|<~@^^[J{ߏkgjwzἜvJwhpXwm"m#2`rC ڍ[֡M|u;!$+8n(Lo=~>ZH-?$tZ$LKgY8iV ֿ,&WeW9LC3duYa&W(Yz=x=:ݥ^^27vJ={{oJXqëjL¢WRVF&Rk#.YÔ/ba;c~ӷ9Mg"Vw覱`MXWxڧ/&%*uŒaL<uJm^kSҳN`t-3UWBSyh5ʕct_D>YkaɆsZއ aF(z#.'Q9"\t]L ;!_Wc/ s!Bc#.`z.]$ufXEe^{KΆB6Q9/tFSFL0Cyh x \v+5aŬK CJ K C{# G+#20Pd24Vt3f,]ȂQٔ:ANХ',$f1tms&( r[JIw>@}T?װE1:n.f0ƹ@]"/#2ֽxvgš&.lIˬyXgZOH\xc3GY' +JMAq\ J-s@L2S=.mA?L['6\U"ٖ]5GtWVS\/1bZte$gE`\#Lkxk?WܦyJG#2E[ъ<}<}[g='Q͊]fʶA5`÷;X #.N'nEks:)ͽ:KpO^W5xe.q64p[J݇ M1~;%m#,t@u~t"m/[~t#2!V -"> &oLcI>h:^XapSu߾7 &H!us8hv"R)Ƀ̮~߷dZ"Z!Xϊs=*!/}0pt:8z{M{[|b:MU Jd#2E3G;TP@H} 4l50D  ."-#.|YPss!HӐ#{Uf6pv|xmNSEb1#|՞Y4Fn|>2Rr\`L35tOL/fwUk/5r#RM 8%j7#2#.q&vس5 /MPy70Lspes8s@ˮxs=QsӪ"@ QBL; kFdsW^+u"#2D#,N&JW_](?ve,eء('qBI _kh^o,$6t`A4dpNhYU{n =d)rrؼn{ć?9¼}]hU諷)kCrsy%1 X1 `0[ d˸Q`[9ַ<;#_%?9úVbh`/#,(5)Zzsjw3ۿ.{^d#iL:4,ERP#,S(O˨R+`7> AD~}Y&Egʮ]FK8CqD)rؒ|ߓ͕hEaF@AB#.=΃WcH n8[-13ڿ33LunYH$P`#,&ׇz:wL?l#.8y֙k$Yz 3G#,f`}EaR#,x~Ϙ%XA5F6bUʦEPA%qn8~5?$@Po(͡mI{p&WE:{RDQ )qnlNy b 9C#¢޺fף-Q`{ WWеO]ĘZF5jJv .zXfp'E=nHS]TafZqtVs#. C?qw ߵhmzfM3g1P";ǩL!}) xq}ine#28ˆD4tw)O>#.Шd?-ACC"H "*yD2`f,#,>qaIO-kSDH]ԁ[@;!`{@`f," 5:k٥˩#2O4'g|߼#.ThϭE`#dBӡotgǭ8XE($q5޺7`yf>йLgML ,VUv{fP#2ADfXAi%zw%fUbƌ7OLe{į Ha+ IE~?G$; Fi!G#,C#.sq'W*7%j kZh EDn8 G̪l1^^ꤞR#2dUM7;6(ܩ:4`ļZ^!ژ L sOiV8e3[m8{H`\ LlAAp(-(W~d/!ּǑgnAp Z^L#,_[cԬvQҌn߮{TYN&g, /m'(Ee#"V¶XmDzrr^{*B0Vd̏KG8IC4#.@8T#,(HpP3ރ;䤦E[\ktYbGym6!b$t2]^;GLpc#2#Яq#.9$"Zm#2@CeHC 6OYa[ë!#,%-D_|;q!rp^o{OsãF2e?`bL.607tG/Ʊ"v]W^>G7ؠt5ώ\NeP1GHMͤ<A%7Y+ЌWЇ O.R}â71 (mz5Gm>XY$G#2BcO}Srڟvvj:sϫN-if#2l;r#,\>`gˍh <[z6wܾ߾ ^`Ga^ٖ{zT7t:pK@QbQ)xAK'yC:cٟ@/pn~P\M|35(ԛp܈K\| rq'0;*鄧SCfJ#N)uv9rk[9pPnFp3}Fkp׌1x:,4R0x%x3c[ܴ[盯Uxg_+5Ş'MCTնhgb#.nFH]\bEUx4G\_U?" +|Y'L2𠪧4tĝ^ۣ׸!O~}xb/!E:PqC —&'eL#,甸H<ۧĎ@Ȁ弤g1#,W/51L)0Nq(O_Np;"&/Ҍ|j$zt޷K?|\ukb|DN:Kq&<;} \*p;H#.]F#.?a! v'orF:jb2f{<Ep1M %bzޙzO׸/R穆 #.%#.ڋ}R?r|^uӅ5\-4IꊂcSqMd)QݙC Xp{˔l,_ _g?J›q S@6C:*l6[CR!_j0;ˎ@C!lt1Tj"*2P,9`s\PCXjՋ&YD-P5AumP@#2\Ꮺ#23)$rDȀ{K* aw8&C#.)@T=;ɘd AE@m#9ī`3cD3WPk`Mdӹ<fD]چܱj͹U%kj[bܵsj-ڹk۝5쪙%zwҪ#.&#E&a7:'Ȓw辈` tpC;Åj43743n2$f˧o8Y׿_UJ=cʃ"_RѠEb4bP<6#.x>%|\2?~Ku69H*dR,\ѐG6KT$2xII y8:(9(Sε:#2x`.flg~]\;Rp#.1}tm5 hk{[򯀨Pk_ tQ5bp*{hvcDUkó5e(mSFC52P Ѿ,,P^t ]5:}&>;糚1Xy(V:t[L`Ä4˯ew^\w2Jt\cɋ3ή҅%$ I#,XTỞZw9߫f$26;7R=#,d 5bf^KU Pi% ,Ј oGJn(J+"##.q혘On(P;&/AoFϚ/#.o|!#2%s <Р0bѕ*a#LH0EVꗿ|#OעG#,y5+!ꭶ`~ijAt&&ww>rp4!Hy[Bx>j%}U$ "! 2-hpXd]#2r7n2M@C :qS|\t:d{6>LqVBn!2I&aהvOƘ.i{C:097McS緝52JK?<K@Ҙ $}Z2%4D<< 4H#.TqVFX-y٘> 7|=oCmvv[eTmH 0"44@@Pᷔ+%MybB#2ChV=y}pe\$ns˸cu*54GjⒼna=c`Vw}NӢA83ǂ[ slS,Y#.F! _?_lH(Um/਄"^㈀Ƃ\5О' 7;S,,by&YwѾah$â;)\= 1G-fT əTlO0Ζ1qzo|o]J:S tZ9Iobew-{fPks]V^9o|mm?zgdש Ϝ@Xn`|-ݗnDy]P2'eqGɃb}q:_@}dñXbBa@olך~xbQ7 61 :P6HCA39x78 *FZywe Hy,YpΤ[qE5ʤHA$}{{3CrN)#2C =#.ߴ7κ9dwCלԀ{{^z`L1ivӖ4m9ssm܊0cűv~&]*{8YTQ(R Pp~`iAP˵Q̂0~NN|O#.ƽن5P񚥌:%00 ̈́i`4Dwe$YSuD&9@x#p#28T$#,A1&ty#Kp%ֆUZrm"HK6!ɢn!gd[]jfi6jIX^upۮ Hٚ;{*~'[RՒDHTkC9 {&DÏna#ry6[#,x#@4C^4=BO#2 @9Ε_Y2".*U!QMKu: r(,:bLuURW#.nA0NsԻXw*:|8O[L~#.y3"1*e8ӷᒺyA˳]?vU?B`bPyD}w1H #,>B:g`611@K=v_(c@N0UM"an#. %uNa7Niπ#2}{~9QK;E^zU&]cŔk2C01&>j K 'vn2uV?6OaH**H,#.QjbIW?w7tN^;8R=s+ $dL1g,9@#2f#2 w~#,V6i ~q\"_??&z{{^xڦuQ2a}V[\s vzOa V#W_~eK#,3K?+V䘁XOژs OFD`**DD"]hOh7GTĐO;xʻ*x\mT>Q;뉑3yO ÒhÊ3)c=*Pbɫ>c.ĪXD^B(:No6o?e^ 1}~.DʀlNۨrttKplmZAŇt^%StVug`gQЋbY]rmJ-WZ6>p+?vL>2JȘbOƁ wzR%>T)_˔6y72>^4@_?;#,=Pw*KD0f! (HOCqO]m#ܸ"i򆩌UCwO?O;A~ݝ6;?>cw@kB{_; vqfTP&j#, ;60ٳ<ޏ*Zf!꽆gvs"" ACߥak 4DLP2ȣ>>ZP#.;5Xl m /BsS#.&&= A!)f٦Fz\^UzY˛F.w>.կRX<>ܚ/1Q~7#,#OMvpy:pvV=Fgօ-T'"~kSs`cǿȿ_c# !] ~]b QdՁ&> yjN?fa뛵G~rslCpuqUt'Ȼן?P2q˗(|#,oWa=Y %}ZuT\-{֔:UG5Dr%(}#2jԸ[YCKʔڼ,f_3a2Nq;>[ˉChv+"]s뗧N"KdfП|UKb"e2"ۤ<#2MKDMud*5#2&+*(KC h(t&w%Z/zav7A?xOxuqUק?ʧT#a}HPj<ς3uwnO8& -`WYwa|DUzk1Zb(<:3rKLl~Zw)UWGTcɩ|rNs@kW>ɁphIܪ+w.]TȱҬ߫UjQJ:H_k#.a#Hȓij)ttq,k Jty_$F;4ĸSW>;Dz˙C!R{@;E( %`!d >=/kkr%lIW4ջoѺzwxrACC:t!qģ+~6yluXp3[I"On|^Ӻ-t%nNc*1Zc.kƲpl90BZģڜ))?hwr+o&P"^#.TsivQU:%ڟA&1EvrX=W++X\\bFvV,䨅>5i(xz)I<܉7vB”+2q}^ #,]wN)a32yx\\ȣo5-x2Lo{Y9K:D) sjԬ >YH5`=kMht\0;T\IVabaGn*<\AVAҊqF>EȦ"/rdќ*V ">mtEA_=M|;A^6eqkMk29cSӇ\rj|J-%C~w_&`֒XwKdfP=¨dPj'W^zA#,R8fZ3IgG~>"-s(2WkSͅՙZexug;鸳PD}6wi(p K}\}O֘z)ҊЅ7Ėwdj).ΜId]z"pgTw+e>TH^~Џl-~W^C2Ywd glwpXG ~Ksg kOg2?axh.W#2T>-h10UIt_pq-rݕWBc8}V|vj&Qg 5g4J}j)C~.gow2lj6 l H5@%EQΡgj%Dyc6g I=}4`m}>|19]H0{vIb.qW:'h2,3>ߕ`t>jh1߇[:qL-^ԫ5[|^E8_~M@_"v=S5g tCS=}2Q؅YE3#,جRog:/?/r>Ϋ홃@IEeIsf-sᤸ $ $iO@]$Ci]Lb@VKĘ^RT*uL" p"(*ZZۿOSkmA{X@xX#.~)\,}"XOo s&ޗ¦b:>!ʮ5J1xĐj o8$ _V> #,\tg=x,^?ҾϯV^_*; 2r[ξ[g9́(#2r?OLOOUrP{<#.db0?)p籟z'oBvAPS0Wjk]{jy#2t%O{Osm8< P/h3X_CfXP._#._f>}]ۻ. <rmZRK ֧0#,2sDnсq80}jڿ"٘k#,9U]T:C~G%~y.)Px2#.J^A k˧ 9fHzᙥ'n?lj3~:B*#2z{5)-5~)%Q4߆ g2?*˰ mr‚_lsk&Q7Rlh$#,1MbKSa`>W;9CT)X$ߣOI<](zCog%R#.(PV``R8O)p(]}v|;'6*ƤT ㎉Gir/#.!6qeDig7l6VOݘe;gUTH"NGPPjB3nQ05>RT=cF0;~;%i;4.Z4$ yܥA~#20)0Do|j.OE:O5p\#,-ې*E̳yo\JD#2Ufd0=u}UKϿP4jWU#,&zT#h<9)g\Hct CTݶ>)Λ̶[6Rr2ʌPX{._fD#.H.,謷|}9~n.Ѡ#.).|qwTiߣlᠭ򗽈aE>D|s~ʪ=%޺xa.)bȳ68̊pA#.Vg="7PA.V;^)۳bC$u[n" d:㡧ԱQ-轜 -i&itʻqlkjܼ+5sOm;\8gN"4Fc#,p(J5rT⹽rl&)WLXto/E$; V=҄d󄫧GoI1\OnI3WeX2‹$hjnɨb$0[ +r=f[Y%")apͱW#,tU /#.ͷ9kn8h!Lʈ}NJ):߾0E_Fnx~!#.zOF#2ưpc` ZDz?Q,R2jP.%Rԡ#.bl7&7sI0>$|Cq:Hns{ZCkNir䩞B2ntaBs2!0g#.O\t@LZ7߼kvrv94>" [gnLKm%M[{<ݘoN\v4` &4Ilxݯ$-G~AdZ^=[3[_- "<ӫ<+\rmL49-5 #2yzyGn}2gCk;>ɪ(r@|lۻK}sB*qpߠ^o"n{?gz>,RT#wo]F (#,g[$ga-]6HDNG#.ը#ϭx\j(:x/xZq7ldQ"D 7=8ғNP.=bDŹuXd!s %kÝ#u=Z[O@fѣ7a#cX;I֮[مڌ-Cxh԰; t-' ]<3̀h-eꖇ#.vHD#,5\w|JS ;Ky%dj$(1`6EDʉ')ډLLf7j;A=֫Bz±һVW l6L2)gxx`Eg`scx=EkxFH#2p9ysS46DpےZGǖ+ve7;Fvrvqƨ,:"75wE#{tPЂΉؑc8Q5E(+>XD}[ 9PE[tH%V5Q=@ӪqMPSa7%&-645Rbp8Ll:_Cy %>s.@@Juˀyܩl[n!EdGCcMNeaOv;tkh/|kf}ugAݜfϴÜdUH7{h!#,Bɳ"I#,L  U2gގɑIbKDB'v#+6RV#.'Q@m#,9GN#.aԈ2ht *قMߙmQδhǔ8]T.k#^1ƘË*9CZOeXHChY֑KTȋ)gIl؋KdثH^m\P%‚B#2'˹g^\T? 7"#VFlj8{-MR? {Ú .}Vesɍ#,|!ϻjB@4?VYI,ߡ/g\`KG;e <[1_9_'3@9_yӃ"IZG1gc?ӁUU}Ä{o.͔#,aT@pCv2#,s1 }E@'#2B" zRJ R*aR3UP]K Er|H騻4ED#2X5 .r9vQ} #.7w]2r\C4tM#,~wM$6p"eݻW9}T1ۄX*{)Wd#. c"sm(ل`K]^V1+#,w<.svEj=NoPV>O2D90a/#2f~gגdl(j$"׵z/P v'O\.,tb ~մv f Y!nm[ޱ^W3 KhFۥK__s:`#.v[d}Ly~N^#.mP(XmTDsUs_?D=Czt0<5inA) l8#MJ478hieP.4<>CoO\jјX K+e#,\9l59N"b`ӘZf"`oB`%'#2aiN2xq#2)cՕ5[,rOg/CzDzw`s^']x35[JRnG yóG}Y " ذRAI Yar.^+JQl E8Bs\#.r$sV6GakhaXS :1+ x~4@:Oz/W;d2Ĥj_> !}!&gŕS%|Tl'XߣX8 kQ+]h0C*5:ؔ@ˇ6ȐCR,¦;!Դ2n[>[gctZiY~6dO@Iڜ#2JVWJ0>SQf#񻝼$2Vp,.BވN9aeeڥQA#2i5/;?6:$#274ͩ%%nErv8 qAF#=4Ɖ(`*Dy0Pd^bO?hXmk-TE^'q Wd$6w>o돸X,ITϔڛZh+(c[wVj91Jg8M%lAUʏz\[Be$!6|ԃ|^3xLi,*t$XLӰ̚y44 #̑P0OVֶ֑jf=L1oR[VF #21 l+i{zWmFw~."glcfx#nZSc 4;̟EכQۑ"J&#,=G #2.yfFŎ,0y̠m@!Ȍ.A#Ĵ?1B[6]X ~ǘ=#.46w؈ZjH LQlЪVY$ rPRm82d?ۍc94,HoWy];rJk;t CH%#2:#.;֛oPWsi?!ʶѪ#2j8ڦ}+ܘ?]mKUD=<["QRR"2o!;w[[ fd@00}ig:LO6wn!#.#.#,8Ψ*ba5K! uJd(?̣mxj"`/Y0t ܮZ4 S#,_#2a糎#,<~HA#,'goM?bW"[!.R~0RHI>vEXKz޵JD@Sfb'fݼr0.yݎ)=9#,=C`,!ߘBD"H>~vτ>E9?3>ڠye4[(@e }ŐEАE!pdt¥@,J4x~8C^C{5 Ke$حO$=O'B{bH#.d>؏HӬT+CN&Gzj#8˱\U(A"(uQ8 hw`qhi5 r;|_dR0]w4#2`y*"4IjM5 98!۷SK4%2vƵ#2k. f1ID 8xhу0-G- %8gW7&)D^,0dIYAm*ُڇSp`Jm('wDj]6U+wj@t# vo9i%^i4P!lǁUJ/s~IP[ak `SS"KMpiF#.U3UyT+qĆÔ5]L#.*ECبҥB5Q%VӫzN;g`9DEi| tR$jaѹq*{@l4 /9r9}߁s(x)1cD#.}eE  vҝ u8u'a^W#>A1/CMSt~!O…)BPpVGֲX@o8)'$ l0Qh_fҍ#2y4lNtmCn:#,b9#. k#2=vXSvUX]+2\b\2R*nO={'(.4w}1Rks0i?|LSB=-HJQEDaxУвO ErӾwC3f!@#2yf KHQAhW)#,#,mB9R.(g2"D6lR#,`Fj1z{v!TQ]!x!pJ|{=90#204~drHS,a]Wܑ'#C@ +#Igk=!+ btla#/f d4#ጻ"=#',1"&BO(Х_6U(E:ѵQA0>zɩ]Y_hP9) (]BR~w%ǁE #,Ͼ'=t"mWza#,Av|50LWCϰ劝A{'SդeSF(#2IAAGP j#.)zn!.bNs{r.X``@w|o2]ܟCܪI7q8UP!h}|pSREg'E')2ѭ-Sc#26ęD#шL$&A=qCLO)u[z S_JL;l-hǞTkP=`ʥ0*dqVTBSm Jh6 6 1sA`˧:Anm%]\|P_FfhˀΤ$#,Ap:c]"(FiV }űާ6#,@8Z8o a,LT\_k|]Km>8yʲ*y">|.hm !_yh960^qn딸,5a8D]'[r]msTsM#,V82@ H* !cksPذ)on=бDI`#.1!VB :RkwԽ1ˇܢEd2xPc_"XT^vO>˾0,bhAC#2ݹ4knauRq1*$*bS09Vڇm6R;BP] #,P@Pv%T'bQ\- ¾^H{u|1Kܝ}`d%)# 6{>F(wsO(/- oO܀3p:pz(j5$ ^S!n$?;{Fx9KU۴Jk$"#,\9:F(u~~ coa+@ #2dQLƑ#22|qkp $I-G\뀟#J7g$J1\{z}<<]7ՉJ.#,M Ȫ-m*[{k14 &*L_LlL~a̔pߺE$19|s ˼ ~6ưt*#2 ,#,P(be#2J`Iv˃)j$4/uc-U0_nLnQ=tu n wPHMa_(K`4vf#2A} qXy3}Zbo3.͡ƅ&eS[#.Q/F2$ˣ =mMo Bf9f_~&h ~Lf@o|&vj-:YB<t0ia񃋆լiLqfșzg5^Vp}2.\n." LgˬnŒ#yMFdsۮ|N:q7L\(nm;VaM+xv9;b#2\&5=imށ֪srţkz|r/]۰h`(S4h-|zml]0?T:b[>X% ah8m!8/#`ao#,#, K4GA[v<=Hy6>,E9UhqU;r95"]?V;(s~'WspFzò_͑ιgKHI$0eCF}#.޾e?~k0Ev05T@`P( s)#,X@K}26_f-~K ~1U;kDZ?6x׽v5ONVG~(vD\%vmQ[UmL?t)DHP"{#2h?cj3観iiHIv aȀ}M;sB#,)agWf?RBrP,(0г#,B RǨpÅ!*vm<:J۾wcsʯ#2MBqb,|%+b]6[J;KE3`Np6ʋ9^}:lf =52W#.$; 9GRXEo탦,g.Hv`9a$`tsMZ$\X!ަQyت{otac$DbHyꘫqڲd`2֗#2ä9#,*MA|{ @aYOq~QK= ~-hD}z𶦡iޢ;CT:ffNqT#,|m2 lڤ?eO?~rY?lL993-yHNY|+#"(6EYݼxћGY۠Q{ab6i )R1B#CjNỼ);'VX#.p:si0L@ɶvnWw>pb#,ĴMw&q[Ms{ˑh#.;/A FRHEJ 5¡f9qb)e$qz/\h6Sjl)aT}KxW!g,)p'QFoy&DtZv4jz/\CaOaEvDm{wVh6e70pfAB 8Ji$bA4##2Q3K@Ep0v+ f"%^wyê^~KF) sC '>˪-!0$X.ad''#2wBGo:N7{G1_TFMM]{~l_)EHv{ԐXIXmZp1ɖTD͢Aj2c-*U@iE!]&DX#2lk+"O7b H8IEJXX?_?N#2̯灂<Ң"ݷfЁ_p HcApAh`w6v!6?jL,ɰ*% vۃ=|#,Q C%"Hnp18 #2Õ2({@{).1#2;/U&{9yb#GQb]ZT4(a\:|$}9<#,gqbol&,`D0֓JIaӺ۽!BsĠrln`##2˕Sh%wp/qߌse͖&qzXUZTq3eu>h`첯CR=[Ȥλ=v0ZL'Y|T)2xuם:xÓIOܗ3:[1iR6KE&xq4.PXv^'Ֆ-oB8#DvOG5{arŒF;gHvWg0qSېԅ#,i=9vIb:R{S!Rq\3rX3pM!#|Ei6#,lGڦ ZșaT))UTl:lPѪ^;}N`" 㙭B*-QxzG#,6#݀cbg/lNXk#2i4`#71 TyWfHƽ2IzڽJ75ؘݨ%/G]snT\(9\UAZ"mCD`Th͢#.YS P5IR#.lշ}n0SDyeRN:&#A]MҗqTzH4#.BB]YP=Jc+RtI"n-P;@-bv*hR[`v,dTP1K;olwP#,12%b_#2hzN5opOފA6i2[xzݻ%;Y#2rY)CU8,Y~͡Yh #2UDuJᤝʗ=7tȒQ#2(M,b<>ӯbx`R&=EtNX4NEN aG 2$t{:v"QھdžeaGurS^uuPdB'bu~MC*%#.ZCyh0w`} ц\C!`)D#.RL2lַ? F}؜x6'q֜i(©T'ϊ٬8`HMtrO9)LV7#}"1ߟC]Y `UT*eM~^ڭm=گ_9-Νڢj(y`|毪Ȃ#.Ic߾,;# } B&P P"|2f>|밲pc#.P#.fMwjY,CMUm# $ 5 2c@#ÅB\xe7s#Q>W oc#.d`ОjBS0XRyB<3#.\Q#2O̼7.z9ĭ{cKEmR#,Re5GJe\msֺĕ6x^."*IӼq#Gsz1&ziuM6bY2{4Un(/li>;Sbg":`"iYcKX4)-a9¹G{X($juam׎#,Ƀ0!#,ܵOnN#,[$HBq–BDi@T;#2#hAٲjAHJۀ_K3D(x*:^>;Cs#,#2#,5/NJloSMu#.6iW1<Đhl3fm6D͚۴m/mCaB_"ޮ! 0G3jGMY{nvպ ^,IRhDieZt8l^Á!"3V lzrWqm#.MzvE#2YAsyjTAv02%y=B|HXfa.O="21 33S͝y-K#sۧ I" 2Xa8GW3ׁNys3ZšC!iKN=a gxse̍0.Ž~.r:kq(|< F#2*ǧN=fm"<#.y$N|$ߝl՛eɛq8C~<,(,u{k6'guP sRh(HZY[].lEgu-u,RA6 #2(Zq#.CQ(#Tb +bK݄V#,8NN+hBTA($&Nx(–Hi@,YǺT귊Cl]v'f#2D\lB_rh >D |BIma#2@";N#,C [{خ#2#2AT@@ CZAep4l5㪵maXkZ\Mr#,PPQ#,~[6QO<:<'zAy!>Xף,c@- 0%D(s:1A#29ar$DܓGC>ɦ#*#mf+iiim)cFغTUMW{p ɗɡsNm=6j0#2!Q܄ F #[35ܹŲ+O hI@r63x`Il;aT ?W'%]!߈tu#.N8_te3!H#Py9tj~ujugCrXb5Yj6C^BV_4xaF8[~*B3{@]k[$NYK' ۃI"AڶoIt-LC BӅԥ+\d*kWNle42N&*U~֤3sSHv7T-nM6Qxfl5%[ b#.)KG#.<#.3Pa#,BBP ā,9ͮqa>4Dgr#. $A@$̬LMMo.#*H)F%diCB&(@48O805 'c,)l(ho0iinme6mo+k]}s(1v0}/ ^Ѝb{ܩ3ײ*:VMeRMrP4ۏJ#,'g8v`Bm ;Xtn{XTG'zgW>!AH@WLO5-u#2y %˵$a4N,+c^<g5@y$g+kʮ29 K8ykGءrut5#./]=$$& қ4,~yDu8ЉnQ@B? 2b#,;8;ZHK<ᜱ*Y:aIcF~ x뛕+Y }RȜ[.*1" ^ bQ$:h<"Y16z-W'Ql8#206*$c#,ȥ#2O#2WIsx)AxhJ @!LB,wΎ]A#.-VNu#t`^[ɠFBO֑$#lhя0!Mn0d`Pu1D)5%zRBBi&zx␛Uh#J3#.HྊE;lL"Tcɴf1W"Jz80d(e'_gɡPa|c),ٺ/LjxÝ+52"1f,cTX0lNi?#C j TCs;ll!KqXtf#.p1(ʽU9ZkGԄ4O<שMF-fd)cIf90"ꗬւ.qE`v7#a%ӥL XqvvSZ[撳:NjDӊ /^$I.0ѧ6r@^u4};ѤuŮa!*wwsؿ7I(Z,[ȦwS[[v)rV]]vLp_+K73#W$L%)P&O/*@w )[#,lbHki6mh`L#.j4(m !L$d#2IbFLOLJq%#,Е%A6ZLS&yw+1W+4E>aa̱Rx˷{;jdi/PJH(1+9ڮZ{Ѷzc5AD/aDy$8O@mBþSnKS(fi]NKB;o:ZIߧQv|zF87|}==j| K*l(bs{iI#,`â(ЖAs/KUJ%abYV#cW#.̀7d.9gɦC1JB`#,y7G(Hb->#߷a$݅SzLFo$3f6z mG?z96L[U)f%Db}ӴSjJpb~&K3.+&)_h $Pt첄4E='$[_t:4VmZ[W+nmHPл.'"pzNmq#2`#ZlBHFFIA)2J*d0bTZL C*&2RJkK cI(3VhS&&i")FU2JP;K,)4dIE0Z Ҍ#Flgtɭ1Mb&Q4,5R"#.4fLƒ)'*vh|(RhnB@g~'|B81P#.a 2lQ֪p=qM"vD%wwϚusrFhI#,ܘο#,̣~t,fZΫiQNivqD3p[sZ;GxqX۝|'hg 󭪧kT[iqojNfJ]ѭ>  ZU_ZVڐ(ilR1/Þ1q7PGүcUkrd: L|d^]w^rߒ2.6a1nh5\1 g *T`䇽5)*Y|'unt篸 x-^& a$='&}=ҡfiAFq1/xeA6#9nX#24z6K)(-uozog"]h'7:ZN|wԜ#,1>;v>_^; ?z_|t؍'s~2y集~'vn\p#@F$#2îi Gcԟe}{ dKUΆ0Ljt%'Q O #2;>9u6B@F+-#,NQKF#,6y25#2{cjYRzu'h֘W܌qfeֆٓU(kPFN]t3#.s썘Ny:r1 1tR2!Т3F;k{8@<5iuɘSLkou'˭>d/n6v_ahD4`S*g&eTYgX*Ovdy)JuCt}j#.#{v6{P#Ix3Fӕ3f dgfx-֒,px;!궒4,T\T&._gvb#2T\6(社JhgTU6$UQґ`"!CI1sé4#.f1a|֎&"ŚcmvSw :!A텷k@KZ|'Q #."3]F0~[}G#ly-27<6٬l*C4fkI.2Ry^j#.mGyxĚN(%k|c5ɛ|8$gC#,o"50P3<އ&fmOQ~t%%١H\XFv·31OR35v-%(qW_7n5 ̽^P8Z}-g@Yr;#Eiy'ދl Lc֠an[tzr>Sa4B,Qah7jҹ#.4 ݈ R,hmpD͑"ZvDZA(2(‹lc0iSW(m^mK Gw+8g!oh›ђzX9!2-!VCZ#.y钰u˹IgNw]8k'[Lp36S4Kcxe1B4׌)fF#.2\bp̦׆WA4\6%CӶ6ѽQBfă-N0qH^N.O: ò5Rʡi֓ !W#2 qIQ ̾[pD& MrإDaakZ9[>#.PЛ.#2J%S"ML>?#ڳMlJQJaB>s!]398IR#h&Y4ox>8xl.\$d7K5l\;`#Ԛ3F2k`s5 ֙dYnjήMX\:,>q›g}CM9G_#,fS@324N;-&KL&UBB͔KOwj&57-gmyqo|LWŨ2[Ce4L>P{%i>gq_r lĉ\)MaɮɼۉHf{Lua&G֗ H6V O-f%[0X#vfwP YgkCCױ3t#.MŴ?P5n.pd.P,Iw!CuZ]n8ӹjkLFED"X( "PUx[L#RHЩM) c\8(ĥoxb'z\o?$UTA#,#2pb!59uww6f5̹nRȈ#2\*) *[?),(?Ą@)w#2;7*rdrx}CPj(f#28Oy{#,}k㜜 ?P.6W݁p̋#lH{.q[нDF$[!!a8vĔo@Pon F14hƃ"EzU)Q֑)GBf؍J;G&CEy% h?&b"S򷏈\b^zdјVxr>g#, #ض6ƍF֋h1h6 2ѨI!H>#瑚p֧#.]bvSNAA0~p,Y1-F5R$C)QAƐ0 8f!CL3‹_S<! ED_#2r>8a$@!۾;#2 #Ki-[(c[GR(ĕzxyrݬrU|X3X@4+vLhٔxr[ޞu-7'epڀw(Z/<.ĖFDVAd#m&#.%U)nwC Ԑ*]<nM($ɽF\JDd7aPLBrR5΍%fv9[6XhHCr"dMN$ǩ" TB&1#HlS,׉@=ol@610#R~b k%Ed~lE `¶$?#,}b :vL( Ҡ|_&$ ó[G `o\Umu?oxB`2]y|tzqYXSѲ'N+d/&ѥ*\RYY34! t-v5,Qh&#.pjTdat^&mD۬ ERID%:kxJo$fmNy@)6x*GftÐl5rF-N72D3kJ# 4P7Bc #.JwOX6QLLasY FSq mٟv؈4!䍽ɩ Xf\f8Lն>bxLa1ںE#.kD/zk6{QN?{NRP`F410I#.aHRQlZfT5ٳ*ᰁG9>wjKJJCUbPZ1sm[4c,B2aD,ͱ)ChՑ ۛ(=H>\%wqC%ٮwWyΕ2Fe+`#.%f5tKukWuw]&Zvn̫Q1en#.FKF bS6ִji.6yݷ2˲$,ț-5")kKM%R*ji}עj5h)$ *ā\̣(+Dd7/tL 2#2p8.Ģ%(#,A0,#,<;(=xzFCz~K8H|#,q(@ fX N3C(>;3 &k ] ##2-k#.pj2Hp>h4MM>P?8r00Q "%@.HVTŔ@b$ؘHm9q\RQ#2H6P# ENa 98n2;3#,XQpȮz$ (`P:: ~~|MDxa@j.\*;h6'K3 ׉+,!3`ZI!愁d8i)vs6Cd%Gk.h :bɮW$YK8BecF >P|и:cqyȗMxx(|?1U"(}u>lod8YG p#2~* #2)x얣j ?QVMx݅%*%$YC*%fL[{Tie-b"e2SliYg]aI5YbjmTQzqEd[S]MK]Y۷cF" mf&1WJ^dQmUHFmmn]RSTR睼Ji%f3UefogjQTG5-W^wɡuf+j]Q1*y]l/?v5fxwƒXߖrU*x?{vEuw-w^%c಍8P^#2(ӢtYLb"0^5!%=ZZm,ҚBk"-JJ׺\ձYJmwZ򖮚sb[]v^jlRgMtR#,#,t RQdֲ٨RiiĶBZY-Jmٳ6m4TRVUi(%4B#2fͲ&#.3F(6"hmeţ,-cRmjR,YJ)LKIڊٴ,h*LS$&#TEK)ZLemfdRқlm-^wjV[iZ[kmt[SKZɭZ6M\ֽf6UEJ5AT4'qvVt׆)H#2ވ^mjfogD0zNG32#.X#.N{$1<C)QDz#2'ߙ_#,Vy#,{0'5=f]8|yqM7bb q4{L`pg}sִ;vEJWit!!5Ij(E@Yt"nlGv#.0)\%|=]& JW^} R%#,###2|AGn&:Ӕ*h@ٜlq̍qܽ/7cI"{Y! HyMJٻurR0&qCh$YOԏ̬KF Si(7aߨQjc*LX*/} SRʷP#2>fqم ٳGg_'ch$T \.nnũMFmi$I`BTcTnbrCp yw#,#,#2Ŷ5T`|뤥ҹjH@R0A '\\ͽ[3T3r04" d[#2("|T<%Nlՠ'05Th&④T`S iD,ZkSaO)3E@wjô=z_q_Hn>@#BƕFAX[5VsgI/Dyعݭ':8c_G6 D6U) "g¹w}hԱPכrHB^oTKI#tiv&t&fX#.nS ԖlئT >j_Pw܈4XBpìGV>PvUh96C$AXP$S >4b$-v|\zA PcBeK'$I{|>7.*XwiWVH"%'=DVM@*,rɔ8#.>v7 %>b:00.Pȵ`=G"3U#.6q7#2 ]N#23ERBdY&Ȝ08$rtu>4AV1Y\WKT#2"@Ɓ4מ²3>#BJ!kj,ݬJ&2@AYaזDq$#2#,C&AYRxfHE<@F`ԑ#.3''8OoLfDhEL&FMNGNUMZP;MF"o#2M#.4ҋLFE;bev7Zr#Fė#,f9NX=$;xa2tk8I̩-וak, Rel-&!WSgrzKd=;Mgn5=PlQhՅsv*,?Tej5pMgql 6 sQ#˥r+4Wv"B) #2Di5#.[zɡ1ڨoF'X5Fp%vBչG HP1o;}S#.㼚ĵE.4d,qk<%#2a1|+LL28H90ma`2h"No߆#,#.Q W0L2op^2Υ?yxQ8=ԞC/ӧE\zwqy!Bf5ՈNs}AÏDĄ# #,le5E6 C_ˀgD$IWTR*EUEJ#,HFŘI."((*%!b bmP D-e)EpxI'q:;GߵylV!$H jzSڔfu4-c"odA!-~u^1ӕW!qV/k}Y%)Tbbrp.X8e,0}ƥܘ.Vw'mnJKQqyGbTII:fIi+לem(JQH 5Z%4t`cZILTU#25=4hF X!, ZBСaAcoƙ\*ea)"$ H$a@.UtkDm+sݰHa2 t5$FhlUdlm.תobu޲ytMjyGh+Ccbn|ʞv-F׻#. , YKM)(0"0ނ)-$"ۑ{^ZWklHX1#eb#ŨƖكZeIHX!Bdo%#.*°aZ,M`IN[h:IViQ˻s6+Q\1&7Ro8R[(6dDU%"$mar#.$ ƭ:c1'Fu"'Ya#M#.jƎCH\؇oD28& Z++STSQؔG*c6a*CKmyԘ\ՎBUKϺF0 h[uvtEM:벻mh5k4X% ?~X=%0tn'.^G5#.ܒA!#,u#D{BFdSRfi%TacXv]KcV1jinɩ׶Z£nZ$A$IJwh#2q,;4"-1!#,?3̰bRN=c8Ջ#% -AIBAXabqn"T`m@p6h"Q" yᄊV><9\Z@!A),k$hl^A(),-njYkƼkzm}#."(J4#.#,61"Pb1lF]\ڻKim]i$RVԙdj#,mia$@B( 8+.Hu4Cɦl&A]C8-D*%]m5#2\Q>n ) $ UpDq#*W{qH:@#.ʟ=lF i 7I{$7RwyBUHǟR;H,JF.2j3Q#N]E?_>fai#,#,EC>Q7%\:,թ|{ǁIk1KJ=qIFZRMM5Y&ݶ#. *0'#.v<. ZwF7J+" I!>ߩ}dBHaep1.lw֡#0U=#.Qb=qf^&\0YP(tƳDJdI 2kX]QbiLHj"&#.#,(rmoH 4-%zC=/_|dHh( q7+:}nBPˇdW#"V2E#. -EKD0_x#.G=#.#2>3jm&75DpMYǍGKW!tb5)͘hL#.F@$+RM6a0 1aB؉ IrwlV2 gq׍|M~6Ńէ&w69τ?%&$nd☣j.;sec*#.:ASMtpb Y;"؊ZM3mJ%d̍{H$JvZY5[m6clR#.,ImlMK35AYDU6͵&ͱ-"AP4?KJʘAHQ?Yu-(E8ԢDZ2#,SE]M6ݛ*0mM^ѼښNhF-A*R#2@ 3$""?1#,?|A;RB4eQaH:FL@O=#;eX+#yNx`)rQ#,{bxjsCh~ d{C$ H@(u D#,j%EnE q`/g+B/1|xc&.k7#,e\CB>(Ρ5N@ȱ͜x C0?B-pSOx CH#Ld$^!G֪(4M~ұx( A@8]ƻmlݦqwɩ.IG5whzDB+XI#.#.Gژ(E#2D!Eq`.\y>}#2h^P̶[qN1f ɐeSC&Lm7H$Qm㖻0kO^mSY#k}JTΟnC}/@RMXY Ae% lBY)OvCMu!^o!&+/X߷7uBE?S &@RaBhcM{@EnJq#.0#.YT`bLU)yb`HE#CB=; WdD^4,ea$0(^$K h&cBk-/"l)P!=J$#,Q,H™  C7?uH"hȁL^ P40";O-rI`#.J^s462i!F9/#,`=gSЂ#.-6.4\*緷V0dMTKb4#.K)) ^-{JDz</Ɨ;v*:ϧ3HvT(;c"S+{MbGȉUDH$"`HEZ{"# ڌÚ6`ޘp%Y ?,~gA< 6;t9Y)NEMt!ц+#2/s@->CuHzC$() B,'At:Mҙ) } d2ڊ EќEC_* h!t 5v`.fMP* c#..)UhVal!?>*,C&X##.%g}W)JT˸$&,GaT(Q? "xrk.X!9t*O_1•ElgP/ۛ;Q2e1kI?#2:$4U~um-yM%VRdlj~_n~/ZFw-UKKwO`hLvCk5d* r)N=G.;񷳐#,fiW[cFdL!R#.t1㫅:rxѓ~K" /wsQ@>HgL mg%`CP8-z 7(2)ak#&XS7{34S,Jj >E#.|^jn6<(sӹ-Way~oI9_IqkE0,|#2P_n9F#,V_p:RwAP<{!d%]1^bSp9|:g:kWH8VX5{G?"YM]PJc$#.t>2f ctݨy(ÊdjP&P!/jff6Xnnd3վʉctD=uĆ8XE"Ո#2ϵ1{*[JBA-Z^e[~ o hB&2 "g"7-jF,DUpDq"Dxɩ+,E 8@nlPI(jp LU`HK4,HȀQAp*#. p'PlH()x@C5 zΎUMǁA풊 UYZŭ[Ĺ,8O4zxiÃzv>#.44ZnLc=jX!$#2L4Okh: ӄny -V_^m{I7ˊtr^oC>\M%АA%% dflDtL#,pHDnNҊ(MF6۫ښZ5YզdkmlXS//.o,RRPdDd;lzaNک18dm?15cv6+ 2 5ZC 7Dž`e&#.p}3jtPo}xY!"T*2;98~b]<8` tI GX9 MC thzr:K!ev HW2#IcÕnEsw!(:|#.eGqyhF<˛R-SPJ:-!1$yMΓƾW}vTbF򙵧Hg-A<< I@RqU}UD]-NJ 3"#2'wo9oCl> ̩2wA>=#2Cg$CL#,.օD& k/xB.5349\!r&c#.5iEM/d 8$H Nyvt\Ny[LaV?KFs<f,nqc<tԖDr|ÙG55K:&̎p͆pQ'H_"rdfM.׊`@_#,lf;#.ސ 츣,Q0#QH#1Da0gzmDƖ+a~X#.1iT[ٌ`cKlP}HAYgJrlGO<bb3ن=ld3GnZ*\ʇ{bziG>> F#,ꂩ^*!lr.G%H"9i׶kmhyj実bǍcjɬjѴZ5m]R[F4m`]kƫEUNܕ9+e#2D(RꃃrX]BAvm8Mݿv #,8ϬMӺE Q&=p`ye)h1">$@H#.50\oujF+c̝^!BM|yo8dg;ad\40oq)iS$k S: #24"('Mu5= `vN3x` ʩKT*)<K=yz3 FB⻝voALൈ_K>Sa{婸z!.#.z='d|9?3[TKDL%t̄r93C;P[r]u!#,`_; &kPUQŏu&]S?է1wT#.pz =6&;bz0W#2޺7_^=5r#.#,#.pOFjNor(H#.:A*몝uR6fZ,R #2*P,a}c`qYEanh cEQ.#.E5dAת֌Q K i#.i[1# 3`1NPnmme+\D2,*4&FyuQ#2A]pq/z3L{nf亗hYHZHTfn# ,XbAS[)Y+I$Xҩ&F,ۛnZ1m+yw4Rf7-뽞fi#yq"#%Xu&FZkf"#-իB DQ4kŬcۣPۺvL5Lq0Ϊ50m#.܊$qy&i@f⛑Mp0!#.#,eaFSC%B)I#2׭(kܬ8iAQycXbG:LͯJ*vIDD5i@-6b{!ZZYX؛i y6`QH1ᅸУJh5XCL1dƆ301fs7! l.2ASf†fD;+(&sZ.kXy6fSsà!b )@ɷ,G;#,87i_{uh^KfE#.Hl32=P }{iya~ \7Xcf:WGjo' +)d1!fiKi*lK7ơ4◍jCuUjlP-RGi(^Z&vɰV=gc&r #pN$VQS-6q'Rz!AUnsp>,/ăϡ*cDD@*#.iRL1 "b #i`HQ#.4(JB("'bzѷumӺiFNiX#22e#,ҴZB]w.t4TwS!K#{frj\z7x;]uّ !B.R[G:D$幙ru7WlmL#d.a{:kEoƆX4!S(ቘV,В*o1E8ù!6稹PhOFm#0vAL($L~ppy)k(}YגnxnyppqYa|$S΍)ŕ4hm҉!q3D3Ados/;Ox8Mހ-kfl#2놓l*52b=zYq0#.Fޑh ͮ۬Ȋ01K\#,Fȱ~T#.1P\ftԹV%Tn54;MFU+nԚxXL^M]ۻts_$)նImEa*IEK/z0;yz-z?7>eت@2r,Y pH ̲.[I$DQ&Ld(B],n;zqKj⺦G0B`*^#2uX rOlFЦ,a7Dɵe>-3Z4gm-"0N2L4Ļi#2N҅c,{|BAܗ8/@3%qH&6g-lƇLUfQS(VuReM@{/<.4 8~QAVdPKogU)&鷿ګVOo$ܱJF"/]hᗿS h\~y`!"Em~VoCf/#,E@(I$QQ)I"  ,`ur`̡C B ƕ" UL'b`' $\[(&(mm\Ҩ;&w\D]"65N,=yv&Ԧim)@qq&.+VѶjԥ8%[h"#2(chPaBTBB i/Dbf Mp$#2X7Kdnl`~F@' Y,(ӓrzx$?ESa`sp%Xgdͺlۿߚ9bpc׃t Y~1< #,ȕ^BAME4mMD1*L8c#53l}ɄИ-bi(6l]Q#25C̥hT`$b@#,4V1aFjW$x$#,5^9룯I%|CxjKF썶oF{#.45A!g< zO(.v[[-WP#2F!(nСkw"* jf[W۪հ2{1Wyl_dd$YNY2#.FF7 +((ħ72qY`K%#aM6E)n(x Y>z}^;^`V(7/Iӡ=UWӭ#kQ跪=! TYQr錂+e:ܬaAXASJ /.Mrݹ֧;wRF7vשky,߇&j#.BXq V z #,9guW)I"eĢ2$3`.ƪ]IHXצ[ԖdTJAij\("8\4:n!: )L(20*@$ 1(3=:] -TjղͥmS,A# O.oY#,rV3hEHH1ET$ ^ŌbuV_RRjeL̊?S#,O*H` x g}mLO)CU}QFFtBP$z}ܯ:ͽ<<\9a,B|!!Iƾ'1ΖZ-EZQ1A$9hMFGVlӊI81:!:%ob!ԑg['qh<]R.5%,eHBVYhDS )j]@P()D. %"2FB" Rb+Z$%DRmьb*3UV#2o[?#2nle$0 ̩#~͊/8n8xT;~ H \0h6<.SL$yi?.QC&3ETHc6Phم`!Q@1mEշvˠD ~8q3Cebb ԫIv`\ Ǝ4gBB5uB7yԺXޫf"  { XL6ݢ%GY& t;Sz=w7pԑG#@T,@X#2%B րRZo5eviKj`C!AgV$bA3nv 2N WJjp֮o FT-7$n =?N(ʂ/k*Q{LCfk6v,oIHc#j06i1;k #.LѴM(S@#,J>,OXUڥc}vz)--.ދX >a(ț;9sm0l7-+CnA#X36ƒި^ZS5h!šfg.7u٥#.#49e%2;I#,07-E#,QT64V~ B<],(s?"_Ȑ M'V,LĤ(vDBpguAs+9FcrT`0#UNo09!wVN&A|sѴmV㜏_ܚ>9taAhD.7N{+$[S#.0m;ѪnZm=M}S!cQf}w翃5Ac)!'4ogmµz=iٰ y/v3|S|#ؒѼ-5dі܏s`(8kc.һ1B!@6RabBPCy,oW.MCpފPUz=/i0UhMq"(6Tny*~8EuBo~#^#lL#,Β'a^ |o4kpF:-^z. ZExc`4zSTn!#z(#2kT&Oi#.B>{716ɜFڲܯ4D(JU>.yeA@f٭FUUUUgL]bi@j|%*bᐅ"BK#$0) .Ֆe\{Y_{')ߍWfl*'(sEnT8QAiIeͪLk9Fق:ckO&P{ g,ўA2#2B#2 ivL! _Jj fZTe,9"i<^Zh x)I#2 dgSw;"j lKtL53lw(%5=Ru:qzFczW:QJ z1`zu2I/v\'羀k3t~~l*}%#.%1"/ȌH E%_zߚUEIj5T;loR}=)̍ԘƔR@MpbG|i>60-< sE zNf\:[r>#,qpP"X mAZ;-Ĵd&2[! (:T;öET4t&]|G)#2#2=vM}=9ە(;gC5a-#2XDi>{T(!@B#,( c0β{78$GPf% B#,(AfVROm?"zAFgI#,>"4U";XA!4}_G\d79+=N=~)PB-%EELͨi$[Fֽ CIuB0:bU<"1zr0qwH̸.}v+s<Ļ_hY Jpw H3c#,195`#ܛbm$&C#,dJ"81Mt H#߳T+%}gL#2U1D̉|#,MTQ9(ݑGT#.uetU"#.cv&IYէzؘjjQu=[1t)M#.jH!}#,Xg˥$8xn_J抍q^!&#,Q6W-uMUKfHFR 0R#,sg9Z$9K#.>22Q=TCR#,X "x26O}dmeI$kݙe (i˦4J1HIdaQ1RsCXX'!Ϊgo<%˚aY964 dT#IMk Y" Θ~`~x)km>ce0,R,0l;,Jw+y񜟗wFw4#.2#2#LTjM~L6g,uʲi4 Ϫeq6vL7SpamEayNDd`x%:pbl]U!42Bro9niTݙrРn?'to5I" d_|S;^2*RinD  YrKrTS@#(dTU4#.fM1RA5;ۊW5k\#2k%Ջ$c]-,V@q¶i2#H"/+tJ%4m8bL)Wē(n͹&#.t$*ԉ(rBjd f"+xQhZZA{=8d\3FTZeF^0 $!s4S#2\p#.de,S4`7a, P9)Tqa(hj#.:M[ˊKb7wo,Ce(#тN:jiYZ2w(lCng%* -&mvwƸJ !}lW6d$Y$m3.I+ y% #.j7p>k%q3m:nzP5EIvm$b~F[ #2N&Q(H 1bIYp<#,#.hFu{<"ł%\ً o9Z|vGȦ%2w#iٕ?}c\{NOe]nءDL` nYͽqϪeO`Av҇Tj  W؜9yQB1C%h_d#,v[=Tn`]Mk9O>J\jt `$jwD_@&ԂnA$ETQ$mpcdcG"O*F#Yꬰ΃#.5#Ih2+i#.6#,rY;56I$9 j0RrvV^h7k%kkv%wvkQ,rҶ6Ʈm%[ecr-TkQTPbo##2mJb{\;`OOHk<2՞Lc &rzLPE!7PH "!*qx{̂Z0woUdJNB=p*#2P>W.?SȈtCh0#.X2 ąTv=9֋0$Z뻎m:-}\Z`6@DA6ڬ{hVIPZ@D骷,*RbT]6Բ&ؓF@D?i|,.ґĀ_!ғбs#,}S:)J҃H∠/cNDASmJźxԁ·2bDVGkݮ߱Ve5 $PFZ4QXR3-)"6*mZ&ҴRѩ+,d=UQXf@4\e6ڌH7$y-Dpp(5^4(L @B*䂌yL@(`6A`V;hƤtE#2A BEYX -P!#,/Y|BA}9\,oo^%O]tԮٍí?JzweUֈ#,Dh m8]T6TUF6Vt%}U-R{$>!@B~ݍg;8Pš;mPMԬ}a%mQ6k{K7R5NYwiA!`42PeQ#,<SIZtۇx7]ԩLn\[lV-rT!<0ډw?*cIe+"}jgƪ.fviu#.-x j2}L8vdq5uX\[sެ#2L)F{~l݉wdt7Z[;U}[l>-wNIMOG$$pG#.#ETͧqlÞ.Qz.\ !$mG9%+횏 b%qPrg['8zs:}:%Nxm@=ӕ,J&*dy2WKTakVFN$ZqGI$=V ?28vokpmGÉ%t<#.5vK8hmLĮyG,;}%vԖ_zt1Q!]5ʡVS]3B|%ڗvbAs XɌ)FndBjAnq!|3dQ;8Xf[^+b.Ԍ4cAn>Рn@/#I<7R{P@L#q$b6nNꉽ3qOW:3r0Di#,bm*t+@ P\B߿(J-K7Tb^[9'8B%Bi-#2բ#.TsN}nH]+#2U0QG69v5\0ct?Jʨ22JTa#2C]#AǶm=P9W}HJ%#|@C(Qf|q-ysS1 dvxwu%55#.HZc\/3Ju|Ҏ ;,J5"ukd\bNBƟ놢(w4>#v9F~von`qqdžd]wCW^<.uVVӥKqmM(Chkhph`'(p &W^δx1J|ʨٻۧ|ݳ[KG~6S>dջ7Ve'pNZEuieD]ww䡶,JX!{Q 9x.Ux=-oKMQj@́0Í݆==mK2*-O۱!?nQldLQ`Ì@@<>9CC0h\ffС.lˀ;lh<+8sw5;0ڡ~X#\a y eR5WDhkG{Jo#ʤj=iDBBB5LPmb\VQIFe3LMMnNap4MP#,\BOÎ`Wj&p!oVD]>0w6cR%ņ? VA:CKyP3|c(#211("фZExh1n#.`9e1M#sDpMX[2]L5c3m>+Wcxw 2*sKZ:t+1hT H<j fV'٭mִ"##, hĐŀaI QKX7Yk,c`μqR2q `ٖ5U2D>'ssRU \l`nxF#2gЅ,U$bŔ'@Ar9K2#2%D 7BhkyFЌ!)YSTV3cZ#,LegJ $UUT@aOSMx6OqeӦ3~g"M$68AcО#,WXRBGsV&@ R.K(6Z\Y3osշFn;y9;1cUSC-I`㴮8)!TCzSTc6ސop)psH?,@]ɹa'7@)LzC@²"ڦSj떱WMm#.#2*`CY'G8/*^W>^R(#,4[aF61F&1H̡jV)%V)4UVMSf1h!BjF$ҒTF4#Q)EhMMSFI0 6a$FI $Py9i\̔#u]Sz{3GJ󹘟r5O"HHbHpa+;*V*#,`sQiTcqI#e5bD7F3% 6L}^^2Gq Ha5۸,Hz.E;JBoY#,S8BY7^I$.[nP~ޝщz4q ۨ/_WV6K]am;C3-[Vj؉-&"lhk]5hTZR6MDQ,:#.FXGؖȲ  3;A!52Bۨfe0[)ϰ#2 #.#26##.O.V4C8C:b0pd)G)1ms%kuZj-DC#q*KI%hg ;w̷wQ3oa^Ro4Kg848(.@,]B,!hJ,hDJJE#,7<|,嶺̟#2#.FpȰ93rAn.qP Qb75H5#)!J#;CS8.L6lG:f6r1JN2,=0ybq)Lc@`% eU,х#2*#,( \@p AIpKy2HI$pQP=@LL)\2ni民+yE{;HVgoW=Q<Ն:741~7q8q ꖻc@.|kl%`# Tԕ &PS}^%!#,>Shbd=>>|^˔ī2]g匪(~Tmz֠)Ipي/z"2`:VK#, `-L$AG.|XXY\\\f66tDespHhEzmH^A; 䜆%:yQxV笐#2"[#.oO s#oMn`GKfG*(5+F1b"6"cvRB #2s#,:ܓăն[B}\ 77V< ! (=&(ݻ0\@y-jUh$U0i^Ŀ75A;Qr\Ic!}Ee+t3H4Rb 9(ùIi-VH@tl#,V@rO*}>%{lO0-g*0>bQWIq坔o^3]@ on(Ynp" ÄL皚j"e0:]Nn3"[/*f I٠QH&XpK[x#2 #.$cN tJ(7fH.17YHQ8`TDŔH.E7Wm]$:% T ^Ju&*RSqs*-Q\fPˑьpءM rlsgTqXA[Rt$ \aI|aA66I:ojpXN|e(͆t{OAlѦYF=#.;;-#2t9&+LFe%oݑ=̙,u`LCpÃ78ڃdԟ<6Et#)٨5WM.$3 hSN%ɝɑެPaʹtѩ" ݯ|Y:N7"q$[vB։^FL[3gWuBA2dѮټ ^I:rX3W5kr]3&;8k\@r2n&='NJ'RˍnjaVj&dKZ{w&^;Kfv~E0Vlh9+vv&?g{w#2뜣_Nr.HHXj7f$m:75)@4qt9)Bù3`ppN(7 " at-pCQG+f6[Hم0lh SYl(#2J#z+fh$Ҵ2h/gfT#.tHIm0;eW\k+ll6haDbu,y@x+4~ 8w*8KjZ.!mqMB\ca4k)վN[ua6~>D=\˃ȥk_&O2qҶ4#. vvϣN9R ;k7MiX | y)MN엠)SFsH0^m~"aud֠l5-X&0Fk p`Z=u&ר7᥌ XJA@m#2#.f =Kk"m<@mk)&]YxyzP4IZF6~8p,풵W0lo-#,-hb$Ɇq0΂SQ4Zq`0剉.5ʠ#2[lz1ەk;&\ &,z&yєuP)v zx#21,H%ta yeǒ^ݓM7%8qX tTȘ;Kla.:T)fB Q JN3Yl)D.(кQdƃBC_HIj(D{ ha+#.i6;86e9VCdg9ksuAd:%.$ 0CnF6"#.!q6&17SBm;\2hPa `t"N߅Tfb.!5oKG#,m@ p\Q*rQK#2JDI&.x\b:!Зz2 *Qv p.JtANF&Pu JZRUˢsCb<!1`SF4xO X[u#2u#,86#,j`6P&.0XYM#,`![Fk`HsrbQP#.#.2h&&tH҆ث$[, ! R,F#2|>U@QQ`2Wv3]ȑ6yI!Ñ$$EB*ȯ᾽ |O#'y=^j!ZfqACZ0#2n`aMrzci1m;Zm:#2C6kϴ,0mb'(6}JlW%UE`!Du"#2pS_m`vh'ck4Aὥ<UpwmEh;˕"pp2dUtuI;U;rSέLo{vvXوȹF*$ƿ$EGF<8?&5l܇_|@t7`lUC#,,.J:{Nwye&0*vZ0b#i`#c#2m&PwKy6oRe1䐄nYm!BZ\TnPl j!ҲI!#,&쎲Li#2-7CBx h1ECf,3H!;_wC <5-!= y'|a d}aNMZmlhz#P# N3#.fdD4(#.oV!FآЄpJo" ^Ǵ 5sfN2׽!*SҙVA8Oz@'&XFDݖT$`wvܶlOF!qI,̷ܚ*nqw,7 h"qGƞ)pDz B+ʣh䟎b8Ӥ ըB1*7I'87U("#&&hu$PuTTY=#E$GZJ#2&E&q5 <-PEUjwSXXXpr2_ ~. 炆!7suQU-#2=M#xscnĤ#2SuYmqFn&Pu5Y#,Xb$-4#,*@qM_i/Y _ٗ>4{bN(~o[5ͲjIͳIձYl&č5+ZJV6-6Fok~dKB-\qrC^QQAn9hqԊzعm#,HL_V z;5FqOjh>qTĈ#,φZ􄄌Ǝ{(MH#V2F暁5`J9;SmiZT:1R#.iL 54n(6DG˹,O((5p®8#VRmfAD&-3o:9$B-X &t2#¾+#299\FAeKJBXrdL#.G{8>(D_@2K1iSsv*5V0XXpm/&t+ t=ihYbP n6"vwzlwQ\wB"#,WwUQ"ABb{Hxr::tˆ1`!BF dV1z@Β||#2nPBĐ)$#BB5< D1e#.@*xO^Ocm'A4~$2^)oW4}Q5=Ype }'oG0Oxkǁ'gЍ#.TyP{,ٯ#.Nߜ#.ƅ~Ȧ#,.CP(^viq/Wf#,$d/14wW@3Lf_u*<{H"Q%EDM@1d671sn!X(b%EV"JFIh~Ċl&6|_/maJG=qb#2Tٔyo3$RF!EH,dlDj6,(0V-Efe*j;bJ^S5QQSz8"ֳ-OҢ7u͑MPhF6dbEI%*EDxEޣB[*k~h'0uĒwMuF/r_VʘbI~WQl!f!&`y #.pN3 S1x\FgߪX@Y"Or}%Wb{+&4Lq#D#.C9)#}c#SqJ!}BA}¡@S|ԖۤE))Pb"{*#2ݽ:EjN#,%#2xʔZYVD!,qqƨ&{1H;ˣW-f`&cжvfm?#2;M,X\.kui 1?rNJ4M.dfh[?P~"y؁#2iyJ+ut F#2#,mcdT*)W6ߕkIJY,إ^ &*2 %#yrK,aR411aGŠh6j@J_Av@wEK%#2?$B2*5`(j eFD`<5ҕYdC!h2&Z4ƒY$~h0>O&EXM]dlᙑ&Ņwݭ#._4D־hooݳIJ#2vZ+ƼVdےn3vfUuQW;PIl6.iVZMLl`m#2#2D8)V8mF-bk4"kˈղ[)21 ܩ%&0m0iK^E7b bDQFlx3h VMzKHC6h~)E>EFB #,@HSᒀƶn93E(~ 2PwL]#.r@lRHnްV]Z[֋bxar`+4C\Ty|\wb{Ccd@HR&2©p(`~6oܛQ˧i8Ӽ"eNa6Ad#2TԈ2'jq'-#.E,SS08!A(`7@;60D(T179![+v$VB2,/@JCL"T"h& >~^W︾Xc+Q&\J|aVڶolJ w: \m#.L#2R%;#.[RSV(b8lLzv9dT:n8Y ]#2qa,l-DEam_*j#.ROR7ENi+GqmtTPE4+YKcrxkhTJK0ԡmE F-⒨@19 Q8ssC2ӡa i47'# <rHH.C=dC {;= tW5lr46z\JAIb(2[ &x[B!B'А]xO'=S#,w=KlJ9  #,-#,Ϳ??~}~ϧ?/o믧?~??g?|ߚ9̟P@ԃuH`H#,!Pv9sL Ui@[My ~#2M ?TuHfg[mUwLa))mg~ #2#,f[Cq_BgGhoF/|_1 ;Gn @ "q!P,g-S }ZTx$uE":D]’ !\=BhұڲK#,#2iI(7| nqsBNɚn#2{.##2DäQ@`$ mr69#2(#,1Cr@ʡ#,X1$DFiIHqw*‰ ^K&?.fd`adEBL8B#3RQ9ni6֚D񸚉CPmk4[h)J)#2#"_AJ YP*oP xU7E[)lY:@a.ԤEހ߰F`S%&$+'J2!! !~]ɶ!Z.O4[V2E:rԱT>^EhRvpIP.6S kJMqYɴSݾ4JC͏CP&æ#.QH},Xj!>VUKU_Ŭmo}<g/(m\`lqn$ZQ|F7ޘo%Ԗ+jʷ+Wx|<ג(2YFۮt,\9!ȢE3&)B!xneN2ApqQb8nYbSnq!4w JXQAʒp =7툺ƒY"B;%z=܎\0GX5>QOYXEGqݢG[\ٶJ5[mRoνjFѨoJ@|=g>tB <>|ghk2YiY 0٣ )<~8D@M_~i4ygԁb"p:iT"pwo}ztb4Л843;O}O1d!ӌDPKH@(=0JJh\]DۧGg.v|8V~873vM)n'DS8&\e|!ttYX剼#p尖7'ו .φ`Zd]aQB(e׿P`vd%b}rW%m#2oQ9JAk"Oι^S]B@h鑀 +#<== +#-----BEGIN PGP SIGNATURE-----\n\niQIzBAABCgAdFiEEjH6y+TsMRfVzL+XRG6xXHc13IpUFAmkVHSoACgkQG6xXHc13\nIpXDwhAAtbEeolKXInrphJBMw+HF4wnuUCO9NVLkfszN0YyCr3fUbM5T1/lpAuAq\nPuWLH7UEjTuaanWg7q4EJmGKZvpSPaOozIWD4hEYDhYNDPhEGLfn7HaTyFnFNPBD\nQyx9IrKQnu5RlIwx9OoU7zI4SgQyLcjHLSBBQt2GWz9ioueMoW9Ooy6l08ggct/S\n6mQCjZOqVRR6RlRnbP4u9hJTsS8/QpPs76k4USjC9wn1MOY4L+WrIslJVdFBYU+p\nQH5gAHvOEKCpp9PmMxBf6n5weqXAB8oilJUZrhcOjZ0wLkMfr2uJjhbvYH/76X0z\nVeJsfwGGU3JuXeV2qQQeACh66KVQu6WjYKydlhymz1G4WLsYrhNoCFCkoH/7rcLJ\nEpWwRVSPBIkW5hdeQfukBqJYNei7T+NFtZ28+7kfQMNvTnYozOjft9MRO1awf/Eo\ncryjZ88B5NrI/DRtrGeWJcWhwrVfphMPw5/facGV8NGkWKHRJCCdfKsmJO6aDiBQ\n4gN41UD7VYtZvRHQH2f1i+wL0qQSI7dCzXuZ53gZJ80DKPmzuYosFDVonVi7qTLX\nQIh1krF68c+BYU7cXX2H2vtdPuVjCH0Xw30UGbElKj3uMtx2SaK3R1IsrxySbPrv\n4luPoBGo0gon1sO5vi35v1Xl9Aa7ZbD21XsyCQ5mR4lZfp4t6Os=\n=mE93\n-----END PGP SIGNATURE-----\n diff --git a/wscript b/wscript new file mode 100644 index 0000000..8bd9902 --- /dev/null +++ b/wscript @@ -0,0 +1,180 @@ +# ========================================================================= +# CException - Simple Exception Handling in C +# ThrowTheSwitch.org +# Copyright (c) 2007-24 Mark VanderVoord +# SPDX-License-Identifier: MIT +# ========================================================================= + +"""Test CException for different compilers and platforms. + +Supported variants are: +- Linux: GCC, Clang +- Windows:. GCC, MSVC +""" + +from waflib import Context, Errors, Logs, Utils +from waflib.Tools import waf_unit_test + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from waflib.Build import BuildContext + from waflib.Configure import ConfigurationContext + from waflib.Options import OptionsContext + + +def options(opt: OptionsContext): + """Provide basic C compiler and testing options""" + # we can select the C compiler we want to test with using the + # --check-c-compiler option + opt.load("compiler_c") + opt.load("waf_unit_test") + + +def configure(cnf: ConfigurationContext): + """Configure the C compiler and environment for the host platform""" + cnf.load("compiler_c") + cnf.load("waf_unit_test") + + # this setup is for running bare tests on CException + # and not the integration tests that require Ceedling/Unity + # and friends + cnf.env.append_unique("DEFINES", ["BARE_TEST"]) + + if cnf.env.CC_NAME == "gcc": + # when using GCC we can build using coverage + cnf.env.append_unique("CFLAGS", ["--coverage"]) + # we need the coverage library during linking + cnf.check_cc(lib="gcov", uselib_store="GCOV") + cnf.env.append_unique("LINKFLAGS", ["-coverage"]) + + if cnf.env.CC_NAME == "clang": + # when using GCC we can build using coverage + cnf.env.append_unique( + "CFLAGS", ["-fprofile-instr-generate", "-fcoverage-mapping"] + ) + cnf.env.append_unique( + "LINKFLAGS", ["-fprofile-instr-generate", "-fcoverage-mapping"] + ) + + if cnf.env.CC_NAME in ("clang", "gcc"): + cnf.env.append_unique( + "CFLAGS", + [ + "-Wall", + "-Wextra", + "-Werror", + "-Wunused-function", # we need this so we can ensure all test functions are called! + ], + ) + + # We need Python and gcovr to create a coverage report + # from the coverage data + cnf.find_program("python", var="PYTHON", mandatory=False) + cnf.find_program("gcovr", mandatory=False) + if cnf.env.GCOVR: + cnf.env.gcovr_module = "gcovr" + + +def build(bld: BuildContext): + """Build the library and tests and then run the tests.""" + # build CException using the custom configuration file as this is + # how later want to test it, so we need to define + # CEXCEPTION_USE_CONFIG_FILE + # We also need to define TEST, as otherwise extended tests would run + # that are not meaningful when multithreading is NOT enabled + bld( + features="c", + source="lib/CException.c", + target="obj-cexception", + defines=["TEST", "CEXCEPTION_USE_CONFIG_FILE"], + includes="../test/support", + ) + # archive the CException object into a library + bld(features="c cstlib", use="obj-cexception", target="cexception") + + # build, link and run the test binary + bld( + features="c cprogram test", + source="test/TestException.c", + target="TestException", + use="cexception GCOV", + includes="lib test/support", + defines=["TEST", "CEXCEPTION_USE_CONFIG_FILE"], + ) + + # postprocess unit testing results + bld.add_post_fun(std) # print entire stdout/stderr + bld.add_post_fun(gcovr) # create the coverage report + bld.add_post_fun(waf_unit_test.summary) + bld.add_post_fun(waf_unit_test.set_exit_code) + + +def gcovr(bld: BuildContext): + """Create the coverage report.""" + # gcovr is only loaded for gcc and clang as reporting does not work for + # MSVC + if not bld.env.GCOVR or not bld.env.PYTHON: + Logs.warn("Cannot generate coverage report.") + return + gcovr_options = [] + if bld.env.CC_NAME == "clang": + gcovr_options = [ + "--gcov-executable=llvm-cov", + "--llvm-cov-binary=llvm-cov", + "--llvm-profdata-executable=llvm-profdata", + ] + python = Utils.subst_vars("${PYTHON}", bld.env) + gcovr_module = Utils.subst_vars("${gcovr_module}", bld.env) + root = bld.srcnode.abspath() + cwd = bld.bldnode + cmd = ( + [ + python, + "-m", + gcovr_module, + ] + + gcovr_options + + [ + "-r", + root, + "--html-details", + "-o", + "index.html", + "lib", + ] + ) + + try: + bld.cmd_and_log(cmd, cwd=cwd, quiet=True, output=Context.BOTH) + except Errors.WafError as e: + if e.stdout: + Logs.pprint("NORMAL", e.stdout) + if e.stderr: + Logs.error(e.stderr) + bld.fatal("gcovr error.") + report_file = bld.bldnode.find_node("index.html") + Logs.pprint("NORMAL", f"\nReport: {report_file}") + + +def std(bld: BuildContext): + """Print stdout and stderr output to the terminal after running tests.""" + lst = getattr(bld, "utest_results", []) + if not lst: + return + + nr_tests = len(lst) + nr_failed_tests = len([x for x in lst if x[1]]) + + val = 100 * (nr_tests - nr_failed_tests) / (1.0 * nr_tests) + Logs.pprint("CYAN", f"test report {val:3.0f}% success") + + Logs.pprint("CYAN", f" tests that fail {nr_failed_tests}/{nr_tests}") + for result in lst: + Logs.pprint("CYAN", f" {result.test_path} ({result.generator.name})") + color = "RED" if result.exit_code else "GREEN" + Logs.pprint(color, f"status: {result.exit_code}") + if result.out: + Logs.pprint("NORMAL", f"out:\n{result.out.decode('utf-8')}") + if result.err: + Logs.pprint("RED", f"err:\n{result.err.decode('utf-8')}")