diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cdef39e --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +build/ +waf3-*/ +waf-*/ +.waf3-*/ +.waf-*/ +*.kate-swp +.lock* +*.pyc diff --git a/cl_dll/wscript b/cl_dll/wscript new file mode 100644 index 0000000..e835fd7 --- /dev/null +++ b/cl_dll/wscript @@ -0,0 +1,146 @@ +#! /usr/bin/env python +# encoding: utf-8 +# a1batross, mittorn, 2018 + +from waflib import Utils +import os + +def options(opt): + grp = opt.add_option_group('Client options') + + grp.add_option('--enable-vgui', action = 'store_true', dest = 'USE_VGUI', default = False, + help = 'Enable VGUI1') + grp.add_option('--enable-vgui2', action = 'store_true', dest = 'USE_VGUI2', default = False, + help = 'Enable VGUI2. UNDONE') + grp.add_option('--enable-novgui-motd', action = 'store_true', dest = 'USE_NOVGUI_MOTD', default = False, + help = 'Prefer non-VGUI MOTD when USE_VGUI is enabled') + grp.add_option('--enable-novgui-scoreboard', action = 'store_true', dest = 'USE_NOVGUI_SCOREBOARD', default = False, + help = 'Prefer non-VGUI Scoreboard when USE_VGUI is enabled') + grp.add_option('--disable-goldsrc-support', action = 'store_false', dest = 'GOLDSOURCE_SUPPORT', + default=True, help = 'disable GoldSource compatibility') + + opt.load('vgui') + +def configure(conf): + conf.env.USE_VGUI = conf.options.USE_VGUI + conf.env.USE_NOVGUI_MOTD = conf.options.USE_NOVGUI_MOTD + conf.env.USE_NOVGUI_SCOREBOARD = conf.options.USE_NOVGUI_SCOREBOARD + conf.env.USE_VOICEMGR = conf.options.USE_VOICEMGR + conf.env.GOLDSOURCE_SUPPORT = conf.options.GOLDSOURCE_SUPPORT + if conf.env.USE_VGUI: + conf.load('vgui') + if not conf.check_vgui(): + conf.fatal('VGUI was enabled but VGUI cannot be used') + +def build(bld): + libs = ['VGUI'] + defines = ['CLIENT_DLL'] + includes = ['.', + '../dlls', + '../common', + '../engine', + '../pm_shared', + '../game_shared', + '../public'] + source = [ +'./ev_thewastes.cpp', +'./thewastes/hl_baseentity.cpp', +'./thewastes/hl_events.cpp', +'./thewastes/hl_objects.cpp', +'./thewastes/hl_weapons.cpp', +'../common/interface.cpp', +'../dlls/thewastes.cpp', +'../dlls/wpn_shared/tw_akimbos.cpp', +'../dlls/wpn_shared/tw_automatics.cpp', +'../dlls/wpn_shared/tw_explosives.cpp', +'../dlls/wpn_shared/tw_melee.cpp', +'../dlls/wpn_shared/tw_shotguns.cpp', +'../dlls/wpn_shared/tw_sidearms.cpp', +'../game_shared/vgui_scrollbar2.cpp', +'../game_shared/vgui_slider2.cpp', +'../game_shared/voice_banmgr.cpp', +'../game_shared/voice_status.cpp', +'../game_shared/voice_vgui_tweakdlg.cpp', +'./ammo.cpp', +'./ammo_secondary.cpp', +'./ammohistory.cpp', +'./cdll_int.cpp', +'./com_weapons.cpp', +'./death.cpp', +'./demo.cpp', +'./entity.cpp', +'./env_fog.cpp', +'./ev_common.cpp', +'./events.cpp', +'./flashlight.cpp', +'./GameStudioModelRenderer.cpp', +'./geiger.cpp', +'./health.cpp', +'./hud.cpp', +'./hud_msg.cpp', +'./hud_redraw.cpp', +'./hud_servers.cpp', +'./hud_spectator.cpp', +'./hud_update.cpp', +'./in_camera.cpp', +'./input.cpp', +'./inputw32.cpp', +'./menu.cpp', +'./message.cpp', +'./overview.cpp', +'./parsebsp.cpp', +'./ParseBspEnt.cpp', +'./parsemsg.cpp', +'./ParticleBase.cpp', +'../pm_shared/pm_debug.c', +'../pm_shared/pm_math.c', +'../pm_shared/pm_shared.c', +'./saytext.cpp', +'./status_icons.cpp', +'./statusbar.cpp', +'./studio_util.cpp', +'./studioevent.cpp', +'./StudioModelRenderer.cpp', +'./text_message.cpp', +'./thewastes_hud.cpp', +'./train.cpp', +'./tri.cpp', +'./twm.cpp', +'./util.cpp', +'../game_shared/vgui_checkbutton2.cpp', +'./vgui_ConsolePanel.cpp', +'./vgui_ControlConfigPanel.cpp', +'./vgui_CustomObjects.cpp', +'../game_shared/vgui_grid.cpp', +'../game_shared/vgui_helpers.cpp', +'./vgui_int.cpp', +'./vgui_ItemSelection.cpp', +'../game_shared/vgui_listbox.cpp', +'../game_shared/vgui_loadtga.cpp', +'./vgui_MOTDWindow.cpp', +'./vgui_SchemeManager.cpp', +'./vgui_ScorePanel.cpp', +'./vgui_ServerBrowser.cpp', +'./vgui_teammenu.cpp', +'./vgui_TheWastesViewport.cpp', +'./view.cpp', + ] + + if bld.env.DEST_OS not in ['android', 'dos']: + install_path = os.path.join(bld.env.GAMEDIR, bld.env.CLIENT_INSTALL_DIR) + else: + install_path = bld.env.PREFIX + + bld.shlib( + source = source, + target = 'client' + bld.env.POSTFIX, + name = 'client', + features = 'c cxx', + includes = includes, + defines = defines, + use = libs, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/dlls/wscript b/dlls/wscript new file mode 100644 index 0000000..8c31674 --- /dev/null +++ b/dlls/wscript @@ -0,0 +1,108 @@ +#! /usr/bin/env python +# encoding: utf-8 +# a1batross, mittorn, 2018 + +from waflib import Utils +import os + +def options(opt): + return + +def configure(conf): + if conf.env.COMPILER_CC == 'msvc': + # hl.def removes MSVC function name decoration from GiveFnptrsToDll on Windows. + # Without this, the lookup for this function fails. + hlDefNode = conf.path.find_resource("./thewastes.def") + + if hlDefNode is not None: + conf.env.append_value('LINKFLAGS', '/def:%s' % hlDefNode.abspath()) + else: + conf.fatal("Could not find hl.def") + +def build(bld): + source = [ +'./animating.cpp', +'./animation.cpp', +'./bmodels.cpp', +'./buttons.cpp', +'./cbase.cpp', +'./client.cpp', +'./combat.cpp', +'./doors.cpp', +'./effects.cpp', +'./explode.cpp', +'./func_break.cpp', +'./func_tank.cpp', +'./game.cpp', +'./game_deathmatch.cpp', +'./game_lastmanstanding.cpp', +'./game_singleplay.cpp', +'./game_teamplay.cpp', +'./gamerules.cpp', +'./ggrenade.cpp', +'./globals.cpp', +'./h_ai.cpp', +'./h_cycler.cpp', +'./h_export.cpp', +'./items.cpp', +'./lights.cpp', +'./maprules.cpp', +'./monsters.cpp', +'./mortar.cpp', +'./nodes.cpp', +'./observer.cpp', +'./pathcorner.cpp', +'./plane.cpp', +'./plats.cpp', +'./player.cpp', +'../pm_shared/pm_debug.c', +'../pm_shared/pm_math.c', +'../pm_shared/pm_shared.c', +'./schedule.cpp', +'./scripted.cpp', +'./skill.cpp', +'./sound.cpp', +'./soundent.cpp', +'./spectator.cpp', +'./subs.cpp', +'./thewastes.cpp', +'./triggers.cpp', +'./turret.cpp', +'./wpn_shared/tw_akimbos.cpp', +'./wpn_shared/tw_automatics.cpp', +'./wpn_shared/tw_explosives.cpp', +'./wpn_shared/tw_melee.cpp', +'./wpn_shared/tw_shotguns.cpp', +'./wpn_shared/tw_sidearms.cpp', +'./util.cpp', +'../game_shared/voice_gamemgr.cpp', +'./weapons.cpp', +'./world.cpp', + ] + defines = [] + includes = [ + '.', + '../common', + '../engine', + '../pm_shared', + '../game_shared', + '../public' + ] + + if bld.env.DEST_OS not in ['android', 'dos']: + install_path = os.path.join(bld.env.GAMEDIR, bld.env.SERVER_INSTALL_DIR) + else: + install_path = bld.env.PREFIX + + bld.shlib( + source = source, + target = bld.env.SERVER_LIBRARY_NAME + bld.env.POSTFIX, + name = 'server', + features = 'c cxx', + includes = includes, + defines = defines, + install_path = install_path, + subsystem = bld.env.MSVC_SUBSYSTEM, + idx = bld.get_taskgen_count() + ) + diff --git a/mod_options.txt b/mod_options.txt new file mode 100644 index 0000000..a6b19d5 --- /dev/null +++ b/mod_options.txt @@ -0,0 +1,6 @@ +CLIENT_WEAPONS=ON +GAMEDIR=thewastes # Gamedir path +SERVER_INSTALL_DIR=dlls # Where put server dll +CLIENT_INSTALL_DIR=cl_dlls # Where put client dll +SERVER_LIBRARY_NAME=thewastes # Library name for PC platforms + diff --git a/public/build.h b/public/build.h new file mode 100644 index 0000000..2f8fffa --- /dev/null +++ b/public/build.h @@ -0,0 +1,261 @@ +/* +build.h - compile-time build information + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +*/ +#pragma once +#ifndef BUILD_H +#define BUILD_H + +/* +All XASH_* macros set by this header are guaranteed to have positive value +otherwise not defined. + +Every macro is intended to be the unified interface for buildsystems that lack +platform & CPU detection, and a neat quick way for checks in platform code +For Q_build* macros, refer to buildenums.h + +Any new define must be undefined at first +You can generate #undef list below with this oneliner: + $ sed 's/\t//g' build.h | grep '^#define XASH' | awk '{ print $2 }' | \ + sort | uniq | awk '{ print "#undef " $1 }' + +Then you can use another oneliner to query all variables: + $ grep '^#undef XASH' build.h | awk '{ print $2 }' +*/ + +#undef XASH_64BIT +#undef XASH_AMD64 +#undef XASH_ANDROID +#undef XASH_APPLE +#undef XASH_ARM +#undef XASH_ARM_HARDFP +#undef XASH_ARM_SOFTFP +#undef XASH_ARMv4 +#undef XASH_ARMv5 +#undef XASH_ARMv6 +#undef XASH_ARMv7 +#undef XASH_ARMv8 +#undef XASH_BIG_ENDIAN +#undef XASH_DOS4GW +#undef XASH_E2K +#undef XASH_EMSCRIPTEN +#undef XASH_FREEBSD +#undef XASH_HAIKU +#undef XASH_IOS +#undef XASH_IRIX +#undef XASH_JS +#undef XASH_LINUX +#undef XASH_LINUX_UNKNOWN +#undef XASH_LITTLE_ENDIAN +#undef XASH_MIPS +#undef XASH_MOBILE_PLATFORM +#undef XASH_NETBSD +#undef XASH_OPENBSD +#undef XASH_POSIX +#undef XASH_PPC +#undef XASH_RISCV +#undef XASH_RISCV_DOUBLEFP +#undef XASH_RISCV_SINGLEFP +#undef XASH_RISCV_SOFTFP +#undef XASH_SERENITY +#undef XASH_WIN32 +#undef XASH_X86 +#undef XASH_NSWITCH +#undef XASH_PSVITA + +//================================================================ +// +// PLATFORM DETECTION CODE +// +//================================================================ +#if defined _WIN32 + #define XASH_WIN32 1 +#elif defined __EMSCRIPTEN__ + #define XASH_EMSCRIPTEN 1 +#elif defined __WATCOMC__ && defined __DOS__ + #define XASH_DOS4GW 1 +#else // POSIX compatible + #define XASH_POSIX 1 + #if defined __linux__ + #if defined __ANDROID__ + #define XASH_ANDROID 1 + #else + #include + // if our system libc has features.h header + // try to detect it to not confuse other libcs with built with glibc game libraries + #if !defined __GLIBC__ + #define XASH_LINUX_UNKNOWN 1 + #endif + #endif + #define XASH_LINUX 1 + #elif defined __FreeBSD__ + #define XASH_FREEBSD 1 + #elif defined __NetBSD__ + #define XASH_NETBSD 1 + #elif defined __OpenBSD__ + #define XASH_OPENBSD 1 + #elif defined __HAIKU__ + #define XASH_HAIKU 1 + #elif defined __serenity__ + #define XASH_SERENITY 1 + #elif defined __sgi + #define XASH_IRIX 1 + #elif defined __APPLE__ + #include + #define XASH_APPLE 1 + #if TARGET_OS_IOS + #define XASH_IOS 1 + #endif // TARGET_OS_IOS + #elif defined __SWITCH__ + #define XASH_NSWITCH 1 + #elif defined __vita__ + #define XASH_PSVITA 1 + #else + #error + #endif +#endif + +// XASH_SAILFISH is special: SailfishOS by itself is a normal GNU/Linux platform +// It doesn't make sense to split it to separate platform +// but we still need XASH_MOBILE_PLATFORM for the engine. +// So this macro is defined entirely in build-system: see main wscript +// HLSDK/PrimeXT/other SDKs users note: you may ignore this macro +#if XASH_ANDROID || XASH_IOS || XASH_NSWITCH || XASH_PSVITA || XASH_SAILFISH + #define XASH_MOBILE_PLATFORM 1 +#endif + +//================================================================ +// +// ENDIANNESS DEFINES +// +//================================================================ + +#if !defined XASH_ENDIANNESS + #if defined XASH_WIN32 || __LITTLE_ENDIAN__ + //!!! Probably all WinNT installations runs in little endian + #define XASH_LITTLE_ENDIAN 1 + #elif __BIG_ENDIAN__ + #define XASH_BIG_ENDIAN 1 + #elif defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__ && defined __ORDER_LITTLE_ENDIAN__ // some compilers define this + #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + #define XASH_BIG_ENDIAN 1 + #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + #define XASH_LITTLE_ENDIAN 1 + #endif + #else + #include + #if __BYTE_ORDER == __BIG_ENDIAN + #define XASH_BIG_ENDIAN 1 + #elif __BYTE_ORDER == __LITTLE_ENDIAN + #define XASH_LITTLE_ENDIAN 1 + #endif + #endif // !XASH_WIN32 +#endif + +//================================================================ +// +// CPU ARCHITECTURE DEFINES +// +//================================================================ +#if defined __x86_64__ || defined _M_X64 + #define XASH_64BIT 1 + #define XASH_AMD64 1 +#elif defined __i386__ || defined _X86_ || defined _M_IX86 + #define XASH_X86 1 +#elif defined __aarch64__ || defined _M_ARM64 + #define XASH_64BIT 1 + #define XASH_ARM 8 +#elif defined __mips__ + #define XASH_MIPS 1 +#elif defined __EMSCRIPTEN__ + #define XASH_JS 1 +#elif defined __e2k__ + #define XASH_64BIT 1 + #define XASH_E2K 1 +#elif defined __PPC__ || defined __powerpc__ + #define XASH_PPC 1 + #if defined __PPC64__ || defined __powerpc64__ + #define XASH_64BIT 1 + #endif +#elif defined _M_ARM // msvc + #define XASH_ARM 7 + #define XASH_ARM_HARDFP 1 +#elif defined __arm__ + #if __ARM_ARCH == 8 || __ARM_ARCH_8__ + #define XASH_ARM 8 + #elif __ARM_ARCH == 7 || __ARM_ARCH_7__ + #define XASH_ARM 7 + #elif __ARM_ARCH == 6 || __ARM_ARCH_6__ || __ARM_ARCH_6J__ + #define XASH_ARM 6 + #elif __ARM_ARCH == 5 || __ARM_ARCH_5__ + #define XASH_ARM 5 + #elif __ARM_ARCH == 4 || __ARM_ARCH_4__ + #define XASH_ARM 4 + #else + #error "Unknown ARM" + #endif + + #if defined __SOFTFP__ || __ARM_PCS_VFP == 0 + #define XASH_ARM_SOFTFP 1 + #else // __SOFTFP__ + #define XASH_ARM_HARDFP 1 + #endif // __SOFTFP__ +#elif defined __riscv + #define XASH_RISCV 1 + + #if __riscv_xlen == 64 + #define XASH_64BIT 1 + #elif __riscv_xlen != 32 + #error "Unknown RISC-V ABI" + #endif + + #if defined __riscv_float_abi_soft + #define XASH_RISCV_SOFTFP 1 + #elif defined __riscv_float_abi_single + #define XASH_RISCV_SINGLEFP 1 + #elif defined __riscv_float_abi_double + #define XASH_RISCV_DOUBLEFP 1 + #else + #error "Unknown RISC-V float ABI" + #endif +#else + #error "Place your architecture name here! If this is a mistake, try to fix conditions above and report a bug" +#endif + +#if XASH_ARM == 8 + #define XASH_ARMv8 1 +#elif XASH_ARM == 7 + #define XASH_ARMv7 1 +#elif XASH_ARM == 6 + #define XASH_ARMv6 1 +#elif XASH_ARM == 5 + #define XASH_ARMv5 1 +#elif XASH_ARM == 4 + #define XASH_ARMv4 1 +#endif + +#endif // BUILD_H diff --git a/scripts/waifulib/compiler_optimizations.py b/scripts/waifulib/compiler_optimizations.py new file mode 100644 index 0000000..9cc81b7 --- /dev/null +++ b/scripts/waifulib/compiler_optimizations.py @@ -0,0 +1,180 @@ +# encoding: utf-8 +# compiler_optimizations.py -- main entry point for configuring C/C++ compilers +# Copyright (C) 2021 a1batross +# 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. + +try: from fwgslib import get_flags_by_type, get_flags_by_compiler +except: from waflib.extras.fwgslib import get_flags_by_type, get_flags_by_compiler +from waflib.Configure import conf +from waflib import Logs + +''' +Flags can be overriden and new types can be added +by importing this as normal Python module + +Example: +#!/usr/bin/env python +from waflib.extras import compiler_optimizations + +compiler_optimizations.VALID_BUILD_TYPES += 'gottagofast' +compiler_optimizations.CFLAGS['gottagofast'] = { + 'gcc': ['-Ogentoo'] +} +''' + +VALID_BUILD_TYPES = ['fastnative', 'fast', 'release', 'debug', 'sanitize', 'msan', 'none'] + +LINKFLAGS = { + 'common': { + 'msvc': ['/DEBUG'], # always create PDB, doesn't affect result binaries + 'gcc': ['-Wl,--no-undefined'], + 'owcc': ['-Wl,option stack=512k'] + }, + 'msan': { + 'clang': ['-fsanitize=memory', '-pthread'], + 'default': ['NO_MSAN_HERE'] + }, + 'sanitize': { + 'clang': ['-fsanitize=undefined', '-fsanitize=address', '-pthread'], + 'gcc': ['-fsanitize=undefined', '-fsanitize=address', '-pthread'], + 'msvc': ['/SAFESEH:NO'] + }, + 'debug': { + 'msvc': ['/INCREMENTAL', '/SAFESEH:NO'] + } +} + +CFLAGS = { + 'common': { + # disable thread-safe local static initialization for C++11 code, as it cause crashes on Windows XP + 'msvc': ['/D_USING_V110_SDK71_', '/FS', '/Zc:threadSafeInit-', '/MT', '/MP', '/Zc:__cplusplus'], + 'clang': ['-g', '-gdwarf-2', '-fvisibility=hidden', '-fno-threadsafe-statics'], + 'gcc': ['-g', '-fvisibility=hidden'], + 'owcc': ['-fno-short-enum', '-ffloat-store', '-g3'] + }, + 'fast': { + 'msvc': ['/O2', '/Oy', '/Zi'], + 'gcc': { + '3': ['-O3', '-fomit-frame-pointer'], + 'default': ['-Ofast', '-funsafe-math-optimizations', '-funsafe-loop-optimizations', '-fomit-frame-pointer'] + }, + 'clang': ['-Ofast'], + 'default': ['-O3'] + }, + 'fastnative': { + 'msvc': ['/O2', '/Oy', '/Zi'], + 'gcc': ['-Ofast', '-march=native', '-funsafe-math-optimizations', '-funsafe-loop-optimizations', '-fomit-frame-pointer'], + 'clang': ['-Ofast', '-march=native'], + 'default': ['-O3'] + }, + 'release': { + 'msvc': ['/O2', '/Zi'], + 'owcc': ['-O3', '-foptimize-sibling-calls', '-fomit-leaf-frame-pointer', '-fomit-frame-pointer', '-fschedule-insns', '-funsafe-math-optimizations', '-funroll-loops', '-frerun-optimizer', '-finline-functions', '-finline-limit=512', '-fguess-branch-probability', '-fno-strict-aliasing', '-floop-optimize'], + 'default': ['-O3'] + }, + 'debug': { + 'msvc': ['/Od', '/ZI'], + 'owcc': ['-O0', '-fno-omit-frame-pointer', '-funwind-tables', '-fno-omit-leaf-frame-pointer'], + 'default': ['-O0'] + }, + 'msan': { + 'clang': ['-O2', '-g', '-fno-omit-frame-pointer', '-fsanitize=memory', '-pthread'], + 'default': ['NO_MSAN_HERE'] + }, + 'sanitize': { + 'msvc': ['/Od', '/RTC1', '/Zi', '/fsanitize=address'], + 'gcc': ['-O0', '-fsanitize=undefined', '-fsanitize=address', '-pthread'], + 'clang': ['-O0', '-fsanitize=undefined', '-fsanitize=address', '-pthread'], + 'default': ['-O0'] + }, +} + +LTO_CFLAGS = { + 'msvc': ['/GL'], + 'gcc': ['-flto'], + 'clang': ['-flto'] +} + +LTO_LINKFLAGS = { + 'msvc': ['/LTCG'], + 'gcc': ['-flto'], + 'clang': ['-flto'] +} + +POLLY_CFLAGS = { + 'gcc': ['-fgraphite-identity'], + 'clang': ['-mllvm', '-polly'] + # msvc sosat :( +} + +def options(opt): + grp = opt.add_option_group('Compiler optimization options') + + grp.add_option('-T', '--build-type', action='store', dest='BUILD_TYPE', default='release', + help = 'build type: debug, release or none(custom flags)') + + grp.add_option('--enable-lto', action = 'store_true', dest = 'LTO', default = False, + help = 'enable Link Time Optimization if possible [default: %default]') + + grp.add_option('--enable-poly-opt', action = 'store_true', dest = 'POLLY', default = False, + help = 'enable polyhedral optimization if possible [default: %default]') + +def configure(conf): + conf.start_msg('Build type') + + if not conf.options.BUILD_TYPE in VALID_BUILD_TYPES: + conf.end_msg(conf.options.BUILD_TYPE, color='RED') + conf.fatal('Invalid build type. Valid are: %s' % ', '.join(VALID_BUILD_TYPES)) + + conf.end_msg(conf.options.BUILD_TYPE) + + conf.msg('LTO build', 'yes' if conf.options.LTO else 'no') + conf.msg('PolyOpt build', 'yes' if conf.options.POLLY else 'no') + + # -march=native should not be used + if conf.options.BUILD_TYPE.startswith('fast'): + Logs.warn('WARNING: \'%s\' build type should not be used in release builds', conf.options.BUILD_TYPE) + + try: + conf.env.CC_VERSION[0] + except IndexError: + conf.env.CC_VERSION = (0,) + +@conf +def get_optimization_flags(conf): + '''Returns a list of compile flags, + depending on build type and options set by user + + NOTE: it doesn't filter out unsupported flags + + :returns: tuple of cflags and linkflags + ''' + linkflags = conf.get_flags_by_type(LINKFLAGS, conf.options.BUILD_TYPE, conf.env.COMPILER_CC, conf.env.CC_VERSION[0]) + + cflags = conf.get_flags_by_type(CFLAGS, conf.options.BUILD_TYPE, conf.env.COMPILER_CC, conf.env.CC_VERSION[0]) + + if conf.options.LTO: + linkflags+= conf.get_flags_by_compiler(LTO_LINKFLAGS, conf.env.COMPILER_CC) + cflags += conf.get_flags_by_compiler(LTO_CFLAGS, conf.env.COMPILER_CC) + + if conf.options.POLLY: + cflags += conf.get_flags_by_compiler(POLLY_CFLAGS, conf.env.COMPILER_CC) + + if conf.env.DEST_OS == 'nswitch' and conf.options.BUILD_TYPE == 'debug': + # enable remote debugger + cflags.append('-DNSWITCH_DEBUG') + elif conf.env.DEST_OS == 'psvita': + # this optimization is broken in vitasdk + cflags.append('-fno-optimize-sibling-calls') + # remove fvisibility to allow everything to be exported by default + cflags.remove('-fvisibility=hidden') + + return cflags, linkflags diff --git a/scripts/waifulib/library_naming.py b/scripts/waifulib/library_naming.py new file mode 100644 index 0000000..4369b3b --- /dev/null +++ b/scripts/waifulib/library_naming.py @@ -0,0 +1,178 @@ +#! /usr/bin/env python +# Copyright 2019 (C) a1batross + +from waflib import Configure, Errors, Utils + +# TODO: make generic +CHECK_SYMBOL_EXISTS_FRAGMENT = ''' +#include "build.h" + +int main(int argc, char** argv) +{ + (void)argv; +#ifndef %s + return ((int*)(&%s))[argc]; +#else + (void)argc; + return 0; +#endif +} +''' + +# generated(see comments in public/build.h) +# cat build.h | grep '^#undef XASH' | awk '{ print "'\''" $2 "'\''," }' +DEFINES = [ +'XASH_64BIT', +'XASH_AMD64', +'XASH_ANDROID', +'XASH_APPLE', +'XASH_ARM', +'XASH_ARM_HARDFP', +'XASH_ARM_SOFTFP', +'XASH_ARMv4', +'XASH_ARMv5', +'XASH_ARMv6', +'XASH_ARMv7', +'XASH_ARMv8', +'XASH_BIG_ENDIAN', +'XASH_DOS4GW', +'XASH_E2K', +'XASH_EMSCRIPTEN', +'XASH_FREEBSD', +'XASH_HAIKU', +'XASH_IOS', +'XASH_IRIX', +'XASH_JS', +'XASH_LINUX', +'XASH_LINUX_UNKNOWN', +'XASH_LITTLE_ENDIAN', +'XASH_MIPS', +'XASH_MOBILE_PLATFORM', +'XASH_NETBSD', +'XASH_OPENBSD', +'XASH_POSIX', +'XASH_PPC', +'XASH_RISCV', +'XASH_RISCV_DOUBLEFP', +'XASH_RISCV_SINGLEFP', +'XASH_RISCV_SOFTFP', +'XASH_SERENITY', +'XASH_WIN32', +'XASH_X86', +'XASH_NSWITCH', +'XASH_PSVITA', +] + +def configure(conf): + conf.env.stash() + conf.start_msg('Determining library postfix') + tests = map(lambda x: { + 'fragment': CHECK_SYMBOL_EXISTS_FRAGMENT % (x, x), + 'includes': [conf.path.find_node('public/').abspath()], + 'define_name': x }, DEFINES ) + + conf.multicheck(*tests, msg = '', mandatory = False, quiet = True) + + # engine/common/build.c + if conf.env.XASH_ANDROID: + buildos = "android" + elif conf.env.XASH_LINUX_UNKNOWN: + buildos = "linuxunkabi" + elif conf.env.XASH_WIN32 or conf.env.XASH_LINUX or conf.env.XASH_APPLE: + buildos = "" # no prefix for default OS + elif conf.env.XASH_FREEBSD: + buildos = "freebsd" + elif conf.env.XASH_NETBSD: + buildos = "netbsd" + elif conf.env.XASH_OPENBSD: + buildos = "openbsd" + elif conf.env.XASH_EMSCRIPTEN: + buildos = "emscripten" + elif conf.env.XASH_DOS4GW: + buildos = "dos4gw" # unused, just in case + elif conf.env.XASH_HAIKU: + buildos = "haiku" + elif conf.env.XASH_SERENITY: + buildos = "serenityos" + elif conf.env.XASH_NSWITCH: + buildos = "nswitch" + elif conf.env.XASH_PSVITA: + buildos = "psvita" + elif conf.env.XASH_IRIX: + buildos = "irix" + else: + conf.fatal("Place your operating system name in build.h and library_naming.py!\n" + "If this is a mistake, try to fix conditions above and report a bug") + + if conf.env.XASH_AMD64: + buildarch = "amd64" + elif conf.env.XASH_X86: + if conf.env.XASH_WIN32 or conf.env.XASH_LINUX or conf.env.XASH_APPLE: + buildarch = "" + else: + buildarch = "i386" + elif conf.env.XASH_ARM and conf.env.XASH_64BIT: + buildarch = "arm64" + elif conf.env.XASH_ARM: + buildarch = "armv" + if conf.env.XASH_ARMv8: + buildarch += "8_32" + elif conf.env.XASH_ARMv7: + buildarch += "7" + elif conf.env.XASH_ARMv6: + buildarch += "6" + elif conf.env.XASH_ARMv5: + buildarch += "5" + elif conf.env.XASH_ARMv4: + buildarch += "4" + else: + raise conf.fatal('Unknown ARM') + + if conf.env.XASH_ARM_HARDFP: + buildarch += "hf" + else: + buildarch += "l" + elif conf.env.XASH_MIPS: + buildarch = "mips" + if conf.env.XASH_64BIT: + buildarch += "64" + if conf.env.XASH_LITTLE_ENDIAN: + buildarch += "el" + elif conf.env.XASH_RISCV: + buildarch = "riscv" + if conf.env.XASH_64BIT: + buildarch += "64" + else: + buildarch += "32" + + if conf.env.XASH_RISCV_DOUBLEFP: + buildarch += "d" + elif conf.env.XASH_RISCV_SINGLEFP: + buildarch += "f" + elif conf.env.XASH_JS: + buildarch = "javascript" + elif conf.env.XASH_E2K: + buildarch = "e2k" + elif conf.env.XASH_PPC: + buildarch = "ppc" + if conf.env.XASH_64BIT: + buildarch += "64" + if conf.env.XASH_LITTLE_ENDIAN: + buildarch += "el" + else: + raise conf.fatal("Place your architecture name in build.h and library_naming.py!\n" + "If this is a mistake, try to fix conditions above and report a bug") + + conf.env.revert() + + if buildos == 'android': + # force disable for Android, as Android ports aren't distributed in normal way and doesn't follow library naming + conf.env.POSTFIX = '' + elif buildos != '' and buildarch != '': + conf.env.POSTFIX = '_%s_%s' % (buildos,buildarch) + elif buildarch != '': + conf.env.POSTFIX = '_%s' % buildarch + else: + conf.env.POSTFIX = '' + + conf.end_msg(conf.env.POSTFIX) diff --git a/scripts/waifulib/strip_on_install.py b/scripts/waifulib/strip_on_install.py new file mode 100644 index 0000000..6522065 --- /dev/null +++ b/scripts/waifulib/strip_on_install.py @@ -0,0 +1,49 @@ +#! /usr/bin/env python +# Modified: Alibek Omarov +# Originally taken from Thomas Nagy's blogpost + +""" +Strip executables upon installation +""" + +import shutil, os +from waflib import Build, Utils, Context, Errors, Logs + +def options(opt): + grp = opt.option_groups['install/uninstall options'] + grp.add_option('--no-strip', dest='no_strip', action='store_true', default=False, + help='don\'t strip binaries. You must pass this flag to install command(default: False)') + +def configure(conf): + if conf.env.DEST_BINFMT in ['elf', 'mac-o']: + conf.find_program('strip', var='STRIP') + if not conf.env.STRIPFLAGS: + conf.env.STRIPFLAGS = os.environ['STRIPFLAGS'] if 'STRIPFLAGS' in os.environ else [] + +def copy_fun(self, src, tgt): + inst_copy_fun(self, src, tgt) + + if self.generator.bld.options.no_strip: + return + + if self.env.DEST_BINFMT not in ['elf', 'mac-o']: # don't strip unknown formats or PE + return + + if getattr(self.generator, 'link_task', None) and self.generator.link_task.outputs[0] in self.inputs: + cmd = self.env.STRIP + self.env.STRIPFLAGS + [tgt] + try: + self.generator.bld.cmd_and_log(cmd, output=Context.BOTH, quiet=Context.BOTH) + if not self.generator.bld.progress_bar: + c1 = Logs.colors.NORMAL + c2 = Logs.colors.CYAN + + f1 = os.path.getsize(src) + f2 = os.path.getsize(tgt) + + Logs.info('%s+ strip %s%s%s (%d bytes change)', c1, c2, tgt, c1, f2 - f1) + except Errors.WafError as e: + print(e.stdout, e.stderr) + +inst_copy_fun = Build.inst.copy_fun +Build.inst.copy_fun = copy_fun + diff --git a/scripts/waifulib/vgui.py b/scripts/waifulib/vgui.py new file mode 100644 index 0000000..7f1b5a6 --- /dev/null +++ b/scripts/waifulib/vgui.py @@ -0,0 +1,79 @@ +#! /usr/bin/env python +# encoding: utf-8 +# mittorn, 2018 + +from waflib.Configure import conf +import os + +VGUI_SUPPORTED_OS = ['win32', 'darwin', 'linux'] + +VGUI_FRAGMENT = '''#include +int main() { return 0; }''' + +def options(opt): + grp = opt.add_option_group('VGUI options') + + vgui_dev_path = os.path.join(opt.path.path_from(opt.path), 'vgui_support', 'vgui-dev') + + grp.add_option('--vgui', action = 'store', dest = 'VGUI_DEV', default=vgui_dev_path, + help = 'path to vgui-dev repo [default: %default]') + + grp.add_option('--skip-vgui-sanity-check', action = 'store_false', dest = 'VGUI_SANITY_CHECK', default=True, + help = 'skip checking VGUI sanity [default: %default]' ) + return + +@conf +def check_vgui(conf): + conf.start_msg('Does this architecture support VGUI?') + + if conf.env.DEST_CPU != 'x86' and not (conf.env.DEST_CPU == 'x86_64' and not conf.options.ALLOW64): + conf.end_msg('no') + Logs.warn('vgui is not supported on this CPU: ' + str(conf.env.DEST_CPU)) + return False + else: conf.end_msg('yes') + + conf.start_msg('Does this OS support VGUI?') + if conf.env.DEST_OS not in VGUI_SUPPORTED_OS: + conf.end_msg('no') + Logs.warn('vgui is not supported on this OS: ' + str(conf.env.DEST_OS)) + return False + else: conf.end_msg('yes') + + conf.start_msg('Does this toolchain able to link VGUI?') + if conf.env.DEST_OS == 'win32' and conf.env.COMPILER_CXX == 'g++': + conf.end_msg('no') + # we have ABI incompatibility ONLY on MinGW + Logs.warn('vgui can\'t be linked with MinGW') + return False + else: conf.end_msg('yes') + + conf.start_msg('Configuring VGUI by provided path') + vgui_dev = conf.options.VGUI_DEV + + if conf.env.DEST_OS == 'win32': + conf.env.LIB_VGUI = ['vgui'] + conf.env.LIBPATH_VGUI = [os.path.abspath(os.path.join(vgui_dev, 'lib/win32_vc6/'))] + else: + libpath = os.path.abspath(os.path.join(vgui_dev, 'lib')) + if conf.env.DEST_OS == 'linux': + conf.env.LIB_VGUI = [':vgui.so'] + conf.env.LIBPATH_VGUI = [libpath] + elif conf.env.DEST_OS == 'darwin': + conf.env.LDFLAGS_VGUI = [os.path.join(libpath, 'vgui.dylib')] + else: + conf.fatal('vgui is not supported on this OS: ' + conf.env.DEST_OS) + conf.env.INCLUDES_VGUI = [os.path.abspath(os.path.join(vgui_dev, 'include'))] + + conf.env.HAVE_VGUI = 1 + conf.end_msg('yes: {0}, {1}, {2}'.format(conf.env.LIB_VGUI, conf.env.LIBPATH_VGUI, conf.env.INCLUDES_VGUI)) + + if conf.env.HAVE_VGUI and conf.options.VGUI_SANITY_CHECK: + try: + conf.check_cxx(fragment=VGUI_FRAGMENT, + msg = 'Checking for library VGUI sanity', + use = 'VGUI', + execute = False) + except conf.errors.ConfigurationError: + conf.fatal("Can't compile simple program. Check your path to vgui-dev repository.") + + return True diff --git a/scripts/waifulib/xcompile.py b/scripts/waifulib/xcompile.py new file mode 100644 index 0000000..08e9022 --- /dev/null +++ b/scripts/waifulib/xcompile.py @@ -0,0 +1,660 @@ +# encoding: utf-8 +# xcompile.py -- crosscompiling utils +# Copyright (C) 2018 a1batross +# 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. + +try: from fwgslib import get_flags_by_compiler +except: from waflib.extras.fwgslib import get_flags_by_compiler +from waflib import Logs, TaskGen +from waflib.Tools import c_config +from collections import OrderedDict +import os +import sys + +ANDROID_NDK_ENVVARS = ['ANDROID_NDK_HOME', 'ANDROID_NDK'] +ANDROID_NDK_SUPPORTED = [10, 19, 20, 23, 25] +ANDROID_NDK_HARDFP_MAX = 11 # latest version that supports hardfp +ANDROID_NDK_GCC_MAX = 17 # latest NDK that ships with GCC +ANDROID_NDK_UNIFIED_SYSROOT_MIN = 15 +ANDROID_NDK_SYSROOT_FLAG_MAX = 19 # latest NDK that need --sysroot flag +ANDROID_NDK_API_MIN = { 10: 3, 19: 16, 20: 16, 23: 16, 25: 19 } # minimal API level ndk revision supports + +ANDROID_STPCPY_API_MIN = 21 # stpcpy() introduced in SDK 21 +ANDROID_64BIT_API_MIN = 21 # minimal API level that supports 64-bit targets + +NSWITCH_ENVVARS = ['DEVKITPRO'] + +PSVITA_ENVVARS = ['VITASDK'] + +# This class does support ONLY r10e and r19c/r20 NDK +class Android: + ctx = None # waf context + arch = None + toolchain = None + api = None + ndk_home = None + ndk_rev = 0 + is_hardfloat = False + clang = False + + def __init__(self, ctx, arch, toolchain, api): + self.ctx = ctx + self.api = api + self.toolchain = toolchain + self.arch = arch + + for i in ANDROID_NDK_ENVVARS: + self.ndk_home = os.getenv(i) + if self.ndk_home != None: + break + else: + ctx.fatal('Set %s environment variable pointing to the root of Android NDK!' % + ' or '.join(ANDROID_NDK_ENVVARS)) + + # TODO: this were added at some point of NDK development + # but I don't know at which version + # r10e don't have it + source_prop = os.path.join(self.ndk_home, 'source.properties') + if os.path.exists(source_prop): + with open(source_prop) as ndk_props_file: + for line in ndk_props_file.readlines(): + tokens = line.split('=') + trimed_tokens = [token.strip() for token in tokens] + + if 'Pkg.Revision' in trimed_tokens: + self.ndk_rev = int(trimed_tokens[1].split('.')[0]) + + if self.ndk_rev not in ANDROID_NDK_SUPPORTED: + ctx.fatal('Unknown NDK revision: %d' % (self.ndk_rev)) + else: + self.ndk_rev = ANDROID_NDK_SUPPORTED[0] + + if 'clang' in self.toolchain or self.ndk_rev > ANDROID_NDK_GCC_MAX: + self.clang = True + + if self.arch == 'armeabi-v7a-hard': + if self.ndk_rev <= ANDROID_NDK_HARDFP_MAX: + self.arch = 'armeabi-v7a' # Only armeabi-v7a have hard float ABI + self.is_hardfloat = True + else: + ctx.fatal('NDK does not support hardfloat ABI') + + if self.api < ANDROID_NDK_API_MIN[self.ndk_rev]: + self.api = ANDROID_NDK_API_MIN[self.ndk_rev] + Logs.warn('API level automatically was set to %d due to NDK support' % self.api) + + if self.is_arm64() or self.is_amd64() and self.api < ANDROID_64BIT_API_MIN: + self.api = ANDROID_64BIT_API_MIN + Logs.warn('API level for 64-bit target automatically was set to %d' % self.api) + + def is_host(self): + ''' + Checks if we using host compiler(implies clang) + ''' + return self.toolchain == 'host' + + def is_arm(self): + ''' + Checks if selected architecture is **32-bit** ARM + ''' + return self.arch.startswith('armeabi') + + def is_x86(self): + ''' + Checks if selected architecture is **32-bit** or **64-bit** x86 + ''' + return self.arch == 'x86' + + def is_amd64(self): + ''' + Checks if selected architecture is **64-bit** x86 + ''' + return self.arch == 'x86_64' + + def is_arm64(self): + ''' + Checks if selected architecture is AArch64 + ''' + return self.arch == 'aarch64' + + def is_clang(self): + ''' + Checks if selected toolchain is Clang (TODO) + ''' + return self.clang + + def is_hardfp(self): + return self.is_hardfloat + + def ndk_triplet(self, llvm_toolchain = False, toolchain_folder = False): + if self.is_x86(): + if toolchain_folder: + return 'x86' + else: + return 'i686-linux-android' + elif self.is_arm(): + if llvm_toolchain: + return 'armv7a-linux-androideabi' + else: + return 'arm-linux-androideabi' + elif self.is_amd64() and toolchain_folder: + return 'x86_64' + else: + return self.arch + '-linux-android' + + def apk_arch(self): + if self.is_arm64(): + return 'arm64-v8a' + return self.arch + + def gen_host_toolchain(self): + # With host toolchain we don't care about OS + # so just download NDK for Linux x86_64 + if 'HOST_TOOLCHAIN' in self.ctx.environ: + return self.ctx.environ['HOST_TOOLCHAIN'] + if self.is_host(): + return 'linux-x86_64' + + if sys.platform.startswith('win32') or sys.platform.startswith('cygwin'): + osname = 'windows' + elif sys.platform.startswith('darwin'): + osname = 'darwin' + elif sys.platform.startswith('linux'): + osname = 'linux' + else: + self.ctx.fatal('Unsupported by NDK host platform') + + if sys.maxsize > 2**32: + arch = 'x86_64' + else: arch = 'x86' + + return '%s-%s' % (osname, arch) + + def gen_gcc_toolchain_path(self): + path = 'toolchains' + toolchain_host = self.gen_host_toolchain() + + if self.is_clang(): + toolchain_folder = 'llvm' + else: + if self.is_host(): + toolchain = '4.9' + else: + toolchain = self.toolchain + + toolchain_folder = '%s-%s' % (self.ndk_triplet(toolchain_folder = True), toolchain) + + return os.path.abspath(os.path.join(self.ndk_home, path, toolchain_folder, 'prebuilt', toolchain_host)) + + def gen_toolchain_path(self): + if self.is_clang(): + triplet = '%s%d-' % (self.ndk_triplet(llvm_toolchain = True), self.api) + else: + triplet = self.ndk_triplet() + '-' + return os.path.join(self.gen_gcc_toolchain_path(), 'bin', triplet) + + def gen_binutils_path(self): + if self.ndk_rev >= 23: + return os.path.join(self.gen_gcc_toolchain_path(), 'bin') + return os.path.join(self.gen_gcc_toolchain_path(), self.ndk_triplet(), 'bin') + + def cc(self): + if self.is_host(): + s = 'clang' + environ = getattr(self.ctx, 'environ', os.environ) + + if 'CC' in environ: + s = environ['CC'] + + return '%s --target=%s%d' % (s, self.ndk_triplet(), self.api) + return self.gen_toolchain_path() + ('clang' if self.is_clang() else 'gcc') + + def cxx(self): + if self.is_host(): + s = 'clang++' + environ = getattr(self.ctx, 'environ', os.environ) + + if 'CXX' in environ: + s = environ['CXX'] + + return '%s --target=%s%d' % (s, self.ndk_triplet(), self.api) + return self.gen_toolchain_path() + ('clang++' if self.is_clang() else 'g++') + + def strip(self): + if self.is_host(): + environ = getattr(self.ctx, 'environ', os.environ) + + if 'STRIP' in environ: + return environ['STRIP'] + return 'llvm-strip' + + if self.ndk_rev >= 23: + return os.path.join(self.gen_binutils_path(), 'llvm-strip') + return os.path.join(self.gen_binutils_path(), 'strip') + + def system_stl(self): + # TODO: proper STL support + return os.path.abspath(os.path.join(self.ndk_home, 'sources', 'cxx-stl', 'system', 'include')) + + def libsysroot(self): + arch = self.arch + if self.is_arm(): + arch = 'arm' + elif self.is_arm64(): + arch = 'arm64' + path = 'platforms/android-%s/arch-%s' % (self.api, arch) + + return os.path.abspath(os.path.join(self.ndk_home, path)) + + def sysroot(self): + if self.ndk_rev >= ANDROID_NDK_UNIFIED_SYSROOT_MIN: + return os.path.abspath(os.path.join(self.ndk_home, 'sysroot')) + else: + return self.libsysroot() + + def cflags(self, cxx = False): + cflags = [] + + if self.ndk_rev <= ANDROID_NDK_SYSROOT_FLAG_MAX: + cflags += ['--sysroot=%s' % (self.sysroot())] + else: + if self.is_host(): + cflags += [ + '--sysroot=%s/sysroot' % (self.gen_gcc_toolchain_path()), + '-isystem', '%s/usr/include/' % (self.sysroot()) + ] + + cflags += ['-I%s' % (self.system_stl())] + if not self.is_clang(): + cflags += ['-DANDROID', '-D__ANDROID__'] + + if cxx and not self.is_clang() and self.toolchain not in ['4.8','4.9']: + cflags += ['-fno-sized-deallocation'] + + if self.is_clang(): + # stpcpy() isn't available in early Android versions + # disable it here so Clang won't use it + if self.api < ANDROID_STPCPY_API_MIN: + cflags += ['-fno-builtin-stpcpy'] + + if self.is_arm(): + if self.arch == 'armeabi-v7a': + # ARMv7 support + cflags += ['-mthumb', '-mfpu=neon', '-mcpu=cortex-a9'] + + if self.is_hardfp(): + cflags += ['-D_NDK_MATH_NO_SOFTFP=1', '-mfloat-abi=hard', '-DLOAD_HARDFP', '-DSOFTFP_LINK'] + + if self.is_host(): + # Clang builtin redefine w/ different calling convention bug + # NOTE: I did not added complex.h functions here, despite + # that NDK devs forgot to put __NDK_FPABI_MATH__ for complex + # math functions + # I personally don't need complex numbers support, but if you want it + # just run sed to patch header + for f in ['strtod', 'strtof', 'strtold']: + cflags += ['-fno-builtin-%s' % f] + else: + cflags += ['-mfloat-abi=softfp'] + else: + # ARMv5 support + cflags += ['-march=armv5te', '-msoft-float'] + elif self.is_x86(): + cflags += ['-mtune=atom', '-march=atom', '-mssse3', '-mfpmath=sse'] + return cflags + + # they go before object list + def linkflags(self): + linkflags = [] + if self.is_host(): + linkflags += ['--gcc-toolchain=%s' % self.gen_gcc_toolchain_path()] + + if self.ndk_rev <= ANDROID_NDK_SYSROOT_FLAG_MAX: + linkflags += ['--sysroot=%s' % (self.sysroot())] + elif self.is_host(): + linkflags += ['--sysroot=%s/sysroot' % (self.gen_gcc_toolchain_path())] + + if self.is_clang() or self.is_host(): + linkflags += ['-fuse-ld=lld'] + else: linkflags += ['-no-canonical-prefixes'] + + linkflags += ['-Wl,--hash-style=sysv', '-Wl,--no-undefined'] + return linkflags + + def ldflags(self): + ldflags = [] + + if self.ndk_rev < 23: + ldflags += ['-lgcc'] + + if self.is_clang() or self.is_host(): + ldflags += ['-stdlib=libstdc++'] + else: ldflags += ['-no-canonical-prefixes'] + + if self.is_arm(): + if self.arch == 'armeabi-v7a': + ldflags += ['-march=armv7-a', '-mthumb'] + + if not self.is_clang() and not self.is_host(): # lld only + ldflags += ['-Wl,--fix-cortex-a8'] + + if self.is_hardfp(): + ldflags += ['-Wl,--no-warn-mismatch', '-lm_hard'] + else: + ldflags += ['-march=armv5te'] + return ldflags + +class NintendoSwitch: + ctx = None # waf context + arch = "arm64" + dkp_dir = None + portlibs_dir = None + dka64_dir = None + libnx_dir = None + + def __init__(self, ctx): + self.ctx = ctx + + for i in NSWITCH_ENVVARS: + self.dkp_dir = os.getenv(i) + if self.dkp_dir != None: + break + else: + ctx.fatal('Set %s environment variable pointing to the DEVKITPRO home!' % + ' or '.join(NSWITCH_ENVVARS)) + + self.dkp_dir = os.path.abspath(self.dkp_dir) + + self.dka64_dir = os.path.join(self.dkp_dir, 'devkitA64') + if not os.path.exists(self.dka64_dir): + ctx.fatal('devkitA64 not found in `%s`. Install devkitA64!' % self.dka64_dir) + + self.libnx_dir = os.path.join(self.dkp_dir, 'libnx') + if not os.path.exists(self.libnx_dir): + ctx.fatal('libnx not found in `%s`. Install libnx!' % self.libnx_dir) + + self.portlibs_dir = os.path.join(self.dkp_dir, 'portlibs', 'switch') + if not os.path.exists(self.portlibs_dir): + ctx.fatal('No Switch libraries found in `%s`!' % self.portlibs_dir) + + def gen_toolchain_prefix(self): + return 'aarch64-none-elf-' + + def gen_gcc_toolchain_path(self): + return os.path.join(self.dka64_dir, 'bin', self.gen_toolchain_prefix()) + + def cc(self): + return self.gen_gcc_toolchain_path() + 'gcc' + + def cxx(self): + return self.gen_gcc_toolchain_path() + 'g++' + + def strip(self): + return self.gen_gcc_toolchain_path() + 'strip' + + def pkgconfig(self): + # counter-intuitively, this motherfucker is in $DEVKITPRO/portlibs/switch/bin + return os.path.join(self.portlibs_dir, 'bin', self.gen_toolchain_prefix() + 'pkg-config') + + def cflags(self, cxx = False): + cflags = [] + # arch flags + cflags += ['-D__SWITCH__', '-march=armv8-a+crc+crypto', '-mtune=cortex-a57', '-mtp=soft', '-ftls-model=local-exec', '-fPIE'] + # help the linker out + cflags += ['-ffunction-sections', '-fdata-sections'] + # base include dirs + cflags += ['-isystem %s/include' % self.libnx_dir, '-I%s/include' % self.portlibs_dir] + # the game wants GNU extensions + if cxx: + cflags += ['-std=gnu++17', '-D_GNU_SOURCE'] + else: + cflags += ['-std=gnu11', '-D_GNU_SOURCE'] + return cflags + + # they go before object list + def linkflags(self): + linkflags = ['-fPIE', '-specs=%s/switch.specs' % self.libnx_dir] + # libsolder only supports sysv hashes and we need to build everything with -rdynamic + linkflags += ['-Wl,--hash-style=sysv', '-rdynamic'] + # avoid pulling in and exposing mesa's internals, that crashes it for some god forsaken reason + linkflags += ['-Wl,--exclude-libs=libglapi.a', '-Wl,--exclude-libs=libdrm_nouveau.a'] + return linkflags + + def ldflags(self): + # NOTE: shared libraries should be built without standard libs, so that they could import their contents from the NRO, + # but executables, including the SDL2 sanity check, will generally require libstdc++ and libm, which we will add manually + ldflags = [] # ['-lm', '-lstdc++'] + return ldflags + +class PSVita: + ctx = None # waf context + arch ='armeabi-v7a-hard' + vitasdk_dir = None + + def __init__(self, ctx): + self.ctx = ctx + + for i in PSVITA_ENVVARS: + self.vitasdk_dir = os.getenv(i) + if self.vitasdk_dir != None: + break + else: + ctx.fatal('Set %s environment variable pointing to the VitaSDK directory!' % + ' or '.join(PSVITA_ENVVARS)) + + def gen_toolchain_prefix(self): + return 'arm-vita-eabi-' + + def gen_gcc_toolchain_path(self): + return os.path.join(self.vitasdk_dir, 'bin', self.gen_toolchain_prefix()) + + def cc(self): + return self.gen_gcc_toolchain_path() + 'gcc' + + def cxx(self): + return self.gen_gcc_toolchain_path() + 'g++' + + def strip(self): + return self.gen_gcc_toolchain_path() + 'strip' + + def ar(self): + return self.gen_gcc_toolchain_path() + 'ar' + + def pkgconfig(self): + return self.gen_gcc_toolchain_path() + 'pkg-config' + + def cflags(self, cxx = False): + cflags = [] + # arch flags + cflags += ['-D__vita__', '-mtune=cortex-a9', '-mfpu=neon'] + # necessary linker flags + cflags += ['-Wl,-q', '-Wl,-z,nocopyreloc'] + # this optimization is broken in vitasdk + cflags += ['-fno-optimize-sibling-calls'] + # disable some ARM bullshit + cflags += ['-fno-short-enums', '-Wno-attributes'] + # base include dir + cflags += ['-isystem %s/arm-vita-eabi/include' % self.vitasdk_dir] + # SDL include dir + cflags += ['-I%s/arm-vita-eabi/include/SDL2' % self.vitasdk_dir] + return cflags + + # they go before object list + def linkflags(self): + linkflags = ['-Wl,--hash-style=sysv', '-Wl,-q', '-Wl,-z,nocopyreloc', '-mtune=cortex-a9', '-mfpu=neon'] + # enforce no-short-enums again + linkflags += ['-Wl,-no-enum-size-warning', '-fno-short-enums'] + return linkflags + + def ldflags(self): + ldflags = [] + return ldflags + +def options(opt): + xc = opt.add_option_group('Cross compile options') + xc.add_option('--android', action='store', dest='ANDROID_OPTS', default=None, + help='enable building for android, format: --android=,,, example: --android=armeabi-v7a-hard,4.9,9') + xc.add_option('--enable-magx', action='store_true', dest='MAGX', default=False, + help='enable building for Motorola MAGX [default: %default]') + xc.add_option('--enable-msvc-wine', action='store_true', dest='MSVC_WINE', default=False, + help='enable building with MSVC using Wine [default: %default]') + xc.add_option('--nswitch', action='store_true', dest='NSWITCH', default = False, + help ='enable building for Nintendo Switch [default: %default]') + xc.add_option('--psvita', action='store_true', dest='PSVITA', default = False, + help ='enable building for PlayStation Vita [default: %default]') + +def configure(conf): + if conf.options.ANDROID_OPTS: + values = conf.options.ANDROID_OPTS.split(',') + if len(values) != 3: + conf.fatal('Invalid --android paramater value!') + + valid_archs = ['x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'armeabi-v7a-hard', 'aarch64'] + + if values[0] not in valid_archs: + conf.fatal('Unknown arch: %s. Supported: %r' % (values[0], ', '.join(valid_archs))) + + conf.android = android = Android(conf, values[0], values[1], int(values[2])) + conf.environ['CC'] = android.cc() + conf.environ['CXX'] = android.cxx() + conf.environ['STRIP'] = android.strip() + conf.env.CFLAGS += android.cflags() + conf.env.CXXFLAGS += android.cflags(True) + conf.env.LINKFLAGS += android.linkflags() + conf.env.LDFLAGS += android.ldflags() + + conf.env.HAVE_M = True + if android.is_hardfp(): + conf.env.LIB_M = ['m_hard'] + else: conf.env.LIB_M = ['m'] + + conf.env.PREFIX = '/lib/%s' % android.apk_arch() + + conf.msg('Selected Android NDK', '%s, version: %d' % (android.ndk_home, android.ndk_rev)) + # no need to print C/C++ compiler, as it would be printed by compiler_c/cxx + conf.msg('... C/C++ flags', ' '.join(android.cflags()).replace(android.ndk_home, '$NDK/')) + conf.msg('... link flags', ' '.join(android.linkflags()).replace(android.ndk_home, '$NDK/')) + conf.msg('... ld flags', ' '.join(android.ldflags()).replace(android.ndk_home, '$NDK/')) + elif conf.options.MAGX: + # useless to change toolchain path, as toolchain meant to be placed in this path + toolchain_path = '/opt/toolchains/motomagx/arm-eabi2/lib/' + conf.env.INCLUDES_MAGX = [toolchain_path + i for i in ['ezx-z6/include', 'qt-2.3.8/include']] + conf.env.LIBPATH_MAGX = [toolchain_path + i for i in ['ezx-z6/lib', 'qt-2.3.8/lib']] + conf.env.LINKFLAGS_MAGX = ['-Wl,-rpath-link=' + i for i in conf.env.LIBPATH_MAGX] + elif conf.options.MSVC_WINE: + try: + toolchain_path = conf.environ['MSVC_WINE_PATH'] + except KeyError: + conf.fatal('Set MSVC_WINE_PATH environment variable to the MSVC toolchain root!') + + conf.environ['CC'] = conf.environ['CXX'] = os.path.join(toolchain_path, 'bin', conf.env.MSVC_TARGETS[0], 'cl') + conf.environ['LINK_CXX'] = os.path.join(toolchain_path, 'bin', conf.env.MSVC_TARGETS[0], 'link') + conf.environ['AR'] = os.path.join(toolchain_path, 'bin', conf.env.MSVC_TARGETS[0], 'lib') + conf.environ['WINRC'] = os.path.join(toolchain_path, 'bin', conf.env.MSVC_TARGETS[0], 'rc') + conf.env.DEST_OS = 'win32' + conf.env.DEST_CPU = conf.env.MSVC_TARGETS[0] + conf.env.COMPILER_CXX = conf.env.COMPILER_CC = 'msvc' + elif conf.options.NSWITCH: + conf.nswitch = nswitch = NintendoSwitch(conf) + conf.environ['CC'] = nswitch.cc() + conf.environ['CXX'] = nswitch.cxx() + conf.environ['STRIP'] = nswitch.strip() + conf.env.PKGCONFIG = nswitch.pkgconfig() + conf.env.CFLAGS += nswitch.cflags() + conf.env.CXXFLAGS += nswitch.cflags(True) + conf.env.LINKFLAGS += nswitch.linkflags() + conf.env.LDFLAGS += nswitch.ldflags() + conf.env.HAVE_M = True + conf.env.LIB_M = ['m'] + conf.env.DEST_OS = 'nswitch' + elif conf.options.PSVITA: + conf.psvita = psvita = PSVita(conf) + conf.environ['CC'] = psvita.cc() + conf.environ['CXX'] = psvita.cxx() + conf.environ['STRIP'] = psvita.strip() + conf.environ['AR'] = psvita.ar() + conf.env.PKGCONFIG = psvita.pkgconfig() + conf.env.CFLAGS += psvita.cflags() + conf.env.CXXFLAGS += psvita.cflags(True) + conf.env.LINKFLAGS += psvita.linkflags() + conf.env.LDFLAGS += psvita.ldflags() + conf.env.HAVE_M = True + conf.env.LIB_M = ['m'] + conf.env.VRTLD = ['vrtld'] + conf.env.DEST_OS = 'psvita' + + conf.env.MAGX = conf.options.MAGX + conf.env.MSVC_WINE = conf.options.MSVC_WINE + MACRO_TO_DESTOS = OrderedDict({ '__ANDROID__' : 'android', '__SWITCH__' : 'nswitch', '__vita__' : 'psvita' }) + for k in c_config.MACRO_TO_DESTOS: + MACRO_TO_DESTOS[k] = c_config.MACRO_TO_DESTOS[k] # ordering is important + c_config.MACRO_TO_DESTOS = MACRO_TO_DESTOS + +def post_compiler_cxx_configure(conf): + conf.msg('Target OS', conf.env.DEST_OS) + conf.msg('Target CPU', conf.env.DEST_CPU) + conf.msg('Target binfmt', conf.env.DEST_BINFMT) + + if conf.options.ANDROID_OPTS: + if conf.android.ndk_rev == 19: + conf.env.CXXFLAGS_cxxshlib += ['-static-libstdc++'] + conf.env.LDFLAGS_cxxshlib += ['-static-libstdc++'] + elif conf.options.MAGX: + for lib in ['qte-mt', 'ezxappbase', 'ezxpm', 'log_util']: + conf.check_cc(lib=lib, use='MAGX', uselib_store='MAGX') + + return + +def post_compiler_c_configure(conf): + conf.msg('Target OS', conf.env.DEST_OS) + conf.msg('Target CPU', conf.env.DEST_CPU) + conf.msg('Target binfmt', conf.env.DEST_BINFMT) + + return + +from waflib.Tools import compiler_cxx, compiler_c + +compiler_cxx_configure = getattr(compiler_cxx, 'configure') +compiler_c_configure = getattr(compiler_c, 'configure') + +def patch_compiler_cxx_configure(conf): + if not conf.env.MSVC_WINE: + compiler_cxx_configure(conf) + else: + conf.load('msvc', funs='no_autodetect') + post_compiler_cxx_configure(conf) + +def patch_compiler_c_configure(conf): + if not conf.env.MSVC_WINE: + compiler_c_configure(conf) + else: + conf.load('msvc', funs='no_autodetect') + post_compiler_c_configure(conf) + +setattr(compiler_cxx, 'configure', patch_compiler_cxx_configure) +setattr(compiler_c, 'configure', patch_compiler_c_configure) + +@TaskGen.feature('cshlib', 'cxxshlib', 'dshlib', 'fcshlib', 'vnum') +@TaskGen.after_method('apply_link', 'propagate_uselib_vars') +@TaskGen.before_method('apply_vnum') +def apply_android_soname(self): + """ + Enforce SONAME on Android + """ + if self.env.DEST_OS != 'android': + return + + setattr(self, 'vnum', None) # remove vnum, so SONAME would not be overwritten + link = self.link_task + node = link.outputs[0] + libname = node.name + v = self.env.SONAME_ST % libname + self.env.append_value('LINKFLAGS', v.split()) diff --git a/waf b/waf new file mode 100755 index 0000000..f93cde5 --- /dev/null +++ b/waf @@ -0,0 +1,175 @@ +#!/usr/bin/env python +# 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.25" +REVISION="9dbe1df4d0e92facbc1de0486ec78fed" +GIT="ee63711f9792665ffd31c3397ab0e770300b938d" +INSTALL='' +C1='#n' +C2='#Y' +C3='#X' +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 Context + Context.WAFNAME='waifu' + Context.WAIFUVERSION='1.1.0' + sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'scripts', 'waifulib')) + from waflib import Scripting + Scripting.waf_entry_point(cwd, VERSION, wafdir) + +#==> +#BZh91AY&SYjR"?h&_$m~V#Xc~z݉@#X#X#X#X#X#X#X#X#X#X#X#X#X#X #X(#X#X#X#X#X#X#X#X#X#X#X#X#X#X#Xo}_Oﯫc[ٻvvlqVڧYF{=J޾{}fKnncw<ͧwp;jl{}>-}qǧ7׸>usbBMڱUpvx]aJ{[f{olz#X ;kJD3N۷(#Yn8}#X%T#X\vR(6hCCZd 6tE9QUZ˵uoCǗ֤#nv}h0+J-c,{2)kɬy껮%#X=x)iR"s0;a^Wd.Vi#n#n()#XTUBo#n;:NîQu'Eo64G,'﷞L@ҩEu#X#X#X#X#X#Xj=B#n9#XªQh#nkzѠրk:vf۸Ik@Bm#Xnc#X*c(PT#X#XR#X;(4#ndR{Ev^n5GM+&}D}+X(4&s'#SR>ݏ-}w}}y_Tyswz=G}ݛy&zj=>n| vu8PjUH.nmE;]kKhaSBx瞶F=upyϽWmGzط_o.}{|;q}bκ.ޞwu b=_]}:wy2+.^ϝom{]So7tko=t6v}J]oN"@#X\mj׸j[vz;X'_1Is}^ם՝}v쮝3y(wg%תv:EJ=>{;Z![5tm={ֆ͝-Չ]-\{n]JPU^w^P9qkxy]Xwjn]nݕSlH=+B95rvunּ>vNN#X0l#X$D.Iwe[r궪!ج%vҶI^L>|u6ϝ}^o8km;nfwEسP^P#X#X=)/mt&]d:;ywMsSU]s#Xn6ʵ#X(#X#n6GQܰ:=;_n0Ş{xƎ#n#YT\]wr@#XWk}U(-פo'jM>[#XT#XNήĀ͕ÍaTtklw\Ӳ@)zD-8KlOR67nal l{B{t@tJ"L Xܮ#XW3m[o޾oMVyiOy:{k햴+goX|;:B#X@M#X4#X&M#X#XhhFzAj4fdP=M#Y4ڞQ@ d44dʟ=I䇤Ҟ#X#X#X#X#X#X#X#X#X 4h4iMS)OQy)=L4z=h#X#X#XH@#Fؚd{zI?IhP#YPA#X#X#X#X#X#XR2#X & `=&mM2TDF#Y#Y#X#X#X#X5#XL h#X `4ʦ= )zO҇H#X#X#X#X@T*t?SC©ES#YZ"#nfB$l @#XH$GE~ H5X|`qcU)sD`x˨tCKDMԼAPqfA$fqV_"r$="ziACPv#X2&Șbv2Qnp8#n%#n#X(*)#Y- Шb(E&t*B"!߾n o " @L#nBA"RĐ1Dʙ (V%$^#n"3*$GQx@MD444S+lGS#nab"GSBAUr"#n% RP#XP8#nV E"("*b(#nb "&*I"hH"&&"#nf#nJ*jfb$*jf"*h#n)`(Id(bh" $(DB)RPPfXRBI`("XaEJUdA"j bX(#n&* #n"Y#n))#nb&B*H Z)j"ibHJ*f)I(Ia)H*h* !hjY` `R BV) R*"Jj"#n#nbBJ)"jRh*i%(I "`Q&R*&* hh! I(R *f B fh*h"I#n (#n(ZXHR*d)(#n*(#nh*Hbd *#n)**X#na"B!(%*b" jf*("BffJhb abB&(b"!"d("bIf*#nf&ib #nJ"(hf"e"*" "* h&H&ZH#n&#n"$J)!""(!(#nJH( *#n()*()"( b(Z)`& &H j*&"hh""((f"#n%bb)h* $""bARSICTDC4SDE4Q4Pı4% Q5QD$QE),ITKDAM)CQQQ)S0U4PI5E+30T %H0TK4TTK1A$I2%RDTTL$DTR0EQTQT0QTIQDTTMQK0Q,A0ҥ4DTQ!$MSPEM0SA!!EUQ,MQPEKMLTK%A@TERPSDIITDDLHDPI IL35QDE2MD-STSALL30E!Q,S@PQM0EMCE HR%$RARM,UQ-DL$)T0U0EDTLA4REDT-EEQA4M!,E@PS@čDDESD@DPM1U,S@14 QQ,HD4 1DIM$AUDHRTT1DQP4ML1E4T0STUA5QRCEPH)#X2PTL$MA%DLDAS5%RB 2EDIDP )04MTPAAELI ')Ȫ4ԬMD441PDEDEM(L 2PDA%LA1 CESKMDDPU$1%LTRQKRU-SATUE-U4LQDU$UM CIRDDDE-4ME%ML4LQR44MH0YV*j^8MDD 25(PJLQAAII#4LA#XAD4 $UHD L$QKCUI35AE@IAL4C#XPCDJCMI,AIAQ4T1EE$ṮEP$0A!T%EE DTD 4RUUJR$H@K K1UT1QRPU#Y RDPJD(@Hi)h(h&(iJ#nV* ifjJh`#n$҄²E3RULU1IEP%TEDTQS@PM%3L̥#YH#Y(55LDC4 EQSADI254S251IEḎU2TULM%T0ԴPCE15HDUE0AUL)1LRQ$T05DDMBEJPKQHDHQA4BQKE5UD43TM4 I1LC T%!4DQJЅ#n 4-S4BPRS4T%1$Q!)M,#YAUBJ D!@R  D%+%#B@$1,C$PQ-#X4Q@$M0 @0DHD5D LT45MKIL,RQ0TBPMU!$M#AED0IDP!H4-RQ#CADBBRPҔ%+CU0 U-U LIL4JU)3UAKE%%Dą1Q1MT QT%)4HЄE- JHPMQDQEDL+CU T M$2HL3@*1DHD,%T#3M-1$Q#XD, EBERE4EPUHLDM!UIE#YIUMDQTD%DS-T@SDDPİEPQ1P1IAAPPMTE#Y,Q$ 30HTQU1S EQBPUԤISDIPULMMU1#PI3EMPQTU#YKRQELBĴRQ45M DE#ACDA1I4 3UPЕUTIK5@A,ED LTUU4QKK0DM#YTM4@PMCJDR#YIHAKLRJ5PQQPSRPELRPI0THEPCBQSHE@%2QJLU%TE1PLSD3DD,EUAHA$1SLDT,H!$C,KC@MQDE1)12#DSPE5C0!$S@Q@D1RAUED%R5%#Y4#LԕEKLDK0#Y45HD#YUTM!AKUPPSIC,@AR!BQER#D@RSTC REEDBUP#YS3DUID35Q54! ELQ @IE%$U4DDD%4SJ@QB*HAU +K2QE IUC3@%5UU@DILAE 2 HQH5D)1@sf!)& hZHV*DhX"%("VFHh#n( i &ihHh(V $"&f*(J@#nH$&RhHjHBb#n)R@a"JiRTJZbP""!J(h"j&(&"f)I bF$J*@)#n`BedJB&h !J(Y #n#nHJi(j&JX"#Xd"@@ &@*#nI &)iiU#XF &("覚*#nZI$JVh(*"IhZU&AJi *abT$%d"(`#nJJBB`&f&Xjh"&"b)#n)Ba(J.PqrAS?!/T?7mDST?ITWvx}í3r,?kzI'T3[!Ltj#n}z#`|'4ז?mǩ{Bb#niTꢴZ㍔̈́C~&< AfhIOag:grgTrr#Y]?50q;)%\FwU_֫.9Nf4kRgГ,Ou}I< N>:`U-?˥Wʛ%1>to3@y#QLWU4 9-M3"T)N؊) &*ۗț$DGY- `2%P((kT'E?Ə[9k>uVYvmthJW*0nr#naf}zfұ@q$;|6bSNmn8ΰ7U`!85yϛh٘{wLkAf} >-9fz}F Ą*^9DELEl0P;8#YǸF9ӻF( [L|vCZumoGZҖ #rOuC2o(dC+&B(xu6C }!jowmP䆈^(X#nL4l_f.~AQ/J(0Ϋ鬳=!P4tK:sŇ=%gk'>#niB $ C{]:Ƞ̙ HC=*(;QC4U$D#nڦx'#X6RE=dPu4xse`8F֚;YLJw`[[G*>Ïgrz隅SL=&ҡ|Rpx]tA;P;ߏupd3T%(vhUR uJ^l>]KYE S$G[Z#nEi)$+CK;s˲9;6~5:`D98樷xXù1J30՜snRcuFo6yQ9nߛz\.T+˒cf-֢yǶ\-7;IMQaU%ʚmg_w6ikf_ g"G|Bs#YYF7˔<"D9t_l\hkqsbX<9ݓ,8ANoy>/bPAeݜoׄGPA(!ܷFPF]*">CT، nSq$:2K:3V>h]LX#Y·YсT(Bٖ+B7+]aXDa!2n\t%+u=KF^r_&!Ҕf[DNK#nzՂ@*4L<&۠qtWX*N+("|ز"0S.pR6pQ_3a'z4`#n?],xpw>@||!.QI#Y=P4w~{Gq)>y=bua#n};s:2^j"?#n951?֏O{:vζ+5_lFa7;Ao]zo"Բ/* /_,!de*P|ou.hF#n4TтMn,Teg2Ye+jc6k#nVt;D zMp#np,u?sDM&YTFJsRbљ](&&lKC,0î%/}|(_'ư~>vzmBFn*Ǭ#Y6 3놗M1(ʰP^{2_=ϓ&2I_n1h0 /xu?(d$yq8(+ Dݙe0;xFfuc6#YmUeа'!Y#Y.Z:dU`CBuBEJ| iaRQ֪fe7Ϙ8,De c90"2V$_ً0C#\yPů]~(xC{2zDgI'~ex}U/9`>%xHae5!8N=aB(ƤŽ$J4'L}+?Is/ yD$lߏ=N/O\l=k JA#n7*_{`ӷo>sC>J|rPod&8Nªpޕ<'EP3ɼ2lV1nS"-<SqբA~*4!3:Iϖk K8;BK9R ٓdF0X\.5МK*pF"tqbzp~g?K;\J$Bxx%G'?;oV/SU.Ιozrf!HS*cS#Y/ 9#n_^PçOyQinPB.D x=FfC5s_7|H>Ugi:ec6qQ32tJw$cv4$#n^׷,g- W3v[ci`XMbPV"zzrIoZYUTdu0u38̉YKy`&1m!#Yq|V#XAȡ2_tKz|}.-lyo{[P\.ƺŒĕT(8íM%[Xg,Xn#YG~m4+\YӦLˉܚѩ_)AqBP&=X7mH`x\w} {R2tb]L*ԦD`OYOƳ,n]'#YdvԐ݋=/ۦl,ȵ)gokn^\$HÜ޾{7rr_\"ȡ HT$͏io_:[ܦа@\Ҿ%XG\,Ngu=qp3FV#Xp'XoMH.|08)ʥKzAՠ h a?ߨ{ߗ:2;E7ˆ/#nPzMޒow 8y.#Y|z5vN”|*Wg5~~`ʝ!]ʰ2#Yج">dXvoBY똎ޜe;a,n"&i#Y{!lZ2GTU#X$D( 0¡9]UQŝ[q6QuquH1~#XSh1Tfvw8GCY ,Y^ONȽϬFQOiӬ'jxmpAC!N\7a@CzKF H$*-.jL2"Ky?D_愿y"EH6X>H6~sO=IaFREFPxGlc(-Yo'{2#XwR3#XْcaX)l-zFi}8vKݾ "ld`)xS$b$ k_Zl2ɔsI<9p +UNV\ 4^(+΅e\]A#Xo}ly s;2%&URL} \QGunR®e/̸d.heE"Htۚx i7a|PxGFf஡F|D{(g@5#n+[C, oГID'H:(2 "#n蒑QOcP֨$(%0vO'}0wNMКzMY2#X;WNr9n m>mX$c}RAIl$ϥvd2zlH+E#n7T*Z&ƫ$I&p}:& Ż@J{EJXYXǽhV,0'maKm\:}ڕeno'|yv8߇&}ClvMϊFc7FNp.YCE;䀖KKթOڍsѢ_6&hOOdX U~|U^$BcX퐀,A:bkgd8MjB'>6>8dwU;R248dUĞ2>w?/~ͼjOWM aICذi8QMIP$DiiR+y/Rjbnsq%~`u#X5|ɖkTkySJk+0μ(:kWypx"]TV!MSr5i!~W_Bxsog&61\vAX?cKBq܏ fd2sE%rR!AïJAWTX/n{)e:wsofF2.7FN4(@7>7B]P;5D#Yqkt®W榲t~623Fqۊ8b* THBpt/#nt]:ϙ9mz0!cQÜiP8ko ;:yõp7![qryxrEwPL++E[̯ ;2~Gh;,7V#YՓI%JI痮6[v~"`9=P B(am0C#YZ[j1O‰)"6puhrSarŹVSUngO0(D|j>F5ax0q;q#66d2E?YnOJε+4yC#Yh3OL:gLє\ s#n!d:;#nB`Po)ɸf@;%%0ӠdU#NBLk%V#9ؠDB^haYN'$r|S%h0T$Կ%99цf|SQ6FPSCĶUiɆd{S6:öW/Vpg_r8IQq6yeDP"`p\̬@(xh?bndpeN|Mj/%{NsX+qTHmTK0"DJ宕P0Ņ/}aTdq i6 #mvޞ36QvˈO`2Lto&Eđl)F(;>R}K33h6,PgEK7o)›M+G ;\bxv˷Bnf;W'(GG,ɮ&k|e1bCh1R*f"$'Tme% 4qY9wM:C:(3(ɵmCשU~g'N?}bTȘi o/SF܊2*Ņj5wG*BC(bFqaj/_m®S7\VJ6ֻШϠ:vl?̇f #EVpii͹d德w>׺,PT}Hb2_F0/Ay~ 2iwnPE#nKF6,#X~X0q43PU=pf[R,G=*̀QS#Y%$b.PH0;OHkGX4E4diͫ׭5Zs{oDcA.K(.Z\>jP_^~8Ebz*`Q9M椺_WP^MA#XI;{e%` '[kUMDz (0tW#nvgaC5}-9v_H:uDLJ#02}҈j/ێrW: P#-S#so w>kqL$9vf2t[!kbaoш|`~99zwi|2qyw?9M'qXʑJgJjwF#Y/Jg%Av: J[) G3Ӓ#nxPXpLH#ngeqr>ټ1ޅ86#Y$jK}Uq59;b+neUZp]:˜K>mTBԨ#n?cs߈.jܷ2#YMr,:haӱm0>h^Y6uy RCr}8{qB݀h+>j@%-;AHf7!G嬘 Mn*#n2!DlX2T[4~m+C燉<y vFM?#hzhuq,ɿpL#X9Om Qd`hgP$c`;{gŋ !9~q?Oz%ד)<(ŌA` #n|O傹 ѓ|(x%"v!H30ŧ֋{{]~C֞IɧչAhʃ m,XX,/:~ƿC(=#C(y:^ϧhj$@9 Z8cs]Ai6hxQx Glh((BK#n=,2hr9}^L4m2@ERrB-261SO@h6 cHVvs(\hk.Z!2zXBùdq-Ddør("c DATq ny?On/->%9m-#n55JIk]iȤtsZ-[,V#Y4۹_o(nqmi|#Y>UHS`rB `n,dʨ#j1ݺûF62ab;u*GHV #n#YI Hz*:K#XHHqs*V&vn3Q~/e&[umXyHv{h4yfk,[Y B*9T2UI*{/GOAplNQQ#XM#X~xuU(~+2$!NtEOR_R$1oǻ1XQ~6"锯LF:A{}#Y1?4A[]߆7?'Bjq|l{lϷCG'nRhj}S}p3L] a鸂J^{lv^X1O6#n9O?* u#n$}#493_>B՟q zPOsSa85)-#VR_ #{c>.<Oz`'ah#YC?7ģ%#nS:0ap%A 1#X#qNrJq)2q% *<`aF΍Y#n~Kl]/1#XbҨ35ҽsǓs\^jO6`]#Y9.:8Hg}#vYx#XuoIsa͕r,"h?X#Ye(#nZeHV:"a#LeJ|ܖj}6ut7aXvd%jL'U-coOwb? >}_2,fq rHmGuLeQg$V} WhQުgAzIC"@ ~ {5?aӦԑ6(>ͻNb^-\pWD`kTII,J`=ّ\g[ێpii*9I C)a!$HyH`u#Y'DДBQ!9R!u۴ATJV*#nd#Y`)5Nwf=h@s)X̫E\pA9ijPݹfK>#Y[^JĿa(XmpyGNi#Y8$Cs~%,2˃Ì%$l#X8卓<7|#YL^#_Dž3EdnNz >Ğ;g tf Hǯcf`TVN:C"Ph60:]0X(m6)ɭ'VnɩS:)(ly4$y`#tl"A]o6?~5[#Y4ch>/F1b0<#Y İ*mw&ҵR z%"b$X٩V!7tfݖ(G:80v,iފH3bEiQpOH46D"ΛFYEY@)2:iu5jQvaBdvgjg6tu1{f#noG#YD##YRA1\D&j;4!5i2蜱#n87LR !! p`HDǫ%z#YwXݲy¾N\<8Ҭƻ2rΔ/?AQ9'W_0t^p`.u"5 * tahV(Ɏiu\o^Dǥh҄q!d BE^ x_9#Xl?-O=:Xxv0,iv+r܎3U<8/hln{ׇ>Bi.KԡjȵCt\XD,TmrqI<nlZ\#nQ#Y0vND퍠ݵZ0ŧj#綃 GUEA"ES(p^lfTsMc3#*U0<%$YPUϟ#XQFAT&JwoQ{H~#X~>\􍞞o7֋w|ZOjkf*r^Ӿ(7M~a6ZyS&;t.Trj<=.>p-#YSvFɈv/S`5=?*jLI%XA)H*.Knf.[F ?Zt*6@?6>jžҟ4aD(85]m~@o~8I 0wѫ?Ll~QPt>#nv1osؕX .Jh>$ɱɅ/ğ&>=#XDz8S*{@З4j,ӯ0xm)ǘ{J#Y: :N[hx+!#XNL<'HdALcBvŴ]F`G@nK"4ZԘ~b=eezܠ![s"nOvIe݀h_ɿI mV5ԃh}](mcI6Kd?õ#X?%IH U#n*#Y) H. <$p9.^U 8Tbq2,d#YkU}auF*&7hW,FP#X>RD[->h?{fYF#nF+2~x]Bd~Y~wZe,sł$:ں;YC.0rĘQCͩJB]17u@(P ѡWc>wR!hH7#n]$'qi~vO#X1H3ƈ`zuA1)+/4ijp3|8) @WP s 76Ō xK9;#Yo+VY-GNtvsKN\20ΰ3MTLoTkwPPIΕ7"/) ' <6p~4GT$dmf]!% o4poʛEsv=BM-}L}lhaD'V=3ׯN3W#YّJj ^G1)0F23U1#Y8on_aG_ Lrͳ򾣩c{^$$ r7܄^c93'wE  2_Me˱= ,a(mf˦+et<3Xj3XkMkci$C5:n7ê¢go1ַ˔jؕ'x,1\>M\c֊"Io7̻ͷ&3p̎,* p/5=^%d%#YeQ=#nol̢;X޴Aj$CK3lG^J2#YA*m9#Y>>0@FR[\0s}]嬎qڶFZ(xlOiU뿣#wyw)> (#X T[\gFB]ꘀR)f5EY35#e`\`k8ˈC8 Ʀ@sTC{ᅩӛ5._]iں*xCd13:iR3 gU.! ;vF86e<.$ cb;;-הnq (1𐔧J#YtWLW~M:<3B2ojmE_L`l)(N<}h\6**5=K}ԫ9η9 tθ}u$E&F8c a#Xi|e'GK.yɜ{U|H0f/O;2ZvUFM#nF+}3R0K($Xx$ &#Y~Qf~ʩ+~[fZ;,$&\dN'diƑ<'1O9~*0x;2Z1vdku߇--9̩;KAA7'iyDa4k.Rfq~}ax!Te.Q"QbvJoe{&1bxʠ]JĊ模t^圄fv4lӘJ2ن_Ӑ.ϋah @r H%05.tSeevGp{#X.ey,Q E_}:BTLSN3]*nH-uq&h Гq`G pk"fec!sNMLJk"Za٣xP"^?I0^ExY~zBy_|G=3O_|I\hA72'l0<#n%mD`Ju%#nQ=y(|2E5t۴~Fq'QԵ끸&cH,3m`/ {`Kwj:.>Hq[ŇJ#XCqUsUC}Og=~f6Q-LHl?!N}5aASBs'#X3Xd#YNO]ut)1Qw6.j>c/H.Em(Y(΂ tUyzEaL ML^of'9GFh5[,PE7'Wo;DcUFUaAώ!!b(( Fk9ʖ#X}5#Y , .ڀ&)9}m{\r<0HLQ?}Gl5 ,ө֡hfF2%@P78!N|,]ȅʒf&xJ"On;oW]7;0 f>(pwR0 ~/ka<,0 Y5"'b$Q [s$}>*F#!^Z& Gu=#n+(I;?i #X. )ΉF PnɍESZ|6/G)tg^*U#Y-ozŽ _H  $rbZ@(^?wW?ZN>Hn[vot89ޢ_F( ,xDfMj!RD/wH#n.#Xbn'A3)vA0>c=㐽ÊHu#YYkw&b{誘#QV+ eLILY\zCpb{C2#`Ez/#YJ#X / 7/;]gHR(Z(*Jq%z'/@9r2o^fDP~,#Y=#X*LwJH"$Һ:Ă^c.ϡ1-+HiPϋ󿐉WӟqfTn]L3#Ym #XMx1h lLE|}_6k19!g$-tHZ~",Q__&}6cJ0B#X';}~?ֵ_|tf?#XG\#XāDڋAQ#0`%C1';UMtb&l]m~_TRsF[RG x_#X}BW=2WN_ߧA"S$\c32(9As^k9EPBilm<9h#X8~#n";DN􈢘(y|"FbļM[Y4'uL>;,HiTQ"~#X|#XT1h7SU QqI/&B#+e0:- ꩘A~>n)G1ҍFnJQJs @LnqÆu" 4&pͱ^A "f.RA r^ʟcj"]k#Ywiͳ\m9#XB'O Dng@@Mh(&vj;>Y;sb^nqo%l4Ɔ̱"0PrI"7S|s8G?S=_u3@vz Ե2r1,Hރ~~/`+4.HZo.pse92ܷM+<$zI*Ѷa rє*]r^a2~^*Ҽľ>Xh5}uXu;"QJy&r<!N`{s>Gh |g4lGT`@tX6n;4$Q܎tҫyU&-o]*#nFqUJ9^WMqShkBo g)\B#s5R&9V#Y[58U,䦔fRS;8[ Fljm6%G D޲fjssNqTT5h!S,tAΡ𕹭P>k0w  ݷЩUǗW#nܣ9>vPp<<#XlO;SSN1w׌EۀzyX}c/.R\oHmd?qNub\}31N*Qo\#-Ǯ>'rk)pL'ξ]{xy/. X!C u"G1>|ÐЎ_'f2\/#X7O(_,ЇͻA0.BZ[ޘs ۇ&E#qvGY\jNzp10D#ne: |鍥P_l[CO ճCbb7(?GΡ>|ec?a{~LƱ֨Ҭ]UTWY5ui:mMc#Yt@?BtcBD JrL+6fLF:ϝ<#nMzhM$~SםP"*oƟǖiӤ#n>az:-N:'nrDzy]?L! _}#s=ɛ  R/("i3(Sg6 ~S4Ӌ<NX07&qYgrs~VOb#XQ#X9n#IPngy~qz>3%1C!O7Px&zZ\V]MK28ӯOP3{b…s#ĩl0vLhm2<4<=i[VBF8jiֵV*k5k$ŸpMf}K ri˟Z*MRF=٫&$Na|> QFAh >X~Qk0=aǢ?gt#Xq#Yߵf7梥-Lߢ<χ@*+HKMbz$:C`r f¢vfZxqI֞KМFĜ/bhDAL2:/w]d$EOBUwf'Y9 wWQjRșa#yИmAcx.2#Y21(MbWy#X#YH*$^\fB#XLuzA{xLhޫ}b22i0PU؄OE56k51oϧ-OxcFonE vgl  aFOܴx̚,֜Lr#XmrjF$)%#n[z#nf}:9Hi3tQ]? ZD.:;<hx#ng >˖X*HzUtj^#ܰtyFsIZufo*Yv#nI.`Z.2$Cڿrp>PCߠLm}F6RB\z [;=,zU1|_ۊ"FK T-.A:YvkVO7SJ.]NϐyT/0te'2oEtz)?i!2;K${eh+LY59 T;2+Q]҅Ba[ࠇPX% N :}8O>l#pU*:L}exS#YVĴesc2o:q#nJK JuV+gc"2m晨 )A: JLxrɾSF@vi>GAvD >C yC^xK#Ysf$`, :0kU0QĝB/)f:`0D!k;0RNgI73 i͸E)l#Y$C-_ .1@%pD oJ=);JݷC%R ),n#wN!/5*Ya& cMA󇏅G}j>3_i&ewT@bUQ~?kco H0ތU@wE0=v$IT8]˲QHF'=PgѕHq^T/:3|[JRgl@Zucc.cܿzܢu6q%gYگ|b#XٍaQYD)5;pyka0<t`+ƍ?Z9qGoVkYپR\۫diI(Ty4lp7#n 'ݴ/x0~܌}x]!|up\hdV:h"6QdQŷ(gePYǓT=}{`F.Qa{\h+Q8X>9Ks$.&LDOs\6cһez:r#Yna3$4$Y80;JkFY P4#YΗ_?E.AzKygF#nCV%!rx4Eh"%yx)yAu-~2u&t닯9g޴7n80Z!"%c1kXHV#Y~ Fnٍ΄1N(M{Lc<@s*]RȌ/UUUs^]_IWw1 #YB% rT^P.\f0<6ǚF@I-D* bu2BҠ#nI8n1IDů=#X04okEƚs)S{B1pB#nγTU_oeԝiJ$!r7Zl9P-T#X!n'69m#YT!ժ7rʘ}N`,*rAskp5iZ#AA3!,I淔~s 횋#n5UsaQeEwJ#XUe.f2XYW "b퉽ݶ†G5HFJ?)ۍoqSJ2b6eA+jvzCN ދ= -H'&J-V* P{<a!o) 1JHJ [XgH~#=h#q>T@8mL)\#Y:櫃^a|#X=p`'QBwOu;'3#Y:VD^JBE(#YvA-FT%RAFlV'd]"'XUVLW<﷝{]բ䞤;qAh!}]֫Y{sB,P2e$Z)+ xY8u>?b֫BxO PKoЪgg5F<2 v'('EpHⶱU1K`/[x!k #Y`*M-&QM`u"LU@H׶y+7(8#X{Mf-#X` t>{lP0V_W "'(l1Ԗz$(s-ٖQ*e }C.u ְ"?+j!H(έU"]1Q)n#Y@#R|B<n=FVbkg#n"H'sPm(DGzNEKê u'"^Bʣ.7nT4ԁU8WuSjR,A-=uP$"S8j0g#w#Y6^<0Ro:I̖N)+|_4r?^f 㗕OtsB#Y8.EZ8NFGMcYRt+f%<|97 TA='] HKesB'7}>qfEvץ>_-䀡Tq-fAIN|_G/X<{wÓ{ 9SGnw]BkF80mE+aC'Ob{duk*gG Ź\WRj7PsQM#YXiip=ӝŚrj#Y A#YHf ^x}81s#Y={_,2yF3uģ'+qPcx  C` d/j;8#a{`}nql-#Yy>)xx+`e2Ԕ@MYc:9>5BVߊJ־cig;0WIЙ!$(~}qWʝPzRI`2)h/}j{Jm0 ) xN|.8["ݮz96t#Gb+u.BϤz(vY6YE5;#YMg hp`E'?r-%Ta k#7=[})|}(o{; .gӒ #Yy)j<#YA ʂ`5&;"bʬ#n0v)Ncg1xS6'_>ۖbueQd"ݯ0ok1y?fJϺSNXP0EՀGo =VX0YNk lq7Ѱ/ӦhOu3Qp y 5O.رMBHKyt<4#@e#Y.#n̨IMi:8(F({1i ڀۇ~rCBeWN=BuSҴa,'أjl"~$#r$ Nc2aYm#YES5#nL_tT׫o7Ή¯<&FV9azbeYJNǹ0]0y9EΞ#na۲ШJ:":r9V#7x9yu3a|=#yM/UjW18d0ˢZ2;(UU5a']fKTyvp0e(ݹGN7:D@^.eTl 3qq0m]MȇϚu/J Raљ[}HnL?muF09`8x*Bp3Gdk82?io 8!xT,-uc jp@5 X%A&WׂO,%p5tܿ#nBXJzYaiQw(y6j/m#Xb )#XCXވGW@YTT[FV>||e\Lz}feWѢ*Iԃo^(ɖGЅ¨F*4SgGiԼDw#Y@{x 27 G]f.wFWN#nF>KRETP&tM3:sw9^^ocF8$@mCg< [wY$w#YC.ԏ#JdD7(iA#Y PKQltk넔g4&eCy晜iC)(J^lӔ-#XB1eI, ]맿663\7y/,01݅1i)"ϴ&Bقp3;Lώ%>#YQgLn5"=ݷ`t3g;g$LZ#U9l7>4\BUvɝ"-BB3ӻ8|erΡ\4p5bQoQcSɴf06!7(FO'}~}#K*[%gC4-mXfZ2'QAi9[Ń2\ ZA69 U*v~㡰Ё!to:-I&xCٜLCKryU16!9vdոbh .لǥ-9n]VF6LpL´˓c9w#Y&pw9*dm7. є2 H&# HuʙrҟΌwM'/Geٲsݘ^"aջzA^:~УǿZΆ8yGZ,X`]HL#XigqdN@rR6'~WwCʓHh:wAFDn [i]hV#c,֭#+Wqtm8x;JOyKQR#KnAsL@]m4ar<åP&GWM&Kl#XoJј$1CiLs) Jr޴<P-GɄL|wiô,+1IvX=z;W_UU]]#Y(vj@FPTKM3 鷣@/Imr>EK*iMB]Y %VX1:ܤw]IXr[s|0z/Lwy |PQ;:<0h'&sBIv),#GA?-\۵"7q1b"1#XtV0@D?pYn8BCq7p1S{#nΫg #Y#n-^12D{(b )TNx -X>\% n_xZz0$#Y~O~FƟ#n#nf hݜ7pjpc02(Ў?H#X .ۄL2V5RLǧEQ9Pdz-ⶠW&~sݏO3Ca@yԗe)B}]"ؾq[S|#nۢP[ʸK# Íc-(~798>mm&&;=qKoa*)z0G&9L L [Ag>DOwpI.3.@k B(k_R^kULR?hvB-:ǾpGE=@g>CU)C,?ݛ[LerSUE7,m-|,t3| vBU#XVTx;:-;?9e}-53;z}x -xd _cp:F* d:1AP{#X7[Jڵ/T9i4}aaI|b^;qMs4O7! iL%ɒt`pl~׌qFlqT`+{QV`wN">YofSe'~ZF8|=_I#n1Gn~RzrBMg*^IH]#n1B8w3= "qܪ[{{ qB艊<;:#Y(M+oextLw#Y y;V-̧ѧ8ehzE*XX,1nҲ&,C8"+6e5fq D]lXLlc6nX{Nb9eiвpELj#t^YuTQHT麧6aÚjMĵ{`^0Ⴥ돔bV5[/=s(>uׂ#nx-xIЦ}TLңԹ4U#XDJ~,3 dӾ G}p!ziĴpoΔOx0)_M_}H[vt}1=C42wuMͿ!.A~-`-g7Ǒn'#XqOi:'z|5S~>ν U-/k2fJH%$8xq G"~C5.>g K{5~ߩO8jl8@#Y2o80OinG<Fvx2n4C7F.d#X`M1'\85"]*;M0/`x$vDF*32%6q77<\s)#YyYt:P6&uy.I^zv&{D+k[OQťeQ:}ϝB(O#nFWlJ('/imK#Y,$D*񅶔 TV)7#n#YqQ)#!Kz+wej8,JqwkOz?SFz#m,#YCFhVckYMo႒0陽by)gK96Us:x5((hp/{ahS5"@0"[ 3a r$5y2wC`a sPj eFo #EIIiC(ǔKcJcqBbw@#Xɔ.6䟣#7> 47{3y|gBK{ތ#v{Q-\jԩpi)8D}RNd+ fS>(TbVn vZͤU+l#Y-w*)a\w`0(8HwidTsGQv7?V!71Wibi 7ÚY51*qȆ n?)8%Fvl5 ߘ彅~Bsp9O#n>ɿ~|(ri5Vt@c_7xK!Qrv,;c1iS/xu 8;u 0ߊ L%948P\Qߪ⒈nAiVUX-ջNXe'8#XbLHˏ&_qh3%#ysFBŠ؟8w;U.Ptr߇ ,w5PRR#G9&Vo.։q-pc201l6xn?#YN"5xxp@p)Fqϟo^j#Y/nd>7oeG|1_k|pݒHAB:}Z&Tc1 AIKM)q۱VTN?DV#Y9-&2\AdվKp)qL_ؘ0(7R2~P%٧T]i]׫;-TXݖK !6Z'4ULP%(4{`-ZT%%VH]A#Y$y**O;``Q6KX^_T\Z72#Yœ,ePZ#na,RjȠ#XelPVt0#n$ޒx7XN4WDs.]>n$=6)؁!z<@d#n&ޒՄ6NHs_#nQVb!D*z0л#n ]Ô*6Q̰fYܢkQvJy7",,MYJLG@`r$&bq<^Ng y|4Lb9np.P#Y@ 1W_jo-M_ǐy=clS_ByA)\iL6Oy\~pQV軩V4`po ,;o@f+aIψf;A<|is$s\ 6*#X-NA>T߫~ MQIR|PYnvNO)3/^FHNjjJ%'J?=ԨQ=gwNgoNͯV`fG& Qx,wL9chfC#nn*FU(;ch[{w~gW$!F3dGh} ڻN+cATȝ3t}Ld6"oɹSu$j.`F6@m6MCb/#X#XYdd R00LJ#nEyJ\4D]%@#XaY᫼JQc48u۟х05s? = 9i`š8$SQ ޲#D2=4toxg钎kXZ|b7]}LW7y"b-d˕0qCƺ!ai|}ZkhK9ԙ1/[un/#X$Zk,D?%b[sĘNZBq#nZ&]/Nx;#L2uMUJr(: }V3viS90'EqY臾cHܪ%~V`zuY)q5Z֧8z ͹w q9_-mqҡnRsdAx \1Z+yi_q|n؞G7<kD,0qWkIA]Epf>19GrtCܧ'HBZZj-K'+WJrSzf55 꺇̜#.t;k7#({#~o9Mm'Ax|ӌu\G3diu/NY#0sػiY9(7x=ດLM˝~eL*UZb.Nq#nSՍu^@>7ʹ9v?꣕9ߜZ5VqYU¬aBGnۜ}0Y ( gF:EM$h*/eZ] !l/YZ ^,W+NpW-)ӭ "R1gqqLF1#Yk|uzPs~2t>#Yx٥x9>ߕی̈֯&1hHt0zZm•T?ҟdLl|6PaRnr\F/)\9=eai4ZHgԘΑJ6uW^ۇ5qo3{˧#9ŒbG͏懏ɬ^=oF<ׇ'.yC^&0a9YF> 1P#nF*F4+ž];w)uG?(i!tE7tF"0xHByXҾ?3)4l.$9CM/"Ui@CZ#n^$1Rk`JNBvB$#k%״^@H5ܘi1H 8wf+~kj1,A#YL#nH&!ĝqQ\,4BF *8tQe.S,ي3hJu7+z%gK.1')hD@1ߍ/_>汏O8 0epIcue3Xd#nY(BS,Xa#YImq$[/s'# /)V.{]ڭҠTkMD<ͰC\3)+fNA^ruD sB;dLq.ML ߍ%o,IJ[K'&9ud=e#XnpPr]\,4 g_E#Y'3Q\.2'v¿j?f|&>/Cx7Gڭ༚^vhyhg 9i;UYm|'6 ZTH"\m&f!x]zVMC I `#X}b#(r4& xl?#Yo{Uű板ÇZ5:. AR]D@."1$?( ݩ,#XWba%*Nwt%4Ofy;Rh՘_v(_^|zK5EqN\o3g |k7[YO1EF V|5"HU|#Y]csCx7뻩C{OT7JG{.#Yf;WuM#n?$yW<97o`:Lg4}H]ױG 6YXg)C4DE&RWܛbAL$-Oanf] f@NnWtT%3H/ϖIHs߷_qRF s_2  7x[e'q{V9 &d6sR+XwRoas^\bXJ@2qu}g[X`#n:$Ta#Ys{/BiF2ei+ILRpSO?f8,k38ZMJ4lqhȒ50xV6ZqF] vEI#fqW#n5!O}2kB+("~wně zeBiS-39'NX/Ҕ#Y!4ZF&AMq?N(a#nH?q) 6s9d@ȵh4 na㋽<1 6SїلH-Uso}W Qpx-d44kE\*辑-Q9>(/MM#n?Xb128ڕYtV*˴iR*R;hmz`ܵAAZo&cfX#ۘVriHF9Z[ԇ-X1vVlrⅻD4I#nї*#Y(׫G>ܨNO\Oqaŵ_TCu+z'=;8F?F 3H|bk˧oN;@qƭڵc=)#X#|( uB#}G_^,_:@eNZ"}xXB%"J"hR4 Ȃe$`=|cqp4;3<˰1AϦu{#Y^vi{T$6I=I#X퐊|XU9wnOaM5Rt@%2QtKGߧGpQn(E AJU#Tb"ć!/ T<|#Fs|;<+XU،NANZ!;z|5(߸FR:*ْB1sKSp#nu}Ɵ еQ&K3~%/R%XvQeqq]N!1P!S#F1oX5܎y,-=! 0b] Z ņ>AU?UqxH8/1%tv"'Vp%f@ƛ:VJ>]LT,9sPG5C,#>]?[w#oӯV?֙k=;A7-kь`.*viQ֕$syM=_Pe8{?~]6UN{4>1HP,7Etxv1qgN‰ 7k"o`ݺj9Svſ#kƟO';!3n*O#B#Yc9mUHgPQPB[c?/20"Zڏ>S{xyaJ>}i4a"[[$5uż{:z]A"0)BK(#X\0Z#X}ΐ6rTР(!H@U}#Yl4 x2w@t/x_<-HDԧ}:Jx4@!׭?H0/`#X]tz{mQX7_:v"No\g25S‚꟟r%--#nڵHXePMzP JQ/"XmNˡv(0xoWY/xoA|&B`_6*ĀRa޻5pi?`dS>6MQe|_NǁN##Jq_KIdRT9>#Y'Yܳ=P }H2Obw'u'4Jm̆+J4՗#X)0 胣hrOQχ8z~/Ug~Ξhm0_Wn;fM>wRhkߍ0.Q> w4M/Lf;zJ=1":kWg5>ve/:zGH HS^ru3:9Yash !0jB"[&MjJMI#dvNdF#Xݡ̆Bx,N MG+E TD4U@A5Tb F,W~gG'yI?pd:=,?ށ9)IJG?͜Il_&"P=w'yG;:Y$}O;#nN#XP jW0;~vOw\5oĚ\vO 4װ}~mk|yyy~X/u×>CG3r#ْ*S^װxO-$_?|[OiRó}X#n"F|qQt-{qq}J+B_HOTߩ[^=Ow+aˆyڋXퟟQ˜y>nݗѬ|yaxj>DQJ#՗ɖ'7u'\8wm:mdYSd*@~iD>]v>]ث0’(\4w݂omqy{:ȇ~:#Y)D0:DzS?6~M:4Qޜ~j.-]OFݹa)~L]ϧ~|&Rr:#Yݟo|q/-8ѮPO!/F}6\kvp9, ]ƣpǗ,Z0o&l1o.Z?wmכ~>kFӴy䨰v;ۏѶ#X^/Kt`z9]}Ki!dZO1.b#2͂S7])l5[.0Ɂwwv{&HI[ }C]0wp)ց̅q._vf͙{ݿ_bTn}_tk!t7x?Zizu8 q??3H~?u>#Oi|rHWzna:Ud/WH`a40= <8[DPxR>B}~A]PZ@mc͌o8,_Mkm~άD|_S#nxW~X3|x1tHhWCO&%^|>|#Y?=f NaGll*;^0n BsauWlGo5Ѷw2cg#Yp3=7长Z<߷K)ՄJm,!~m'?w7>L3B4f))#Y4w0B8?#ݳ!/?Us/h[׵g>#'e;dR'p϶fZ<>D(hmx`AQ-ӈA?]z>|?#Y{n#Ytf"4=.~̻"/l2<z.bQѳ GP8TFOG~O@##nHO7.~Њ#Xp$?mB|I?mȗ'X|rS}Gy=+2_h|7~F{N۱Ͻ)뚝#XK5D1R}nnyg!Yj1aaa`L ut(2=cq s +p#XNRbaTʋݳ6G 8#YwffgxLvsjߢiSp])qW~ 3E- "pslKoNq>HGH{_[P/XEM3©7oT׭\i\t>ah-3?G<S]" a\ciHz9=z1w2]?c|:śp/@6ɿaL,n:%*ShosE=.^HR -*Y8a8ݭoRu`|7 oPFѧ'r(ܩ8 1;jUξ]3l>c2BSgjk0=#X0翄*:xGY9GBAI$usp5 V\a>ƈm5:x0^YGDGJΰy9MX͹yn_y>>ȍ٪s5nܧjxB݈}xK#nRze!MuCi0aA +ğa[C#|Ox9f8awvNp8Ps޸wIM;U#nb6󟟣o\F<|s=a)V]g{A`o=*RØ\@[|&ݒ^/֓ HN*9"ϙ|cA}eUd:s16h؜w<6 D\ٖ(bITє&#ni1\9p1΀8.VҘ*$I8Xb64Lij<uqޞt 'h#Y1E#_HWM,l|F.-r?"%U QjV VBçC.}Y t&?!"iJ{2]~c'( ӅE^7$N@AHI0eq/`#X4BC@Fp4@( (A#XL}zw5q5t^{>ח'ָ)Id >9n8wq_ʽxKW0x~q'VH-!EԧDJ6&UTZD*kGЎDU%t+hchPh;#n8qWidADPbw3D'tSHչ׉Ew̜2bKFޖ!!\,`ʮ3#nmbƆWY ,w1Zƈj38D#n>lYF&g[d LN,C("\>6J8pQfI!s7B8g#T^q0$C٣]n׎~>vs3;87/O/7Ňe8c%;rQ;ڽG.JRp* #n! pȰnҐqdqX\.D/z=EE '2:L]QͶ%C"=~\y`x2#nֽC0{#YݳsK^u焁keN@^HOA5:0pQ#͹?G7\ԏ$Gng6!珤qI%I*m`$8u'0J'9&s?z1vm_ѹGa-oDZ_L[rÅxjg?W-1P?\llj@j6Aa6J6s݌W7ѸGk!HDEz^'\Μ7bbIMØmp5 jSũ*#nA$4-K7?_Gvb4$^a?,M8#-Sq"n:@ghKtM !5pNruSp5Z= *LnEȼJ=}=E5$C٦N } OSz{b4RU6 VS:yzu^\#nRF9*qr\^+탱N)Jq '^iH>C djvﲠ}VQCj"KAL3m z6p#Eh6#FqƠ4BZecBXkFA64DQh|V1vpmB2&Ru'G?^b{)O`"쵵-mwX`IdƅU#X1빂l&Bf#D9atb#Y'0=i:<؂]LIEݶ1'o|lfuxXIN#n=(,iK48#Vy"60@s0TAS\EhMjcY6TcN>K6 PmZ<>fc;;7l Tl0+&(zrpqڎ-m;j-۳ELT~LSɶX2DfQ9HP֢#Ybbj2S?:#nʱΉ[;85آ =U’;rV؍d6lr11'?YW'P#Y)QGNCv҇pO-5K1c )\cGa1#nTzь:~&EױywJ=R$?_O@!!E߅1:&%1o{ϑ{9犍w5֦H1J0Ce`FDp3ӷnOҙYF,34Fsgbw'wa̰[m0a1c'ݎ#&d>m̅v&h}XqrDlCMQj)Igf8Fnd,*]=fc$܍hG0.nlv1*8<s(:h&h׿vYaO9"D#q4 aẹIPviAbȓBzjuz8?m a88 99@eONSHmXqkY6 fsFC†V,@MD^#Y鱶3u9!F#nhD7}4RJZoT$΢"ʜCs9m'N7A") kbcON(c&vv̥jՅrhr 61paYMx{[l3(iG%475n [#Y{uӝiX.>ZƼ8g/~tIeɇEE=ݡ5*\J"N';Fx$grQ{-Sgy참sb&fyr\.>Y]3n?=gprtVy]U,RYTfnD%51'L/Q+V3C!fBWFM4:1\kF bӅ/cgm;KKC|N-cNb&lN`LLF)1 )3;Q-_D!QB{ob,c ˬ׈,Q1iuT1,k=шwroҾr֏ub}*̣{hMgO8Wtm݄ljʼnz /_5t2o ͠MQᾪΪXجA\Zda#Y4RٙTz%e%!.l 읩TRWpZN: Lz{/xmj4HnȤJy[) we7l(Qbgp0#.'lF*A dV#Y43m!5vڝb^Q  $^p jޑe]ޝ7#AO`yX TSto0~JAf[/W҄Wʣr~G>ep=p#D#n,{E#Y6"q@R _2&a3HYc_*Ǹeb(OhW@Az#Xj 1pT7u홚Qo݉LϓZēԹQ#nXG`V,~V4Æ򈤣TZ%"H;+g둨;qѥȑ'z#Yvhx1b|jfc*dH&>Ia[jpꔜ5|dV7G6v-rs8dZtmC烆ʚljd]fJNvzܴ7oLfYU=d+Y|DiSKC`EdzA+&TՕb~n-Cfu8x{CRuH ֆ2sD$%L0y&rd(t"#nh0@JzT|S[@ei}<+${#t'w3q,og o'x;b;' ҠIv! S]٣gCK>fξ]q)/Y琦_41kȒ4[X1Ƙ8[0|mii;ۜꖹ>s4Z;b#YeAk}y>ϫ+LJ|2vNv6I|F3qϧ$a(*\ * A}c/e7P>2H",oKI٪P7CtzԽ,ԅcZ>ߢzgGKLP?jluI6fv4[Ki{(!;/"=PøpOv9B$M#nb L#O"]S~6|M;q#7$nq}Sύ+j^ɡL#9֠#ΈNcfFIo@(Uz5,!hp\&q71nNN212Bn1B&'Ԗ[OTUc[.$:<(vXl]#otHǜDDei0Z0y9>~ٿtpB]#;,a0*/ᑂk#Yb)D2G+j9k918aABNɡE5ߔY@UǨ%| Ai ;/Ey*jC^2,ީK!(Qאee=$Qa7v7':QgM0?: ?XU^Kbwc&\Yi7{jB [PɖUQ'#X嵳ƶ*eE+sRmTN5wa<$f!κ]8E˾yH˕]!,<`CĶgR}QMJ57e ;KOQ3#\Af2|\c9t4៏=w8]#XFmeAU"IР\죿O M׾-^#Mأ1H֟}Qhw/.O#Ym&{- >p/fe<i#Y2-i#YҎQjG]ԷeÜ>˻E#hP;a-w z~5#44pCÔK|x(4䤰oR7_ʣOMБNrFk˜&d ?5@žX^^"Z_ďdlx(SǩݳËgSA/a=5>KdG:ƳXAX36u+g4Y.4 ZCӋL{)e?fn=.g8M:mSbMo:ۛѿtx:FZD%0VlWx<ӽHiaiᝄ*2l&A4˫RE ܆K24f^@&SkB4rsn:n4(J&almj,;E ;0GJ!dbh[\ƽg[e1c9ٮj4jȸ}Y52}z{'^/w^MF02؟n>0 |bJIqe3p*xrqόos?X[Zg yVpC?P~9@90x12݈$|;e9!o &gCG'H&#Y)ϸSn2ӋsiaAs[iVq %3g  D ta^}j)-#97(- -R: q8VY4=y鷏ҝܲ6h|\ zȺ!Wm b-|]}<xx^.ՆJ)tɁ^QWF3مberv]60;†,5ܸV>ofWm0VDGWFjnq9=*vcob,F;{h.F7 MU-]1@QTD z IsR_?/&soMrz}^F]R!ܤ^QΦZa.~O Sn|cg(pnot7Y} + \~xOo]xּr6LE-b `6[@s΂ux˄!E}+YU6#VKJanlfK!dg*vsZ d_ϝhcO<fҍ@7Q0Ung:s<[,Hֳ/#nqcJZdQY3ӓ"dE#YҗYk;u1|b;J2DhQ 4^sʎb!$H?:0P?.b:!Vﰑ4m3WZ M50x0ͧqqUePR(B<:6_8nkiRd,ctq倍ĨeL7SzQ3a-5ƪ(5®楃Z o`w+y; h)=Fs"|LE EX]8sJ'&#YʘPG=ZV.[ЙwU[|GrOCL80tjm,B17 \>aQi4IPWJXc#X\f!,^>2#T*%д,SO0[ Jm`t>pa"h-3EpWOTb0x.״9>`i| qƯ|eVѝhΡViOVZdϱ›ﭣHV0t%|zNG°g^b#6yT-i+9\q6Ҵq#n#XL/`<1`u9OgX w%?7FPƋ7V(Cm*UD t_#Ybr5؊2@e=yZ̨j۾;UUSq6qZle銛֦޶#Ya҂l1DDR`#Yv-}˔[l[YV:/j;Υ(lZ)Y4oK5m6Y2sW<x!ݗ.xDGj"|%bxQJDoü]z\WʛIц #\^ :;ۆ炃U 2l#nJ_9WcݔOJhK8=_&3!ςr.5'$$6f`@"s GzCw>!x:BlN5Oar/ K^#X7GC:k& uR"_U~g$rVSqF&NY`}4$^SZM tJH#n[kaԃ0<^.}{:b'7Q)` ]`b3A#X{#njc 3+z(db䜖5 Nj%l GPn=@,d4G34F>w hDϳ/QK"fX'x]*q&lW_.lP(Đ_|Tw|B!sOuɿd&od*ԳP?(xW18ΎS)b_O2Z}Z,Q+-X}ݴ[[wzǺC>0z~G̍9vm*>_"KΣ1j)7(q;`z׮]D(wϖ]pJ9nM?xsQ''w gK^ek*v#n 9sUaJvGsЏ-q#YXI俣=Bqv?xwq5ߍVuQտSьj\ >X31[O Ew0-==GHᝊ2/!CC,t ? ٳ9tJO#Xenv5dz#Xpe/MKS{lcW"i4ل!ozҐ%SPܝF6f=ac+Jtyے+擞/Q1)U;{sR0GU7K:czȷYL.^ tV~!@|= ]+'lc*gO]E%MT3(PR98z$y%DbZþ4#X㒀0U32=he6Kڷ|bO)eRY>{k-v$?7,S#X!/5Rh9V~5y59r͈.>,7.xUo]`ޑ񘘝#t'\k﹨txg?wvXb#j*t ~=5xiupnFtlPE=sJ.utu|}K&!O0#X\֒TSk)3#X,f7*ƭC7cVV6+AT@9a^_hDVWly)12.=³g#Y .x$\Go}Տϡ=ϓ;!#z36w_*FRuMuVl.vح[_F&pBJ`Omnt ‹vc[Ye[暻0* L?)uz٪ QS1s"jB) >hFcŋ\*mBJ6$ m֣9jLF[z^у^;(#4G,G03EoA,?DIx=vo0{K|/<2lCъ.rd"k?'D:sd#]J#{TDi(&(";7RONA%DSj5{ql!֐D$O6_Ch:L5v׍*5}{"CHz.尤JIO=z9{㛼(񓽱#Y_w{9o#Y"0r$.ObLv87OJ@$)XX),pK@=vgo.ywFg3=,J{t'77#R; uCfj#X+`DytR h ƃݺ/0o6K߻a;zG}W?^F,̶@ad>'G*pwߕ{{3ï.#YJ.ʷ'1I/6Adp9[.F{Ձ$R~B?.?0 @}^&#XȒ"G'+]=~e4N>N7 Db2>7B,Fzf{*\zHvݏuqj:[[6^d1$@Rp7 j%bE!{yZ;qst7^;<70}=y(|aBNNYsXL'؂B#n3}w.+Uo:٠Aځͩ%ymDs (?C&rL,H CI@-(4gCjc@XH>{'!dpM(bCAK]Vʌ#19VI!:Tq_חExjt҈񧂈@|~(RQƒܾ+b q׍VDkX|^Ϸͳ݄#7mU?=#nT`bUI~tȴ,&>#Yt:kN.t:>%nW8<#Yˑď#XI4*SUE;5L_%l]#n,֖߭d&,drf$Ld!}uqqی @Û*\TC^#n 2q;p 4Qy( ǎ/l HJmkxJ@"?#n<%݁ d<~:kJ@5d!lA7Jw hA^i/W̓ߪϧ'mP;5TOp=p`BF !t?]SWKZOvX%nrKyZ0cHr\7dMV5Nt8'gW~S*ohM|Hs#Y0 zKes}]a_zoxtǩL!&oPPtAŠ\H!R~z#X}APJ#X`T]r#X |z!w W`IU4H IwzZx.H?))?nش%O':_o/~8;#mT#RS15rы$4#YidnCx_{k$:~(ZqvBtBLUuP Q}䲐muáǀI^Q, ;@{ rjj1 f|+Ob;$ mb˗JXX,x 3(҃g(xOXWArnyO;u0 #X#n#X'#,o>Q\0;B#YG RzQ}NulŠ$5}@DO7Dzq|a@}1:cŠ<\Zb}3E!6#n0VTUj/>n]E03cv<#nS"ќ[GX7S>ţ&TH#Y]86CՂAzaDEYD5ޘ !Kw:br"9Q?(~6z7ڝJeAW}a7+Nχ"T<9ȡV^%|@ ~+Fˆ8MT&Z~| #Y$LR+ĄpXla~K?o0߁mK"8d~A2̅B# Nu1T`"v8__RjPxVy6԰ HEzgFOf䊮<*Վt#YJv*\lFw*Wn N>!I{:7ê$y[<|#n=hTy`0A]v56S(Lpß; &j˵8q\\h4|y}jZ.#X4Ub%};̺8}jòÃh :*ؕ\(Ĝ]#X [rU#nUq?Y|j]gV"Dَ#YݨȒad_N"G/r MHASREMtH"=!&dfu]%-!!Y#Yîq՘OC'Ifh,9G㯇k{؊%OqކDc¸︡% b*Bu8yg3ﱭrV3Ê_B%Glys0dG`яVM SSQ⣓+x`GWoXI\ctuG7[m 0a3h#Yn LJ]Wƻ`>O~a2lm#(6IO\F^xJyG.^H#Vsc U&7#Y(aCSl#YIB! (a+4C{N"f_54W&İփÅ459!Zu8T m7LY*^c|`E#nx2wCi&dz{DAx!}IQ#Ydc:i>,I0בT#X}D)vA?MWN'#Y|!L .HI8zqF#MIܟ/0Bp~#X1ˑLqgg4o1ݭRH--g @w,߲[F]g66Cc5Z*#3sҞb)%]qW8{qp1on&[w!s_dIЗn YPĩ2%l}X#n7m:lʧRf'Y\ǒ>IV-\:Nz57oc^Gbq:uz)X3.ev;Vpfы/.KcR<_J#nfL,؄1DlbF&׆!0wmA%@A巶w'LagMՙ50`!b8PD UXn3֩ g.|Ekkv#{uڒ[WHepvN6%xYﹼ.j‡ 1ޫM⫄4 ?9ռ&RvdВIf~ܝ.zF_ůt #Xz E0 #nk?iq 'A'5^|O/$OA>{D;&'_?_Mg?gWO:ofu{h>/sŗdZ-;& ~Ծn#i0VphGz% <e7EfJWg#n#n7~RlGΎm *]ăUL)0bɠend߼4MxX IYYW*{цxm +|c0nب Gh|No-- s@zŞᳲ!y?@NE*R ^A4dM>2vY)=z;a~G4QAԚ}a {D3#XBPleb fH&#;m6?|*#.ө9e#K'J^xqN}`sGE$%c'q#X5`o͒bBm/ˆXC~ CC!E. `yBz&,Qw<;f#X"J9GaEJ5!2Ed;^#ʇgvޏ gQ8EdDE`d0!fvvx'C:bA[bzrn@&%}H`7qrSzz#Y8e g۸5C{݃i)#XU|3̻NɲFq0d{7g u:vI ԁGŸmMP:Xf:S Kizއa|ԝڞP|AI5[uυ @5Y{b\yALl>axԊ[z,tԄ|nb<3!.y-˘T@vЦ-:A4 ː/`;pehJxs`^!9Ăi1W! 6=JUIMPhPDLGσ:`gK(;$p4`C6hr;AY2{<Z˻7f*ckฐrz6ǿ:ے 2#>Cѝ%Ĭzjt>$\<\;@m 3 Q8u&f@J2yܟN`*Pyf8H)Ǟa0S "B#nBZBT8@HΕ$@U"C]Q8gKI Ab׎L@%d5&_M7Hva;y`_[rhlQnEbQ,00LeM[H`:ao.w%(PXT#nډ9`oDAHv#FE!JwdV+$.vQ7b6T[VYv̈́D#X #nΧ@~A/I3ȝPĹ2q M^JwiFCP3$güF #nM$0$axs#Y7' [(<:UO0d}.^#XL7f x#X{J9xogɾ'nխ3^YP8+1;I _t68Wk!N9ƫnc0؂"RZ,*s;uzC^a3a3RPpӕnۿD3Wrlӄ5TNF~<)wiܻv9&- #nهwu0ue%k#YC^2DFM榓1#X!F"6iH |M@^ׂ)6R,.O'`h|FC* -Q.W{YD.;/}:9.5O5[J0}J5'L4~kw5?8C"TuN4BZr#Xj)Nq87jqmU v 1C\5u8?2`\#Yp2xKژ#Z/(6@lX8DD0ɱR 2?}J jJRiiSzye}q؇ĆZB) 1O**5z1Q`iYM~|tUd>{oO#nr]t}TY#Xhal6^3s3b0෠pC(|Ow2;t`={,k!ω A lxCMΝ60,t\¹G!ށW|_DJ"_#'YxM%UVO*JMgWg~}#YƺQh]ҋ6#toMg連uU`\chFg}r^>U#az3QwcϧԣGE|q\=oRp#,LYȪj|i{E8@r{0vȏ2ƀ&pHΣJ^M`ʸS~OOI?N]Gx )̓D1i bDTCQ4MBlDYETJݔL'puJ1c~(['h0#W I+,`dvY>d#X>j&3k-" 97y396IHpeXxEc(zd H} El@'iпLC7]̹c~Pxo3d;ܣqpqGO_}H&DTAjbPxhh8ფ?a&OIZ~o2h[hUܵD-2zv' GSzʹw´V<<+3;w.OSws;9o%;,JQG(SߘAJXzslve5IA9(#Y93X`xf'c%!fu)SR])"iRcKmdw\)+6lR{|yHôn'@}P#YhPߧjmlHJHyM#Yo_+8h|u'* {O`uzv(;/A~,7a^W<@v_)wYL#nw*Ӊ~,)ӚM;;,XzX{˿&"b}z8, DU-&3(MdJ&8>+mPy}.2XQ@V 6uKVh~׋@݂%~M2aW A@XExu{k1J^#Y?oV#Y~df=, #YXl?q>Mc:\0fzaВT W7S#X,*?|`̈́!PHHz=Û/ϩη#BxC͍F"jp6ƶug;; aCpۺ@qQTTPF&ч""#n-n'a7X> 6m#XJ]yR_];z ^ܪIqI4r196ޗG|3ʸr"@ޜS7a:\F?$$U"rOh x>|ઞ:#Y}sU>"~~^mc 0Յ&% ,!l-iE;f2@w]ٹPv8waM잭]4P]ΌeHJ^x z?˂>P{᭏I8.My#nNEj $)0HBwZv*̀1˜o~ ՕZŝ#YLY4{B#Y?r;|97X:QM3 rM~f.^d'{j|}v8yw&I ?34 l_Gw5ۿvIu^ҭ0=d)Y?4i<`Ju|5?_TZf 8[#n#>¢lDg/cU!bbrSG<Rn|t3z7cLnr#n",XN?C9pz naHMg}^ (|6#Y4k51n; PWZ2COd;&G_ꚾUP8/X2D@[SHCuOwEOwf#6D#nvkNs`@kXa]{\B#X@jrhH\̰?)>Lb߀eGNG[D#ff?Mk?ys6IL-9ȒA7#EV(<}{deF,vN:r|~p ""`:11?{:#X #n#Y\_#ooX k^2tzJ诿?I~(C͐qhNҹkWqqC)_ZYʿ{:mi&I䝞] {?ZGxRV6 #Y{HȋҬd*AޡG>rýWe7G_\j!lZF"Y>8#Y T(;Lzrwd#X$:B'=A>G W ; Tq0),;*GG2k^o$$dvdفlH?g3nûCwW#Xv,~+lEvL5 #\)%'8h_6Xޫ/a oT@oݩr3IZK/&@#n- 8@ކ&ڟNH)O@£(5^?%P>4@\~NO#ƾL#(c =ØwJ''=zr+# __|ʷ7t]c$I /O1H DNt!:y]gA4}hD#nG[^ʁ0&Х`#XcU+ӟU˲_krg`\_u^tKy1"J_`r{Ac30}S##n8|0HPJw}1:o,a)0K#Xxsbm#3e\&:`;Dž0T)FrgUM([6Yh@u'˞9d 8l*1g??r!WAD]|,͍qռ'żjS !AKW`薓i첛 `oKra[UG尯*lQj4yӧ/ŜgbI \l,xi2#X=_!sHd+ A!Y%Ġh:&9n? EA@j7S0eHN)ͺ#X" 髡}d1E]KjW8_#Y #Y18QEra} VcQ=Ag”hY\cc,S0[>#n#Y}of‹Q?g}^~}6@#nR2#X 7 #z@!Iq>nqO|)9 8A$nCa/>ɧl D`.8B$nˉ?)lt#Mg"F;Dɼ۱sRp&Hgp+@}ӡXuCnoq̠%G %~lĨA |J>_{[Kf#Ky89#X2? FYD|x=%jR #YXfP r @4.6UDXpa!mZ:v (UM؟3Y(X5pUrl5B.Ԋg~.j^a@4!#X#Q Hڟ#NmeJ z-&"܄ϣ!&S")HfB$ԚKuDs־od:lG8UmGό53B;K9F#E/ޒJln7cy6W\hB8.*#Y_zt3Y^r_q_$ 972ή(Ϧ{l 4uH )҇DޢQ墫qf_|y]w'%9S.[1)>răm{Sܶ":eNoIV]W&]W#dv|N;#ŶN|jЄ{;x?ǔ )rG3vŰ []uT}]<õif\Ah.W˘\Pc߱JWi]9w|q{1%|f98u~LNQpbA;cB*p*Ii1S|Bc]c6ΖhŠ. `/)X-׵Q<F7!+a֫nQ.񓃎><~]pڸb^KK}G4ԓ(5_^*^x"5?k#Y1蝈ޮa>X8=b;ju;rfhON8_s]k.ĝxHgI!#Y_)ݻVk ANnR1B-TԐl>63|0fBqZpo}yǞ4Eɐ0/;5?WEvJ݂ZY2zo^28L9䠎wTd}As0e6?"D^4B {^ӕx%8{T!LJd/+CZ7<6IFX1Ö0#׹z(+g;/*lV"QĚhq)CTX5걝Cȑ6iEȱ{3ʔ78{xFK`׺s;6;r#TÜoɕ|sI+]ZեO.X=-[Tft4J(v' ٗ eItNfv#Y/F`yNQ3_&nZ-E]C~ۯ}}qT*D3`#XnG w{z- dɕ;mLj?n"Et3z]3 *3R!f+:̠v}np`QbH Vi!4 n^m>YLo`\l_&'9k9yb>BG3w"EY^#[3{y mj[GOK4coY)@+cSAωT$rEr^\Mx#XD=#HA;';֥,8EDc.vLJfj|nFqc#"wn67_׭}5Cpձ6n!|Vad7c ҘΝ-xaєb%~La0ⰊlyZA?t{ZA:˂F#Y~V\)3u3 ~~|ٳ#Y?M_6@vOX2\R" $K;Yd<@G!5%5) ׾6_'qH(Jy3{dU9?O:3EK|p21'D1z z6Y-TOR~#Xmya>BB?dBWl26i5`G! Fm}|&|\dY]zp$ҟۋM #nH.ia&˸`tڿ(}2Q$3GCH~"&_TVz#YvѣӯӇ#nfO8_f.Q#Y#nG (`I%b #nUҡzYbރEb珫u^LdCȃC#XTB I G1HjC#Xޟ`4o=uni!\{gu>0|0LjG'э<87ڐ$G밇݊ 2~qۀz/KeBʽkU E3j&3S|QbB m.4 #Y2 T#nx1L`2HAyRBr"LUsۅ#fRŁ q Q.IvBߛ.'"?p 2i-߁y?eesS7I?=7M#YLU$OSrRXw⪚t"g .#Y۹#XOAvy IJb{\#Y/AȈr9w9I7F }8G#YEݚwW?[#X#nQK@'圕#XrJ9 iBhSA#na&B#n?=)ʃ^797N{D" \((5tpMh'< C #L!~#X|2~2u{?#}?~=vm`ȈkT,$_OF4}>LyQnPTBcC>)HLxzU嗋Z:khO14(%@#Yʒ((`š>#n0DIfHNbMfy"#Y tЖ,AzHr QG<# Ez`ȡv#XFJbX$\[ײxd%iE`vCK,{OVr>{ !0 46Yr LQlE˜SfK/z4jCɏVz_o,< +gݚ_v#Y}LADDzw:M[`{ݍXmg'AA茔?wxwF*"4kˣEHv''rK}/2b)_ʡSx#XcbqKK&/Ώu?dD`#LIFTDmFyp lFN#՘a $dNO}!#n#XЇ*>gj>'W̍PA~\yw$rϗ#UOP ꒀ]"8't |;#XhY#X콑ď bPHPSsXC2=YZQa))#X>1)"~T^)~sXh|r"NABԀ@U{#XCc{#X#XxQ Pk#nz?_X5wg7_\ݴG^"2G"iDkzy(|*3 !ۿt?y}ϛUp!7=\ng% ^SmK~Y(|2Vp5g6|x) Gو4vd4?lc.g[%Jtr"4gw6ޔBD]kSׅiWUl1Bo{k D<&*mޡJj?ܨ G4I:ad>,ílJWAL!p.ٮ$1a$]pY$ΉQb1A:X>(PJF#DfKUuv\]xDP$n;q-gx&>@,PeAx@ [\O_}zjf̂?b?2ǏCA?sFy{<(Ω28^:YDAӸE4̌mup4Fxkbzzxyp|v26d'vql)DMCPj#X)'tP^*x5f_C8on#Xˋq P6ٯ#Y?_~?o1p7g)@%臯2=3uR:1}h#n6GK3D@߇DP _&ߠ #YxJ%#YP?oQ5hәot:kY_yt1b+GqotzvcԿܯ M?˪5#X?[C].cgתW>ar:i @Л#X}^GF[ y@eC)  @2"NG#X\!#YgZ^Alm3dso%nf21##n[|7MSg$"but#XSAatBGwws#Xy#XP{.Ngi9>q=48ǒzұhSTCƽIF6(qIcipGb#n#XDȑX(<2t0yM#X*(Y G 3QݭHϘPGWtj@l)#nses)P`bPvdh֧=Fxg &Bvš's&hs't_W_l쁷r>`ȄΙ5>ΖCB}Aa8Tpl?k~s#9Fes_ fQ1=`fK'x0u]`%t^7PF(,a`,2SXZP~+|:9Nê'm:x;C#r**D{f6:o=:'4.b]3Zƫ^ Z{#n=@~_@#X_]5o<Œsߜ'2r02طf2 6x' )Tq5#Y0BJ;撔(c[4m :=栽\S#Y4H>9n' q:*‘c$0pFU4ǼIh.OIN1v5%#n.i%#n<ժJ j5k:.i-ԓ^ =%F#ך2`8}9q_O5 tnCf<" #nPMӇ) z_HJ 6xEik:HVWMDD5_ɳVr~7G02@@u3D]_;sO#ngk/%)+#Y'Gk#Y^J{#Y [Z_HeQ_Rﻴ%q"6%7*{7}_{BrWvCZֶUg0X(>Nͳ}-3qɿن#`8Ra~8N_JPkG#nj2,Lw.{4z@#n'R:ذRNG&c,;?JmD2ml.:D y, IA#nRyZg Si_.ͱGcDxi*U]wTi _T>2y'#c˔j6}E-"p$EL%A4eξGsmo#Ym#E7I 8;x"0-}|c9 tJ,#n'E~Ѣchwp`d7p/#STI}Lدb=$( Uߗ_V'Ɵìx15kl~PVj`Xa$#??E-#Y2 AN?q˗n]kC=.n -=L<Ncop4O=afr"'$K9Rl_( )0>?/ç3z,a - g#X Clp54d`v/Z/ 殍0T U<]#nlɲG^I3tZk˭FmIUkUK[V`LUɸd%z ְ͔240c5K2=wS4yT>^u}5R#XL_J64C[431K||8GCM$)#X2;5tYYJlbs(ה&2׌$8{| 4lM`CG?=~(vIGA &?W3O3$ J/-(NH=#l11^/d#Y|~@5#Y0#X8O$!}#X>>?BU9n>>Z^J)D@j8W8c$m57d;ƺWEAx>f+WB#X*˾l}_hXlo:^p;D HhG䚩4!"K~ñ#B9a?bNW`?\JeMƺ:yi|78\#nA#Yh'~3CY{GOtT&ә|IeSP?JHz9Ǟgw8z4%OO&Sm#X1z?Uo-H7 'g3>MSH#Y EAD\Ϝv#Y:#X#Y^esۜzaM̍ YCc KÒ$ #X֙~-&ED(ݛ0T S.44#nXzd,e蠗Ygy'gs#I_ˡ2Jx! ji +!rE*0z83iH}N7`aKF'I]'Ȱ:43NO_@>sm>i!~ /JXO_$ѦD֧#Y,sT^Rk![`r+ql\p0A8zx% #gκ>_G>#n]>9]וԝ_Po& 9Lx'U8zQ%c/D&]܇aMo 8XdĜ|q7.֏RkT+#3i괆#YM@lBŽ#nUSQ #XӜU;TN[; L̰Lِ""{r;]ci#XQ#&<: \#YC64UQo4B/ӿY !\#n-19@}Mb aWrv#YĴxxt)dO@~r|HzH^b>3Ծܙ{@u"g~1ź'#oZ{~Nx[ @3qMN`67`}hLCH704nu+8r-c*[8i$j>#Yk94Mh񥦍2<؍MjXpO :aq!-p#nw~*UԦKv4UBXnn*~ú"w#Y0#n(<[?Ԩ^ u@#n?Hh0Ai o,Ѝ;uU{3+#YzG$-z?fvc"h,&4h2@;! cWOÿeO_wIA&c,W"08BdzW#X$^r辒ϣL݃xYW ||}]6$_Yf$ 9BwV\ƑuHA1!i﹏V琤dzICTDR2$Ai2#XAz#n#:CxO'W/`VJy0g^5:NϤ:T7a9wGCMI>c%؃ٱ:8jzy$:'éϬ#YYvGUGo:fROrKAX(8AԱ#ޙJ-6p{1I cYgJ Gٙ &I1C!8t#n?Ӱ.'49ubilzXBCqt\#X^KsҜc]HeCG领ͧ{AfGS=#X7r*zP#n$۬;#X:O?W &&y#Yہz ȃiw=C0U]4Ƿ:!6ɬ#X)d?aHb $R. o ;vʽ;=#{ԴP***X~~*X{_/50ԲƲ?B܊#n&Ilk^.0a$% GπѾ:4cM,F[c!TM>?5`|zHf Yag#n5nl,]s?)T:lt8zGhTE9pCÌ'`y Opξ=?yA¿W7?z]y#Wx!yYoF{tOH_zӏ(LgrK>(ɦ=rW @HH`3јKL# e*t,DCEdWgs/6m-#Y?E̅YB$tӗu?\€(au9#XMzH7+h9DDrC0I(#X=#X>K;,vZ_N*8_2fu!,g!(Bw|#Yu5|f'|xtHj4U[Yڬբ?ҊϣAHaM$# 7߆F~RNVV9rnAgٕ)Lʁm&SFA{y;yws$''WA~@w96#YJ(fNFUT 66D,CHAx:D88A2Cg=IݧSuOΛt2/9^cO5#X`]T>~?rxo7{CМ^{{ڗLd-*@#Y`WvaR`6yn;4+jId˸zrrs@0۹aK*N#XzP9WQK!TWr2xZ_RWƣ#ag:^kNU'Aj~!F]3x嚰wd)`8TGDz8w\rrUֿ_NlJCt b^=/#XA(q1DwHӭaDD3mU*6gdƍF OdPD.#Yx!h#YZX**vuUQt*͗P 9"R`V9%.=‹1o<6A%_3ٶ֟s/{`_HRCHv!97$N~ϏwoS$#nS#Ymԥ n6;$&=ej5FCz/?f倈'`8m_ ,8>T?IWIGU?<Ĕ,`D W bw~z_=ch(Oa׉p$tAӀ9Jۂ#*=#x$6(h<}&uX|EǗR:cH~8l`ԝƠxs#[Q.l:gf_ Dȹ~tFx?v٤:~9oҷ+|@,Ku^(MHzR 6|~x#Xh&&C,{Ba&8n05#Y d,D%j蟣3]@ &?/EL-!<*DI"BdO?A}l >ň{_|Wǐ>'Ψn(B!Eb/C.&^4;?]Xs'8p ΁̎9#nY@k Ќ9}sr[gÏmR+&;#H_׺seS 6|OF:!2'8M#nsr^*2 n3 S#n!}H9VM-!=Ng 'U#~f #Y1:~n=_HIF 4c#XC=3!pW> 0+g$$9:g@ C}@5Wq^}vI2 Ֆjp;OB(J$0ÿWT/HtLlOb|$#Yw>E?BJ`e+YI$QVY$/k/(<ΖuC2/ذ#YHc&΂iA0T1ez*96ev|X+f>A8Hd'#YWMA7Q$hTGHm?eHKH9mDqqac'?~?W4>Plr+~*,#X`!5=S:^֒bu`@߸55k#n;"WryӰ<=P#YBo.lXڀ<"/MwaZ˦G1*poFhm0X Ї#Yab2!?XT?ro5m%&<~t.L6($!E#XLQ^?"("6#nkv~W'R QzV Lӓ#XgWʸi#">HA "ʠLC$߾|1I|:$_ΗF%#XR#)Ez#Y*la`#n}QGJ.iP3Cw _@%H#YሸoPWgn[JمQFx`;ߧ>!){.ab*P;&ҠD kXFğDcQTX#nE#Yz}_g. XC~hOׯ,4ߩa?)Q'~C!ݴwC9/)w :}xE#}k80)HŅe2=" I\Rz{.mV}-bh䘂RS NQF4@J1b^Ļ:Ppk*(ɪIOsױZƲ#Yue z6 Z#X*^9dQTdP'@QoRDRҊ  /~0Þ2}M~'P#@?n٧n3 ~#Yb?_.^l/v|'䖞HqoBwT\rĂE`6#YeD".[2)H]>m=v%rRb#noLE[x26xa^ѭ7";Sj08[xc0 8d#n&s&If)Q7N?u-٭l01`!0u7 aցtP8}Z?=ӊoǶA~)#T 'C#n.*6AØo#2~PpAL BtVl#X^#Y :C#Yc-0q¢,3z5N8QH+ľHTQ>-E,㮚kק"H>6I2#R~"=}t흺_b268L@AI,@R e%krE8'R"4glq8({Ƌ >'".f :W>qym5Oc(]#nJi"8sEɭE3t(Lzpг2RNּﭛ tG5|gb#Yʖe#XcW3[#H0V`dP)s22tWl4Zxr#n@ 07A*)Z+tZ2|խ,j@d뛸TdpDH|7b#q++=ı{"-ښ*:{g9̑.#n61JIByƫ*f ~l"K!bn+j>9'ז#no>Q_|sIEiza/5 BjM ;RI}jܲ|&58M=#Y]2^4x1tCKbcƼyw,KL4a%0jNK#Y U:cw1,S2f }}tUTVjQFs&%:$r΋꬙hɌUElwZP2Kc.P2t> @%V>'l8pC*!__y~Jdzzyi#nI;:燞l%yʆ!> G*z}ß;D9Ӈ"&p^"lX 'P O9'(@xDExK#4S CO;UDRAS򦁑h>?y'{чTU.<Lg#}*z>IdDd8dk#X[7!ANETEX+3*&X`N͙ X4#YJBޞ)m[A( }}I@l*w"b:Qmk!uPsYvlC!SܑF8ۜ[m i`|#Xh*XxFBWh<0O3O0cyMvxma .a//Dƛ(KI S~d0hcl7&a<8I#Y:aٓ#MYņ+L4Q׾62 m B`li6]FE+rm;nk^dw5ɮ\a͜-F5Dq/$I(ۅY$6Ί&ShM#n 5FXb#Y*C_s^%گq\Q0pǰ:`vwy2"io$cN'@l'j&{Y C̳O8K:ϟd,%#Hb#YߒI#n{B0ǿ6Z׶/d&Oc<GHbd榏csr]ͪN Q*/{]PF5k2xb1(uAR.eS":iZTJlj7MIН_!R:O=%׸-3 _ E&ˋ)8ۮ<8նl8# eK'Ap+'/l4HzN`tmBCr;f\4)4yDg}e.{xoA=LۓIw_N4Æ>5>%ed8_yzRl"#YG~^=TPͫ_8y[v-D2yC8=@csT㪃E?=Uͮ#X 5=$-qI{aϣK w gBE.P<$YĔbYfg#YJ"vfu_qM1[N3P=dž/Ԑ<@Eב?Lj Նb鬠IpG/ѧ;GPMpq5@ Rh8̠+P)qRy#Xh8wpﳯB*i>>Ww vOȽ#AcS0՝#Y;e^1{4iH<DǣS6NG^f`X4PRQ1UPI>EwᛋKM˜6½=TȪ*-%eyr,YnaAb{1ӣ}Ky,D`0a#oOv ;fi (^W;:֯wXr'#&lF}׵v\=^iBu]:8v$#nBi{R#Y鳢P8-eKFnF8gd.;)jGZphǼgGݶ1oGg `j0#0r'{h xqϳ+#YArnqwdW"NTv;'@aޒM7}ɻ3Ok2rCjėF/%}/AĈeE#nykZ#YE8o䏘1!#7/7bH^~_O92B#YyECy!굅w']hDe4:FDߴ=)j|S !lJ59*!`:a!|uBܜV_#XDX~OӡU<(+Yr@ A<42p2p,*,/݅M-b2|{֌]vY;Lk&=kA x$lyKHLa9y&OU4Z g"16SˆY@`LT@?/j|vM9r(Sz8#YGӄ<ĉG/nF:we{T=#Y=sosO鎳c}-tk[^kJB(?_OOc^}Uڳ#X-/2Lyf:I,iOx@$#{Nu@/t\8Bp=4kߌ̃h*&#YY.16?oehU؃އ!C A_Fdo Y܆xEn'S1όx܌`v){e@|N#n< buд_ϬݮD"wsDۗO/Jj7*cQEg:+$ y*cx1xcmIc녌)!r-;#YJ!*I8G\冎Aa zRy)c7F0cHԌ,ŀԩMFqlCr+'R r?֯4+(qsJ/R]A`Hp7eGI:k`ٟX0&lbqFY#n§B^>ϛއ{#np~ļu4w%N9}a j<ˈtN{9?DDLE%P$ʖI)#X&)eB!eO%6EKd#XtćF7iɑSe,H(**ߵ#X#n@UoA%PWDU{5ڣ@TqP-I5$tWWo*}Z)ة9o,E чDG??WLD,T E @0k'b?#X#Xs͚5#YVx䮲z1u|ɶČ?L+<5: {!(_\A?ZL#Y[Olh4"$q&9M|7e$2f`JQlM vT:H ||F)`w*RBNqF*~2r$kN!#Y5#YJXPeE&2J>@!gAW{GO!x"?`vXsց˿,Lصj n|gNř,Q9&tݭwTh5#YIPG 2ۧ2CQDV{|DoӧVZ2#DDۏP#XH#XPJBPߞA`!D)A;#n#Xh@F4%*BL2*߬#Y>NTW%**#XJ1DD &tPDvPРЊ#X"C#n/ IP}pch.;*= JֆVa>V[{>dEt#n1]Q0ĩ#XUb<{2$R ڂQ֬`?)'i,S1ҙL6M2^` Bd3Isą "$B"t8&qѹMAОR-0L)#nZy4I0P4iLHb$t#XQ%(fRh(HsWj#Yn!0 bqNZ7"$!OÈz(8=]}>4D;Fx߬b@(b=ćb`kc%d>!/<"W-^ (#YF7<Sˎ&IIК#n|RtEwm;R J4Q9IP#Xg].r, <{Λ0EЈwq17bb#n-A$Bt`b#X(U:z=uW̾8O7"&i@QѥsyS?OupZm\4QY9M8Z¡Izfjv6 N:qU7pU=~zQ&#ne^&LqacҘ(M:k&LB:naFJ$׮eW2z32ux#X8!@?C8}j~Y#ni( H Iy!#XP0#X W/كloXs&IqpI:MkMrgwbq*" tzs$A5>od 'X/mB9#@0 j4{5Q,Z69N@,Lu "~l+AfTpUA$ߞu^,i1J6IzDecf%1$#Yxf?vZb4]T8CLtEQ7䭹#D2& -4#Y֙Rd|']%\.(X[2W8ۗP" 5ZC͓l{ʡxxB#XBcU]眺`Q=p!l#nH#;^'9̐JP*d{y@=s܉7IJQXࠞ0 Ǘjg|DB%$Q"])#YTP5B@#UK[b$ڣQ ?\#Xn=-&LMLT44PIU!H4Rn@hǕNH>CqpQ5(@ki@>">0Rvd p~#Xzd(h҈Pw35uaHwy<DDShJ/U#7M~/%ij'._Ou|{ʩ*X.gqDzky2E)/tX+;ᮅ@ļ!>`6#Y #X@U)uڅGm2L^ CG LI$ m9:(݉XX iL N d?/}ZF&ԅw=Op=\slĜANـ[CUnwOb}l!֕/cyQ:J>*u8#YG[AO.{~CGUΩPgRe43EbR#n&؋v@-L`4E?0%5NC|+;S>GO ;!; Cx!&i#n4 $Qg^' I C=tXO& pӋϩz\O\Jb-3G=),ρ2aӤ;.e csfcDI3u6>I #YlU:y̕AϏf0fAAaMy؆Gg[C#*#X 0/#n5ʄ7 J]/lP-(_}!ʙi,E>< s#nL#Xޤ.ĨmDEC] |>p^-'H(\UeL";+DP3!#n;/XF # T݄}z_ݭ BlW N^ԋ"v狡aD;!ϣ9=_Lw݈Psz8ϋ`l:#c뮝0F UDio.-S-#c)h=z$'ow;džzU T0Ԇcm,^=|yi[iª*R,UݤΛz5U#9% c~UU֕&́Y/t0T( IV&Ou'YG9$'rOnP#Y}3rP"DO*ϦZY孇)#;s H9dt}ٹ6ŋ":ҧY˝GgN/{tqipFY|7:edTq2AŘ۵F)?˚,`-jkG\yOA SlM8)xxz-}"ƫ+2r6Yay}GpA@{v@2#n0H65v;0g<9|1@)otFʆhQt]OhcV8l<9Au7M6*Q"T}v=>z[E3ŠkCc|+j,|CZ$H0}?sYHܵ%E2"*]ԉpM5ܥ`Q%Mq/n.8w3A<802ˋxZ>Ғ##C^.Z9#nX@Cwm{'ɥ<<`@uX%8dLj)5R\nQωpk×RÚʈu7Dn#nUTC!ǿM۶mɶ{D`]D1 Q7s$#n˔0U(﫹^=6z88(5=xk&= Tn:|or@8`v<.FG0SH;g=ECi#^%P$*Rto鸾z.X'GG˰}yI@ vUM2#C?^vѺZgS^l}vTѓ kHj#Y#YSuTRDn8q'kb#q24Ziڅ)h&#n&B%%SVWB!Vr}XS5v0ݍ @p?D5u='Ԟ|tG#nx ӘYQcV*-*¶O5)F̎UbyHr]#b#X@$2Fy@bTCc7='8=7#h>ǒ}bIzNʳ#Xl)BF~3C5ZH<1#Yف#X(Tal:T*[J5[u42i(#YkTtC::q+}P 5 :Nôf:2y@?=WN^[E$a0G0zϟh|PmE!~-]ynuz2u3* *Z1QA#+1 Lэ:$09ejd"B#n0"Ex q!AF6T~sMrmg-WHѴsp \$(R׷nnaZd;-'0@t I8W%6HHs!:J(QVC#7x8 qO@}wfR{jKL81G郔=hgOnehd$>D0L:'m, ' {".f ax$v#nWo8櫧}GJRi)b@)F"@6t 1PpҖ2tTTE*iQ.k˓f 4fX#=G4Ө~[1ֆ@&gjE+(|>o'}܉3ɠ}¨>ҏ4J Yhn$>5̷KM,X dwHCn--"& T]0l>X #Xa4ԙC:VS؅ 0w*6iKĨC0kv;a֬E!RE/V|8Pr= ´+#Y4 [QF* l~qy")Ɂ;؏[Sbl?Q@FUXOX{1'#}.Cj(l&(1-Dó!) kU#n#Y1lQj hc].C0>׬1c6 n!!CP FLt L0 gj 7@ۙS uav`=Ω?)6!F#`81#& dxi8s_#Y۸DdHl4/"D's8<4f#n4B3(.L=D]=y9@]g!Z,J_Xc=9A(UApn=3|_'׳Wi#Y&Q$sJ\Zyp< pXX1 !%\$T|ȩY0`iP!ihD?V7h`NsAs;ױ`XiL%KjoaJ; 6n8聊p{9yUH/{f,܆9s> 磓 ዏd`hvk#Y["HuD?[):.TBW`H׃JyB-_$P%MMgEth CۄSM6B`OCOSD~M,'p ?2Jz[[u:xM RJCyXtprkR3_Pzt4n6֌>ߨL F!'80IQLRvF=7D'T" #XxD{Lݬ/ICZgpUIOMa#.%4!=@Hؙ#Y#XpQ|@it'ڵ)mj1;_8wJS?CݒBhTQ#nGA-#XLs=ɹHٲyѢil;MAu$G" Y Q#Xs"(O#Y*YBQhsdT䈈h*Bh1R )UJC|5!"i $;)#nD s*( & N_}E)NE9J/g11A]D(P1:z7r_]tĘ^!MQ%.ㄍ)CDgB: "d ֆt7N' d9{MG}|#X<͐:;֘Mjp32C3Io0>CIG\Ǿ2^:rLK&wNX3JAsZ5A#naY$u2Parbi1W {-(HP<ޭ$m<"l'L7Xc\Ӛ24 IN700r#nx #Y&44<,5%c_Ec ܕa5+]ZEzj#nmH8]ܦF#Y4Mi3pn5LK(h< si<Ǽ #(MVƨC]3Q̓VQ,ڥAO,uhAGdXi!+5UG:HVpYCVw{=L$#XP,S4P˪jB*`ԺgMa] >y;Y[>\:u3V܆%{PDm6!*CN|>*qVH+|DViXFqauF [l}69aƗDX<79nAN ԆL5GcqG/6_ N`]#bχlD! '#X&g"j3 8/46L#Yͺ`kPIڢY^B~ ڂ#nTV74uçf1W>C)P1n:`WO˿~މ$דz׻j@]l~@#X4@#X!_5.Z D^ՙ2z-QTl{[zIzYUa&hy4Dj;Y{#vVMo:-NL=eWD7^}Gpv[dæHs1TDuzh8 BN杧@uw$αt9Η|[/f@D )@ Jg@~z7xG#X0?O_?(_;`gj6Լ\cEg>!$7c1mN'J1EK=3GIԋ8"M;u,.881X8#=`3/eP4OAT-+fEJ. a>'Rҥ>nWV|V/&x%.N#--Oljl;opSfv(19}L#YӦeQ)Z\T8~0f<:8E>ɼщnOOu֔jtJ(tf=D<\vF3xw:{1] t݆@ڧEKM/9`#bx3tIEa[fv⸚èC#nLr=ѻr(៧t"QY:u]m&kl^#Yb2$9+4;τǜ9xf+&gkM" %EͲ=U5D[Y_UT\#@H굢NCoҘf2;væf;aMM\0ݧ42}:/3~ciY3ЗA;wh#nY@lIQӶ+ӨQotqAYe(%Ă(g}.^_)w<)Gavž<1}PoakҒtcz㞎Y5:۷sHM4{10֣\3?9xz3A l"/PRrpĮc0$x9Î/9za%<{OtԆBri0gX@ g !bM  R*i<0 *Xv02mqVq?n:<3ƞNR h7#nXʤwn6ա%ByeJCf-ZêٽB0fE?q$IX^^VX.Z-xDhRPOYj! w./)E*];)JPʪ "ޭ۲TPN%ijQR&NA#! Ǡ4 I9l5|B306#Ydiяa6"5(gh`Dc1X5`1\C¿H0#n"Z8{)r*fwb *\-9 E5MF+vkz3oX/P &<%E~2+Yt#+Thumu- BbJʽLSOx xG/adgn7unpS[$g%[-JS&rs#Y# rX9)E6Ef3 U$Rfa dF>sU}U#*8'Ih%ţ6Zvf؇^-2tЅx;iƔh19DL)u­*d"ICQZtmH:a["8;*r923&rfh/@b Ž~p%EŽ<.8f,ΰ8wFDn)Q&0VLW j(;.^ָ=IH[;h[2ptxVNYs\BpuZ;a#nC%; f])6s6HC,ڊ"TB͔9t4ZXmepgXwxyO&m#s/PrO3@sQD%[kqYBI6?t1w`b;:|kȍFTc#YNZ^&&߉#]&*gZ|,c,Tfb$H™֎mnMd3p6#8;!wlVwЌhQFr/w7pET'_bZ}лkMYy^J^ u@#Yd,t$ Nt7D/ro:SG*, ؛2rN ,Hqd:O$<1pWeBd&1̹m0l dL+\uF")g83̱S!MMMyktxda";QHj_XHI6jBPO3Mb$+)"MoF:&tۿJԍ4\ː+,h#Y ږU&L7*#ΚN#nWas=͜Ga3q! v9vV$H8(848̊k]=F}Nm>T8BKMO:fUNf@E;0)3Y 6=l(&#Igol89#Y(t0SWvYÇT{%L#Y``1sյbTMΜ^PZAXN:dvx85>E84 PF)ph.3d( Neƒm66 ##n*)#X}D7G`dY|KԝR"E8M6 p!$⼒9tE$DxG0h4C:K#Y2QX4d 3ث@ѡɆBL01L53#YarXa̘3I,n39DpKp#YYAБa.R 3#YtX6LPqZ6y㐩f֮iwίGMVoa3,*yHYİHJPID*JQfȝAjSh5s䰡#4094 " 0潯2#nNC>fN#X&^ϣ}_I ČI {qȪ`tC&%#n#Xe,WOrG{D!GN0s:OZNݣP$.GM3#Y$y#ny<;c=u<8v iN#Y ^9!;~]#YXdx2#YgxKIBB{#XA#Xy.P#XH6L#X0~.v~6Oqflfni\ӗGGrxhx:م#n4}f ;'wl%-SΥ%K PCZI8r򇓵YB "8rDf3Y]r:Coqרr0 XLs3>2xwlpO?YI B0:vZ4*J]PnL tU΋[\֪BU38{ƢYZ(6rznq)p$Lэ ӳM.X4Kı^NlnOe!Sc+I)qU(q99)9;:|&$Chw̘xj55G;oz:>ap= ,rqJ0gt&}(Ms҈I:EBeuҠ X|O%,5T.tqv߳U֣dΩPjĦK=䧗bi#Y9l;"J0x(v4†)s㬔 |$,ú %ߺ.(/fL(R!_^JżxRZxv$̃ œRIL1#YsT@t9҉d:$4U9unpOY@zZ(j lӚL Gϻ+o8оziѣ-\#Ylr+$N<#X;DoMsT0Q!-IH~80'@D))fiĤO#Xv B@C/W (T71v<@5ub#XI׉z6`SƂCM*nh.i4?j0ERn;M҄QzѲ%}#f8VbuI"qu::R^.I AT@:HugI0V ƜbpHV iՊ# 5`}0z|#XЯ{G©zׁNP}#X<ݲ4usO8>ф+Ϯ%)ǎBiQd)8C̈́6/ 0ߠ pLbC dHțN|(VMOVd}Rd͑(@b,?C#XT @Þs!Se`s]ŷ}7`c[]6st5(‘}E26&mpe}RKumE5:&Z˥Gȧ3v!Տ*("'\pfNR#׳]#4'B$#X&Ƒu/X>#n9e93d7LNF%&#nqr[h:bdሼN!VЛh19p-BEGXza]~uS #n-1O!M~#XL1x N ><"JQH%#nDM!CDKTLLP--\JC: (/u>e5ސ~`b7G x] p#Y5HZvf+\G=oa#Y 2l/ܻb,}çN~k1̘{w):"'Jm2#.ɍ'C,1zrceT성|2 x2sny!Hs֟XD=N< \lC$˶39+u]yis߯Cp`>ÅТ"x%tC T@J VR nzZ-g(PMXIGBhuYV]( oI3!ZYE@p(.crp_JBU#YQNtf0J4;~r GG[*f(fyS.b#J0D E#t#Xب˒ H_2t+1#nA#Y [lPPRݢcF9hJGCwc_-LLhb9R?! ?˳htUkhwgaA {Zg䦔4tn"͎U1qꡱe99wISܞ_f"4w~v3\T0Kb7YŤYYڸ4$nbrxG#XX0m sVXk5g ;+o7G)2c$]Fu-*֏+al#nrѶA#5$¤ca:![uXc ÙÓ xr2 ew2=:KtZ$#Xu(2f}:| @U'W@xBʑ!mC$t4ddX%0fay4 XAM*)T :h6E{|$rj xЬB!w$Гbr,M#XX-E<+f9%wWBPqf؄U`r xsf?ԨRqp#X~\!o]9TLc }F+#YL1jT$:CFcM3##Y}ԴOAV}FCq27S:Ot-} 6HXaéBs@#XBZ$bS#YpL%) KB4n!@MY>F+s,Yg"x#<ib"x]C;ԝӻ Zoxw/FfyÌخ1fRi%Lz[Sܿ#YSi89gIAҤ6O8?n&Պ7t܌OXz֓5E#nHة]nOʬHô7i"|L:>g1u&&jUICd'qm#Crf1zHvFPP^Z0}甥5I'4RoVV1)LKq^]XݽgӉo1Q]D+sE#YUF˷If"$18̏MHg#}:Dm @`BoX;?P*꫙nf- Ϫp_کm %6TLIݥΩSh+䗴BncA8k %ڱ16KshIz9 6.&/.s÷s~` ka`7vÌR`;]7|g>RiлQ\=QC11T Q47jzwװqdӘMQv2`=m,!4s*drX҆u孓#nFĄj#Yw$pL6ա:9M5t" !CG&07Bp!I#n"i|;CrT=J:J,$<#Xiu9ʬ( ̳#X?АURi~ewaXG :UEɳm=UΈ$,&{]Sҗ@0l9#X:%ۄ.R@`\[>d9h#^b י>( "HR v;`Hz8:3!JRDqd,-\멽 :k.)*c!Ď'FoUpy;b!ۛf,m||~zaQKJEA#nA(S%F9 V;Zݷ';8ֈZCYIbbXĹIhI#)WF4f %T"VtxHxx0cξ#XNPJDEHAD$#XХR ˂@# @J ,==Fr#n#n)(P#n$B-=ݙSTU0SH3)C*hsB)cE/2L@P>>Ԛ]`Mm1{"RMYTt?=wM߁H*H"B#XE%-DM4U)"Gk#X|PQ~t:gGSBl Dh<3@pwICBIԉ] EK- {rQAN,Cvq¬P2)U3F%A"L{\kLĸ5Y%u~&$άu!Iv,Io MRsr}@:P=C^_Bv6ybͤ+514TڂO6"b>&)ik;?wƕ"/V2N@p2PBT':%b%d&HdfBy&v@БQE""@LB-#XyfFHdtCX! g"SKHТRo_UN>#n"; #nDЏiT`&hhH#nG T$#n+ 4)#YCK亨)$b" b#nh#n()&""#nZba#n H"&X*b $ab*H&$ hj$h(i#n`#n$b*"B" "ZA#n f&"I"e#nI@!X#nP"b"TR&!) $`dNȩ-4$AEMDB L"3(#nX#nA40 !*$h"Q$!DE\Nz#Yq雑7^c/x5ЙƓwrJ'#Y1(.'<;a6&| ϴ^#Y/+!/2zȁİ(>{#)'Ѱoւٰ:&:O(ō,q&}1y.`se(ݧa9RtZK<׿8 S~.ι#Xb? 'li6R&]ͲRĔ8󺁱 ɀ 2&`ɩ5q## $xI'y:rf(vT&qC!>Ą#Yow#Yԫ  4DDCRSxb#XzBh1& WA w$#Xi5f$ p#^s~ZLv|Ja\u`:X dz& Su˯#X2'`$b%dF̓/<3KMY0x.,YX#Q1IS|**~2#Yehbx8G=qUЦGGɮ§DW׀i"kc|i #C*~ۮT[( *$DKkF2hflAQk GENQ}@@ǣ%"mUUTUT#HRQvC@leW|ɋ=j +lh )Y sr ׁ#YNuTXl*zߙ2'^s!щfe~`&8cژ悜PF'rjw}SLIsoOp91wU>MW}zz;t_(G0d`q_!E'!?Ay †I:'#Y(#Y*k#X{\'ѩPʤGpQG_0#n~$*AQ=v:İKE@M{rRXe.2G#ngYͰb$$f)d.gۣ$ N8s45ytT&b gK2I#ARH^Rxh;e*& 6Væ H"cM#,쇦%,t*%‘Ӽ&UU'mݶKQA鞩Aч#J!pCG0$t"X*h#n@L`;@$E?4'@#Xxp};nMP#YRa``O÷e/E.[̓ƅ0##X(w(xvccX,a#Y,+6XLoG<jQ%W Q#By(kA3n$&#QQc(KX#Yl6:Gm#n"ŒcA!T4EO&3Tu? ^*y9W +텶Zɮ.]\sߜIpuoqzpмbKh\*1O`3A e;1O)FJ0_nU(^oD/@UcbA!LdJ  nY+Ks,|3̽9;ki4AZ2kBŜհybFS6NObd4Sd@j ?RSs-(DChv#YH؄d7B`1Y#XP$>Zk]EǿEMUQml{,A5ЉnzlIn %CQ$ y]], z,ri#XJUbSm0zb!̾Yۭ0iw;Sp8xxq%DLFpjLBii#AIH!o_eOHxPiLf$b!yȫ戲䷪Cv^(e C3I2D #X˯FEMN#YS]{Bb#nT#niG/#nJOi腓@T#YRĴ1w`bU!BSO:ʢMB44#M0T$TEyNf$`/ڠ6X(y۬t28DSU UAT%дG`|E2 w$MiBUL)i0h|%8QDPkLz#X"]/lSڃB4M#Y=|+ m294@ʓӂImzͧ{Ls;_< 4i#n;3p=#X!郱d)ٹ7gMbe2ӚLS2ՃJʃh7+{N!P2 iR~с*wD<7(`}1E#Y պχO 9K`rm6QFeWKզ3fuDz=HaϦ"MSV\ <:BZ(`a{|КjfGA]R,Ovv5bL8xGu_7FʚqE& pM}RP4ҩxsdO%]vz{~|LT?BN؝ P(-)I@WJP4%% R4HB+IT DP S2)B,N44B#Xi#nB4#Y!HIRP5K@,E(#Db:#X,B4PSD4AET@4-#XD4%H(ZB#XJJJi)F()b"B)) N#nD$"m#X©7gOxhJ#YC !﯒0vB^] +֙+E* $UJFh)H ״#n3 >Μs*>~K6Abœ!@<Ay&EQ3YD#YMv H8#XH1gnE\Cp˲ ;1UQ#Y#Y'xtOЩ9T=P[[bb)l6PE ?&LUE& >RSMPS4QMPTAID@LLBJ4AMRp8$Аzչ?Ё?P4#Xΰ5@T64RZva PhLi7&8$8"%#Y2Â#nXF!Gz'?;@6#n#XMQ7mBf)l?{"=F𨠕A/QC=ضuq _^tԐM ()1X799es;7;#X+Q!@wcm롡%z'FIEa 8˲"L)''Q4lDQ449m Oi ^D EZPZhĠM(CH NJ*ҁ }Up6j NB)HJ#nGOp(|ِ&VUooSZ#Ygj47[Dk(-&Y36Зg t0ӗJ2fi(<7O#+dFQOϫ$,;#X^sn|^| ^P#X?׎RN"D#Y|;aU,J4J4#XbJ,0 ДjHx?ÎQI5ZjN5B4]_uU$;O$2(DT::]\Rn#n~E"ZJHi7͆}Iy`p@r %5iuW>/{([_E4TOH`4]Y"zhRɝ֤ƹ D=d8&Clc2^MŒ`ܹLK%^Y*(%()+Fŗ*)98'#nf@$NΨ,?SfSLR̵~\]Qόtvt%+),; QJi#Y#qm!(i+8chk0vNG}IF4{K$"rGr֢#{%yDvy+x@mdLh 5vX7 IM21;v)]9Ay<܁`(i#nD";&zuRWsӆ'"!b(#YDmtEQ6栊VHHr ãP}kFr1ƴ3@Em#,K^l.V5rc}dd"b3TLG#X_y%0TEd| P#n Tu~eG+rA!Im_ x:KIDډQe2Δe(@"82Ƀ8 -.4P?"TkB᪈k 6XT5'C9;HGU0 {NlEdC#XAD*$@Ҕ#nz xR#nh#ntRb46A/B<^Y"4p K D&C %UĀP.@i ($)#n6&bW,JfI@H YMPR Rs}BN $() M#XBL 6 ϢS@ss"RJ_e3D@Hf\(ai]A?.Õy}%@pY3%9@=~uQ#n {\0>WtΑ0C ?!vA'5=D? DNJbhvMgo2gPpz^z!g``0a18 !!0hc!WRQGB4Q2lvv%.$##XH& k&i.)B4ٺG]@qE8t@ZMY o7Gdp\0IZq_npN]jp}-VOHWne N 1pLoXCUcq oc^^>{(lЯc!R.f("\9 x44#YXTuÑS{Wnhs_JhRp 5Ѣ,|A8!}ҿuupre}$TǢ0Ao6$[P9<@E8*j& R_2xI$IRCpA44׽1@PDPS5P RN=fd폯V&e8B}Meʖ*1{o(9.O)]:I&#C K#Yd&t g&S[K,[]Gf]䤿ųXڧgPcWr'TmL>4aQ}vSLG.lgRi=&yn&L;v3S#Xd w'r4ftG~G\~o*{v9$x_41A(!Ec,f =(ēk9 "#Y.ŃƼE!nuM3#5*?5p-+ANWPG3d6pT뻾;۝E+ gݒU:*egюv,:cjL$gz$RtNbcVr*z˜f$.>rQ(]nX1aGrҷuvkXЈ+Z1 =0̠c2"N"Q) !LiPQFx-U#g˧[SL2#Yvc2wx'ICO{7q#XUI'`Oա֡ &T#n)-̀/oX xpPa U/#nk<_#X;VXpz:yyG?ǺqLo~^ۻG#YjgB?auJ{Bۀ{ 1@Z΃1ƑlqQ/bPtʼn7Fwe;ODgDS^ !CNPS:M:po1 ́ڃY+ԋE#XmS'}k77okbkf*9`i<\ Uta!`HlC*jn#nHxr4w:d#%ThΠ?y˒tFfu#X>N)F^3*'b>MIDԅ4R -E% !HR#LC@LTSB5TD(1%4@Е2Q1BRM4̔#nДDTPRAM,KIE$Q#(@ԅ13I h*BB)!! $* *U T  DMA "D2EIU$HIEB%CH)!(,"%E$LQ-PC,%DT5TS#4LI$PHLMU )EJLQ$JP%5PpzrI&!c`ٍb1"F3D2̝NaP7N@;?UtCr#X#XJt"PY;@hE0Z@ J2]N3TDqD)#X" DB` [!M"%":{#X(td96Z"w2| "`AT~?ߚ~x P"z׌J4ܿ8ЍP'RQ04@DSHD1BR#XD4>J^ #XA8@8`:@/8oYL@6ؠѤ0@`;Ԛ'[N+7Χj̛3 ]#YѓP9:ğ$'(g#X$kI!˽֊Թ$#a%DmbApbK:W}0uϖ8Gl#XB'D6#XaDy]*xWJX|.{Q#X>H4(oʘ$yioȓ J3LA (X}i1=>2Y9}f@59 (Rb(F@9#X.V?=Ny"O#$f"@w`;dRR*L`m4Dd9q^B "$KeQda(q1i4)JT`ZhljY,9O/{?z}Ip-`H1 ;0#cͫ?Fi⮠qݠ& >ϳ͵$#nBŕp5 Owg,1(/\HoHi{z#n(\9EEJQ0ITRPĥRB4UQEAQP Ü*(dB*#YyOQߝۦeMnHHpa'$3h%*N)',<9}@V1"t/Lh# Ԇ˼´^Ӎc|IZԴ- όbLu1 w.#Yi>1q#g2ΝL$ٚHMmf>(wSE=}'|g#$gpA-4W)?\hB&,J>E(*ė {GRA/} ^ƛ;u C~.$ʣd PwqDB-RK$jBw#3BXƌYR/DŽzn(#n]'֠]j-B#X(Sۀx-U]qG\1boNM#Y,(Ր=lB!!u0#E-@/`<')r}BרFsR; SJD$,޾*^9An+ͧMsI?\ C0䎃#nHb"&!&eN)!H(8|1CX#YMwQ#YŦPAE ;jMqѵOrvy#nTq@Ys`1L6ƷZihiIi@h59H&#nv!Wk?)C`8H_x!P {˦_(A# $'y#Y 2`Ϸ^r2}gTL1vzQ; ݇ GIS!QÞGjjRR!͈i 'Ѵ3N?<,F+"!E!J`#XDL 4F@i(n3^v]Am([?I ;>V9S6':bۥQF/©.F*8A ;X^*pS,\ ٥!R<=#Ys+jYKV{&0RvcN9##YXGōq&bUA#n# hT.5#ۉq-45dEvX ؒDH5jCf=#YVRU2΃qq82yx 2/? $$Ew\҃!#nj.)46F58Z1hYm;i^=:Kg'h;GC^$[J'J oߍ#F#Yx=URxLꂦ^,MdH`Ox^wcς"I4P$mf(8XYn#X4Bv]"A#X?7#|$ wi\ZPy!QWjH"*D ah((Ah )-r"AJP-$H @P1$46#n@4_⢪YH^~QAkh4)'}11L Wu(Kr5enH/+ Q4ɲTc1duT%lミ0䨝308.FԊ( 8O0dnפ-1͖B,kiVA/}G6CAx)HR#!~#] 1>8cm۱=$.A 7@Ł-1`(R=8896qc҄1`Vy!QZ.nѻLe%ݘR'O(TVT١,̈́q "`4E@=)N2*q;{I'%|l!{#8)HN#XOm֕/6Kd~9TSac4dY//?,>#Y`vY8N-1C,0IY׻ҁ#XY7 }#X]xBXC3^Br"Q(+KӍhնk>(1o\̴RçTds4Rϯؚˀ$ yzpI'_Ç0-OWr8=#Y$_ #Y#n3~9U#YHsr=pǧL!Q(e&Őy7ϸӗN)ɾx 8}r@ fS5v^E9Lv´ܦſʰW[fE%:^ocMK9u4rjThcSdbq'VE #K#lmuyVkq+Jq,RZˆ?ThxHϖ\N]#Y_#Y&S5LT82s ܡTq2 ʴ"gV썱R KgRp8,w$m:.*['#XP$3w!Ģ#X9C˴4$(6DIS% SSP4%$O.BS j#nm{ 206#n#XǴ.€O_UFڙBvGD;~&kLS}lvzbCvCZ/:sǓ4E3f#n倨#ns xBEAh[sIνN $\n˃qr(jDpD#n*,rhP#n(iM@= p#Y@| ~fJWq}Ǟdzl=_k}+| agj'XB) #n#XgǤ82Gå:U{i18/ݷ{Llw{X7\l,Ӥ}$w\ʤ!f/V,LgF0\1FѸnzkt`V4%Py I}<n0xǸ۴$Bi;zTۼВ\bƆSiv ÄĤ 8`@$"J# #Xp#nR$HDQ%(,BP#n$8&ǐyAD^X\0ulsAHjhHf,PVsQrR4aGJB%Vgv0&cuRq#n#c*.A6AN"ArC=MB8ASM#@D@$Y:_tyFN{BX"Vk#YE}:N|7:31B; q ˉ=y95$$fcծn-#鑶~^cJSs58g0llŪJ)]9p k10ӫW&:x^SJ(XHL#Y><'Ğ!pfc$pK#n(-`_i$|h^q,4\g .EE1)`B DA#XiJN;h˽0~DBZ xd 'N3kckyӞ|/Bzw@R3)^Q)$˔3ynln 9ʃC#04#Xxb<%U'R`NsH ĤHhp+C 2E.>>N)qʪ#X#n@?_` 1GjƳJz? hHy||_&C$@s-N0tg̺Ia6ʰ}ffhowhZ 4MHk&`&رW"h3E1c7t@58W 6@$ak֊>%-B ?:^NNLi1^bMk`-DP:'{ 8#n:'#4^Vhŏj.#XX `šx.F(sP={^ypB8Kj]sy1 D=ݧo1@gvOoc'#Y2BJ##!J!c85U4#X @.ln u$=}Dvkq);."*BwDXEͲ?Iy#YL60700+8 SENw:ݽrSO{3+ tϺơ:'9UmyC==σĞ=6#Ci-Y"Ho՜Ih<]+*Tè!ېū)d8aHz(C@@u>B~M"bP<1g"q;∻|K`񖄠#nZ(RF#XiA[~<9RiqbAQ9i#Y#&"JaTB wK jه׸sV"8v2i#c*IL7#X۾th,>|)C>(9j*6G22^N䈝!Hj `)TJ#X#bMU Ga8$4C89GFI;#)c/J}f59Jxð1~T0,);0/4}|z~>U^3@ m#Y%8)!IEc#Y(|XX#X% P>Gۛ&Kf#SFc]!Bp2D CO0?#XyHcAP DOs90#nH{nslHl2p2ʓX@tC0?:<͂*>LM4 B\2@?úQ8 4*ȴ&FRhn#Y^ Go~f\hQ@hC Z,NVN,E.'#YmzF~-Ym ""G>;!̅6zPpAIz| ~7v]02ƛ]BO_;yvI(`I’Eݗƶ[)BWu\ #nM?Ţض&_?:4fl3Ҟ|̹w}dFHlg4 @0@5\E陇)99:nQ`pY4-I>#n|om/ iˣC_yf>j}nE:'Ը(y@wss\#n9ց&}ΟVC875?(f3Y q#YŻl44>TH횽MPьE1B[\"4H<NZņ#nF)%,AACM,cfssTҰSALյQ1r5OC> ŗ|c`xG#DT#Y4X)-9Q8\ AA@1jj`w<C.$!#!~$pyͮУVS)] 6SQ d"V*PbfhގfѾ7o|~ѭf"Kn$"\#Ln k6˲G#YXsp/qBban5%Iс#Yj>\j DœyҌy8KZ>\3kT4{0瓂q2$7SCɪbPI.#Yai-(H1kA# JBHaLi7pnkkq;9yDt"7#X14z=& LLRf#Y1X*4(cyBw;ewhE"@ ojޱ̼-1iY:nݍʍ=2Dqڄ-,0v_ϛW` >F6-B#nHއL`{DƵ㕙5}50Ed gQ2QRx#Y]u,cbfJ 6#r I$@hO<}xGN+<%Q׬,x@qJ2A3/FV2#ce1&7a Je#n*[o~)=IFg՘#m``#YjXh 66LԸe8$b1L@xB^ $xY )*bBUBJ%)H%%a!^BCnjffHM#Y49#91uY!"`E`{\8)d?t6,zR ,tpU4$pqv c=4iuF91UI7m]wcKec! Mi#,, Ì&-Syr*48^Z0c@p]׭[] K|iPm6 Lm#YZ 5+#n9Њ ct\QaO1+Mclxeec5,S5ce4#CSk(ֱ61ŭi6be5@E#a1 Ó0LXaD1#nEJ6w.sˇSɖ+xn)|O<bO8'0L( bk6pRD0r)ՠNv;ÎmAT,#YGҹ6**nF:YM54\pFICۑ0nrkݏ,t~#nm{m.ftqM̝!M;' uçm eY*6Hu#yoJeb'Nna:Zi;NSA4sDib{FK\"ʩ±cD( #n(vXBzHm[f2Ŷ2~+9f;eLXzAtWSڞrѾ~8nŘіL!IWgf[fBAeHڪkX6g6fFE-ԄٺѦQ P\s<%pq#nĀK'=NPQXH˸84`3c7QYJˏ0x;iq#XK`Y͊V(`U,|tE 8#n!$A:&7ՂЪP+!o)#XA#X]9#Yj1ŴFk!ssmwuoz;eItMMHKdG@r @)#nܯ`+vh"W=c#X҃4 I3E1gAPM0*mt\Ar)4f;b*(Z#nTaNB NM!!sDM#XRrTŊY@llPR2#]<ո}tUg fDu\%HaGhHXL #n}$/#Xw9Fd#\H(Uio R&)qR@¬#X'.9ʡ3-b2Ch(yP:(#nOw$:M C5(RA#JS4$UAdUT4DEQDxXDEnFA$ECLD4-#XRAKTT4%H4(K@LKQD0E L @PHy11 HRʨ9v#w$ |ȦH8 1y`bop>8G E"A3kF݌E4#Y4!MB"0 @X_V*'Y|Ӆs4Ak >#Y4:E*{!d)E(p pCJ"Izw{#Yd{BJh@L2Д4A#nbQ3O D4+LLBA0U I'A@:i#Xq0A(#XrRbQF(6 ȃ(IR !#nHPJRT(k 0]*8In~U@{o tF?J21HU'rac@4*ГpFS#n&k#Xӷp&"Pfb"Pً@x,[0 &ma:0 H3"wI%^J`J`-P᷁[!^rA@"|T.}6ϿQ}IH*|?Qd"L&Zro\5&haVYxRɆ.t(E#nS!&:'=]R-l{JjFH۾k[wwp#Y]Ir#YmFưN(2pj:\r.ren??O: 7aF"tZ+U4jYH&TQGzP24/Y YTd+d2Պ7We$t?lDTTY'HP't,#'^6 MP"#Y_+s:=#FOtE^@݁(#n5=j\7qy>X:br6Sb¹4W3'p$! ϲ#X&pGp#X(xH$QM U(DRPM#XPy~WLH^INʽ1zEB#n/ $R(}.ah _>]#Xzqؘ#n>ԑd~N#n&_"c$a䆴C;R_[F#X#nPa$/fG^y|h+eVۜ5QMQ1E`qTr8rhg~^ J T!,(WߕOH~8iWER\}! r$?'pɢkXYshHJ(+4C _܀ b9zEMAGd~Fq¸t|a "M?ٽ6qKT5uC~|4^S3q64n7c?$QT%AiE UD+PhF? ^?Anh͔JcჍ|@x\S^e3:OX96f"3YIwq2{+b:}lH(4ddR;վ6*H Vѐt:tD 0DC^TT-Ed4Rc35#XY1t JwD5ҩ`v`I5(s=(qA&6ƿ"/qrxz՚r`F=d@{46}rV:M=@w==thF#X!S\<1#X - +4@dKI(n}~}7j¾ #n\ŠR׽)Ep~{r*4Su(O_v0P66ybu*k*=ԀjripϟLL_0DC6Kq}]u6[c#XIyc_^Fr0]kUҰKl4"iF(VH:u¡qOCYx*MP!vE*aX**#YMU)N 74<4LD,I:8Pd!Ԍ')e>ykz=H:Kg&.j#YUu_b#Xf*t>N(o*cאS&Z:fM$5NX&ODry RCvZH&_# J@z p$<]{RɽnbJy? D2<)()(NL#X!B{E A]>(#Y{\-lb2AP;#X'i}+F 0,bA݉Ȥ#YE5ݦr_N z)N $0y"CbV%ϣ@,T?!\n1cd#n^BRvX ]7>_m8R@#YTQ;A"fh)I)#n$(VB!I#X(!j%۰PӫӈJ|ǬAQBZTRD;#Yî%YI@B$ Z Zb(EfF!DlR,__'@:+0aػ$.TPG *b)LJD|(xՁ#X 0*LDE0nEOItӷepyGd(ӉA{:`Iq`'F(e^_9؊/4gi@~[;"-0?Q0#nHaGyL@8lFtYllȞ6$#Xv9ytq~e<9BrEO& M##Y-G8 H> =dͿ'o":+#tF92v#XHT0wBrQ^w`4BZdPQ?dddHRJ ")}7GP6r050 e"B ʓY^A$AH';{8sv H l9B\+޲m1똖1A#XR1`HJKȨ̚\sw.#n aM(39ДO}-)êYH7ݰRA)$vC#IB-&z>aД% v#YW"#Y"d^Ө!E WH !.NA?i *3>HhAQPG] eU4dfbѠE6$e mT%#X%0L#Xp'dSGrD`c.pOWN#Y #XinU<*BSG2To(!ABWFID>4(UOPJD #Y쓠@ H_`/#YQ俉Z#{bU4zɦCTETR #YW##XX0u#X;#|ь"#n5Xj J7>xIM!8P/LH9@$OAI-`HC!'P2mu x"sLϫcXI[ND/IJM<6ӓU>:JWTEYd0oZh=#nd0 Ad(T}EP=E }x.P!qգi9P!1vb2A/ytQ<@ ''XMZ$XuF#Y󮁵(j~8 )q2VMy2Fm Oiٍ?œ\+/ӌ,Q0,qO}1rI=̨klfsbeN b9JLg,ȸzg-?҃ G;36X83SZSV@%A4JhUW[ƮTIaMbj\g'65h-wDaaÆN_N&g642fA3l?1B2gJ8R#n9d5}_ MB ';6aQ:yqDso괐5 #Y͆ǭb1ǢM)5#Y/셉uLљu,G#Y~"$r11N}Ă߲ai,$@ #=x1jqw0xcN/i~ ɓ{*nH@m6pwpA{Lڢp-yhhK6#YCM^>l!."Qc[FSwۑ#nH<1۷'<"_0!Z1toGT~苑Y.6#XdrB %T#Yȓ ~>r0#XB#XsJ."cXcap ;=PcqO7"#X›&H9A^;׿i?/JR"[.ݚ+cX>X n^+{С[#X(QT>'d$yi읺sj,!+8H}WI3kQ_j#YRNݑrYSw܌yOّg/H1äyЩv^sOה4^F5^J$޵Yypv%q#6Npݣ<(Қy+o9_c26#Y[޸ٍ{{6ɨdS)T"rͭ=,`dAj[c\1W[*dc\`t:z@S$zYaMaBu&#[҈-68I$*N( 2E$D Ill𕡝/S7.bȍ_g\=f/4#fdBu+BrE4:%#YT$LjJaNS&=9 4sQ0x}FIT68%u#~nEAzyYulVs8{*IF@7ܨyB썠5(*:f(B/!P dp4b76A}ҋ%_yh^R?98+PE U"C(AB ?! 漓6-5]5=<[O\^uO=&ÙMg䚀=Ϧ\4<'9Ӣ7~8'OFC{CKA#Y1y5אz<8Pw'z7KOy#nIEJ#n'H[@( c(21 z<r{C*#XWȔ&9)1"!67NVhF!:@[-hǡ_y c ӅfT4o_9+:ԍ3\z@~x?g8qb`]B=d <}:?%@qTDn+#XW-KV Mų9Ov(%e2}#Yh4q|q Ќ v60'ϳ)ld#nƊ!}߽WF7|^ Aغidh`i5C',dP5 l0Vߗcn433q 2zQY.SE|`6rc4#Xu4 +0qSٷݦ l{^^cȖ1ڤ#X(1ɒHOv(ZݖF3a6sʏL>n~fa8zUKjMQWIpMA*$h#Ysd#nUIXReIe He@P" ݈ͪý9/^k?FB@ʂ)`22$#nf& HIPsobLdL`0O|lbk"#Yyvj{~ZT`Zo0rey18!}!t Oq "ArOS휌;15 `q*dؒCHvT=Y1<,&93(Și ֘cJjEƴig Dr2e6M˜.G:ctM6̍/yhh$۷l%JH $#nZ`c$+M9X` dέawIe*VX3Dt~vHypz&mad"x"<eybtScMC 0n3 jecpkt >"|&urr}JgLLKj[lGEFBi:Hhi$#n^"@#I -3yA Q6oe¶)B{:AҚ'etG8=(6s0\+6 j P;pֹkDHY4V6]cޗc^iim 1#X|Z'7q{3.^Or#n`5AR7:8dGHRͪ:J(} )(P!ÎAk6uWǼzr|t Fϋ=P?1yRI>lN75BA$)A' G&qB``#n"()Q@ECBi#n!I"(6q5L_h% Ć;n|uLDlD.pήF#YAWxCXy;pp:Mߓ"0 fo8qMaĜ$/6oiGlcc t0+jchZg3FM36CX.4!9UJ ŴrHvZ ! u4PD5,SXBj(A55QrlpN;թ;o\tDH2zh!QHpwzU4n4tƞ^!r4aN79s ')x|1SA#n^ybV5maQ# 0kxEsV@& n|H7i(nZڱD&i$%8426ߜ~&*c(*[y2ׁ|f󂦈?!C"$J*G*V`(h;t$bPв0 $Wn_",}CTuf8uxixWD|v(BLI#NF>bdHxxRssS%չ#Y 4#Y<q^wW@U#Y$t;m##.$_O3#XYbсiνӧ&{ډ}7{j[h tK컁|M xWSN pT/51FX#>@`w04XEM%#Y(P-@ĸI?qNRvkvnAMArT9*@ɜa9oyi)B&Jy01Q(,~nm&Pdya}#Xm^ }+#Wԉ7pw.KO#*5Dvv{y4{xxHubs#Y(j"i~Ge =._V_{==;+(ZAK #Y4SHA\Ftq [TEW6E.b2rXivҺ#X:@p N4KJNTehZZiLJiPИbit@:V!ѭBSsE_Pw_Y#HE %ՀO().Ixc|6f #X>yRC_&.#XPN2V'H1)"!A@]\DXQx#XcJN )"LD7`nm9GBI/V !p9h 8rS_Ard()F {kIJ@5[XGuKBnҧ L447v#XuΛapVԿo/ @IE̐4< mX5u8CVHY`Δ&D3p:<EhV*h#X)@PL+#X$I E$*؝t5J$)"c:\:(hiWhڀ1-%31@!zzin~&ZZ-dPsZu)PhpR#Y/5$Nv@3#Y,?Gu-_Sc $\ö֊BHH}O`F+L ȩjH"6T[#YG +$X;; CtX#Yk%ERvus&5ΎhL= P5L\,E1LQ3DBRRS$F(BcxK;!^ObT}?GrY2n~O!<ˑŔp#cMf)ʲ!% 2 _YxA:8[|&j^ab$0$ uO{CJɓǘ̠~p_e֔9t&s+_I?$Mc̽&VGN{ABҘf;pPŨ;^^X“Ѝ`v23%3hm.CF1'#nqfVi ICxóՇ;T:Wǿo$_M&)́&`XVN)PZJ:LRXeg.͹YAWP?cR#Yj4%)#Yg+$d7C|us&e ~nM{\b26YI#6iFLwա+/Ŧ]x7>rc8;]|r MJUÎ9(#nXB{I(N 1Vv7=N'^K܏~˿-+.%CFw-8 0=)ו$cYeWF" 3pB};fS]|t{;}Cӱ¢YVze'YO›wk/LY}t>S6Ue8EQc*Ppb)LJТ3;Db5Dr9jL,s{'MWT6NZgSH%JQN̄1I7+At@Χ׊.ýIwtt-7dh:û[N>UReamd3t:hpYڡUĴ׌kL\կvq>l߂;&ڮ׷沲\4zP)91#Yg'f2\--!BK$h:뾷j=_o7#nc.4e~61y}H-^`VٜQ#nb)H{ԫx}Uphkyi-_ewGNviŅ=`+~B4ϧWå_Pqb3-qcrR0#%69qiJF]#nTָŨsk;?"~GCHep8}3cUCXrE1/ΐ|Ś︦^ݜΞä>>ރlY&4#X`QHidU'3j|@%D6EmsK{Fr//gv|0|uiiAbHvD`#YT7 R=y%2FdpB¿.7w |3"# ӵI`}q#m:2w]:&9p~f33BuJ;b#YWI4#Yn&#Y9ۣҟ)_LFo'{b͡ UĄNM*)ʚY@ l(KV)xш}3$B҉ڔt]*k\Hm ^Sb㚀`^d6O=m/Ry|7Aq"egW :yyi#n$4$q#Ν^)ƖX`rmӳvIHZ!0‹ф CU ٟjk#X`PT |'Н@ D9#Xg#Y`~=c4q&oS%q#X^eG0@́$`A2v8MxÔ=!C|% $DX8n#npW4%cTy2PC/":4b<*cm$'_]{0R`0q֠&#nf@]R),!d N\wȨ+7Q,ƹ>eAqY! =Ee7(RZ-V|74[Cw^qq&J.h#nd>$5.w``h\`?~C3wT"kֹ9 BdoM0zyrf:˾=qLa0N38J#YWge ıt|&~&S͐8vdh8#Pui*9*p_x-h^hs d#X64GZLṵJ<;!#X-XdB6:UTQՎX":f@bΞ;5pz'=)+;/mB(IS^NgzQ\Ŗ\B8=qQ-Q m+=MV<^?s9Q:膫dn/mX3=6ܹ&`1PЙX9vVMüQR|я=9?it8#g!MS^6kݯg5!,<#YC000ߜ!d"&.YC=LN3d7#Ydrz1F@`!SQ5ErB(eO)(TM rt6I}c1ѭ:5syECb6twbJF0cbw+6&ٌ}q=%1E"qFA0sd䕠5my`AhNAn$Dǎ=sTkD--qr(`w۹"#nR6>N#2ZB̆&3+=Bgig$Iʂ)x >-B[j% ⎑]AmD)86Mڧüx F( x)<ƪrg@5z<7hBaQ7!i.!B&9b %X8s`h"%w8QSH]%.!T:NVWxdKA[Ca m=kys#XPP(v Fcj+1j,r3i38>y3^#Y:w3A 2K#nElm #Yj$H7pf.d9'C9D6;_8!FBAqsi> EINpj"$F z\?#YWkQbR>pO91BvxcI<ؠ5,#YEAdD] hmmQE TU}<S g#F 5u٦#IKUܲss76%/W+w!,>Ʉ=#X'$(NMP6!`PQ:2PUUD>uzmИ2&] )04}ꂅW-kJ~O.#Y=Ԇzө@]>:M2oPužcߦ0SZ`l#XK-'d%^@JI$cNy^T ;Pˋ^ j:P4AztésSیh`6a`J 9qΫCY< >YT'tJt0%0TL6I)`]o>KF6}5"bϹrT:mRaQ7`0Π#n)R`&"HGXɵ4S KL 1D$%1#Y+lM j!"T*F(#nh(h&h%$bBm%-@S~8R8`T҉`#nPP5G1P)$*Oگ^*jdJ*Il<%(ہliA3r=H4ثrW i϶Lo5Kw}GSH22#nBRg}Hhg0h|{$.$*"cNyC1merҙkѡޤY-86a-c^8oLL$ĝBJ]A[le5aU\`lxQJƶoch+W Y,Ey(#Y1&n]ňܝkWSTt$&QraUH6ˁ;#Xr!9EUl89IA-0IĴ걳wLΜt@Nr=WyIx@=DF21ȄJǣQըm'gIH|ɥnϛp  >DP:2nS⮷} @,)r~#Y?G.r;eת{F+z)T!wI,0 >31(i AIBP;#0H:& 5V&CH9#n%|HЗ ,$-.r/A" !n4%14_B֟O/ɯ5K:HP!"l驖#XxqJrبo}8Z޿>EwU4#X0~oCB0F#n+HPK'ɤ>c>uSծIom\k t4!NP:'uG1@W5ATM'#n-3o<%OoJho_f^U3mz^I)Nq>f2nꪹf+9ƀrS,˙~kkswɹ6lÏNfN )l!8#nwJekXK<-v#iJ^<1ṶSG1w.6()E.Q#Y.$\bafxĖxlE)B> 8)ߑ6xG/k|6 yыr΢V5ΦyU#Y! VNMbA4p8Դqp#n`9}mITrC_s/amRiH8Тr瞛w-8Q-:Z_Ϫ >MϗCEBt&23 !bT#"#÷j`0VG.& '4ŗt{p|6a#hmK; g#Y&Ì9irvaƸqq!#Gbƹz3YF* t9A0\&}o;s1jslzw#X$V5xJv6ZlQcFI˼=Bx)Cpcnc%aAkL7I:Y}TG!2]Tt0McB!QM-3,Z\#ň; N3>r׹#X.#n!sq3s˙-k|٭,v/zR14Mi;]4s#X_t^) _CfW۱YJ4j}GtUVvv޸p;j fmގ8\K}L\ f@4 p3.iPjJE1ڱ́ Zӯ~t"Pu\$b^{;JNGBH5 c{'BD#XQp,cb4mѪeZO2He$x%4ӫwX{w:QU;cq.WT#Y,p pH+8阋DbGi#nq`ʂ]gK hѨoMi-Gﴶ\"|UwcHKZA:,jd| &/(bk*Ydf=b e͹<`=rO{SPbdp&噞d$t #YvsC,'˚3(`CĨ0Awhp#JCf#Y2al&.KvQϖptd#A"I,2ewT{ ^[[_-xRd%Mμu2ːvQFjv4qaM*%55DO4,XW[d{3a#X-"V8N±RD#HMyLU4&GKw \qs_Bb(L#nNP!9 )`3(HyE"Y%Am.G)pָ rWUDj?%Gy$.kz[~nfE!nl>D1MI'k#XA>/yP\4&'1ɧB~ΥMGUѐtCeጣ0A"R|q5by#XA'˹: 0%0]伇F8=[U8pc6(*4fD#nqbXJY9Cf80f#n-A) Ez $ted)81FR_x5\tC;$hRȃb*i6uð>CrF*{3&ѐ|پ>v9)DG#`h9ELWQS;#Y+h:EG` K`g{Х$01wJC0#nhB#ps~{I80M 8]Dtc t2W+}I/8xc= #n \1oF+#V_vLN{hײ\h'" $)bT<.\4\h9lvX:`ޡycQ#XįAC:$Nϯ*0>T19d! :#Yy#YsLQX)H #XIp~TH8B3yd_ڦ&tZ8Hؗ|A4113!4?$RP*)#YȹLGx0m@#BBpH3Z`a/#Xu:G2h(p9Ж0ic&NG8#nн dNNHO8S#nf \y02#n)Bz70ÅC/=JFqdo,mtnv=*Rk,+m[Gd0 vtq>YNyX  +5Zz˱"4 I:ID#Yҵ~\Gߊd$]T))QchZC}IDP .~t~54p3;sxC9iˣ鄢srneYIEkn 9}.>effKT#nҌkJfNxWW%P[DiL#6&(ZM#Yb8f-/DY|kW b;& }$WSEzKB>,M{yυBsm4394W)iѺ9k)1i61#Yn1S9jh5#Y20pCg ^57z+#Xu3|=&`C,"E9SP}'vH((64bmI62ʙhL=l)ϊ4רRFقNc˲("ΔgMS;f ʏ5~gyr*|nFp5!oX}o >#ظHRO_ #)Ű074]L""ag Lzb.*#nIP<;.ف!AchU4d.0)r\+&YƤ#Y cwwy%#Y#vA-qDq_gHT{^QɯQ?& ;֢?vffV1Vr}TZqڦƈ [#(D:䰅ٮ\LhhX)X"'4d.b뿨S#XPA3P?\PHP ]3wn'&`6! #X2DAHMD"}ҙ@4DBN hC NBWaB$IXy#XPC$ )31A)#n@iE5V]#XihD9#XiG#n#n:F B#nY&XOGjt%e%U4=rtaxH?XnA0̰6Dy%#X4%tO@@#nD#STP/]?Ҽw1m {-xҡHR!D#Y#Y3 #_ǰ;?*H{"wCۇDNwh ۱ŎP*#X )9U2<`j3u;F^mrrNo$: :fkz;x{w^iнFD4OiE9x-Ri2b>DȓFrE>h̋L4Ɲ5uִMkurd  VАɴ#YL&#o:\拠$ipibp-DrKJUxCn#Y'#X* LzLTz8%:X-g*krmb7-G6 +RVfLv[s(-#&mٌF!#Y0U+l1!X$mǁG`I`Hnj y!poCTpD<#n:\81/s&hK#nJj%)Okj9lT):pgZŋni6#n)My#Y#X#XZD(2L("K@恩+U?ٯY;gx4_.vnl\`MjcAQw1Y |q i-@3K"(Moa6rT27aHPz<<ܑAYPāK,ibJHjje̡Q/e!SB(R|2@h%N@4*R-H֑)Rh8dz}P_al#X?x%p+#X 01!BC0M4 U#X+HD)HCA@@#nQxpp᠃2ʑSw] MߡD/^X}R4z}^oGeP!.{ 0tGV T P#Y)J4B&W.>YLv{<5@$ #~P"P|#YS׷/5O85>O9.kxTe|*z@f[ZJ[2F?rkw+U)hES;PeΔ1:ZLatW!С1-8#Y%J,C#ngIf"%LG9AmKA(|\V(Z*%s9 T%2K!"8h^p56VmꩪD\+unur^*r^#nYɖ"NZ1x7Y;&r쎡ShyQnb"tۉ7H6ݔɼLP%A4I(‘J̎#na|,X'02d^iwQה@$AQwnic A}KL@#`iRiIP;۔j‚t^ZptH3hPb9tn qC|MdĔK7'MW9BGI<C؂h`eb'gC9 䝊Xy?'A1vsJ&21bo4FOW{f#neSRHI"^O]*-mZRuq72AKZ5pJa%R`mՠX(\s#Xߓ~ '=a ~1W7Q<H4#X>qhJ=APԐN;e:(%B(5uX#Xwj"-o4AITm[&"eby.\5 \^n.d]ifB#nX"Y D&(PIE(ZUTs҃4TQ_#8ǵQzk@RQARR 1P4LR H%4QTPCLKA !LPSB@rEUOWNȠ*I0?ND.p8ᓘ8 ضRsiD *HaR, ÁI-¸;>9%+c늪#Xy#XpbA;:D(DV]d$#Yt$) #X( (:1GP8!B=p#nǫsښa# F& cx$؇OњWs}iSIDB#HU-c$5Tɂ2 9*M"ala[DF6Ӫjm嬑%+I$A--%CIHmVc1"B#nx_^sHI#nQ.DǩWWM#X~:Ԡ qcr(?K J;)2,bd`xBDRx=*4fRv(x`y,z`|N)'v9a(4~Q)LnQ}&4H@ %3傉P*ϱ rd1h2"Tan̈>qk8g9{k(t6~v*gJAu=o>cZǵb6#Y2C_SXqˤ}7囻wE*t|/K."$~ƚ^u`n˶h!B*XPrn#n#n&oNUQжkXA 9\ŸsEgV,tg[{¿{UrN#Yd,4'dD l j-"l[Dc#XnY8s I;M"v馲J(C6E/P#Xut2} H$1ßKQ]nP0rIaI\⥦&#X8P<\9:/\|DDh10q,NNwr!`D(krAPA.FS9ra)ȝv9c?^ha,kJ} đ~R1f1Å.pĝj 9=m#Yq_pH8#Y4*҃SS:br4Nxtϖ*#<H4Q{ՊPʓUR*m(9\!>a$=;5_@$S7sG@#X5K'98 ]t"Y=,Un'"Ib*jI* -ATDM41' ' \ogf+cdMhA<_#Xׂ-G|gPb=@H(>ǭy}о`CCT?=\Jm#Xؐ 7N~AyF щHҋaLK_יfbQ51TM2tV#XY#X5H68'ci1~B㍫w{iӠ E(ꂛ!#E[:vvB#M8zv;:μC;K#X0Q ph?c;iMQWFս-֤pO&yu(X~DNrųJE+?Dzlq_eVcS$wl'(#n!dx^o|:4O"' gJxE,k@ta7R3qTG_6 :욓lE4&HY'>}z>.jGt75/3=#Y!C[*:P%#X@'|ttP#Y@$JF&"d(eYtxC+;g(Z#Ylb$&1O,^!ch:|t?f#?R.UaBV|$5@Q_V?2~>>PUB20 A!ޘyAʧ:u]:.b{i#nhb#n (SB$#n#XH!*)@d&@iBTO~t?l#XiA8~Y0 CC_Gc1%A8T>~Up6L1#W^60RE%RE#n㷎/qk0+35clv#nU-e~`̔bj$K@JeH+TxȚD>#׼k7nlx!;XCxSٸf`N44BJPwSkppAc#X|zL|9Y<2p9UjcnWS8h ! !P;*#n)kst3Ѐ7^jq2}HI][+)xz?dz BP:GTsǷ+6ej#2 2IsHwx#ȥ1$āi 7_*)ELQ2TR@PHEEK̥:?#Yez@L@=b[J4Y56]Ӵthxؑd8XﵟGIGIwFu (~?m2 胄ufҏe)*qP;̀"'|DQ~Go}.63*(?>L?ş}!ǭxy|)ΟpO'Y0=8)w)[ (<΋}'F<|6Խ%p#n1i)[V AN뀖$7#YЗ]{#XRgq^ï>NLb #e1HV/7 K/j)pzD$?"(H5R) +#<== diff --git a/wscript b/wscript new file mode 100644 index 0000000..02efd88 --- /dev/null +++ b/wscript @@ -0,0 +1,252 @@ +#! /usr/bin/env python +# encoding: utf-8 +# a1batross, mittorn, 2018 + +from waflib import Build, Configure, Context, Logs +import sys +import os +import re + +VERSION = '2.4' +APPNAME = 'hlsdk-portable' +top = '.' +default_prefix = '/' + +Context.Context.line_just = 60 # should fit for everything on 80x26 + +@Configure.conf +def get_taskgen_count(self): + try: idx = self.tg_idx_count + except: idx = 0 # don't set tg_idx_count to not increase counter + return idx + +def options(opt): + opt.load('reconfigure compiler_optimizations xcompile compiler_cxx compiler_c clang_compilation_database strip_on_install msdev msvs msvc subproject') + + grp = opt.add_option_group('Common options') + + grp.add_option('-8', '--64bits', action = 'store_true', dest = 'ALLOW64', default = False, + help = 'allow targetting 64-bit engine(Linux/Windows/OSX x86 only) [default: %default]') + grp.add_option('--disable-werror', action = 'store_true', dest = 'DISABLE_WERROR', default = False, + help = 'disable compilation abort on warning') + grp.add_option('--enable-voicemgr', action = 'store_true', dest = 'USE_VOICEMGR', default = False, + help = 'Enable VOICE MANAGER') + + opt.add_subproject('dlls') + opt.add_subproject('cl_dll') + +def configure(conf): + conf.load('fwgslib reconfigure compiler_optimizations') + conf.env.MSVC_TARGETS = ['x86' if not conf.options.ALLOW64 else 'x64'] + + # Force XP compatibility, all build targets should add subsystem=bld.env.MSVC_SUBSYSTEM + if conf.env.MSVC_TARGETS[0] == 'x86': + conf.env.MSVC_SUBSYSTEM = 'WINDOWS,5.01' + else: + conf.env.MSVC_SUBSYSTEM = 'WINDOWS' + + # Load compilers early + conf.load('xcompile compiler_c compiler_cxx') + + # HACKHACK: override msvc DEST_CPU value by something that we understand + if conf.env.DEST_CPU == 'amd64': + conf.env.DEST_CPU = 'x86_64' + + if conf.env.COMPILER_CC == 'msvc': + conf.load('msvc_pdb') + + conf.load('msvs msdev subproject clang_compilation_database strip_on_install enforce_pic') + + enforce_pic = True # modern defaults + conf.check_pic(enforce_pic) + + # We restrict 64-bit builds ONLY for Win/Linux/OSX running on Intel architecture + # Because compatibility with original GoldSrc + if conf.env.DEST_OS in ['win32', 'linux', 'darwin'] and conf.env.DEST_CPU == 'x86_64': + conf.env.BIT32_MANDATORY = not conf.options.ALLOW64 + if conf.env.BIT32_MANDATORY: + Logs.info('WARNING: will build game for 32-bit target') + else: + conf.env.BIT32_MANDATORY = False + + conf.load('force_32bit') + + cflags, linkflags = conf.get_optimization_flags() + cxxflags = list(cflags) # optimization flags are common between C and C++ but we need a copy + + # on the Switch, allow undefined symbols by default, which is needed for libsolder to work + # we'll specifically disallow them for the engine executable + # additionally, shared libs are linked without standard libs, we'll add those back in the engine wscript + if conf.env.DEST_OS == 'nswitch': + linkflags.remove('-Wl,--no-undefined') + conf.env.append_unique('LINKFLAGS_cshlib', ['-nostdlib', '-nostartfiles']) + conf.env.append_unique('LINKFLAGS_cxxshlib', ['-nostdlib', '-nostartfiles']) + # same on the vita + elif conf.env.DEST_OS == 'psvita': + conf.env.append_unique('CFLAGS_cshlib', ['-fPIC']) + conf.env.append_unique('CXXFLAGS_cxxshlib', ['-fPIC', '-fno-use-cxa-atexit']) + conf.env.append_unique('LINKFLAGS_cshlib', ['-nostdlib', '-Wl,--unresolved-symbols=ignore-all']) + conf.env.append_unique('LINKFLAGS_cxxshlib', ['-nostdlib', '-Wl,--unresolved-symbols=ignore-all']) + # check if we need to use irix linkflags + elif conf.env.DEST_OS == 'irix' and conf.env.COMPILER_CC == 'gcc': + linkflags.remove('-Wl,--no-undefined') + linkflags.append('-Wl,--unresolved-symbols=ignore-all') + # check if we're in a sgug environment + if 'sgug' in os.environ['LD_LIBRARYN32_PATH']: + linkflags.append('-lc') + + conf.check_cc(cflags=cflags, linkflags=linkflags, msg='Checking for required C flags') + conf.check_cxx(cxxflags=cxxflags, linkflags=linkflags, msg='Checking for required C++ flags') + + conf.env.append_unique('CFLAGS', cflags) + conf.env.append_unique('CXXFLAGS', cxxflags) + conf.env.append_unique('LINKFLAGS', linkflags) + + if conf.env.COMPILER_CC != 'msvc' and not conf.options.DISABLE_WERROR: + opt_flags = [ + # '-Wall', '-Wextra', '-Wpedantic', + '-fdiagnostics-color=always', + + # stable diagnostics, forced to error, sorted + '-Werror=bool-compare', + '-Werror=bool-operation', + '-Werror=cast-align=strict', + '-Werror=duplicated-cond', + # '-Werror=format=2', + '-Werror=implicit-fallthrough=2', + # '-Werror=logical-op', + '-Werror=packed', + '-Werror=packed-not-aligned', + '-Werror=parentheses', + '-Werror=return-type', + '-Werror=sequence-point', + '-Werror=sizeof-pointer-memaccess', + '-Werror=sizeof-array-div', + '-Werror=sizeof-pointer-div', + # '-Werror=strict-aliasing', + '-Werror=string-compare', + '-Werror=tautological-compare', + '-Werror=use-after-free=3', + '-Werror=vla', + '-Werror=write-strings', + + # unstable diagnostics, may cause false positives + '-Winit-self', + '-Wmisleading-indentation', + '-Wunintialized', + + # disabled, flood + # '-Wdouble-promotion', + ] + + opt_cflags = [ + '-Werror=declaration-after-statement', + '-Werror=enum-conversion', + '-Werror=implicit-int', + '-Werror=implicit-function-declaration', + '-Werror=incompatible-pointer-types', + '-Werror=int-conversion', + '-Werror=jump-misses-init', + # '-Werror=old-style-declaration', + # '-Werror=old-style-definition', + # '-Werror=strict-prototypes', + '-fnonconst-initializers' # owcc + ] + + opt_cxxflags = [] # TODO: + + cflags = conf.filter_cflags(opt_flags + opt_cflags, cflags) + cxxflags = conf.filter_cxxflags(opt_flags + opt_cxxflags, cxxflags) + + conf.env.append_unique('CFLAGS', cflags) + conf.env.append_unique('CXXFLAGS', cxxflags) + + if conf.env.DEST_OS == 'android': + # LIB_M added in xcompile! + pass + elif conf.env.DEST_OS == 'win32': + a = [ 'user32', 'winmm' ] + if conf.env.COMPILER_CC == 'msvc': + for i in a: + conf.start_msg('Checking for MSVC library') + conf.check_lib_msvc(i) + conf.end_msg(i) + else: + for i in a: + conf.check_cc(lib = i) + else: + if conf.env.GOLDSOURCE_SUPPORT: + conf.check_cc(lib='dl') + conf.check_cc(lib='m') + + # check if we can use C99 tgmath + if conf.check_cc(header_name='tgmath.h', mandatory=False): + if conf.env.COMPILER_CC == 'msvc': + conf.define('_CRT_SILENCE_NONCONFORMING_TGMATH_H', 1) + tgmath_usable = conf.check_cc(fragment='''#include + const float val = 2, val2 = 3; + int main(void){ return (int)(-asin(val) + cos(val2)); }''', + msg='Checking if tgmath.h is usable', mandatory=False, use='M') + conf.define_cond('HAVE_TGMATH_H', tgmath_usable) + else: + conf.undefine('HAVE_TGMATH_H') + cmath_usable = conf.check_cxx(fragment='''#include + int main(void){ return (int)sqrt(2.0f); }''', + msg='Checking if cmath is usable', mandatory = False) + conf.define_cond('HAVE_CMATH', cmath_usable) + + if conf.env.COMPILER_CC == 'msvc': + conf.define('_CRT_SECURE_NO_WARNINGS', True) + conf.define('_CRT_NONSTDC_NO_DEPRECATE', True) + elif conf.env.COMPILER_CC == 'owcc': + pass + else: + conf.env.append_unique('CXXFLAGS', ['-Wno-invalid-offsetof', '-fno-exceptions']) + conf.define('stricmp', 'strcasecmp', quote=False) + conf.define('strnicmp', 'strncasecmp', quote=False) + conf.define('_snprintf', 'snprintf', quote=False) + conf.define('_vsnprintf', 'vsnprintf', quote=False) + conf.define('_LINUX', True) + conf.define('LINUX', True) + + conf.msg(msg='-> processing mod options', result='...', color='BLUE') + regex = re.compile('^([A-Za-z0-9_]+)=([A-Za-z0-9_]+)\ \#\ (.*)$') + with open('mod_options.txt') as fd: + lines = fd.readlines() + for line in lines: + m = regex.match(line.strip()) + if m: + p = m.groups() + conf.start_msg("* " + p[2]) + if p[1] == 'ON': + conf.env[p[0]] = True + conf.define(p[0], 1) + elif p[1] == 'OFF': + conf.env[p[0]] = False + conf.undefine(p[0]) + else: + conf.env[p[0]] = p[1] + conf.end_msg(p[1]) + if conf.env.HLDEMO_BUILD and conf.env.OEM_BUILD: + conf.fatal('Don\'t mix Demo and OEM builds!') + + # strip lib from pattern + if conf.env.DEST_OS not in ['android']: + if conf.env.cxxshlib_PATTERN.startswith('lib'): + conf.env.cxxshlib_PATTERN = conf.env.cxxshlib_PATTERN[3:] + + conf.load('library_naming') + conf.add_subproject('dlls') + conf.add_subproject('cl_dll') + +def build(bld): + if bld.is_install and not bld.options.destdir: + bld.fatal('Set the install destination directory using --destdir option') + + # don't clean QtCreator files and reconfigure saved options + bld.clean_files = bld.bldnode.ant_glob('**', + excl='*.user configuration.py .lock* *conf_check_*/** config.log %s/*' % Build.CACHE_DIR, + quiet=True, generator=True) + + bld.add_subproject('dlls') + bld.add_subproject('cl_dll')