From 661df527ef0ea326ab46daa006a4ee3fd6580631 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 13:39:48 -0400 Subject: [PATCH 01/77] DRR - Cpptraj: Start adding TNG format support. --- src/tng/AUTHORS | 11 + src/tng/COPYING | 25 + src/tng/INSTALL | 21 + src/tng/Makefile | 37 + src/tng/README | 5 + src/tng/compression/tng_compress.h | 223 + src/tng/md5.c | 406 + src/tng/tng/md5.h | 113 + src/tng/tng/tng_io.h | 4961 ++++++++ src/tng/tng/tng_io_fwd.h | 37 + src/tng/tng/version.h | 16 + src/tng/tng_io.c | 17852 +++++++++++++++++++++++++++ src/tng/tng_io_testing.c | 1496 +++ 13 files changed, 25203 insertions(+) create mode 100644 src/tng/AUTHORS create mode 100644 src/tng/COPYING create mode 100644 src/tng/INSTALL create mode 100644 src/tng/Makefile create mode 100644 src/tng/README create mode 100644 src/tng/compression/tng_compress.h create mode 100644 src/tng/md5.c create mode 100644 src/tng/tng/md5.h create mode 100644 src/tng/tng/tng_io.h create mode 100644 src/tng/tng/tng_io_fwd.h create mode 100644 src/tng/tng/version.h create mode 100644 src/tng/tng_io.c create mode 100644 src/tng/tng_io_testing.c diff --git a/src/tng/AUTHORS b/src/tng/AUTHORS new file mode 100644 index 0000000000..ff6aa32304 --- /dev/null +++ b/src/tng/AUTHORS @@ -0,0 +1,11 @@ +The TNG trajectory format is developed by: + +Magnus Lundborg +Daniel Spångberg +Rossen Apostolov + +The API is implemented mainly by: + +Magnus Lundborg +Daniel Spångberg (TNG-MF1 compression) +Anders Gärdenäs (C++ wrapper) \ No newline at end of file diff --git a/src/tng/COPYING b/src/tng/COPYING new file mode 100644 index 0000000000..4824ad9708 --- /dev/null +++ b/src/tng/COPYING @@ -0,0 +1,25 @@ +Copyright (c) 2012-2013, The GROMACS development team, +check out http://www.gromacs.org for more information. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of the GROMACS development team nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 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. \ No newline at end of file diff --git a/src/tng/INSTALL b/src/tng/INSTALL new file mode 100644 index 0000000000..c7c3611054 --- /dev/null +++ b/src/tng/INSTALL @@ -0,0 +1,21 @@ +mkdir build +cd build +cmake .. +make + + +Test by running: +bin/tng_testing + +Make a system-wide installation by: +make install +(this will require administrative privileges on most systems, i.e. 'sudo make install' +on a Unix like system with a sudoers file) + + +Useful cmake flags: +-DTNG_BUILD_DOCUMENTATION=ON to build the API documentation (requires doxygen) +-DCMAKE_BUILD_TYPE=Debug to compile with debug flags (recommended for +feedback during development) +-DTNG_BUILD_FORTRAN=ON to build the Fortran MD simulations example, saving results +in the TNG format (requires a Fortran compiler allowing cray-pointers). \ No newline at end of file diff --git a/src/tng/Makefile b/src/tng/Makefile new file mode 100644 index 0000000000..58db3c3997 --- /dev/null +++ b/src/tng/Makefile @@ -0,0 +1,37 @@ +# Makefile for TNG bundled with cpptraj +include ../../external.config.h + +CFLAGS += -I . + +# Variables +DEL_FILE = /bin/rm -f +AR = ar cqs +TARGET = libtngfile.a + +# Source files +SOURCES=md5.c tng_io.c + +# Objects +OBJECTS=$(SOURCES:.c=.o) + +# Specific rules + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + -$(DEL_FILE) $(TARGET) + $(AR) $(TARGET) $(OBJECTS) + +test: $(TARGET) tng_io_testing.o + $(CC) -o a.out tng_io_testing.c $(TARGET) -lm + ./a.out + +clean: + $(DEL_FILE) *.o $(TARGET) tng_io_testing.o a.out + +uninstall: clean + +# Dependencies +md5.o : md5.c tng/md5.h + +tng_io.o : tng_io.c tng/tng_io.h tng/tng_io_fwd.h compression/tng_compress.h tng/version.h diff --git a/src/tng/README b/src/tng/README new file mode 100644 index 0000000000..ac091b0419 --- /dev/null +++ b/src/tng/README @@ -0,0 +1,5 @@ +This is the TNG library bundled with CPPTRAJ. Original source taken from: +https://github.com/gromacs/tng +commit 14dd68ff46df1ef1cf2d9bcc1f4f5bddb974ce1c +The Makefile file is not part of the original distribution and is intended only to make a library that can be used by cpptraj. +More details can be found in AUTHORS, COPYING, and INSTALL. diff --git a/src/tng/compression/tng_compress.h b/src/tng/compression/tng_compress.h new file mode 100644 index 0000000000..0082ba35d6 --- /dev/null +++ b/src/tng/compression/tng_compress.h @@ -0,0 +1,223 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + +#ifndef TNG_COMPRESS_H +#define TNG_COMPRESS_H + +#ifndef USE_WINDOWS +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +#define USE_WINDOWS +#endif /* win32... */ +#endif /* not defined USE_WINDOWS */ + +#ifndef DECLSPECDLLEXPORT +#ifdef USE_WINDOWS +#define DECLSPECDLLEXPORT __declspec(dllexport) +#else /* USE_WINDOWS */ +#define DECLSPECDLLEXPORT +#endif /* USE_WINDOWS */ +#endif /* DECLSPECDLLEXPORT */ + +#ifdef __cplusplus + extern "C" { +#endif + +/* tng_compress_pos expects positions to have the order: + first xyz, then sorted in atom order + then all the frames repeated, i.e.: + nframes * [ + natoms* [ + x, y, z + ] + ] + desired_precision what to round the numbers to, i.e. integers will be created as: + round(pos[]/desired_precision). + + algo should first be determined by calling + tng_compress_pos_find_algo + + The compressed data is returned in a malloced pointer (so free can + be called to free the memory), the number of chars in the compressed + data is put into *nitems. + + If too large values are input (compared to the precision), NULL is returned. +*/ + +char DECLSPECDLLEXPORT *tng_compress_pos(double *pos, const int natoms, const int nframes, + const double desired_precision, + const int speed, int *algo, + int *nitems); + +char DECLSPECDLLEXPORT *tng_compress_pos_float(float *pos, const int natoms, const int nframes, + const float desired_precision, + const int speed, int *algo, + int *nitems); + +char DECLSPECDLLEXPORT *tng_compress_pos_int(int *pos, const int natoms, const int nframes, + const unsigned long prec_hi, const unsigned long prec_lo, + int speed,int *algo, + int *nitems); + +/* The tng_compress_pos_find_algo works the same as tng_compress_pos, but + it performs benchmarking to find the algorithms with the best + compression ratio. + The search is controlled by giving speed: + speed=1: Fast algorithms only. This excludes all BWLZH algorithms and + the XTC3 algorithm. + speed=2: Same as 1 and also includes the XTC3 algorithm using base compression + only. + speed=3: Same as 2 and also includes the XTC3 algorithm which will use BWLZH + compression when it seems likely to give better + compression. Also includes the interframe BWLZH algorithm for + coordinates and velocities. + speed=4: Enable the inter frame BWLZH algorithm for the coordinates. + The one-to-one BWLZH algorithm is enabled for velocities. + speed=5: Enable the LZ77 part of the BWLZH algorithm. + speed=6: Enable the intra frame BWLZH algorithm for the coordinates. Always try + the BWLZH compression in the XTC3 algorithm. + + Set speed=0 to allow tng_compression to set the default speed (which is currently 2). + For very good compression it makes sense to choose speed=4 or speed=5 + + The number of items required in the algorithm array can be found + by calling tng_compress_nalgo +*/ + +char DECLSPECDLLEXPORT *tng_compress_pos_find_algo(double *pos, const int natoms, const int nframes, + const double desired_precision, + const int speed, + int *algo, + int *nitems); + +char DECLSPECDLLEXPORT *tng_compress_pos_float_find_algo(float *pos, const int natoms, const int nframes, + const float desired_precision, + const int speed, + int *algo, + int *nitems); + +char DECLSPECDLLEXPORT *tng_compress_pos_int_find_algo(int *pos, const int natoms, const int nframes, + const unsigned long prec_hi, const unsigned long prec_lo, + const int speed, int *algo, + int *nitems); + +/* This returns the number of integers required for the storage of the algorithm + with the best compression ratio. */ +int DECLSPECDLLEXPORT tng_compress_nalgo(void); + +/* The following two routines does the same as the compression of the + positions, but compresses velocities instead. The algorithm + selection for velocities is different, so the position and + velocities routines should not be mixed. */ + +char DECLSPECDLLEXPORT *tng_compress_vel(double *vel, const int natoms, const int nframes, + const double desired_precision, + const int speed, int *algo, + int *nitems); + +char DECLSPECDLLEXPORT *tng_compress_vel_float(float *vel, const int natoms, const int nframes, + const float desired_precision, + const int speed, int *algo, + int *nitems); + +char DECLSPECDLLEXPORT *tng_compress_vel_int(int *vel, const int natoms, const int nframes, + const unsigned long prec_hi, const unsigned long prec_lo, + int speed, int *algo, + int *nitems); + +char DECLSPECDLLEXPORT *tng_compress_vel_find_algo(double *vel, const int natoms, const int nframes, + const double desired_precision, + const int speed, + int *algo, + int *nitems); + +char DECLSPECDLLEXPORT *tng_compress_vel_float_find_algo(float *vel, const int natoms, const int nframes, + const float desired_precision, + const int speed, + int *algo, + int *nitems); + +char DECLSPECDLLEXPORT *tng_compress_vel_int_find_algo(int *vel, const int natoms, const int nframes, + const unsigned long prec_hi, const unsigned long prec_lo, + const int speed, + int *algo, + int *nitems); + +/* From a compressed block, obtain information about + whether it is a position or velocity block: + *vel=1 means velocity block, *vel=0 means position block. + It also gives info about the number of atoms, + frames, and the precision used to compress the block, and the algorithms used to + compress the block. The return value=0 if the block looks like a tng compressed block, + and 1 otherwise. If the return value is 1 no information is returned. */ +int DECLSPECDLLEXPORT tng_compress_inquire(char *data,int *vel, int *natoms, + int *nframes, double *precision, + int *algo); + +/* Uncompresses any tng compress block, positions or velocities. It determines whether it is positions or velocities from the data buffer. The return value is 0 if ok, and 1 if not. +*/ +int DECLSPECDLLEXPORT tng_compress_uncompress(char *data,double *posvel); + +int DECLSPECDLLEXPORT tng_compress_uncompress_float(char *data,float *posvel); + +int DECLSPECDLLEXPORT tng_compress_uncompress_int(char *data,int *posvel, unsigned long *prec_hi, unsigned long *prec_lo); + +/* This converts a block of integers, as obtained from tng_compress_uncompress_int, to floating point values + either double precision or single precision. */ +void DECLSPECDLLEXPORT tng_compress_int_to_double(int *posvel_int, const unsigned long prec_hi, const unsigned long prec_lo, + const int natoms, const int nframes, + double *posvel_double); + +void DECLSPECDLLEXPORT tng_compress_int_to_float(int *posvel_int, const unsigned long prec_hi, const unsigned long prec_lo, + const int natoms, const int nframes, + float *posvel_float); + + +/* Compression algorithms (matching the original trajng + assignments) The compression backends require that some of the + algorithms must have the same value. */ + +#define TNG_COMPRESS_ALGO_STOPBIT 1 +#define TNG_COMPRESS_ALGO_TRIPLET 2 +#define TNG_COMPRESS_ALGO_BWLZH1 8 +#define TNG_COMPRESS_ALGO_BWLZH2 9 + +#define TNG_COMPRESS_ALGO_POS_STOPBIT_INTER TNG_COMPRESS_ALGO_STOPBIT +#define TNG_COMPRESS_ALGO_POS_TRIPLET_INTER TNG_COMPRESS_ALGO_TRIPLET +#define TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA 3 +#define TNG_COMPRESS_ALGO_POS_XTC2 5 +#define TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE 7 +#define TNG_COMPRESS_ALGO_POS_BWLZH_INTER TNG_COMPRESS_ALGO_BWLZH1 +#define TNG_COMPRESS_ALGO_POS_BWLZH_INTRA TNG_COMPRESS_ALGO_BWLZH2 +#define TNG_COMPRESS_ALGO_POS_XTC3 10 +#define TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE TNG_COMPRESS_ALGO_STOPBIT +#define TNG_COMPRESS_ALGO_VEL_TRIPLET_INTER TNG_COMPRESS_ALGO_TRIPLET +#define TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE 3 +#define TNG_COMPRESS_ALGO_VEL_STOPBIT_INTER 6 +#define TNG_COMPRESS_ALGO_VEL_BWLZH_INTER TNG_COMPRESS_ALGO_BWLZH1 +#define TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE TNG_COMPRESS_ALGO_BWLZH2 +#define TNG_COMPRESS_ALGO_MAX 11 + + + +/* Obtain strings describing the actual algorithms. These point to static memory, so should + not be freed. */ +char DECLSPECDLLEXPORT *tng_compress_initial_pos_algo(int *algo); +char DECLSPECDLLEXPORT *tng_compress_pos_algo(int *algo); +char DECLSPECDLLEXPORT *tng_compress_initial_vel_algo(int *algo); +char DECLSPECDLLEXPORT *tng_compress_vel_algo(int *algo); + + + +#ifdef __cplusplus + } +#endif + + +#endif diff --git a/src/tng/md5.c b/src/tng/md5.c new file mode 100644 index 0000000000..f6a2391635 --- /dev/null +++ b/src/tng/md5.c @@ -0,0 +1,406 @@ +/* This file has been modified in the TNG library distribution. Modifications + * are marked below. */ + +/* The define below was added in the TNG library distribution of this file. */ +#ifdef TNG_INTEGER_BIG_ENDIAN +#define ARCH_IS_BIG_ENDIAN 1 +#else +#define ARCH_IS_BIG_ENDIAN 0 +#endif + +/* The defines below were added in TNG library distribution of this file + * in order to compile properly in MSVC */ + +#ifndef USE_WINDOWS +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +#define USE_WINDOWS +#endif /* win32... */ +#endif /* not defined USE_WINDOWS */ + +#ifdef USE_WINDOWS +#define TNG_INLINE __inline +#else +#define TNG_INLINE inline +#endif + +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "tng/md5.h" +#include + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + +/* In the TNG library inline has been changed to TNG_INLINE */ +static TNG_INLINE void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + /* cppcheck-suppress unassignedVariable */ + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/src/tng/tng/md5.h b/src/tng/tng/md5.h new file mode 100644 index 0000000000..80fbf6c8c1 --- /dev/null +++ b/src/tng/tng/md5.h @@ -0,0 +1,113 @@ + +/* This file has been modified in the TNG library distribution. Modifications + * are marked below. */ + +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* The USE_WINDOWS define below was added in TNG library distribution of this + * file in order to compile properly in MSVC */ +#ifndef USE_WINDOWS +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +#define USE_WINDOWS +#endif /* win32... */ +#endif /* not defined USE_WINDOWS */ + +/* The DECLSPECDLLEXPORT define below was added in the TNG library distribution + * of this file. It is also used in the function declarations. */ +#ifndef DECLSPECDLLEXPORT +#ifdef USE_WINDOWS +#define DECLSPECDLLEXPORT __declspec(dllexport) +#else /* USE_WINDOWS */ +#define DECLSPECDLLEXPORT +#endif /* USE_WINDOWS */ +#endif /* DECLSPECDLLEXPORT */ + +/* Initialize the algorithm. */ +void DECLSPECDLLEXPORT md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void DECLSPECDLLEXPORT md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void DECLSPECDLLEXPORT md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/src/tng/tng/tng_io.h b/src/tng/tng/tng_io.h new file mode 100644 index 0000000000..167cca6ada --- /dev/null +++ b/src/tng/tng/tng_io.h @@ -0,0 +1,4961 @@ +/* This code is part of the tng binary trajectory format. + * + * Written by Magnus Lundborg + * Copyright (c) 2012-2017, The GROMACS development team. + * Check out http://www.gromacs.org for more information. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + +/** @file tng_io.h + * @brief API for input and output of tng trajectory files + * @mainpage TNG: A flexible binary trajectory format + * @section intro_sec Introduction + * + * The TNG format is developed as part of the ScalaLife EU project. + * It is flexible by design to allow parallel writing, custom data blocks, + * different output frequencies and different compression algorithms. + * + * Each block can contain MD5 hashes to verify data integrity and the file + * can be signed by the user to ensure that the origin is correct. + * + * The intention is that the API and ABI should be stable, but it is + * still possible that future changes might make that impossible, in which + * case that will be clarified. + * + * The API and all examples are released without any warranties. Use them at + * your own risk. + * + * @section authors_sec Authors + * + * The TNG trajectory format is developed by: + * + * Magnus Lundborg magnus.lundborg@scilifelab.se + * + * Daniel Spångberg daniels@mkem.uu.se + * + * Rossen Apostolov rossen@kth.se + * + * The API is implemented mainly by: + * + * Magnus Lundborg + * + * @section License + * + * Copyright (c) 2012, The GROMACS development team. + * check out http://www.gromacs.org for more information. + * + * The TNG API is released under the Revised BSD License and is free to + * redistribute according to that license. + * + * A license file (named COPYING) should be included with each copy of the API. + * + * @section install_sec Installation + * + * \code + * mkdir build + * + * cd build + * + * cmake .. + * + * make + * + * make install + * \endcode + * Test by running: + * \code + * bin/tests/tng_testing + * \endcode + * + * @section change_sec Change Log + * + * See git log for full revision history. + * + * Revisions + * + * v. 1.8 - Added GROMACS energy block IDs. + * - Rewritten build system for the main library. + * - Added block ID for atom (or generic particle) mass. + * - Fixed bugs, such as: + * - Do not switch endianness when reading and writing TNG compressed data. + * - Update pointers to residues in the chain when writing multiple chains in one molecule. + * - Update frame set pointers when appending to file. + * + * v. 1.7 - Fifth stable release of the API + * + * - Added function tng_util_num_frames_with_data_of_block_id_get(). + * - Merged some functions and data structures + * to make less difference between data blocks. + * - Bugs fixed + * + * v. 1.6 - Fourth stable release of the API. + * + * - Removed OpenMP option when building. + * - Functionality for migrating data blocks. + * - Improved handling of molecules. + * - Improved installation of TNG documentation. + * - Enhancements to CMake usage. + * - Required CMake version raised to 2.8.8. + * - Bugs fixed. + * + * v. 1.5 - Third stable release of the API. + * + * - Fortran wrapper split into separate file + * - Added more block IDs. + * - Some new functions and utility functions added. + * - Improved compression precision settings. + * - Improved tests. + * - Make appending to file work better. + * - Modified CMake settings + * - Bugs fixed + * + * v. 1.4 - Changed from LGPL to the Revised BSD License. + * + * - More flexible support for digital signatures in header. + * - Block ID numbers changed. + * + * v. 1.3 - Second stable release of the API. + * + * - Added multiplication factor for coordinate units to general info. + * - Added time stamps and time per frame in frame sets. + * - High-level API functions added (not for managing molecules yet) + * - Added functions for reading data blocks into 1D arrays. + * - TNG compression added. + * - C++ interface added. + * - Avoid memory allocation if no data is submitted when adding data + * blocks. + * - Added function tng_num_frames_per_frame_set_set + * - Added data block IDs for charges, b-factors and occupancy. + * - GZIP compression added. + * - Fixed bug when updating MD5 hashes of data blocks. + * - Fixed bug in chain_name_of_particle_get(...) + * - Update frame set pointers properly. + * - Moved fortran wrapper from header file to source file. + * - Write sparse data in mdrun examples. + * - Fixed bugs related to reading and writing sparse data. + * - Fixed memory leak for non-trajectory particle data blocks. + * - Fixed bug when writing data blocks. + * - Fixed wrong values in dependency constants + * - Write box shape, partial charges and annotation data in tng_testing + * - Bug fixes in tng_testing (frame sets not written before) + * + * v. 1.0 - First stable release of the API. + * + * + * @section examples_sec Examples + * + * There are some examples of how to use the library located in src/tests/ + * + * @subsection tng_subsec TNG files + * + * The build directory contains an example_files directory, which in turn + * contains a very short example of a TNG file containing a few water molecules, + * a box shape description and positions in 10 frames. + * + * It is also possible to run the bin/examples/md_openmp_util + * (see src/tests/md_openmp_util.c) + * testing program, which will save MD simulations output to a new file + * (saved in the example_files directory). + * + * These files can be read using the bin/examples/tng_io_read_pos_util + * program. + * + * @subsection c_subsec C + * + * Example writing data to a TNG file (just an excerpt): + * \code + * for ( step = 1; step < step_num; step++ ) + * { + * compute ( np, nd, pos, vel, mass, force, &potential, &kinetic ); + * + * if(step % step_save == 0) + * { + * // Write positions, velocities and forces + * if(tng_util_pos_write(traj, step, pos) != TNG_SUCCESS) + * { + * printf("Error adding data. %s: %d\n", __FILE__, __LINE__); + * break; + * } + * if(tng_util_vel_write(traj, step, vel) != TNG_SUCCESS) + * { + * printf("Error adding data. %s: %d\n", __FILE__, __LINE__); + * break; + * } + * if(tng_util_force_write(traj, step, force) != TNG_SUCCESS) + * { + * printf("Error adding data. %s: %d\n", __FILE__, __LINE__); + * break; + * } + * } + * update ( np, nd, pos, vel, force, acc, mass, dt ); + * } + * \endcode + * + * Example reading positions from a TNG file: + * \code + * #include + * #include + * #include "tng/tng_io.h" + * + * int main(int argc, char **argv) + * { + * tng_trajectory_t traj; + * // Assume that the data is stored as floats. The data is placed in 1-D + * // arrays + * float *positions = 0, *box_shape = 0; + * int64_t n_particles, n_frames, tot_n_frames, stride_length, i, j; + * // Set a default frame range + * int64_t first_frame = 0, last_frame = 5000; + * int k; + * + * // A reference must be passed to allocate memory + * tng_util_trajectory_open(argv[1], 'r', &traj); + * + * if(tng_num_frames_get(traj, &tot_n_frames) != TNG_SUCCESS) + * { + * printf("Cannot determine the number of frames in the file\n"); + * tng_util_trajectory_close(&traj); + * exit(1); + * } + * + * if(tng_num_particles_get(traj, &n_particles) != TNG_SUCCESS) + * { + * printf("Cannot determine the number of particles in the file\n"); + * tng_util_trajectory_close(&traj); + * exit(1); + * } + * + * printf("%"PRId64" frames in file\n", tot_n_frames); + * + * if(last_frame > tot_n_frames - 1) + * { + * last_frame = tot_n_frames - 1; + * } + * + * if(tng_util_box_shape_read(traj, &box_shape, &stride_length) == + * TNG_SUCCESS) + * { + * printf("Simulation box shape: "); + * for(i=0; i < 9; i++) + * { + * printf("%f ", box_shape[i]); + * } + * printf("\n"); + * } + * else + * { + * printf("Simulation box shape not set in the file (or could not be read)\n"); + * } + * + * n_frames = last_frame - first_frame + 1; + * + * + * // Get the positions of all particles in the requested frame range. + * // The positions are stored in the positions array. + * // N.B. No proper error checks. + * if(tng_util_pos_read_range(traj, 0, last_frame, &positions, &stride_length) + * == TNG_SUCCESS) + * { + * // Print the positions of the wanted particle (zero based) + * for(i=0; i < n_frames; i += stride_length) + * { + * printf("\nFrame %"PRId64":\n", first_frame + i); + * for(j=0; j < n_particles; j++) + * { + * printf("Atom nr: %"PRId64"", j); + * for(k=0; k < 3; k++) + * { + * printf("\t%f", positions[i/stride_length*n_particles* + * 3+j*3+k]); + * } + * printf("\n"); + * } + * } + * } + * else + * { + * printf("Cannot read positions\n"); + * } + * + * // Free memory + * if(positions) + * { + * free(positions); + * } + * tng_util_trajectory_close(&traj); + * + * return(0); + * } + * + * \endcode + * + * @subsection fortran_subsec Fortran + * + * The TNG library can be used from Fortran. It requires cray pointers, which + * are not part of the Fortran 77 standard, but available in most compilers. + * + * To compile the fortran example -DTNG_BUILD_FORTRAN=ON needs to be specified when + * running cmake. + * + */ + +#ifndef TNG_IO_H +#define TNG_IO_H 1 + +#include +#include +#include +#include +#include "tng_io_fwd.h" + +#ifdef USE_STD_INTTYPES_H +#include +#else +/* Visual Studio does not contain inttypes.h and stdint.h. Some defines and + * typedefs are used from the GNU C Library */ +#ifdef _MSC_VER + +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef __int64 int64_t; +typedef unsigned __int64 uint64_t; + +#else +#include +#endif /* _MSC_VER */ + +/* This is from inttypes.h (GNU C Library) */ +/* The ISO C99 standard specifies that these macros must only be + defined if explicitly requested. */ +#if !defined __cplusplus || defined __STDC_FORMAT_MACROS + +# if __WORDSIZE == 64 +# define __PRI64_PREFIX "l" +# define __PRIPTR_PREFIX "l" +# else +# define __PRI64_PREFIX "ll" +# define __PRIPTR_PREFIX +# endif + +/* From stdint.h (GNU C Library) */ +/* Macros for printing format specifiers. */ +/* Decimal notation. */ +#ifndef PRId64 +# define PRId64 __PRI64_PREFIX "d" +#endif + +#ifndef PRIu64 +# define PRIu64 __PRI64_PREFIX "u" +#endif + +#ifndef PRIuPTR +# define PRIuPTR __PRIPTR_PREFIX "u" +#endif + +#endif + +#endif /* USE_STD_INTTYPES_H */ + +#ifndef USE_WINDOWS +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +#define USE_WINDOWS +#endif /* win32... */ +#endif /* not defined USE_WINDOWS */ + +#ifndef DECLSPECDLLEXPORT +#ifdef USE_WINDOWS +#define DECLSPECDLLEXPORT __declspec(dllexport) +#else /* USE_WINDOWS */ +#define DECLSPECDLLEXPORT +#endif /* USE_WINDOWS */ +#endif /* DECLSPECDLLEXPORT */ + +/** Flag to indicate frame dependent data. */ +#define TNG_FRAME_DEPENDENT 1 +/** Flag to indicate particle dependent data. */ +#define TNG_PARTICLE_DEPENDENT 2 + +/** The maximum length of a date string */ +#define TNG_MAX_DATE_STR_LEN 24 +/** The length of an MD5 hash */ +#define TNG_MD5_HASH_LEN 16 +/** The maximum allowed length of a string */ +#define TNG_MAX_STR_LEN 1024 + +#ifndef NDEBUG +#define TNG_ASSERT(cnd, msg) if(!(cnd)) {printf("%s\n", msg); assert(cnd);} +#else +#define TNG_ASSERT(cnd, msg) (void)0; +#endif + +/** Flag to specify the endianness of a TNG file */ +typedef enum {TNG_BIG_ENDIAN, + TNG_LITTLE_ENDIAN} tng_file_endianness; + +/** Flag to specify the endianness of 32 bit values of the current architecture. */ +typedef enum {TNG_BIG_ENDIAN_32, + TNG_LITTLE_ENDIAN_32, + TNG_BYTE_PAIR_SWAP_32} tng_endianness_32; + +/** Flag to specify the endianness of 64 bit values of the current architecture. */ +typedef enum {TNG_BIG_ENDIAN_64, + TNG_LITTLE_ENDIAN_64, + TNG_QUAD_SWAP_64, + TNG_BYTE_PAIR_SWAP_64, + TNG_BYTE_SWAP_64} tng_endianness_64; + +/** Compression mode is specified in each data block */ +typedef enum {TNG_UNCOMPRESSED, + TNG_XTC_COMPRESSION, + TNG_TNG_COMPRESSION, + TNG_GZIP_COMPRESSION} tng_compression; + +/** Hash types */ +typedef enum {TNG_NO_HASH, + TNG_MD5, + TNG_SHA256} tng_hash_type; + +/** Non trajectory blocks come before the first frame set block */ +typedef enum {TNG_NON_TRAJECTORY_BLOCK, TNG_TRAJECTORY_BLOCK} tng_block_type; + +/** @defgroup def1 Standard non-trajectory blocks + * Block IDs of standard non-trajectory blocks. + * @{ + */ +#define TNG_GENERAL_INFO 0x0000000000000000LL +#define TNG_MOLECULES 0x0000000000000001LL +#define TNG_TRAJECTORY_FRAME_SET 0x0000000000000002LL +#define TNG_PARTICLE_MAPPING 0x0000000000000003LL +/** @} */ + +/** @defgroup def2 Standard trajectory blocks + * Block IDs of standard trajectory blocks. Box shape and partial charges can + * be either trajectory blocks or non-trajectory blocks + * @{ + */ +#define TNG_TRAJ_BOX_SHAPE 0x0000000010000000LL +#define TNG_TRAJ_POSITIONS 0x0000000010000001LL +#define TNG_TRAJ_VELOCITIES 0x0000000010000002LL +#define TNG_TRAJ_FORCES 0x0000000010000003LL +#define TNG_TRAJ_PARTIAL_CHARGES 0x0000000010000004LL +#define TNG_TRAJ_FORMAL_CHARGES 0x0000000010000005LL +#define TNG_TRAJ_B_FACTORS 0x0000000010000006LL +#define TNG_TRAJ_ANISOTROPIC_B_FACTORS 0x0000000010000007LL +#define TNG_TRAJ_OCCUPANCY 0x0000000010000008LL +#define TNG_TRAJ_GENERAL_COMMENTS 0x0000000010000009LL +#define TNG_TRAJ_MASSES 0x0000000010000010LL +/** @} */ + + +/** @defgroup def3 GROMACS data block IDs + * Block IDs of data blocks specific to GROMACS. + * @{ + */ +#define TNG_GMX_LAMBDA 0x1000000010000000LL +#define TNG_GMX_ENERGY_ANGLE 0x1000000010000001LL +#define TNG_GMX_ENERGY_RYCKAERT_BELL 0x1000000010000002LL +#define TNG_GMX_ENERGY_LJ_14 0x1000000010000003LL +#define TNG_GMX_ENERGY_COULOMB_14 0x1000000010000004LL +#define TNG_GMX_ENERGY_LJ_(SR) 0x1000000010000005LL +#define TNG_GMX_ENERGY_COULOMB_(SR) 0x1000000010000006LL +#define TNG_GMX_ENERGY_COUL_RECIP 0x1000000010000007LL +#define TNG_GMX_ENERGY_POTENTIAL 0x1000000010000008LL +#define TNG_GMX_ENERGY_KINETIC_EN 0x1000000010000009LL +#define TNG_GMX_ENERGY_TOTAL_ENERGY 0x1000000010000010LL +#define TNG_GMX_ENERGY_TEMPERATURE 0x1000000010000011LL +#define TNG_GMX_ENERGY_PRESSURE 0x1000000010000012LL +#define TNG_GMX_ENERGY_CONSTR_RMSD 0x1000000010000013LL +#define TNG_GMX_ENERGY_CONSTR2_RMSD 0x1000000010000014LL +#define TNG_GMX_ENERGY_BOX_X 0x1000000010000015LL +#define TNG_GMX_ENERGY_BOX_Y 0x1000000010000016LL +#define TNG_GMX_ENERGY_BOX_Z 0x1000000010000017LL +#define TNG_GMX_ENERGY_BOXXX 0x1000000010000018LL +#define TNG_GMX_ENERGY_BOXYY 0x1000000010000019LL +#define TNG_GMX_ENERGY_BOXZZ 0x1000000010000020LL +#define TNG_GMX_ENERGY_BOXYX 0x1000000010000021LL +#define TNG_GMX_ENERGY_BOXZX 0x1000000010000022LL +#define TNG_GMX_ENERGY_BOXZY 0x1000000010000023LL +#define TNG_GMX_ENERGY_BOXVELXX 0x1000000010000024LL +#define TNG_GMX_ENERGY_BOXVELYY 0x1000000010000025LL +#define TNG_GMX_ENERGY_BOXVELZZ 0x1000000010000026LL +#define TNG_GMX_ENERGY_BOXVELYX 0x1000000010000027LL +#define TNG_GMX_ENERGY_BOXVELZX 0x1000000010000028LL +#define TNG_GMX_ENERGY_BOXVELZY 0x1000000010000029LL +#define TNG_GMX_ENERGY_VOLUME 0x1000000010000030LL +#define TNG_GMX_ENERGY_DENSITY 0x1000000010000031LL +#define TNG_GMX_ENERGY_PV 0x1000000010000032LL +#define TNG_GMX_ENERGY_ENTHALPY 0x1000000010000033LL +#define TNG_GMX_ENERGY_VIR_XX 0x1000000010000034LL +#define TNG_GMX_ENERGY_VIR_XY 0x1000000010000035LL +#define TNG_GMX_ENERGY_VIR_XZ 0x1000000010000036LL +#define TNG_GMX_ENERGY_VIR_YX 0x1000000010000037LL +#define TNG_GMX_ENERGY_VIR_YY 0x1000000010000038LL +#define TNG_GMX_ENERGY_VIR_YZ 0x1000000010000039LL +#define TNG_GMX_ENERGY_VIR_ZX 0x1000000010000040LL +#define TNG_GMX_ENERGY_VIR_ZY 0x1000000010000041LL +#define TNG_GMX_ENERGY_VIR_ZZ 0x1000000010000042LL +#define TNG_GMX_ENERGY_SHAKEVIR_XX 0x1000000010000043LL +#define TNG_GMX_ENERGY_SHAKEVIR_XY 0x1000000010000044LL +#define TNG_GMX_ENERGY_SHAKEVIR_XZ 0x1000000010000045LL +#define TNG_GMX_ENERGY_SHAKEVIR_YX 0x1000000010000046LL +#define TNG_GMX_ENERGY_SHAKEVIR_YY 0x1000000010000047LL +#define TNG_GMX_ENERGY_SHAKEVIR_YZ 0x1000000010000048LL +#define TNG_GMX_ENERGY_SHAKEVIR_ZX 0x1000000010000049LL +#define TNG_GMX_ENERGY_SHAKEVIR_ZY 0x1000000010000050LL +#define TNG_GMX_ENERGY_SHAKEVIR_ZZ 0x1000000010000051LL +#define TNG_GMX_ENERGY_FORCEVIR_XX 0x1000000010000052LL +#define TNG_GMX_ENERGY_FORCEVIR_XY 0x1000000010000053LL +#define TNG_GMX_ENERGY_FORCEVIR_XZ 0x1000000010000054LL +#define TNG_GMX_ENERGY_FORCEVIR_YX 0x1000000010000055LL +#define TNG_GMX_ENERGY_FORCEVIR_YY 0x1000000010000056LL +#define TNG_GMX_ENERGY_FORCEVIR_YZ 0x1000000010000057LL +#define TNG_GMX_ENERGY_FORCEVIR_ZX 0x1000000010000058LL +#define TNG_GMX_ENERGY_FORCEVIR_ZY 0x1000000010000059LL +#define TNG_GMX_ENERGY_FORCEVIR_ZZ 0x1000000010000060LL +#define TNG_GMX_ENERGY_PRES_XX 0x1000000010000061LL +#define TNG_GMX_ENERGY_PRES_XY 0x1000000010000062LL +#define TNG_GMX_ENERGY_PRES_XZ 0x1000000010000063LL +#define TNG_GMX_ENERGY_PRES_YX 0x1000000010000064LL +#define TNG_GMX_ENERGY_PRES_YY 0x1000000010000065LL +#define TNG_GMX_ENERGY_PRES_YZ 0x1000000010000066LL +#define TNG_GMX_ENERGY_PRES_ZX 0x1000000010000067LL +#define TNG_GMX_ENERGY_PRES_ZY 0x1000000010000068LL +#define TNG_GMX_ENERGY_PRES_ZZ 0x1000000010000069LL +#define TNG_GMX_ENERGY_SURFXSURFTEN 0x1000000010000070LL +#define TNG_GMX_ENERGY_MUX 0x1000000010000071LL +#define TNG_GMX_ENERGY_MUY 0x1000000010000072LL +#define TNG_GMX_ENERGY_MUZ 0x1000000010000073LL +#define TNG_GMX_ENERGY_VCOS 0x1000000010000074LL +#define TNG_GMX_ENERGY_VISC 0x1000000010000075LL +#define TNG_GMX_ENERGY_BAROSTAT 0x1000000010000076LL +#define TNG_GMX_ENERGY_T_SYSTEM 0x1000000010000077LL +#define TNG_GMX_ENERGY_LAMB_SYSTEM 0x1000000010000078LL +#define TNG_GMX_SELECTION_GROUP_NAMES 0x1000000010000079LL +#define TNG_GMX_ATOM_SELECTION_GROUP 0x1000000010000080LL +/** @} */ + +/** Flag to specify if a data block contains data related to particles or not.*/ +typedef enum {TNG_NON_PARTICLE_BLOCK_DATA, + TNG_PARTICLE_BLOCK_DATA} tng_particle_dependency; + + +typedef enum {TNG_FALSE, TNG_TRUE} tng_bool; + +/** Flag to specify if the number of atoms change throughout the trajectory or + * if it is constant. */ +typedef enum {TNG_CONSTANT_N_ATOMS, TNG_VARIABLE_N_ATOMS} + tng_variable_n_atoms_flag; + +/** Return values of API functions. TNG_SUCCESS means that the operation + * was successful. TNG_FAILURE means that the operation failed for some + * reason, but it is possible to try to continue anyhow. TNG_CRITICAL + * means that the error is irrecoverable. */ +typedef enum {TNG_SUCCESS, TNG_FAILURE, TNG_CRITICAL} tng_function_status; + +/** If tng_hash_mode == TNG_USE_HASH md5 hashes will be written to output files + * and when reading a file the md5 hashes of the contents will be compared to + * those in the file (for each block) in order to ensure data integrity */ +typedef enum {TNG_SKIP_HASH, TNG_USE_HASH} tng_hash_mode; + +/** Possible formats of data block contents */ +typedef enum {TNG_CHAR_DATA, + TNG_INT_DATA, + TNG_FLOAT_DATA, + TNG_DOUBLE_DATA} tng_data_type; + + +struct tng_trajectory; +struct tng_molecule; +struct tng_chain; +struct tng_residue; +struct tng_atom; +struct tng_bond; +struct tng_gen_block; +struct tng_particle_mapping; +struct tng_trajectory_frame_set; +struct tng_particle_data; +struct tng_non_particle_data; + +/** Data can be either double, float, int or a string */ +union data_values { + double d; + float f; + int64_t i; + char *c; +}; + + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** @defgroup group1 Low-level API + * These functions give detailed control of the TNG data management. Most + * things can be done using the more convenient high-level API functions + * instead. + * @{ + */ + +/** + * @brief Get the major version of the TNG library. + * @param tng_data is a trajectory data container, it does not have + * to be initialized beforehand. + * @param version is pointing to a value set to the major version of + * the library. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_version_major + (const tng_trajectory_t tng_data, + int *version); + +/** + * @brief Get the minor version of the TNG library. + * @param tng_data is a trajectory data container, it does not have + * to be initialized beforehand. + * @param version is pointing to a value set to the minor version of + * the library. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_version_minor + (const tng_trajectory_t tng_data, + int *version); + +/** + * @brief Get the patch level of the TNG library. + * @param tng_data is a trajectory data container, it does not have + * to be initialized beforehand. + * @param patch_level is the string to fill with the full version, + * memory must be allocated before. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_version_patchlevel + (const tng_trajectory_t tng_data, + int *patch_level); + +/** + * @brief Get the full version string of the TNG library. + * @param tng_data is a trajectory data container, it does not have + * to be initialized beforehand. + * @param version is pointing to a value set to the major version of + * the library. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for version. This includes \0 terminating character. + * @pre \code version != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_version + (const tng_trajectory_t tng_data, + char *version, + const int max_len); + +/** + * @brief Setup a trajectory data container. + * @param tng_data_p a pointer to memory to initialise as a trajectory. + * @pre tng_data_p must not be pointing at a reserved memory block. + * @details Memory is allocated during initialisation. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_trajectory_init + (tng_trajectory_t *tng_data_p); + +/** + * @brief Clean up a trajectory data container. + * @param tng_data_p a pointer to the trajectory data to destroy. + * @details All allocated memory in the data structure is freed, as well as + * tng_data_p itself. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy + (tng_trajectory_t *tng_data_p); + +/** + * @brief Copy a trajectory data container (dest is setup as well). + * @details This initialises dest and copies only what is absolute necessary for + * parallel i/o. This can be used inside pragma omp for setting up a thread + * local copy of src. It can be freed (using tng_trajectory_destroy) at the + * end of the parallel block. + * @param src the original trajectory. + * @param dest_p a pointer to memory to initialise as a trajectory. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre tng_data_p must not be pointing at a reserved memory block. + * @details Memory is allocated during initialisation. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src + (const tng_trajectory_t src, tng_trajectory_t *dest_p); + +/** + * @brief Get the name of the input file. + * @param tng_data the trajectory of which to get the input file name. + * @param file_name the string to fill with the name of the input file, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for file_name. This includes \0 terminating character. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code file_name != 0 \endcode The pointer to the file name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_input_file_get + (const tng_trajectory_t tng_data, + char *file_name, const int max_len); + +/** + * @brief Set the name of the input file. + * @param tng_data the trajectory of which to set the input file name. + * @param file_name the name of the input file. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code file_name != 0 \endcode The pointer to the file name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_input_file_set + (const tng_trajectory_t tng_data, + const char *file_name); + +/** + * @brief Get the name of the output file. + * @param tng_data the trajectory of which to get the input file name. + * @param file_name the string to fill with the name of the output file, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for file_name. This includes \0 terminating character. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code file_name != 0 \endcode The pointer to the file name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_output_file_get + (const tng_trajectory_t tng_data, + char *file_name, const int max_len); + +/** + * @brief Set the name of the output file. + * @param tng_data the trajectory of which to set the output file name. + * @param file_name the name of the output file. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code file_name != 0 \endcode The pointer to the file name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_output_file_set + (const tng_trajectory_t tng_data, + const char *file_name); + +/** + * @brief Set the name of the output file for appending. The output file + * will not be overwritten. + * @param tng_data the trajectory of which to set the output file name. + * @param file_name the name of the output file to append to. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code file_name != 0 \endcode The pointer to the file name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set + (const tng_trajectory_t tng_data, + const char *file_name); + +/** + * @brief Get the endianness of the output file. + * @param tng_data the trajectory of which to get the endianness of the current + * output file. + * @param endianness will contain the enumeration of the endianness. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code endianness != 0 \endcode The pointer to the endianness container + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the endianness + * could not be retrieved. + */ +tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get + (const tng_trajectory_t tng_data, tng_file_endianness *endianness); + +/** + * @brief Set the endianness of the output file. + * @param tng_data the trajectory of which to set the endianness of the current + * output file. + * @param endianness the enumeration of the endianness, can be either + * TNG_BIG_ENDIAN (0) or TNG_LITTLE_ENDIAN (1). + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @details The endianness cannot be changed after file output has started. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the endianness + * could not be set. + */ +tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set + (const tng_trajectory_t tng_data, + const tng_file_endianness endianness); + +/** + * @brief Get the name of the program used when creating the trajectory. + * @param tng_data the trajectory of which to get the program name. + * @param name the string to fill with the name of the program, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for name. This includes \0 terminating character. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get + (const tng_trajectory_t tng_data, + char *name, const int max_len); + +/** + * @brief Set the name of the program used when creating the trajectory. + * @param tng_data the trajectory of which to set the program name. + * @param new_name is a string containing the wanted name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code new_name != 0 \endcode The pointer to the new_name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set + (const tng_trajectory_t tng_data, + const char *new_name); + +/** + * @brief Get the name of the program used when last modifying the trajectory. + * @param tng_data the trajectory of which to get the program name. + * @param name the string to fill with the name of the program, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for name. This includes \0 terminating character. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get + (const tng_trajectory_t tng_data, + char *name, const int max_len); + +/** + * @brief Set the name of the program used when last modifying the trajectory. + * @param tng_data the trajectory of which to set the program name. + * @param new_name is a string containing the wanted name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code new_name != 0 \endcode The pointer to the new_name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set + (const tng_trajectory_t tng_data, + const char *new_name); + +/** + * @brief Get the name of the user who created the trajectory. + * @param tng_data the trajectory of which to get the user name. + * @param name the string to fill with the name of the user, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for name. This includes \0 terminating character. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get + (const tng_trajectory_t tng_data, + char *name, const int max_len); + +/** + * @brief Set the name of the user who created the trajectory. + * @param tng_data the trajectory of which to set the user name. + * @param new_name is a string containing the wanted name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code new_name != 0 \endcode The pointer to the new_name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set + (const tng_trajectory_t tng_data, + const char *new_name); + +/** + * @brief Get the name of the user who last modified the trajectory. + * @param tng_data the trajectory of which to get the user name. + * @param name the string to fill with the name of the user, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for name. This includes \0 terminating character. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get + (const tng_trajectory_t tng_data, + char *name, const int max_len); + +/** + * @brief Set the name of the user who last modified the trajectory. + * @param tng_data the trajectory of which to set the user name. + * @param new_name is a string containing the wanted name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code new_name != 0 \endcode The pointer to the new_name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set + (const tng_trajectory_t tng_data, + const char *new_name); + +/** + * @brief Get the name of the computer used when creating the trajectory. + * @param tng_data the trajectory of which to get the computer name. + * @param name the string to fill with the name of the computer, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for name. This includes \0 terminating character. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get + (const tng_trajectory_t tng_data, + char *name, const int max_len); + +/** + * @brief Set the name of the computer used when creating the trajectory. + * @param tng_data the trajectory of which to set the computer name. + * @param new_name is a string containing the wanted name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code new_name != 0 \endcode The pointer to the new_name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set + (const tng_trajectory_t tng_data, + const char *new_name); + +/** + * @brief Get the name of the computer used when last modifying the trajectory. + * @param tng_data the trajectory of which to get the computer name. + * @param name the string to fill with the name of the computer, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for name. This includes \0 terminating character. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get + (const tng_trajectory_t tng_data, + char *name, const int max_len); + +/** + * @brief Set the name of the computer used when last modifying the trajectory. + * @param tng_data the trajectory of which to set the computer name. + * @param new_name is a string containing the wanted name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code new_name != 0 \endcode The pointer to the new_name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set + (const tng_trajectory_t tng_data, + const char *new_name); + +/** + * @brief Get the pgp_signature of the user creating the trajectory. + * @param tng_data the trajectory of which to get the computer name. + * @param signature the string to fill with the signature, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for name. This includes \0 terminating character. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code signature != 0 \endcode The pointer to the signature + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_first_signature_get + (const tng_trajectory_t tng_data, + char *signature, const int max_len); + +/** + * @brief Set the pgp_signature of the user creating the trajectory. + * @param tng_data the trajectory of which to set the computer name. + * @param signature is a string containing the pgp_signature. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code signature != 0 \endcode The pointer to the signature + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_first_signature_set + (const tng_trajectory_t tng_data, + const char *signature); + +/** + * @brief Get the pgp_signature of the user last modifying the trajectory. + * @param tng_data the trajectory of which to get the computer name. + * @param signature the string to fill with the signature, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for name. This includes \0 terminating character. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code signature != 0 \endcode The pointer to the signature + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_last_signature_get + (const tng_trajectory_t tng_data, + char *signature, const int max_len); + +/** + * @brief Set the pgp_signature of the user last modifying the trajectory. + * @param tng_data the trajectory of which to set the computer name. + * @param signature is a string containing the pgp_signature. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code signature != 0 \endcode The pointer to the signature + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_last_signature_set + (const tng_trajectory_t tng_data, + const char *signature); + +/** + * @brief Get the name of the forcefield used in the trajectory. + * @param tng_data the trajectory of which to get the forcefield name. + * @param name the string to fill with the name of the forcefield, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for name. This includes \0 terminating character. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get + (const tng_trajectory_t tng_data, + char *name, const int max_len); + +/** + * @brief Set the name of the forcefield used in the trajectory. + * @param tng_data the trajectory of which to set the forcefield name. + * @param new_name is a string containing the wanted name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code new_name != 0 \endcode The pointer to the new_name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set + (const tng_trajectory_t tng_data, + const char *new_name); + +/** + * @brief Get the medium stride length of the trajectory. + * @param tng_data is the trajectory from which to get the stride length. + * @param len is pointing to a value set to the stride length. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code len != 0 \endcode The pointer to len must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get + (const tng_trajectory_t tng_data, + int64_t *len); + +/** + * @brief Set the medium stride length of the trajectory. + * @param tng_data is the trajectory of which to set the stride length. + * @param len is the wanted medium stride length. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred. + */ +tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set + (const tng_trajectory_t tng_data, + const int64_t len); + +/** + * @brief Get the long stride length of the trajectory. + * @param tng_data is the trajectory from which to get the stride length. + * @param len is pointing to a value set to the stride length. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code len != 0 \endcode The pointer to len must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get + (const tng_trajectory_t tng_data, + int64_t *len); + +/** + * @brief Set the long stride length of the trajectory. + * @param tng_data is the trajectory of which to set the stride length. + * @param len is the wanted long stride length. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred. + */ +tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set + (const tng_trajectory_t tng_data, + const int64_t len); + +/** + * @brief Get the current time per frame of the trajectory. + * @param tng_data is the trajectory from which to get the time per frame. + * @param time is pointing to a value set to the time per frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code time != 0 \endcode The pointer to time must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get + (const tng_trajectory_t tng_data, + double *time); + +/** + * @brief Set the time per frame of the trajectory. + * @param tng_data is the trajectory of which to set the time per frame. + * @param time is the new time per frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code time > 0 \endcode The time per frame must be >= 0. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred. + */ +tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set + (const tng_trajectory_t tng_data, + const double time); + +/** + * @brief Get the length of the input file. + * @param tng_data is the trajectory from which to get the input file length. + * @param len is pointing to a value set to the file length. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code len != 0 \endcode The pointer to len must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get + (const tng_trajectory_t tng_data, + int64_t *len); + +/** + * @brief Get the number of frames in the trajectory + * @param tng_data is the trajectory of which to get the number of frames. + * @param n is pointing to a value set to the number of frames. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code tng_data->input_file != 0 \endcode An input file must be open + * to find the next frame set. + * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (could not find last frame set). + */ +tng_function_status DECLSPECDLLEXPORT tng_num_frames_get + (const tng_trajectory_t tng_data, + int64_t *n); + +/** + * @brief Get the precision of lossy compression. + * @param tng_data is the trajectory of which to get the compression precision. + * @param precision will be pointing to the retrieved compression precision. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @details A compression precision of 0.001 (the default) means that the + * compressed values are accurate to the third decimal. This function does + * not check actual precision of compressed data, but just returns what has + * previously been set using tng_compression_precision_set(). + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get + (const tng_trajectory_t tng_data, + double *precision); + +/** + * @brief Set the precision of lossy compression. + * @param tng_data is the trajectory of which to set the compression precision. + * @param precision is the new compression precision. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @details A compression precision of 0.001 (the default) means that the + * compressed values are accurate to the third decimal. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set + (const tng_trajectory_t tng_data, + const double precision); + +/** + * @brief Set the number of particles, in the case no molecular system is used. + * @param tng_data is the trajectory of which to get the number of particles. + * @param n is the number of particles to use. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @details When creating a molecular system the number of particles are set + * automatically. This should only be used when there is no molecular system + * specified or if the number of atoms needs to be overridden for some reason. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set + (const tng_trajectory_t tng_data, + const int64_t n); + +/** + * @brief Get the current number of particles. + * @param tng_data is the trajectory from which to get the number of particles. + * @param n is pointing to a value set to the number of particles. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer. + * @details If variable number of particles are used this function will return + * the number of particles in the current frame set. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_num_particles_get + (const tng_trajectory_t tng_data, + int64_t *n); + +/** + * @brief Get if the number of particle can be varied during the simulation. + * @param tng_data is the trajectory from which to get the number of particles. + * @param variable is pointing to a value set to TNG_CONSTANT_N_ATOMS if the + * number of particles cannot change or TNG_VARIABLE_N_ATOMS if the number of + * particles can change. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code variable != 0 \endcode The pointer to variable must not be + * a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get + (const tng_trajectory_t tng_data, + char *variable); + +/** + * @brief Get the number of molecule types (length of tng_data->molecules). + * @param tng_data is the trajectory from which to get the number of molecules. + * @param n is pointing to a value set to the number of molecule types. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get + (const tng_trajectory_t tng_data, + int64_t *n); + +/** + * @brief Get the current total number of molecules. + * @param tng_data is the trajectory from which to get the number of molecules. + * @param n is pointing to a value set to the number of molecules. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer. + * @details If variable number of particles are used this function will return + * the total number of molecules in the current frame set. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get + (const tng_trajectory_t tng_data, + int64_t *n); + +/** @brief Get the list of the count of each molecule. + * @param tng_data is the trajectory from which to get the molecule count list. + * @param mol_cnt_list is a list of the count of each molecule in the + * mol system. This is a pointer to the list in the TNG container, which + * means that it should be handled carefully, e.g. not freed. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE(1) if the list of + * molecule counts was not valid. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get + (const tng_trajectory_t tng_data, + int64_t **mol_cnt_list); + +/** + * @brief Get the exponent used for distances in the trajectory. + * @param tng_data is the trajectory from which to get the information. + * @param exp is pointing to a value set to the distance unit exponent. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code exp != 0 \endcode The pointer to exp must not be a NULL pointer. + * @details Example: If the distances are specified in nm (default) exp is -9. + * If the distances are specified in Å exp is -10. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get + (const tng_trajectory_t tng_data, + int64_t *exp); + +/** + * @brief Set the exponent used for distances in the trajectory. + * @param tng_data is the trajectory of which to set the unit exponent. + * @param exp is the distance unit exponent to use. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @details Example: If the distances are specified in nm (default) exp is -9. + * If the distances are specified in Å exp is -10. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set + (const tng_trajectory_t tng_data, + const int64_t exp); + +/** + * @brief Get the number of frames per frame set. + * @param tng_data is the trajectory from which to get the number of frames + * per frame set. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer. + * @param n is pointing to a value set to the number of frames per frame set. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get + (const tng_trajectory_t tng_data, + int64_t *n); + +/** + * @brief Set the number of frames per frame set. + * @param tng_data is the trajectory of which to set the number of frames + * per frame set. + * @param n is the number of frames per frame set. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @details This does not affect already existing frame sets. For + * consistency the number of frames per frame set should be set + * betfore creating any frame sets. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set + (const tng_trajectory_t tng_data, + const int64_t n); + +/** + * @brief Get the number of frame sets. + * @details This updates tng_data->n_trajectory_frame_sets before returning it. + * @param tng_data is the trajectory from which to get the number of frame sets. + * @param n is pointing to a value set to the number of frame sets. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get + (const tng_trajectory_t tng_data, + int64_t *n); + +/** + * @brief Get the current trajectory frame set. + * @param tng_data is the trajectory from which to get the frame set. + * @param frame_set_p will be set to point at the memory position of + * the found frame set. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get + (const tng_trajectory_t tng_data, + tng_trajectory_frame_set_t *frame_set_p); + +/** + * @brief Find the requested frame set number. + * @param tng_data is the trajectory from which to get the frame set. + * @param nr is the frame set number to search for. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code nr >= 0 \endcode The frame set number (nr) must be >= 0. + * @details tng_data->current_trajectory_frame_set will contain the + * found trajectory if successful. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find + (const tng_trajectory_t tng_data, + const int64_t nr); + +/** + * @brief Find the frame set containing a specific frame. + * @param tng_data is the trajectory from which to get the frame set. + * @param frame is the frame number to search for. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code frame >= 0 \endcode The frame number must be >= 0. + * @details tng_data->current_trajectory_frame_set will contain the + * found trajectory if successful. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find + (const tng_trajectory_t tng_data, + const int64_t frame); + +/** + * @brief Get the file position of the next frame set in the input file. + * @param tng_data is a trajectory data container. + * @param frame_set is the frame set of which to get the position of the + * following frame set. + * @param pos is pointing to a value set to the file position. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code pos != 0 \endcode The pointer to pos must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get + (const tng_trajectory_t tng_data, + const tng_trajectory_frame_set_t frame_set, + int64_t *pos); + +/** + * @brief Get the file position of the previous frame set in the input file. + * @param tng_data is a trajectory data container. + * @param frame_set is the frame set of which to get the position of the + * previous frame set. + * @param pos is pointing to a value set to the file position. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code pos != 0 \endcode The pointer to pos must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get + (const tng_trajectory_t tng_data, + const tng_trajectory_frame_set_t frame_set, + int64_t *pos); + +/** + * @brief Get the first and last frames of the frame set. + * @param tng_data is a trajectory data container. + * @param frame_set is the frame set of which to get the frame range. + * @param first_frame is set to the first frame of the frame set. + * @param last_frame is set to the last frame of the frame set. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code first_frame != 0 \endcode The pointer to first_frame must + * not be a NULL pointer. + * @pre \code last_frame != 0 \endcode The pointer to last_frame must + * not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get + (const tng_trajectory_t tng_data, + const tng_trajectory_frame_set_t frame_set, + int64_t *first_frame, + int64_t *last_frame); + +/** + * @brief Allocate memory for and setup a molecule container. + * @param tng_data is a trajectory data container. + * @param molecule_p is a pointer to molecule to allocate and initialise. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data, + tng_molecule_t *molecule_p); + +/** + * @brief Clean up a molecule container and free its allocated memory. + * @param tng_data is a trajectory data container. + * @param molecule_p is the molecule to destroy. + * @details All allocated memory in the data structure is freed and also the memory + * of the molecule itself. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data, + tng_molecule_t *molecule_p); + +/** + * @brief Setup a molecule container. + * @param tng_data is a trajectory data container. + * @param molecule is the molecule to initialise. Memory must be preallocated. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_init + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule); + +/** + * @brief Clean up a molecule container. + * @param tng_data is a trajectory data container. + * @param molecule is the molecule to destroy. + * @details All allocated memory in the data structure is freed, but not the + * memory of molecule itself. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule); + +/** + * @brief Add a molecule to the trajectory. + * @param tng_data is the trajectory data container containing the block.. + * @param name is a pointer to the string containing the name of the new molecule. + * @param molecule is a pointer to the newly created molecule. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could + * not be set properly or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_add + (const tng_trajectory_t tng_data, + const char *name, + tng_molecule_t *molecule); + +/** + * @brief Add a molecule with a specific ID to the trajectory. + * @param tng_data is the trajectory data container containing the block.. + * @param name is a pointer to the string containing the name of the new molecule. + * @param id is the ID of the created molecule. + * @param molecule is a pointer to the newly created molecule. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could + * not be set properly or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add + (const tng_trajectory_t tng_data, + const char *name, + const int64_t id, + tng_molecule_t *molecule); + +/** + * @brief Add an existing molecule (from a molecule container) to the trajectory. + * @param tng_data is the trajectory data container containing the block.. + * @param molecule is a pointer to the molecule to add to the trajectory and will + * afterwards point to the molecule in the trajectory. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add + (const tng_trajectory_t tng_data, + tng_molecule_t *molecule); + +/** + * @brief Get the name of a molecule. + * @param tng_data the trajectory containing the molecule. + * @param molecule the molecule of which to get the name. + * @param name the string to fill with the name of the molecule, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for name. This includes \0 terminating character. + * @pre \code molecule != 0 \endcode The molecule must not be NULL. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_name_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + char *name, + const int max_len); + +/** + * @brief Set the name of a molecule. + * @param tng_data is the trajectory data container containing the molecule.. + * @param molecule is the molecule to rename. + * @param new_name is a string containing the wanted name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code new_name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const char *new_name); + +/** + * @brief Get the count of a molecule. + * @param tng_data is the trajectory data container containing the molecule.. + * @param molecule is the molecule of which to get the count. + * @param cnt is a pointer to the variable to be populated with the count. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code cnt != 0 \endcode The pointer to the molecule count + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + int64_t *cnt); + +/** + * @brief Set the count of a molecule. + * @param tng_data is the trajectory data container containing the molecule.. + * @param molecule is the molecule of which to set the count. + * @param cnt is the number of instances of this molecule. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const int64_t cnt); + +/** + * @brief Find a molecule. + * @param tng_data is the trajectory data container containing the molecule. + * @param name is a string containing the name of the molecule. If name is empty + * only id will be used for finding the molecule. + * @param id is the id of the molecule to look for. If id is -1 only the name of + * the molecule will be used for finding the molecule. + * @param molecule is a pointer to the molecule if it was found - otherwise 0. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if the molecule is found or TNG_FAILURE (1) if the + * molecule is not found. + * @details If name is an empty string and id == -1 the first residue will + * be found. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_find + (const tng_trajectory_t tng_data, + const char *name, + const int64_t id, + tng_molecule_t *molecule); + +/** + * @brief Retrieve the molecule with specified index in the list of molecules. + * @param tng_data is the trajectory data container containing the molecule. + * @param index is the index (in tng_data->molecules) of the molecule to return + * @param molecule is a pointer to the molecule if it was found - otherwise 0. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code molecule != 0 \endcode molecule must not be a NULL pointer. + * @return TNG_SUCCESS (0) if the molecule is found or TNG_FAILURE (1) if the + * molecule is not found. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get + (const tng_trajectory_t tng_data, + const int64_t index, + tng_molecule_t *molecule); + +/** + * @brief Copy all molecules and the molecule counts from one TNG trajectory + * to another. + * @param tng_data_src is the source trajectory containing the molecular + * system to copy. + * @param tng_data_dest is the destination trajectory. + * @pre \code tng_data_src != 0 \endcode The trajectory container (tng_data_src) + * must be initialised before using it. + * @pre \code tng_data_dest != 0 \endcode The trajectory container (tng_data_dest) + * must be initialised before using it. + * @details The molecular system in tng_data_dest will be overwritten. + * @return TNG_SUCCESS(0) if the copying is successful, TNG_FAILURE if a minor + * error has occured or TNG_CRITICAL(2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(const tng_trajectory_t tng_data_src, + const tng_trajectory_t tng_data_dest); + +/** + * @brief Get the number of chains in a molecule. + * @param tng_data is the trajectory containing the molecule. + * @param molecule is the molecule of which to get the number of chains. + * @param n is pointing to a value set to the number of chains. + * @pre \code molecule != 0 \endcode The molecule must not be NULL. + * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + int64_t *n); + +/** + * @brief Retrieve the chain of a molecule with specified index in the list + * of chains. + * @param tng_data is the trajectory data container containing the molecule. + * @param index is the index (in molecule->chains) of the chain to return + * @param molecule is the molecule from which to get the chain. + * @param chain is a pointer to the chain if it was found - otherwise 0. + * @pre \code molecule != 0 \endcode molecule must not be a NULL pointer. + * @pre \code chain != 0 \endcode chain must not be a NULL pointer. + * @return TNG_SUCCESS (0) if the chain is found or TNG_FAILURE (1) if the + * chain is not found. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const int64_t index, + tng_chain_t *chain); + +/** + * @brief Get the number of residues in a molecule. + * @param tng_data is the trajectory containing the molecule. + * @param molecule is the molecule of which to get the number residues. + * @param n is pointing to a value set to the number of residues. + * @pre \code molecule != 0 \endcode The molecule must not be NULL. + * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + int64_t *n); + +/** + * @brief Retrieve the residue of a molecule with specified index in the list + * of chains. + * @param tng_data is the trajectory data container containing the molecule. + * @param index is the index (in molecule->residues) of the residue to return + * @param molecule is the molecule from which to get the residue. + * @param residue is a pointer to the residue if it was found - otherwise 0. + * @pre \code molecule != 0 \endcode molecule must not be a NULL pointer. + * @pre \code residue != 0 \endcode residue must not be a NULL pointer. + * @return TNG_SUCCESS (0) if the residue is found or TNG_FAILURE (1) if the + * residue is not found. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const int64_t index, + tng_residue_t *residue); + +/** + * @brief Get the number of atoms in a molecule. + * @param tng_data is the trajectory containing the molecule. + * @param molecule is the molecule of which to get the number of atoms. + * @param n is pointing to a value set to the number of atoms. + * @pre \code molecule != 0 \endcode The molecule must not be NULL. + * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + int64_t *n); + +/** + * @brief Retrieve the atom of a molecule with specified index in the list + * of atoms. + * @param tng_data is the trajectory data container containing the molecule. + * @param index is the index (in molecule->atoms) of the atom to return + * @param molecule is the molecule from which to get the atom. + * @param atom is a pointer to the atom if it was found - otherwise 0. + * @pre \code molecule != 0 \endcode molecule must not be a NULL pointer. + * @pre \code atom != 0 \endcode atom must not be a NULL pointer. + * @return TNG_SUCCESS (0) if the atom is found or TNG_FAILURE (1) if the + * atom is not found. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const int64_t index, + tng_atom_t *atom); + +/** + * @brief Find a chain in a molecule. + * @param tng_data is the trajectory data container containing the molecule. + * @param molecule is the molecule in which to search for the chain. + * @param name is a string containing the name of the chain. If name is empty + * only id will be used for finding the chain. + * @param id is the id of the chain to look for. If id is -1 only the name of + * the chain will be used for finding the chain. + * @param chain is a pointer to the chain if it was found - otherwise 0. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if the chain is found or TNG_FAILURE (1) if the + * chain is not found. + * @details If name is an empty string and id == -1 the first residue will + * be found. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const char *name, + const int64_t id, + tng_chain_t *chain); + +/** + * @brief Add a chain to a molecule. + * @param tng_data is the trajectory data container containing the molecule.. + * @param molecule is the molecule to add a chain to. + * @param name is a string containing the name of the chain. + * @param chain is a pointer to the newly created chain. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could + * not be set properly or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const char *name, + tng_chain_t *chain); + +/** + * @brief Add a chain with a specific id to a molecule. + * @param tng_data is the trajectory data container containing the molecule.. + * @param molecule is the molecule to add a chain to. + * @param name is a string containing the name of the chain. + * @param id is the ID of the created chain. + * @param chain is a pointer to the newly created chain. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could + * not be set properly or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const char *name, + const int64_t id, + tng_chain_t *chain); + +/** + * @brief Add a bond between two atoms to a molecule. + * @param tng_data is the trajectory data container containing the molecule. + * @param molecule is the molecule containing the atoms to connect. + * @param from_atom_id is the id of one of the two atoms in the bond. + * @param to_atom_id is the id of the other atom in the bond. + * @param bond is a pointer to the newly created bond. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (!) if a minor error + * has occured or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const int64_t from_atom_id, + const int64_t to_atom_id, + tng_bond_t *bond); + +/** + * @brief Find an atom in a molecule. + * @param tng_data is the trajectory data container containing the molecule. + * @param molecule is the molecule in which to search for the atom. + * @param name is a string containing the name of the atom. If name is an + * empty string only id will be used for searching. + * @param id is the id of the atom to find. If id == -1 the first atom + * that matches the specified name will be found. + * @param atom is a pointer to the atom if it was found - otherwise 0. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if the atom is found or TNG_FAILURE (1) if the + * atom is not found. + * @details If name is an empty string and id == -1 the first residue will + * be found. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const char *name, + const int64_t id, + tng_atom_t *atom); + +/** + * @brief Get the name of a chain. + * @param tng_data the trajectory containing the chain. + * @param chain the chain of which to get the name. + * @param name the string to fill with the name of the chain, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for name. This includes \0 terminating character. + * @pre \code chain != 0 \endcode The chain must not be NULL. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_chain_name_get + (const tng_trajectory_t tng_data, + const tng_chain_t chain, + char *name, + const int max_len); + +/** + * @brief Set the name of a chain. + * @param tng_data is the trajectory data container containing the atom.. + * @param chain is the chain to rename. + * @param new_name is a string containing the wanted name. + * @pre \code new_name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_chain_name_set + (const tng_trajectory_t tng_data, + const tng_chain_t chain, + const char *new_name); + +/** + * @brief Get the number of residues in a molecule chain. + * @param tng_data is the trajectory containing the chain. + * @param chain is the chain of which to get the number of residues. + * @param n is pointing to a value set to the number of residues. + * @pre \code chain != 0 \endcode The chain must not be NULL. + * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get + (const tng_trajectory_t tng_data, + const tng_chain_t chain, + int64_t *n); + +/** + * @brief Retrieve the residue of a chain with specified index in the list + * of residues. + * @param tng_data is the trajectory data container containing the chain. + * @param index is the index (in chain->residues) of the residue to return + * @param chain is the chain from which to get the residue. + * @param residue is a pointer to the residue if it was found - otherwise 0. + * @pre \code chain != 0 \endcode chain must not be a NULL pointer. + * @pre \code residue != 0 \endcode residue must not be a NULL pointer. + * @return TNG_SUCCESS (0) if the residue is found or TNG_FAILURE (1) if the + * residue is not found. + */ +tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get + (const tng_trajectory_t tng_data, + const tng_chain_t chain, + const int64_t index, + tng_residue_t *residue); + +/** + * @brief Find a residue in a chain. + * @param tng_data is the trajectory data container containing the chain. + * @param chain is the chain in which to search for the residue. + * @param name is a string containing the name of the residue. If name is an + * empty string only id will be used for searching. + * @param id is the id of the residue to find. If id == -1 the first residue + * that matches the specified name will be found. + * @param residue is a pointer to the residue if it was found - otherwise 0. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if the residue is found or TNG_FAILURE (1) if the + * residue is not found. + * @details If name is an empty string and id == -1 the first residue will + * be found. + */ +tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find + (const tng_trajectory_t tng_data, + const tng_chain_t chain, + const char *name, + const int64_t id, + tng_residue_t *residue); + +/** + * @brief Add a residue to a chain. + * @param tng_data is the trajectory data container containing the chain.. + * @param chain is the chain to add a residue to. + * @param name is a string containing the name of the residue. + * @param residue is a pointer to the newly created residue. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could + * not be set properly or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add + (const tng_trajectory_t tng_data, + const tng_chain_t chain, + const char *name, + tng_residue_t *residue); + +/** + * @brief Add a residue with a specific ID to a chain. + * @param tng_data is the trajectory data container containing the chain.. + * @param chain is the chain to add a residue to. + * @param name is a string containing the name of the residue. + * @param id is the ID of the created residue. + * @param residue is a pointer to the newly created residue. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could + * not be set properly or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add + (const tng_trajectory_t tng_data, + const tng_chain_t chain, + const char *name, + const int64_t id, + tng_residue_t *residue); + +/** + * @brief Get the name of a residue. + * @param tng_data the trajectory containing the residue. + * @param residue the residue of which to get the name. + * @param name the string to fill with the name of the residue, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for name. This includes \0 terminating character. + * @pre \code residue != 0 \endcode The residue must not be NULL. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_residue_name_get + (const tng_trajectory_t tng_data, + const tng_residue_t residue, + char *name, + const int max_len); + +/** + * @brief Set the name of a residue. + * @param tng_data is the trajectory data container containing the residue. + * @param residue is the residue to rename. + * @param new_name is a string containing the wanted name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code new_name != 0 \endcode The new name to set (new_name) must + * not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_residue_name_set + (const tng_trajectory_t tng_data, + const tng_residue_t residue, + const char *new_name); + +/** + * @brief Get the number of atoms in a residue. + * @param tng_data is the trajectory containing the residue. + * @param residue is the residue of which to get the number atoms. + * @param n is pointing to a value set to the number of atoms. + * @pre \code residue != 0 \endcode The residue must not be NULL. + * @pre \code n != 0 \endcode The pointer to n must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get + (const tng_trajectory_t tng_data, + const tng_residue_t residue, + int64_t *n); + +/** + * @brief Retrieve the atom of a residue with specified index in the list + * of atoms. + * @param tng_data is the trajectory data container containing the residue. + * @param index is the index (in residue->atoms) of the atom to return + * @param residue is the residue from which to get the atom. + * @param atom is a pointer to the atom if it was found - otherwise 0. + * @pre \code residue != 0 \endcode residue must not be a NULL pointer. + * @pre \code atom != 0 \endcode atom must not be a NULL pointer. + * @return TNG_SUCCESS (0) if the atom is found or TNG_FAILURE (1) if the + * atom is not found. + */ +tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get + (const tng_trajectory_t tng_data, + const tng_residue_t residue, + const int64_t index, + tng_atom_t *atom); + +/** + * @brief Add an atom to a residue. + * @param tng_data is the trajectory containing the residue. + * @param residue is the residue to add an atom to. + * @param atom_name is a string containing the name of the atom. + * @param atom_type is a string containing the atom type of the atom. + * @param atom is a pointer to the newly created atom. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code atom_name != 0 \endcode The pointer to the atom name string + * must not be a NULL pointer. + * @pre \code atom_type != 0 \endcode The pointer to the atom_type string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could + * not be set properly or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add + (const tng_trajectory_t tng_data, + const tng_residue_t residue, + const char *atom_name, + const char *atom_type, + tng_atom_t *atom); + +/** + * @brief Add an atom with a specific ID to a residue. + * @param tng_data is the trajectory containing the residue. + * @param residue is the residue to add an atom to. + * @param atom_name is a string containing the name of the atom. + * @param atom_type is a string containing the atom type of the atom. + * @param id is the ID of the created atom. + * @param atom is a pointer to the newly created atom. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code atom_name != 0 \endcode The pointer to the atom name string + * must not be a NULL pointer. + * @pre \code atom_type != 0 \endcode The pointer to the atom_type string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the ID could + * not be set properly or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add + (const tng_trajectory_t tng_data, + const tng_residue_t residue, + const char *atom_name, + const char *atom_type, + const int64_t id, + tng_atom_t *atom); + +/** + * @brief Get the residue of an atom. + * @param tng_data the trajectory containing the atom. + * @param atom the atom of which to get the name. + * @param residue is set to the residue of the atom. + * @pre \code atom != 0 \endcode The atom must not be NULL. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_atom_residue_get + (const tng_trajectory_t tng_data, + const tng_atom_t atom, + tng_residue_t *residue); + +/** + * @brief Get the name of an atom. + * @param tng_data the trajectory containing the atom. + * @param atom the atom of which to get the name. + * @param name the string to fill with the name of the atom, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for name. This includes \0 terminating character. + * @pre \code atom != 0 \endcode The atom must not be NULL. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_atom_name_get + (const tng_trajectory_t tng_data, + const tng_atom_t atom, + char *name, + const int max_len); + +/** + * @brief Set the name of an atom. + * @param tng_data is the trajectory data container containing the atom. + * @param atom is the atom to rename. + * @param new_name is a string containing the wanted name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code new_name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_atom_name_set + (const tng_trajectory_t tng_data, + const tng_atom_t atom, + const char *new_name); + +/** + * @brief Get the type of an atom. + * @param tng_data the trajectory containing the atom. + * @param atom the atom of which to get the type. + * @param type the string to fill with the type of the atom, + * memory must be allocated before. + * @param max_len maximum char length of the string, i.e. how much memory has + * been reserved for type. This includes \0 terminating character. + * @pre \code atom != 0 \endcode The atom must not be NULL. + * @pre \code type != 0 \endcode The pointer to the type string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred (source string longer than destination string). + */ +tng_function_status DECLSPECDLLEXPORT tng_atom_type_get + (const tng_trajectory_t tng_data, + const tng_atom_t atom, + char *type, + const int max_len); + +/** + * @brief Set the atom type of an atom. + * @param tng_data is the trajectory data container containing the atom. + * @param atom is the atom to change. + * @param new_type is a string containing the atom type. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code new_type != 0 \endcode The pointer to the atom type string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_atom_type_set + (const tng_trajectory_t tng_data, + const tng_atom_t atom, + const char *new_type); + +/** + * @brief Get the molecule name of real particle number (number in mol system). + * @param tng_data is the trajectory data container containing the atom. + * @param nr is the real number of the particle in the molecular system. + * @param name is a string, which is set to the name of the molecule. Memory + * must be reserved beforehand. + * @param max_len is the maximum length of name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + char *name, + const int max_len); + +/** + * @brief Get the molecule id of real particle number (number in mol system). + * @param tng_data is the trajectory data container containing the atom. + * @param nr is the real number of the particle in the molecular system. + * @param id is will be set to the id of the molecule. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code id != 0 \endcode The pointer to id must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + int64_t *id); + +/** + * @brief Get the bonds of the current molecular system. + * @param tng_data is the trajectory data container containing the molecular + * system. + * @param n_bonds is set to the number of bonds in the molecular system and + * thereby also the lengths of the two lists: from_atoms and to_atoms. + * @param from_atoms is a list (memory reserved by this function) of atoms + * (number of atom in mol system) in bonds. + * @param to_atoms is a list (memory reserved by this function) of atoms + * (number of atom in mol system) in bonds. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n_bonds != 0 \endcode The pointer to n_bonds must not be a + * NULL pointer. + * @pre \code from_atoms != 0 \endcode The pointer to from_atoms must not + * be a NULL pointer. + * @pre \code to_atoms != 0 \endcode The pointer to to_atoms must not + * be a NULL pointer. + * @details The two lists of atoms use the same index, i.e. from_atoms[0] + * and to_atoms[0] are linked with a bond. Since memory is reserved in + * this function it must be freed afterwards. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get + (const tng_trajectory_t tng_data, + int64_t *n_bonds, + int64_t **from_atoms, + int64_t **to_atoms); + +/** + * @brief Get the chain name of real particle number (number in mol system). + * @param tng_data is the trajectory data container containing the atom. + * @param nr is the real number of the particle in the molecular system. + * @param name is a string, which is set to the name of the chain. Memory + * must be reserved beforehand. + * @param max_len is the maximum length of name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + char *name, + const int max_len); + +/** + * @brief Get the residue name of real particle number (number in mol system). + * @param tng_data is the trajectory data container containing the atom. + * @param nr is the real number of the particle in the molecular system. + * @param name is a string, which is set to the name of the residue. Memory + * must be reserved beforehand. + * @param max_len is the maximum length of name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + char *name, + const int max_len); + +/** + * @brief Get the residue id (local to molecule) of real particle number + * (number in mol system). + * @param tng_data is the trajectory data container containing the atom. + * @param nr is the real number of the particle in the molecular system. + * @param id is a pointer to the variable, which will be set to the ID. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code id != 0 \endcode The pointer to id must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + int64_t *id); + +/** + * @brief Get the residue id (based on other molecules and molecule counts) + * of real particle number (number in mol system). + * @param tng_data is the trajectory data container containing the atom. + * @param nr is the real number of the particle in the molecular system. + * @param id is a pointer to the variable, which will be set to the ID. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code id != 0 \endcode The pointer to id must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + int64_t *id); + +/** + * @brief Get the atom name of real particle number (number in mol system). + * @param tng_data is the trajectory data container containing the atom. + * @param nr is the real number of the particle in the molecular system. + * @param name is a string, which is set to the name of the atom. Memory + * must be reserved beforehand. + * @param max_len is the maximum length of name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + char *name, + const int max_len); + +/** + * @brief Get the atom type of real particle number (number in mol system). + * @param tng_data is the trajectory data container containing the atom. + * @param nr is the real number of the particle in the molecular system. + * @param type is a string, which is set to the type of the atom. Memory + * must be reserved beforehand. + * @param max_len is the maximum length of type. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code type != 0 \endcode The pointer to the type string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (!) if a minor error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_atom_type_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + char *type, + const int max_len); + +/** + * @brief Add a particle mapping table. + * @details Each particle mapping table will be written as a separate block, + * followed by the data blocks for the corresponding particles. In most cases + * there is one particle mapping block for each thread writing the trajectory. + * @param tng_data is the trajectory, with the frame set to which to add + * the mapping block. + * @details The mapping information is added to the currently active frame set + * of tng_data + * @param num_first_particle is the first particle number of this mapping + * block. + * @param n_particles is the number of particles in this mapping block. + * @param mapping_table is a list of the real particle numbers (i.e. the numbers + * used in the molecular system). The list is n_particles long. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @details mapping_table[0] is the real particle number of the first particle + * in the following data blocks. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add + (const tng_trajectory_t tng_data, + const int64_t num_first_particle, + const int64_t n_particles, + const int64_t *mapping_table); + +/** + * @brief Remove all particle mappings (in memory) from the current frame set. + * @details Clears the currently setup particle mappings of the current frame + * set. + * @param tng_data is the trajectory, with the frame set of which to clear + * all particle mappings. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free + (const tng_trajectory_t tng_data); + +/** + * @brief Read the header blocks from the input_file of tng_data. + * @details The trajectory blocks must be read separately and iteratively in chunks + * to fit in memory. + * @param tng_data is a trajectory data container. + * @details tng_data->input_file_path specifies + * which file to read from. If the file (input_file) is not open it will be + * opened. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_file_headers_read + (const tng_trajectory_t tng_data, + const char hash_mode); + +/** + * @brief Write the header blocks to the output_file of tng_data. + * @details The trajectory blocks must be written separately and iteratively in chunks + * to fit in memory. + * @param tng_data is a trajectory data container. + * @details tng_data->output_file_path + * specifies which file to write to. If the file (output_file) is not open it + * will be opened. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH an md5 hash for each header block will be generated. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_file_headers_write + (const tng_trajectory_t tng_data, + const char hash_mode); + +/** + * @brief Read one (the next) block (of any kind) from the input_file of tng_data. + * @param tng_data is a trajectory data container. + * @details tng_data->input_file_path specifies + * which file to read from. If the file (input_file) is not open it will be + * opened. + * @param block_data is a pointer to the struct which will be populated with the + * data. + * @details If block_data->input_file_pos > 0 it is the position from where the + * reading starts otherwise it starts from the current position. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code block != 0 \endcode The block container (block) must be + * initialised before using it. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_block_read_next + (const tng_trajectory_t tng_data, + const tng_gen_block_t block_data, + const char hash_mode); + +/** + * @brief Read one frame set, including all particle mapping blocks and data + * blocks, starting from the current file position. + * @param tng_data is a trajectory data container. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_read + (const tng_trajectory_t tng_data, + const char hash_mode); + +/** + * @brief Read data from the current frame set from the input_file. Only read + * particle mapping and data blocks matching the specified block_id. + * @param tng_data is a trajectory data container. + * @details tng_data->input_file_path specifies + * which file to read from. If the file (input_file) is not open it will be + * opened. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @param block_id is the ID of the data block to read from file. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id + (const tng_trajectory_t tng_data, + const char hash_mode, + const int64_t block_id); + +/** + * @brief Read one (the next) frame set, including particle mapping and related data blocks + * from the input_file of tng_data. + * @param tng_data is a trajectory data container. + * @details tng_data->input_file_path specifies + * which file to read from. If the file (input_file) is not open it will be + * opened. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next + (const tng_trajectory_t tng_data, + const char hash_mode); + +/** + * @brief Read one (the next) frame set, including particle mapping and data blocks with a + * specific block id from the input_file of tng_data. + * @param tng_data is a trajectory data container. + * @details tng_data->input_file_path specifies + * which file to read from. If the file (input_file) is not open it will be + * opened. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @param block_id is the ID number of the blocks that should be read from file. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id + (const tng_trajectory_t tng_data, + const char hash_mode, + const int64_t block_id); + +/** + * @brief Write one frame set, including mapping and related data blocks + * to the output_file of tng_data. + * @param tng_data is a trajectory data container. + * @details tng_data->output_file_path specifies + * which file to write to. If the file (output_file) is not open it will be + * opened. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH an md5 hash for each header block will be generated. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_write + (const tng_trajectory_t tng_data, + const char hash_mode); + +/** + * @brief Write one frame set even if it does not have as many frames as + * expected. The function also writes mapping and related data blocks + * to the output_file of tng_data. + * @param tng_data is a trajectory data container. + * @details tng_data->output_file_path specifies + * which file to write to. If the file (output_file) is not open it will be + * opened. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH an md5 hash for each header block will be generated. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @details The number of frames in the frame set is set to the number of + * frames of the data blocks before writing it to disk. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write + (const tng_trajectory_t tng_data, + const char hash_mode); + +/** + * @brief Create and initialise a frame set. + * @details Particle mappings are retained from previous frame set (if any). + * To explicitly clear particle mappings use tng_frame_set_particle_mapping_free(). + * @param tng_data is the trajectory data container in which to add the frame + * set. + * @param first_frame is the first frame of the frame set. + * @param n_frames is the number of frames in the frame set. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code first_frame >= 0 \endcode The first frame must not be negative. + * @pre \code n_frames >= 0 \endcode The number of frames must not be negative. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_new + (const tng_trajectory_t tng_data, + const int64_t first_frame, + const int64_t n_frames); + +/** + * @brief Create and initialise a frame set with the time of the first frame + * specified. + * @param tng_data is the trajectory data container in which to add the frame + * set. + * @param first_frame is the first frame of the frame set. + * @param n_frames is the number of frames in the frame set. + * @param first_frame_time is the time stamp of the first frame (in seconds). + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code first_frame >= 0 \endcode The first frame must not be negative. + * @pre \code n_frames >= 0 \endcode The number of frames must not be negative. + * @pre \code first_frame_time >= 0 \endcode The time stamp of the first frame + * must not be negative. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new + (const tng_trajectory_t tng_data, + const int64_t first_frame, + const int64_t n_frames, + const double first_frame_time); + +/** + * @brief Set the time stamp of the first frame of the current frame set. + * @param tng_data is the trajectory containing the frame set. + * @param first_frame_time is the time stamp of the first frame in the + * frame set. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code first_frame_time >= 0 \endcode The time stamp of the first frame + * must not be negative. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set + (const tng_trajectory_t tng_data, + const double first_frame_time); + +/** + * @brief Read the number of the first frame of the next frame set. + * @param tng_data is the trajectory containing the frame set. + * @param frame is set to the frame number of the first frame in the + * next frame set. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code tng_data->input_file != 0 \endcode An input file must be open + * to find the next frame set. + * @pre \code frame != 0 \endcode The pointer to the frame must not be a NULL + * pointer. + * @return TNG_SUCCESS(0) if successful, TNG_FAILURE(1) if there is no next + * frame set or TNG_CRITICAL(2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get + (const tng_trajectory_t tng_data, + int64_t *frame); + +/** + * @brief Add a non-particle dependent data block. + * @param tng_data is the trajectory data container in which to add the data + * block + * @param id is the block ID of the block to add. + * @param block_name is a descriptive name of the block to add + * @param datatype is the datatype of the data in the block (e.g. int/float) + * @param block_type_flag indicates if this is a non-trajectory block (added + * directly to tng_data) or if it is a trajectory block (added to the + * frame set) + * @param n_frames is the number of frames of the data block (automatically + * set to 1 if adding a non-trajectory data block) + * @param n_values_per_frame is how many values a stored each frame (e.g. 9 + * for a box shape block) + * @param stride_length is how many frames are between each entry in the + * data block + * @param codec_id is the ID of the codec to compress the data. + * @param new_data is an array of data values to add. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code block_name != 0 \endcode The pointer to the block name must + * not be a NULL pointer. + * @pre \code n_values_per_frame > 0 \endcode n_values_per_frame must be + * a positive integer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_data_block_add + (const tng_trajectory_t tng_data, + const int64_t id, + const char *block_name, + const char datatype, + const char block_type_flag, + int64_t n_frames, + const int64_t n_values_per_frame, + int64_t stride_length, + const int64_t codec_id, + void *new_data); + +/** + * @brief Add a particle dependent data block. + * @param tng_data is the trajectory data container in which to add the data + * block + * @param id is the block ID of the block to add. + * @param block_name is a descriptive name of the block to add + * @param datatype is the datatype of the data in the block (e.g. int/float) + * @param block_type_flag indicates if this is a non-trajectory block (added + * directly to tng_data) or if it is a trajectory block (added to the + * frame set) + * @param n_frames is the number of frames of the data block (automatically + * set to 1 if adding a non-trajectory data block) + * @param n_values_per_frame is how many values a stored each frame (e.g. 9 + * for a box shape block) + * @param stride_length is how many frames are between each entry in the + * data block + * @param num_first_particle is the number of the first particle stored + * in this data block + * @param n_particles is the number of particles stored in this data block + * @param codec_id is the ID of the codec to compress the data. + * @param new_data is an array of data values to add. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code block_name != 0 \endcode The pointer to the block name must + * not be a NULL pointer. + * @pre \code n_values_per_frame > 0 \endcode n_values_per_frame must be + * a positive integer. + * @pre \code num_first_particle >= 0 \endcode The number of the + * first particle must be >= 0. + * @pre \code n_particles >= 0 \endcode n_particles must be >= 0. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add + (const tng_trajectory_t tng_data, + const int64_t id, + const char *block_name, + const char datatype, + const char block_type_flag, + int64_t n_frames, + const int64_t n_values_per_frame, + int64_t stride_length, + const int64_t num_first_particle, + const int64_t n_particles, + const int64_t codec_id, + void *new_data); + +/** @brief Get the name of a data block of a specific ID. + * @param tng_data is the trajectory data container. + * @param block_id is the ID of the data block of which to get the name. + * @param name is a string, which is set to the name of the data block. + * Memory must be reserved beforehand. + * @param max_len is the maximum length of name. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code name != 0 \endcode The pointer to the name string + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if the data block is found, TNG_FAILURE (1) + * if a minor error has occured or the data block is not found or + * TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + char *name, + const int max_len); + +/** @brief Get the dependency of a data block of a specific ID. + * @param tng_data is the trajectory data container. + * @param block_id is the ID of the data block of which to get the name. + * @param block_dependency is a pointer to the dependency of the data block. + * If the block is frame dependent it will be set to TNG_FRAME_DEPENDENT, + * if it is particle dependent it will be set to TNG_PARTICLE_DEPENDENT and + * if it is both it will be set to TNG_FRAME_DEPENDENT & TNG_PARTICLE_DEPENDENT. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code block_dependency != 0 \endcode The pointer to the block dependency + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if the data block is found, TNG_FAILURE (1) + * if a minor error has occured or the data block is not found or + * TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + int *block_dependency); + +/** @brief Get the number of values per frame of a data block of a specific ID. + * @param tng_data is the trajectory data container. + * @param block_id is the ID of the data block of which to get the name. + * @param n_values_per_frame is a pointer set to the number of values per frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of values + * per frame must not be a NULL pointer. + * @return TNG_SUCCESS (0) if the data block is found, TNG_FAILURE (1) + * if a minor error has occured or the data block is not found or + * TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + int64_t *n_values_per_frame); + +/** + * @brief Write data of one trajectory frame to the output_file of tng_data. + * @param tng_data is a trajectory data container. tng_data->output_file_path + * specifies which file to write to. If the file (output_file) is not open it + * will be opened. + * @param frame_nr is the index number of the frame to write. + * @param block_id is the ID of the data block to write the data to. + * @param values is an array of data to write. The length of the array should + * equal n_values_per_frame. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0. + * @pre \code values != 0 \endcode The pointer to the values must not be a NULL + * pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_data_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const int64_t block_id, + const void *values, + const char hash_mode); + +/** + * @brief Write particle data of one trajectory frame to the output_file of + * tng_data. + * @param tng_data is a trajectory data container. tng_data->output_file_path + * specifies which file to write to. If the file (output_file) is not open it + * will be opened. + * @param frame_nr is the index number of the frame to write. + * @param block_id is the ID of the data block to write the data to. + * @param val_first_particle is the number of the first particle in the data + * array. + * @param val_n_particles is the number of particles in the data array. + * @param values is a 1D-array of data to write. The length of the array should + * equal n_particles * n_values_per_frame. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0. + * @pre \code val_first_particle >= 0 \endcode The number of the + * first particle must be >= 0. + * @pre \code val_n_particles >= 0 \endcode The number of particles must be >= 0. + * @pre \code values != 0 \endcode The pointer to the values must not be a NULL + * pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const int64_t block_id, + const int64_t val_first_particle, + const int64_t val_n_particles, + const void *values, + const char hash_mode); + +/** + * @brief Free data of an array of values (2D). + * @param tng_data is a trajectory data container. + * @param values is the 2D array to free and will be set to 0 afterwards. + * @param n_frames is the number of frames in the data array. + * @param n_values_per_frame is the number of values per frame in the data array. + * @param type is the data type of the data in the array (e.g. int/float/char). + * @details This function should not be used. The data_values union is obsolete. + * This function also causes memory leaks, but its signature cannot be changed + * without disturbing the API. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_data_values_free + (const tng_trajectory_t tng_data, + union data_values **values, + const int64_t n_frames, + const int64_t n_values_per_frame, + const char type); + +/** + * @brief Free data of an array of values (3D). + * @param tng_data is a trajectory data container. + * @param values is the array to free and will be set to 0 afterwards. + * @param n_frames is the number of frames in the data array. + * @param n_particles is the number of particles in the data array. + * @param n_values_per_frame is the number of values per frame in the data array. + * @param type is the data type of the data in the array (e.g. int/float/char). + * @details This function should not be used. The data_values union is obsolete. + * This function also causes memory leaks, but its signature cannot be changed + * without disturbing the API. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free + (const tng_trajectory_t tng_data, + union data_values ***values, + const int64_t n_frames, + const int64_t n_particles, + const int64_t n_values_per_frame, + const char type); + +/** + * @brief Retrieve non-particle data, from the last read frame set. Obsolete! + * @param tng_data is a trajectory data container. tng_data->input_file_path specifies + * which file to read from. If the file (input_file) is not open it will be + * opened. + * @param block_id is the id number of the particle data block to read. + * @param values is a pointer to a 2-dimensional array (memory unallocated), which + * will be filled with data. The array will be sized + * (n_frames * n_values_per_frame). + * Since ***values is allocated in this function it is the callers + * responsibility to free the memory. + * @param n_frames is set to the number of frames in the returned data. This is + * needed to properly reach and/or free the data afterwards. + * @param n_values_per_frame is set to the number of values per frame in the data. + * This is needed to properly reach and/or free the data afterwards. + * @param type is set to the data type of the data in the array. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n_frames != 0 \endcode The pointer to the number of frames + * must not be a NULL pointer. + * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of + * values per frame must not be a NULL pointer. + * @pre \code type != 0 \endcode The pointer to the data type must not + * be a NULL pointer. + * @details This function is obsolete and only retained for compatibility. Use + * tng_data_vector_get() instead. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_data_get(const tng_trajectory_t tng_data, + const int64_t block_id, + union data_values ***values, + int64_t *n_frames, + int64_t *n_values_per_frame, + char *type); + +/** + * @brief Retrieve a vector (1D array) of non-particle data, from the last read frame set. + * @param tng_data is a trajectory data container. tng_data->input_file_path specifies + * which file to read from. If the file (input_file) is not open it will be + * opened. + * @param block_id is the id number of the particle data block to read. + * @param values is a pointer to a 1-dimensional array (memory unallocated), which + * will be filled with data. The length of the array will be + * (n_frames_with_data (see stride_length) * n_values_per_frame). + * Since **values is allocated in this function it is the callers + * responsibility to free the memory. + * @param n_frames is set to the number of particles in the returned data. This is + * needed to properly reach and/or free the data afterwards. + * @param stride_length is set to the stride length of the returned data. + * @param n_values_per_frame is set to the number of values per frame in the data. + * This is needed to properly reach and/or free the data afterwards. + * @param type is set to the data type of the data in the array. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n_frames != 0 \endcode The pointer to the number of frames + * must not be a NULL pointer. + * @pre \code stride_length != 0 \endcode The pointer to the stride length + * must not be a NULL pointer. + * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of + * values per frame must not be a NULL pointer. + * @pre \code type != 0 \endcode The pointer to the data type must not + * be a NULL pointer. + * @details This does only work for numerical (int, float, double) data. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_data_vector_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + void **values, + int64_t *n_frames, + int64_t *stride_length, + int64_t *n_values_per_frame, + char *type); + +/** + * @brief Read and retrieve non-particle data, in a specific interval. Obsolete! + * @param tng_data is a trajectory data container. tng_data->input_file_path specifies + * which file to read from. If the file (input_file) is not open it will be + * opened. + * @param block_id is the id number of the particle data block to read. + * @param start_frame_nr is the index number of the first frame to read. + * @param end_frame_nr is the index number of the last frame to read. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @param values is a pointer to a 2-dimensional array (memory unallocated), which + * will be filled with data. The array will be sized + * (n_frames * n_values_per_frame). + * Since ***values is allocated in this function it is the callers + * responsibility to free the memory. + * @param n_values_per_frame is set to the number of values per frame in the data. + * This is needed to properly reach and/or free the data afterwards. + * @param type is set to the data type of the data in the array. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before + * the last frame. + * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of + * values per frame must not be a NULL pointer. + * @pre \code type != 0 \endcode The pointer to the data type must not + * be a NULL pointer. + * @details This function is obsolete and only retained for compatibility. Use + * tng_data_vector_interval_get() instead. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_data_interval_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + const int64_t start_frame_nr, + const int64_t end_frame_nr, + const char hash_mode, + union data_values ***values, + int64_t *n_values_per_frame, + char *type); + +/** + * @brief Read and retrieve a vector (1D array) of non-particle data, + * in a specific interval. + * @param tng_data is a trajectory data container. tng_data->input_file_path specifies + * which file to read from. If the file (input_file) is not open it will be + * opened. + * @param block_id is the id number of the particle data block to read. + * @param start_frame_nr is the index number of the first frame to read. + * @param end_frame_nr is the index number of the last frame to read. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @param values is a pointer to a 1-dimensional array (memory unallocated), which + * will be filled with data. The length of the array will be + * (n_frames_with_data (see stride_length) * n_values_per_frame). + * Since **values is allocated in this function it is the callers + * responsibility to free the memory. + * @param stride_length is set to the stride length (writing interval) of + * the data. + * @param n_values_per_frame is set to the number of values per frame in the data. + * This is needed to properly reach and/or free the data afterwards. + * @param type is set to the data type of the data in the array. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before + * the last frame. + * @pre \code stride_length != 0 \endcode The pointer to the stride length + * must not be a NULL pointer. + * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of + * values per frame must not be a NULL pointer. + * @pre \code type != 0 \endcode The pointer to the data type must not + * be a NULL pointer. + * @details This does only work for numerical (int, float, double) data. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + const int64_t start_frame_nr, + const int64_t end_frame_nr, + const char hash_mode, + void **values, + int64_t *stride_length, + int64_t *n_values_per_frame, + char *type); + +/** + * @brief Retrieve particle data, from the last read frame set. Obsolete! + * @details The particle dimension of the returned values array is translated + * to real particle numbering, i.e. the numbering of the actual molecular + * system. + * @param tng_data is a trajectory data container. tng_data->input_file_path + * specifies which file to read from. If the file (input_file) is not open it + * will be opened. + * @param block_id is the id number of the particle data block to read. + * @param values is a pointer to a 3-dimensional array (memory unallocated), which + * will be filled with data. The array will be sized + * (n_frames * n_particles * n_values_per_frame). + * Since ****values is allocated in this function it is the callers + * responsibility to free the memory. + * @param n_frames is set to the number of frames in the returned data. This is + * needed to properly reach and/or free the data afterwards. + * @param n_particles is set to the number of particles in the returned data. This is + * needed to properly reach and/or free the data afterwards. + * @param n_values_per_frame is set to the number of values per frame in the data. + * This is needed to properly reach and/or free the data afterwards. + * @param type is set to the data type of the data in the array. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n_frames != 0 \endcode The pointer to the number of frames + * must not be a NULL pointer. + * @pre \code n_particles != 0 \endcode The pointer to the number of particles must + * not be a NULL pointer. + * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of + * values per frame must not be a NULL pointer. + * @pre \code type != 0 \endcode The pointer to the data type must not + * be a NULL pointer. + * @details This function is obsolete and only retained for compatibility. Use + * tng_particle_data_vector_get() instead. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_particle_data_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + union data_values ****values, + int64_t *n_frames, + int64_t *n_particles, + int64_t *n_values_per_frame, + char *type); + +/** + * @brief Retrieve a vector (1D array) of particle data, from the last read frame set. + * @details The particle dimension of the returned values array is translated + * to real particle numbering, i.e. the numbering of the actual molecular + * system. + * @param tng_data is a trajectory data container. tng_data->input_file_path + * specifies which file to read from. If the file (input_file) is not open it + * will be opened. + * @param block_id is the id number of the particle data block to read. + * @param values is a pointer to a 1-dimensional array (memory unallocated), which + * will be filled with data. The length of the array will be + * (n_frames_with_data (see stride_length) * n_particles * n_values_per_frame). + * Since **values is allocated in this function it is the callers + * responsibility to free the memory. + * @param n_frames is set to the number of frames in the returned data. This is + * needed to properly reach and/or free the data afterwards. + * @param stride_length is set to the stride length of the returned data. + * @param n_particles is set to the number of particles in the returned data. This is + * needed to properly reach and/or free the data afterwards. + * @param n_values_per_frame is set to the number of values per frame in the data. + * This is needed to properly reach and/or free the data afterwards. + * @param type is set to the data type of the data in the array. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n_particles != 0 \endcode The pointer to the number of particles must + * not be a NULL pointer. + * @pre \code stride_length != 0 \endcode The pointer to the stride length + * must not be a NULL pointer. + * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of + * values per frame must not be a NULL pointer. + * @pre \code type != 0 \endcode The pointer to the data type must not + * be a NULL pointer. + * @details This does only work for numerical (int, float, double) data. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + void **values, + int64_t *n_frames, + int64_t *stride_length, + int64_t *n_particles, + int64_t *n_values_per_frame, + char *type); + +/** + * @brief Read and retrieve particle data, in a specific interval. Obsolete! + * @details The particle dimension of the returned values array is translated + * to real particle numbering, i.e. the numbering of the actual molecular + * system. + * @param tng_data is a trajectory data container. tng_data->input_file_path specifies + * which file to read from. If the file (input_file) is not open it will be + * opened. + * @param block_id is the id number of the particle data block to read. + * @param start_frame_nr is the index number of the first frame to read. + * @param end_frame_nr is the index number of the last frame to read. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @param values is a pointer to a 3-dimensional array (memory unallocated), which + * will be filled with data. The array will be sized + * (n_frames * n_particles * n_values_per_frame). + * Since ****values is allocated in this function it is the callers + * responsibility to free the memory. + * @param n_particles is set to the number of particles in the returned data. This is + * needed to properly reach and/or free the data afterwards. + * @param n_values_per_frame is set to the number of values per frame in the data. + * This is needed to properly reach and/or free the data afterwards. + * @param type is set to the data type of the data in the array. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n_frames != 0 \endcode The pointer to the number of frames + * must not be a NULL pointer. + * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before + * the last frame. + * @pre \code n_particles != 0 \endcode The pointer to the number of particles must + * not be a NULL pointer. + * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of + * values per frame must not be a NULL pointer. + * @pre \code type != 0 \endcode The pointer to the data type must not + * be a NULL pointer. + * @details This function is obsolete and only retained for compatibility. Use + * tng_particle_data_vector_interval_get() instead. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + const int64_t start_frame_nr, + const int64_t end_frame_nr, + const char hash_mode, + union data_values ****values, + int64_t *n_particles, + int64_t *n_values_per_frame, + char *type); + +/** + * @brief Read and retrieve a vector (1D array) particle data, in a + * specific interval. + * @details The particle dimension of the returned values array is translated + * to real particle numbering, i.e. the numbering of the actual molecular + * system. + * @param tng_data is a trajectory data container. tng_data->input_file_path specifies + * which file to read from. If the file (input_file) is not open it will be + * opened. + * @param block_id is the id number of the particle data block to read. + * @param start_frame_nr is the index number of the first frame to read. + * @param end_frame_nr is the index number of the last frame to read. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @param values is a pointer to a 1-dimensional array (memory unallocated), which + * will be filled with data. The length of the array will be + * (n_frames_with_data (see stride_length) * n_particles * n_values_per_frame). + * Since **values is allocated in this function it is the callers + * responsibility to free the memory. + * @param stride_length is set to the stride length (writing interval) of + * the data. + * @param n_particles is set to the number of particles in the returned data. This is + * needed to properly reach and/or free the data afterwards. + * @param n_values_per_frame is set to the number of values per frame in the data. + * This is needed to properly reach and/or free the data afterwards. + * @param type is set to the data type of the data in the array. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before + * the last frame. + * @pre \code n_particles != 0 \endcode The pointer to the number of particles must + * not be a NULL pointer. + * @pre \code stride_length != 0 \endcode The pointer to the stride length + * must not be a NULL pointer. + * @pre \code n_values_per_frame != 0 \endcode The pointer to the number of + * values per frame must not be a NULL pointer. + * @pre \code type != 0 \endcode The pointer to the data type must not + * be a NULL pointer. + * @details This does only work for numerical (int, float, double) data. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + const int64_t start_frame_nr, + const int64_t end_frame_nr, + const char hash_mode, + void **values, + int64_t *n_particles, + int64_t *stride_length, + int64_t *n_values_per_frame, + char *type); + +/** + * @brief Get the stride length of a specific data (particle dependency does not matter) + * block, either in the current frame set or of a specific frame. + * @param tng_data is the trajectory data container. + * @param block_id is the block ID of the data block, of which to retrieve the + * stride length of the data. + * @param frame is the frame from which to get the stride length. If frame is set to -1 + * no specific frame will be used, but instead the first frame, starting from the last read + * frame set, containing the data block will be used. + * @param stride_length is set to the value of the stride length of the data block. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length + (const tng_trajectory_t tng_data, + const int64_t block_id, + int64_t frame, + int64_t *stride_length); + +/** + * @brief Get the date and time of initial file creation in ISO format (string). + * @param tng_data is a trajectory data container. + * @param time is a pointer to the string in which the date will be stored. Memory + * must be reserved beforehand. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code time != 0 \endcode The pointer to the time must not be a NULL + * pointer. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_time_get_str + (const tng_trajectory_t tng_data, + char *time); +/** @} */ /* end of group1 */ + +/** @defgroup group2 High-level API + * These functions make it easier to access and output TNG data. They + * are recommended unless there is a special reason to use the more + * detailed functions available in the low-level API. + * @{ + */ + +/** + * @brief High-level function for opening and initializing a TNG trajectory. + * @param filename is a string containing the name of the trajectory to open. + * @param mode specifies the file mode of the trajectory. Can be set to 'r', + * 'w' or 'a' for reading, writing or appending respectively. + * @param tng_data_p is a pointer to the opened trajectory. This will be + * allocated by the TNG library. The trajectory must be + * closed by the user, whereby memory is freed. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code filename != 0 \endcode The pointer to the filename must not be a + * NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open + (const char *filename, + const char mode, + tng_trajectory_t *tng_data_p); + +/** + * @brief High-level function for closing a TNG trajectory. + * @param tng_data_p is a pointer to the trajectory to close. The memory + * will be freed after finalising the writing. + * @return TNG_SUCCESS (0) if successful. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close + (tng_trajectory_t *tng_data_p); + +/** + * @brief High-level function for getting the time (in seconds) of a frame. + * @param tng_data is the trajectory containing the frame. + * @param frame_nr is the frame number of which to get the time. + * @param time is set to the time (in seconds) of the specified frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code time != 0 \endcode The pointer to the time must not be a + * NULL pointer. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if a + * minor error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + double *time); + +/* + * @brief High-level function for getting the molecules in the mol system. + * @param tng_data is the trajectory containing the mol system. + * @param n_mols is set to the number of molecules in the system. + * @param molecule_cnt_list will be pointing to the list of counts of each molecule + * in the mol system. + * @param mols pointing to the list of molecules in the mol system. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n_mols != 0 \endcode The pointer to the number of molecules must + * not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful. + */ +/*tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get + (const tng_trajectory_t tng_data, + int64_t *n_mols, + int64_t **molecule_cnt_list, + tng_molecule_t *mols); +*/ +/* + * @brief High-level function for adding a molecule to the mol system. + * @param tng_data is the trajectory containing the mol system. + * @param name is the name of the molecule to add. + * @param cnt is the count of the molecule. + * @param mol is set to point to the newly created molecule. + * @pre \code name != 0 \endcode The pointer to the name must not be a + * NULL pointer. + * @pre \code cnt >= 0 \endcode The requested count must be >= 0. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured or TNG_CRITICAL (2) if a major error has occured. + */ +/*tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add + (const tng_trajectory_t tng_data, + const char *name, + const int64_t cnt, + tng_molecule_t *mol); +*/ +/* +// tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get +// (const tng_trajectory_t tng_data, +// const tng_molecule_t mol, +// int64_t *n_particles, +// char ***names, +// char ***types, +// char ***res_names, +// int64_t **res_ids, +// char ***chain_names, +// int64_t **chain_ids); +// +// tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set +// (const tng_trajectory_t tng_data, +// tng_molecule_t mol, +// const int64_t n_particles, +// const char **names, +// const char **types, +// const char **res_names, +// const int64_t *res_ids, +// const char **chain_names, +// const int64_t *chain_ids); +*/ +/** + * @brief High-level function for reading the positions of all particles + * from all frames. + * @param tng_data is the trajectory to read from. + * @param positions will be set to point at a 1-dimensional array of floats, + * which will contain the positions. The data is stored sequentially in order + * of frames. For each frame the positions (x, y and z coordinates) are stored. + * The variable may point at already allocated memory or be a NULL pointer. + * The memory must be freed afterwards. + * @param stride_length will be set to the writing interval of the stored data. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code positions != 0 \endcode The pointer to the positions array + * must not be a NULL pointer. + * @pre \code stride_length != 0 \endcode The pointer to the stride length + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_pos_read + (const tng_trajectory_t tng_data, + float **positions, + int64_t *stride_length); + +/** + * @brief High-level function for reading the velocities of all particles + * from all frames. + * @param tng_data is the trajectory to read from. + * @param velocities will be set to point at a 1-dimensional array of floats, + * which will contain the velocities. The data is stored sequentially in order + * of frames. For each frame the velocities (in x, y and z) are stored. The + * variable may point at already allocated memory or be a NULL pointer. + * The memory must be freed afterwards. + * @param stride_length will be set to the writing interval of the stored data. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code velocities != 0 \endcode The pointer to the velocities array + * must not be a NULL pointer. + * @pre \code stride_length != 0 \endcode The pointer to the stride length + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_vel_read + (const tng_trajectory_t tng_data, + float **velocities, + int64_t *stride_length); + +/** + * @brief High-level function for reading the forces of all particles + * from all frames. + * @param tng_data is the trajectory to read from. + * @param forces will be set to point at a 1-dimensional array of floats, + * which will contain the forces. The data is stored sequentially in order + * of frames. For each frame the forces (in x, y and z) are stored. The + * variable may point at already allocated memory or be a NULL pointer. + * The memory must be freed afterwards. + * @param stride_length will be set to the writing interval of the stored data. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code forces != 0 \endcode The pointer to the forces array + * must not be a NULL pointer. + * @pre \code stride_length != 0 \endcode The pointer to the stride length + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_force_read + (const tng_trajectory_t tng_data, + float **forces, + int64_t *stride_length); + +/** + * @brief High-level function for reading the box shape from all frames. + * @param tng_data is the trajectory to read from. + * @param box_shape will be set to point at a 1-dimensional array of floats, + * which will contain the box shape. The data is stored sequentially in order + * of frames. The variable may point at already allocated memory or be a NULL pointer. + * If the box shape is not modified during the trajectory, but as general data, + * that will be returned instead. + * @param stride_length will be set to the writing interval of the stored data. + * @details This function should only be used if number of values used to specify + * the box shape is known (by default TNG uses 9 values) since it does not + * return the number of values in the array. It is recommended to use + * tng_data_vector_interval_get() instead. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code box_shape != 0 \endcode The pointer to the box_shape array + * must not be a NULL pointer. + * @pre \code stride_length != 0 \endcode The pointer to the stride length + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read + (const tng_trajectory_t tng_data, + float **box_shape, + int64_t *stride_length); + +/** + * @brief High-level function for reading the next frame of particle-dependent + * data of a specific type. + * @param tng_data is the trajectory to read from. + * @param block_id is the ID number of the block containing the data of interest. + * @param values will be set to point at a 1-dimensional array containing the + * requested data. The variable may point at already allocated memory (which will + * be reallocated with realloc()), or be a + * NULL pointer. The calling code must free the memory afterwards. + * @param data_type will be pointing to a character indicating the size of the + * data of the returned values, e.g. TNG_INT_DATA, TNG_FLOAT_DATA or TNG_DOUBLE_DATA. + * @param retrieved_frame_number will be pointing at the frame number of the + * returned frame. + * @param retrieved_time will be pointing at the time stamp of the returned + * frame. + * @details If no frame has been read before the first frame of the trajectory + * is read. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code values != 0 \endcode The pointer to the values array + * must not be a NULL pointer. + * @pre \code data_type != 0 \endcode The pointer to the data type of the + * returned data must not be a NULL pointer. + * @pre \code retrieved_frame_number != 0 \endcode The pointer to the frame + * number of the returned data must not be a NULL pointer. + * @pre \code retrieved_time != 0 \endcode The pointer to the time of the + * returned data must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read + (const tng_trajectory_t tng_data, + const int64_t block_id, + void **values, + char *data_type, + int64_t *retrieved_frame_number, + double *retrieved_time); + +/** + * @brief High-level function for reading the next frame of non-particle-dependent + * data of a specific type. + * @param tng_data is the trajectory to read from. + * @param block_id is the ID number of the block containing the data of interest. + * @param values will be set to point at a 1-dimensional array containing the + * requested data. The variable may point at already allocated memory or be a + * NULL pointer. The memory must be freed afterwards. + * @param data_type will be pointing to a character indicating the size of the + * data of the returned values, e.g. TNG_INT_DATA, TNG_FLOAT_DATA or TNG_DOUBLE_DATA. + * @param retrieved_frame_number will be pointing at the frame number of the + * returned frame. + * @param retrieved_time will be pointing at the time stamp of the returned + * frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code values != 0 \endcode The pointer to the values array + * must not be a NULL pointer. + * @pre \code data_type != 0 \endcode The pointer to the data type of the + * returned data must not be a NULL pointer. + * @pre \code retrieved_frame_number != 0 \endcode The pointer to the frame + * number of the returned data must not be a NULL pointer. + * @pre \code retrieved_time != 0 \endcode The pointer to the time of the + * returned data must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read + (const tng_trajectory_t tng_data, + const int64_t block_id, + void **values, + char *data_type, + int64_t *retrieved_frame_number, + double *retrieved_time); + +/** + * @brief High-level function for reading the positions of all particles + * from a specific range of frames. + * @param tng_data is the trajectory to read from. + * @param first_frame is the first frame to return position data from. + * @param last_frame is the last frame to return position data from. + * @param positions will be set to point at a 1-dimensional array of floats, + * which will contain the positions. The data is stored sequentially in order + * of frames. For each frame the positions (x, y and z coordinates) are stored. + * The variable may point at already allocated memory or be a NULL pointer. + * The memory must be freed afterwards. + * @param stride_length will be set to the writing interval of the stored data. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before + * the last frame. + * @pre \code positions != 0 \endcode The pointer to the positions array + * must not be a NULL pointer. + * @pre \code stride_length != 0 \endcode The pointer to the stride length + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range + (const tng_trajectory_t tng_data, + const int64_t first_frame, + const int64_t last_frame, + float **positions, + int64_t *stride_length); + +/** + * @brief High-level function for reading the velocities of all particles + * from a specific range of frames. + * @param tng_data is the trajectory to read from. + * @param first_frame is the first frame to return position data from. + * @param last_frame is the last frame to return position data from. + * @param velocities will be set to point at a 1-dimensional array of floats, + * which will contain the velocities. The data is stored sequentially in order + * of frames. For each frame the velocities (in x, y and z) are stored. The + * variable may point at already allocated memory or be a NULL pointer. + * The memory must be freed afterwards. + * @param stride_length will be set to the writing interval of the stored data. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before + * the last frame. + * @pre \code velocities != 0 \endcode The pointer to the velocities array + * must not be a NULL pointer. + * @pre \code stride_length != 0 \endcode The pointer to the stride length + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range + (const tng_trajectory_t tng_data, + const int64_t first_frame, + const int64_t last_frame, + float **velocities, + int64_t *stride_length); + +/** + * @brief High-level function for reading the forces of all particles + * from a specific range of frames. + * @param tng_data is the trajectory to read from. + * @param first_frame is the first frame to return position data from. + * @param last_frame is the last frame to return position data from. + * @param forces will be set to point at a 1-dimensional array of floats, + * which will contain the forces. The data is stored sequentially in order + * of frames. For each frame the forces (in x, y and z) are stored. The + * variable may point at already allocated memory or be a NULL pointer. + * The memory must be freed afterwards. + * @param stride_length will be set to the writing interval of the stored data. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before + * the last frame. + * @pre \code forces != 0 \endcode The pointer to the forces array + * must not be a NULL pointer. + * @pre \code stride_length != 0 \endcode The pointer to the stride length + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range + (const tng_trajectory_t tng_data, + const int64_t first_frame, + const int64_t last_frame, + float **forces, + int64_t *stride_length); + +/** + * @brief High-level function for reading the box shape + * from a specific range of frames. + * @param tng_data is the trajectory to read from. + * @param first_frame is the first frame to return position data from. + * @param last_frame is the last frame to return position data from. + * @param box_shape will be set to point at a 1-dimensional array of floats, + * which will contain the box shape. The data is stored sequentially in order + * of frames. + * If the box shape is not modified during the trajectory, but as general data, + * that will be returned instead. The + * variable may point at already allocated memory or be a NULL pointer. + * The memory must be freed afterwards. + * @param stride_length will be set to the writing interval of the stored data. + * @details This function should only be used if number of values used to specify + * the box shape is known (by default TNG uses 9 values) since it does not + * return the number of values in the array. It is recommended to use + * tng_data_vector_interval_get() instead. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code start_frame_nr <= end_frame_nr \endcode The first frame must be before + * the last frame. + * @pre \code box_shape != 0 \endcode The pointer to the box_shape array + * must not be a NULL pointer. + * @pre \code stride_length != 0 \endcode The pointer to the stride length + * must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range + (const tng_trajectory_t tng_data, + const int64_t first_frame, + const int64_t last_frame, + float **box_shape, + int64_t *stride_length); + +/** + * @brief High-level function for setting the writing interval of data blocks. + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @param n_values_per_frame is the number of values to store per frame. If the + * data is particle dependent there will be n_values_per_frame stored per + * particle each frame. + * @param block_id is the ID of the block, of which to set the output interval. + * @param block_name is a string that will be used as name of the block. Only + * required if the block did not exist, i.e. a new block is created. + * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the + * data is not related to specific particles (e.g. box shape) or + * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g. + * positions). Only required if the block did not exist, i.e. a new block is + * created. + * @param compression is the compression routine to use when writing the data. + * Only required if the block did not exist, i.e. a new block is created. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code i >= 0 \endcode The writing interval must be >= 0. + * @details n_values_per_frame, block_name, particle_dependency and + * compression are only used if the data block did not exist before calling + * this function, in which case it is created. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set + (const tng_trajectory_t tng_data, + const int64_t i, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression); + +/** + * @brief High-level function for setting the writing interval of data blocks + * containing double precision data. + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @param n_values_per_frame is the number of values to store per frame. If the + * data is particle dependent there will be n_values_per_frame stored per + * particle each frame. + * @param block_id is the ID of the block, of which to set the output interval. + * @param block_name is a string that will be used as name of the block. Only + * required if the block did not exist, i.e. a new block is created. + * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the + * data is not related to specific particles (e.g. box shape) or + * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g. + * positions). Only required if the block did not exist, i.e. a new block is + * created. + * @param compression is the compression routine to use when writing the data. + * Only required if the block did not exist, i.e. a new block is created. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code i >= 0 \endcode The writing interval must be >= 0. + * @details n_values_per_frame, block_name, particle_dependency and + * compression are only used if the data block did not exist before calling + * this function, in which case it is created. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set + (const tng_trajectory_t tng_data, + const int64_t i, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression); + +/** + * @brief High-level function for setting the writing interval of data blocks. + * Obsolete! Use tng_util_generic_write_interval_set() + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @param n_values_per_frame is the number of values to store per frame. If the + * data is particle dependent there will be n_values_per_frame stored per + * particle each frame. + * @param block_id is the ID of the block, of which to set the output interval. + * @param block_name is a string that will be used as name of the block. Only + * required if the block did not exist, i.e. a new block is created. + * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the + * data is not related to specific particles (e.g. box shape) or + * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g. + * positions). Only required if the block did not exist, i.e. a new block is + * created. + * @param compression is the compression routine to use when writing the data. + * Only required if the block did not exist, i.e. a new block is created. + * @details n_values_per_frame, block_name, particle_dependency and + * compression are only used if the data block did not exist before calling + * this function, in which case it is created. + * This function is replaced by the more correcly named + * tng_util_generic_write_interval_set(), but is kept for compatibility. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set + (const tng_trajectory_t tng_data, + const int64_t i, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression); + +/** + * @brief High-level function for setting the writing interval of position + * data blocks. + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code i >= 0 \endcode The writing interval must be >= 0. + * @details This function uses tng_util_generic_write_interval_set() and will + * create a positions data block if none exists. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set + (const tng_trajectory_t tng_data, + const int64_t i); + +/** + * @brief High-level function for setting the writing interval of position + * data blocks containing double precision data. + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code i >= 0 \endcode The writing interval must be >= 0. + * @details This function uses tng_util_generic_write_interval_set() and will + * create a positions data block if none exists. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set + (const tng_trajectory_t tng_data, + const int64_t i); + +/** + * @brief High-level function for setting the writing interval of position + * data blocks. Obsolete! Use tng_util_pos_write_interval_set() + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code i >= 0 \endcode The writing interval must be >= 0. + * @details This function uses tng_util_generic_write_interval_set() and will + * create a positions data block if none exists. + * This function is replaced by the more correcly named + * tng_util_pos_write_interval_set(), but is kept for compatibility. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set + (const tng_trajectory_t tng_data, + const int64_t i); + +/** + * @brief High-level function for setting the writing interval of velocity + * data blocks. + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code i >= 0 \endcode The writing interval must be >= 0. + * @details This function uses tng_util_generic_write_interval_set() and will + * create a velocities data block if none exists. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set + (const tng_trajectory_t tng_data, + const int64_t i); + +/** + * @brief High-level function for setting the writing interval of velocity + * data blocks containing double precision data. + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code i >= 0 \endcode The writing interval must be >= 0. + * @details This function uses tng_util_generic_write_interval_set() and will + * create a velocities data block if none exists. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set + (const tng_trajectory_t tng_data, + const int64_t i); + +/** + * @brief High-level function for setting the writing interval of velocity + * data blocks. Obsolete! Use tng_util_vel_write_interval_set() + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @details This function uses tng_util_generic_write_interval_set() and will + * create a velocities data block if none exists. + * This function is replaced by the more correcly named + * tng_util_vel_write_interval_set(), but is kept for compatibility. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set + (const tng_trajectory_t tng_data, + const int64_t i); + +/** + * @brief High-level function for setting the writing interval of force + * data blocks. + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code i >= 0 \endcode The writing interval must be >= 0. + * @details This function uses tng_util_generic_write_interval_set() and will + * create a forces data block if none exists. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set + (const tng_trajectory_t tng_data, + const int64_t i); + +/** + * @brief High-level function for setting the writing interval of force + * data blocks containing double precision data. + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code i >= 0 \endcode The writing interval must be >= 0. + * @details This function uses tng_util_generic_write_interval_set() and will + * create a forces data block if none exists. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set + (const tng_trajectory_t tng_data, + const int64_t i); + +/** + * @brief High-level function for setting the writing interval of force + * data blocks. Obsolete! Use tng_util_force_write_interval_set() + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @details This function uses tng_util_generic_write_interval_set() and will + * create a forces data block if none exists. + * This function is replaced by the more correcly named + * tng_util_force_write_interval_set(), but is kept for compatibility. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set + (const tng_trajectory_t tng_data, + const int64_t i); + +/** + * @brief High-level function for setting the writing interval of box shape + * data blocks. + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code i >= 0 \endcode The writing interval must be >= 0. + * @details This function uses tng_util_generic_write_interval_set() and will + * create a box shape data block if none exists. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set + (const tng_trajectory_t tng_data, + const int64_t i); + +/** + * @brief High-level function for setting the writing interval of box shape + * data blocks containing double precision data. + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code i >= 0 \endcode The writing interval must be >= 0. + * @details This function uses tng_util_generic_write_interval_set() and will + * create a box shape data block if none exists. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set + (const tng_trajectory_t tng_data, + const int64_t i); + +/** + * @brief High-level function for setting the writing interval of velocity + * data blocks. Obsolete! Use tng_util_box_shape_write_interval_set() + * @param tng_data is the trajectory to use. + * @param i is the output interval, i.e. i == 10 means data written every 10th + * frame. + * @details This function uses tng_util_generic_write_interval_set() and will + * create a box shape data block if none exists. + * This function is replaced by the more correcly named + * tng_util_box_shape_write_interval_set(), but is kept for compatibility. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set + (const tng_trajectory_t tng_data, + const int64_t i); + +/** + * @brief High-level function for writing data of one frame to a data block. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. If frame_nr < 0 the + * data is written as non-trajectory data. + * @param values is a 1D array of data to add. The array should be of length + * n_particles * n_values_per_frame if writing particle related data, otherwise + * it should be n_values_per_frame. + * @param n_values_per_frame is the number of values to store per frame. If the + * data is particle dependent there will be n_values_per_frame stored per + * particle each frame. + * @param block_id is the ID of the block, of which to set the output interval. + * @param block_name is a string that will be used as name of the block. Only + * required if the block did not exist, i.e. a new block is created. + * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the + * data is not related to specific particles (e.g. box shape) or + * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g. + * positions). Only required if the block did not exist, i.e. a new block is + * created. + * @param compression is the compression routine to use when writing the data. + * Only required if the block did not exist, i.e. a new block is created. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code values != 0 \endcode The pointer to the values array must not + * be a NULL pointer. + * @details n_values_per_frame, block_name, particle_dependency and + * compression are only used if the data block did not exist before calling + * this function, in which case it is created. + * N.b. Data is written a whole block at a time. The data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_generic_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const float *values, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression); + +/** + * @brief High-level function for writing data of one frame to a double precision + * data block. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. If frame_nr < 0 the + * data is written as non-trajectory data. + * @param values is a 1D array of data to add. The array should be of length + * n_particles * n_values_per_frame if writing particle related data, otherwise + * it should be n_values_per_frame. + * @param n_values_per_frame is the number of values to store per frame. If the + * data is particle dependent there will be n_values_per_frame stored per + * particle each frame. + * @param block_id is the ID of the block, of which to set the output interval. + * @param block_name is a string that will be used as name of the block. Only + * required if the block did not exist, i.e. a new block is created. + * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the + * data is not related to specific particles (e.g. box shape) or + * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g. + * positions). Only required if the block did not exist, i.e. a new block is + * created. + * @param compression is the compression routine to use when writing the data. + * Only required if the block did not exist, i.e. a new block is created. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code values != 0 \endcode The pointer to the values array must not + * be a NULL pointer. + * @details n_values_per_frame, block_name, particle_dependency and + * compression are only used if the data block did not exist before calling + * this function, in which case it is created. + * N.b. Data is written a whole block at a time. The data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double *values, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression); + +/** + * @brief High-level function for adding data to positions data blocks. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. If frame_nr < 0 the + * data is written as non-trajectory data. + * @param positions is a 1D array of data to add. The array should be of length + * n_particles * 3. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code positions != 0 \endcode The pointer to the positions array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_write() and will + * create a positions data block if none exists. Positions are stored as three + * values per frame and compressed using TNG compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_pos_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const float *positions); + +/** + * @brief High-level function for adding data to positions data blocks at double + * precision. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. If frame_nr < 0 the + * data is written as non-trajectory data. + * @param positions is a 1D array of data to add. The array should be of length + * n_particles * 3. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code positions != 0 \endcode The pointer to the positions array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_write() and will + * create a positions data block if none exists. Positions are stored as three + * values per frame and compressed using TNG compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double *positions); + +/** + * @brief High-level function for adding data to velocities data blocks. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. If frame_nr < 0 the + * data is written as non-trajectory data. + * @param velocities is a 1D array of data to add. The array should be of length + * n_particles * 3. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code velocities != 0 \endcode The pointer to the velocities array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_write() and will + * create a velocities data block if none exists. Velocities are stored as three + * values per frame and compressed using TNG compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_vel_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const float *velocities); + +/** + * @brief High-level function for adding data to velocities data blocks at double + * precision. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. If frame_nr < 0 the + * data is written as non-trajectory data. + * @param velocities is a 1D array of data to add. The array should be of length + * n_particles * 3. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code velocities != 0 \endcode The pointer to the velocities array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_write() and will + * create a velocities data block if none exists. Velocities are stored as three + * values per frame and compressed using TNG compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double *velocities); + +/** + * @brief High-level function for adding data to forces data blocks. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. If frame_nr < 0 the + * data is written as non-trajectory data. + * @param forces is a 1D array of data to add. The array should be of length + * n_particles * 3. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code forces != 0 \endcode The pointer to the forces array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_write() and will + * create a forces data block if none exists. Forces are stored as three + * values per frame and compressed using gzip compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_force_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const float *forces); + +/** + * @brief High-level function for adding data to forces data blocks at double + * precision. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. If frame_nr < 0 the + * data is written as non-trajectory data. + * @param forces is a 1D array of data to add. The array should be of length + * n_particles * 3. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code forces != 0 \endcode The pointer to the forces array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_write() and will + * create a forces data block if none exists. Forces are stored as three + * values per frame and compressed using gzip compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double *forces); + +/** + * @brief High-level function for adding data to box shape data blocks. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. If frame_nr < 0 the + * data is written as non-trajectory data. + * @param box_shape is a 1D array of data to add. The array should be of length 9. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code box_shape != 0 \endcode The pointer to the box_shape array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_write() and will + * create a box shape data block if none exists. Box shapes are stored as 9 + * values per frame and compressed using TNG compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const float *box_shape); + +/** + * @brief High-level function for adding data to box shape data blocks at double + * precision. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. If frame_nr < 0 the + * data is written as non-trajectory data. + * @param box_shape is a 1D array of data to add. The array should be of length 9. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code box_shape != 0 \endcode The pointer to the box_shape array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_write() and will + * create a box shape data block if none exists. Box shapes are stored as 9 + * values per frame and compressed using TNG compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double *box_shape); + +/** + * @brief High-level function for writing data of one frame to a data block. + * If the frame is at the beginning of a frame set the time stamp of the frame + * set is set. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. + * @param time is the time stamp of the frame (in seconds). + * @param values is a 1D array of data to add. The array should be of length + * n_particles * n_values_per_frame if writing particle related data, otherwise + * it should be n_values_per_frame. + * @param n_values_per_frame is the number of values to store per frame. If the + * data is particle dependent there will be n_values_per_frame stored per + * particle each frame. + * @param block_id is the ID of the block, of which to set the output interval. + * @param block_name is a string that will be used as name of the block. Only + * required if the block did not exist, i.e. a new block is created. + * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the + * data is not related to specific particles (e.g. box shape) or + * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g. + * positions). Only required if the block did not exist, i.e. a new block is + * created. + * @param compression is the compression routine to use when writing the data. + * Only required if the block did not exist, i.e. a new block is created. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0. + * @pre \code time >= 0 \endcode The time stamp must be >= 0. + * @pre \code values != 0 \endcode The pointer to the values array must not + * be a NULL pointer. + * @details n_values_per_frame, block_name, particle_dependency and + * compression are only used if the data block did not exist before calling + * this function, in which case it is created. + * N.b. Data is written a whole block at a time. The data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const float *values, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression); + +/** + * @brief High-level function for writing data of one frame to a double precision + * data block. If the frame is at the beginning of a frame set the time stamp of + * the frame set is set. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. + * @param time is the time stamp of the frame (in seconds). + * @param values is a 1D array of data to add. The array should be of length + * n_particles * n_values_per_frame if writing particle related data, otherwise + * it should be n_values_per_frame. + * @param n_values_per_frame is the number of values to store per frame. If the + * data is particle dependent there will be n_values_per_frame stored per + * particle each frame. + * @param block_id is the ID of the block, of which to set the output interval. + * @param block_name is a string that will be used as name of the block. Only + * required if the block did not exist, i.e. a new block is created. + * @param particle_dependency should be TNG_NON_PARTICLE_BLOCK_DATA (0) if the + * data is not related to specific particles (e.g. box shape) or + * TNG_PARTICLE_BLOCK_DATA (1) is it is related to specific particles (e.g. + * positions). Only required if the block did not exist, i.e. a new block is + * created. + * @param compression is the compression routine to use when writing the data. + * Only required if the block did not exist, i.e. a new block is created. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0. + * @pre \code time >= 0 \endcode The time stamp must be >= 0. + * @pre \code values != 0 \endcode The pointer to the values array must not + * be a NULL pointer. + * @details n_values_per_frame, block_name, particle_dependency and + * compression are only used if the data block did not exist before calling + * this function, in which case it is created. + * N.b. Data is written a whole block at a time. The data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const double *values, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression); + +/** + * @brief High-level function for adding data to positions data blocks. If the + * frame is at the beginning of a frame set the time stamp of the frame set + * is set. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. + * @param time is the time stamp of the frame (in seconds). + * @param positions is a 1D array of data to add. The array should be of length + * n_particles * 3. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0. + * @pre \code time >= 0 \endcode The time stamp must be >= 0. + * @pre \code positions != 0 \endcode The pointer to the positions array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_with_time_write() and will + * create a positions data block if none exists. Positions are stored as three + * values per frame and compressed using TNG compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const float *positions); + +/** + * @brief High-level function for adding data to positions data blocks at double + * precision. If the frame is at the beginning of a frame set the time stamp of + * the frame set is set. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. + * @param time is the time stamp of the frame (in seconds). + * @param positions is a 1D array of data to add. The array should be of length + * n_particles * 3. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0. + * @pre \code time >= 0 \endcode The time stamp must be >= 0. + * @pre \code positions != 0 \endcode The pointer to the positions array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_with_time_double_write() and will + * create a positions data block if none exists. Positions are stored as three + * values per frame and compressed using TNG compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const double *positions); + +/** + * @brief High-level function for adding data to velocities data blocks. If the + * frame is at the beginning of a frame set the time stamp of the frame set + * is set. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. + * @param time is the time stamp of the frame (in seconds). + * @param velocities is a 1D array of data to add. The array should be of length + * n_particles * 3. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0. + * @pre \code time >= 0 \endcode The time stamp must be >= 0. + * @pre \code velocities != 0 \endcode The pointer to the velocities array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_with_time_write() and will + * create a velocities data block if none exists. Velocities are stored as three + * values per frame and compressed using TNG compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const float *velocities); + +/** + * @brief High-level function for adding data to velocities data blocks at + * double precision. If the frame is at the beginning of a frame set the + * time stamp of the frame set is set. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. + * @param time is the time stamp of the frame (in seconds). + * @param velocities is a 1D array of data to add. The array should be of length + * n_particles * 3. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0. + * @pre \code time >= 0 \endcode The time stamp must be >= 0. + * @pre \code velocities != 0 \endcode The pointer to the velocities array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_with_time_double_write() and will + * create a velocities data block if none exists. Velocities are stored as three + * values per frame and compressed using TNG compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const double *velocities); + +/** + * @brief High-level function for adding data to forces data blocks. If the + * frame is at the beginning of a frame set the time stamp of the frame set + * is set. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. + * @param time is the time stamp of the frame (in seconds). + * @param forces is a 1D array of data to add. The array should be of length + * n_particles * 3. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0. + * @pre \code time >= 0 \endcode The time stamp must be >= 0. + * @pre \code forces != 0 \endcode The pointer to the forces array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_with_time_write() and will + * create a forces data block if none exists. Forces are stored as three + * values per frame and compressed using gzip compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const float *forces); + +/** + * @brief High-level function for adding data to forces data blocks at + * double precision. If the frame is at the beginning of a frame set + * the time stamp of the frame set is set. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. + * @param time is the time stamp of the frame (in seconds). + * @param forces is a 1D array of data to add. The array should be of length + * n_particles * 3. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0. + * @pre \code time >= 0 \endcode The time stamp must be >= 0. + * @pre \code forces != 0 \endcode The pointer to the forces array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_with_time_double_write() and will + * create a forces data block if none exists. Forces are stored as three + * values per frame and compressed using gzip compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const double *forces); + +/** + * @brief High-level function for adding data to box shape data blocks. If the + * frame is at the beginning of a frame set the time stamp of the frame set + * is set. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. + * @param time is the time stamp of the frame (in seconds). + * @param box_shape is a 1D array of data to add. The array should be of length 9. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0. + * @pre \code time >= 0 \endcode The time stamp must be >= 0. + * @pre \code box_shape != 0 \endcode The pointer to the box_shape array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_with_time_write() and will + * create a box shape data block if none exists. Box shapes are stored as 9 + * values per frame and compressed using TNG compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const float *box_shape); + +/** + * @brief High-level function for adding data to box shape data blocks at + * double precision. If the frame is at the beginning of a frame set the + * time stamp of the frame set is set. + * @param tng_data is the trajectory to use. + * @param frame_nr is the frame number of the data. + * @param time is the time stamp of the frame (in seconds). + * @param box_shape is a 1D array of data to add. The array should be of length 9. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code frame_nr >= 0 \endcode The frame number to write must be >= 0. + * @pre \code time >= 0 \endcode The time stamp must be >= 0. + * @pre \code box_shape != 0 \endcode The pointer to the box_shape array must not + * be a NULL pointer. + * @details This function uses tng_util_generic_with_time_double_write() and will + * create a box shape data block if none exists. Box shapes are stored as 9 + * values per frame and compressed using TNG compression. + * N.b. Since compressed data is written a whole block at a time the data is not + * actually written to disk until the frame set is finished or the TNG + * trajectory is closed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const double *box_shape); + +/** + * @brief High-level function for getting the compression method and + * multiplication factor of the last read frame of a specific data block. + * @param tng_data is the trajectory to use. + * @param block_id is the ID number of the block containing the data of + * interest. + * @param codec_id will be set to the value of the codec_id of the + * compression of the data block. See tng_compression for more details. + * @param factor will be set to the multiplication factor applied to + * the values before compression, in order to get integers from them. + * factor is 1/precision. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code codec_id != 0 \endcode The pointer to the returned codec id + * must not be a NULL pointer. + * @pre \code factor != 0 \endcode The pointer to the returned multiplication + * factor must not be a NULL pointer. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as invalid mode) or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + int64_t *codec_id, + double *factor); + +/** @brief High-level function for determining the next frame with data and what + * data blocks have data for that frame. The search can be limited to certain + * data blocks. + * @param tng_data is the trajectory to use. + * @param current_frame is the frame that was last read, from where to start + * looking for data. + * @param n_requested_data_block_ids is the number of data blocks listed in + * requested_data_block_ids. If this is 0 all data blocks will be taken into + * account. + * @param requested_data_block_ids is an array of data blocks to look for. + * @param next_frame will be set to the next frame with data. + * @param n_data_blocks_in_next_frame is set to the number of data blocks with + * data for next_frame. + * @param data_block_ids_in_next_frame is set to an array (of length + * n_data_blocks_in_next_frame) that lists the data block IDs with data for + * next_frame. It must be pointing at NULL or previously allocated memory. + * Memory for the array is reallocated by this function using realloc(). + * The memory must be freed by the client afterwards or + * there will be a memory leak. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code next_frame != 0 \endcode The pointer to the next frame must not + * be NULL. + * @pre \code n_data_blocks_in_next_frame != 0 \endcode The pointer to + * n_data_blocks_in_next_frame must not be NULL. + * @pre \code *data_block_ids_in_next_frame != 0 \endcode The pointer to the + * list of data block IDs must not be NULL. + * @pre \code n_requested_data_block_ids == 0 || requested_data_block_ids != 0 \endcode + * If the number of requested data blocks != 0 then the array of data block IDs must not be NULL. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured or TNG_CRITICAL (2) if a major error + * has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find + (const tng_trajectory_t tng_data, + int64_t current_frame, + const int64_t n_requested_data_block_ids, + const int64_t *requested_data_block_ids, + int64_t *next_frame, + int64_t *n_data_blocks_in_next_frame, + int64_t **data_block_ids_in_next_frame); + +/* @brief High-level function for getting all data block ids and their names + * and stride lengths. + * @param tng_data is the trajectory to use. + * @param n_data_blocks is set to the number of data blocks in the trajectory. + * @param data_block_ids is set to an array (of length + * n_data_blocks) that lists the data block IDs in the trajectory. + * It must be pointing at NULL or previously allocated memory. + * Memory for the array is allocated by this function. + * The memory must be freed by the client afterwards or + * there will be a memory leak. + * @param data_block_names is set to an array (of length + * n_data_blocks) that contains the names of the data blocks. + * It must be pointing at NULL or previously allocated memory. + * Memory for the array is allocated by this function. + * The memory must be freed by the client afterwards or + * there will be a memory leak. + * @param stride_lengths is set to an array (of length + * n_data_blocks) that lists the stride lengths of the data blocks. + * It must be pointing at NULL or previously allocated memory. + * Memory for the array is allocated by this function. + * The memory must be freed by the client afterwards or + * there will be a memory leak. + * @param n_values_per_frame is set to an array (of length + * n_data_blocks) that lists the number of values per frame of the data blocks. + * It must be pointing at NULL or previously allocated memory. + * Memory for the array is allocated by this function. + * The memory must be freed by the client afterwards or + * there will be a memory leak. + * @param block_types is set to an array (of length + * n_data_blocks) that lists the block types of the data blocks. + * It must be pointing at NULL or previously allocated memory. + * Memory for the array is allocated by this function. + * The memory must be freed by the client afterwards or + * there will be a memory leak. + * @param dependencies is set to an array (of length + * n_data_blocks) that lists the dependencies of the data blocks. + * It must be pointing at NULL or previously allocated memory. + * Memory for the array is allocated by this function. + * The memory must be freed by the client afterwards or + * there will be a memory leak. + * @param compressions is set to an array (of length + * n_data_blocks) that lists the compressions of the data blocks. + * It must be pointing at NULL or previously allocated memory. + * Memory for the array is allocated by this function. + * The memory must be freed by the client afterwards or + * there will be a memory leak. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code n_data_blocks != 0 \endcode The pointer to + * n_data_blocks must not be NULL. + * @pre \code data_block_ids != 0 \endcode The pointer to the + * list of data block IDs must not be NULL. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured or TNG_CRITICAL (2) if a major error + * has occured. + */ +/* +tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get + (const tng_trajectory_t tng_data, + int64_t *n_data_blocks, + int64_t **data_block_ids, + char ***data_block_names, + int64_t **stride_lengths, + int64_t **n_values_per_frame, + char **block_types, + char **dependencies, + char **compressions); +*/ + +/** @brief Finds the frame set of the specified frame in order to prepare for writing + * after it. + * @param tng_data is the trajectory to use. + * @param prev_frame is the frame after which to start appending. + * @pre \code tng_data != 0 \endcode The trajectory container (tng_data) + * must be initialised before using it. + * @pre \code prev_frame >= 0 \endcode The previous frame must not be negative. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occured (such as not finding the requested frame) or TNG_CRITICAL (2) + * if a major error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame + (const tng_trajectory_t tng_data, + const int64_t prev_frame); + + +/** @brief Get the number of frames containing data of a specific type. + * @param tng_data is the trajectory to use. + * @param block_id is the id of the block of the data type. + * @param n_frames is set to the number of frames containing data of + * the requested data type. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +tng_function_status DECLSPECDLLEXPORT tng_util_num_frames_with_data_of_block_id_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + int64_t *n_frames); +/** @} */ /* end of group2 */ + + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* TNG_IO_H */ diff --git a/src/tng/tng/tng_io_fwd.h b/src/tng/tng/tng_io_fwd.h new file mode 100644 index 0000000000..68bcafdea1 --- /dev/null +++ b/src/tng/tng/tng_io_fwd.h @@ -0,0 +1,37 @@ +/* This code is part of the tng binary trajectory format. + * + * Written by Magnus Lundborg + * Copyright (c) 2012-2013, The GROMACS development team. + * Check out http://www.gromacs.org for more information. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + +#ifndef TNG_IO_FWD_H +#define TNG_IO_FWD_H 1 + +/** A pointer to the main trajectory data storage. */ +typedef struct tng_trajectory *tng_trajectory_t; +/** A pointer to a molecule description. */ +typedef struct tng_molecule *tng_molecule_t; +/** A pointer to a molecular chain description. */ +typedef struct tng_chain *tng_chain_t; +/** A pointer to a molecular residue description. */ +typedef struct tng_residue *tng_residue_t; +/** A pointer to a molecular atom description. */ +typedef struct tng_atom *tng_atom_t; +/** A pointer to a bond between two atoms. */ +typedef struct tng_bond *tng_bond_t; +/** A pointer to a structure containing data common to all trajectory blocks, + * such as header and contents. */ +typedef struct tng_gen_block *tng_gen_block_t; +/** A pointer to particle mapping information. */ +typedef struct tng_particle_mapping *tng_particle_mapping_t; +/** A pointer to a structure containing frame set information. */ +typedef struct tng_trajectory_frame_set *tng_trajectory_frame_set_t; +/** A pointer to a data container. */ +typedef struct tng_data *tng_data_t; + +#endif diff --git a/src/tng/tng/version.h b/src/tng/tng/version.h new file mode 100644 index 0000000000..81662f4a2a --- /dev/null +++ b/src/tng/tng/version.h @@ -0,0 +1,16 @@ +#ifndef VERSION_CONFIG_H +#define VERSION_CONFIG_H +/* Note: originally from BuildTNG.cmake */ +/* define the API version (integer) */ +#define TNG_API_VERSION 8 + +/* define the major and minor versions + of the library */ +#define TNG_VERSION_MAJOR 1 +#define TNG_VERSION_MINOR 8 +/* define the patchlevel of the library */ +#define TNG_VERSION_PATCHLEVEL 2 +/* define the full version of the library (string) */ +#define TNG_VERSION "1.8.2" + +#endif diff --git a/src/tng/tng_io.c b/src/tng/tng_io.c new file mode 100644 index 0000000000..d47eeb4e98 --- /dev/null +++ b/src/tng/tng_io.c @@ -0,0 +1,17852 @@ +/* This code is part of the tng binary trajectory format. + * + * Written by Magnus Lundborg + * Copyright (c) 2012-2017, The GROMACS development team. + * Check out http://www.gromacs.org for more information. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + +/* These three definitions are required to enforce 64 bit file sizes. */ +/* Force 64 bit variants of file access calls. */ +#define _FILE_OFFSET_BITS 64 +/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ +#define _LARGEFILE_SOURCE +/* Define for large files, on AIX-style hosts. */ +#define _LARGE_FILES + +#include "tng/tng_io.h" + +#ifdef USE_STD_INTTYPES_H +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "tng/md5.h" +#include "compression/tng_compress.h" +#include "tng/version.h" + +#if defined( _WIN32 ) || defined( _WIN64 ) + #ifndef fseeko + #define fseeko _fseeki64 + #endif + #ifndef ftello + #ifdef __MINGW32__ + #define ftello ftello64 + #else + #define ftello _ftelli64 + #endif + #endif +#endif + +struct tng_bond { + /** One of the atoms of the bond */ + int64_t from_atom_id; + /** The other atom of the bond */ + int64_t to_atom_id; +}; + +struct tng_atom { + /** The residue containing this atom */ + tng_residue_t residue; + /** A unique (per molecule) ID number of the atom */ + int64_t id; + /** The atom_type (depending on the forcefield) */ + char *atom_type; + /** The name of the atom */ + char *name; +}; + +struct tng_residue { + /** The chain containing this residue */ + tng_chain_t chain; + /** A unique (per chain) ID number of the residue */ + int64_t id; + /** The name of the residue */ + char *name; + /** The number of atoms in the residue */ + int64_t n_atoms; + /** A list of atoms in the residue */ + int64_t atoms_offset; +}; + +struct tng_chain { + /** The molecule containing this chain */ + tng_molecule_t molecule; + /** A unique (per molecule) ID number of the chain */ + int64_t id; + /** The name of the chain */ + char *name; + /** The number of residues in the chain */ + int64_t n_residues; + /** A list of residues in the chain */ + tng_residue_t residues; +}; + +struct tng_molecule { + /** A unique ID number of the molecule */ + int64_t id; + /** Quaternary structure of the molecule. + * 1 => monomeric + * 2 => dimeric + * 3 => trimeric + * etc */ + int64_t quaternary_str; + /** The number of chains in the molecule */ + int64_t n_chains; + /** The number of residues in the molecule */ + int64_t n_residues; + /** The number of atoms in the molecule */ + int64_t n_atoms; + /** The number of bonds in the molecule. If the bonds are not specified this + * value can be 0. */ + int64_t n_bonds; + /** The name of the molecule */ + char *name; + /** A list of chains in the molecule */ + tng_chain_t chains; + /** A list of residues in the molecule */ + tng_residue_t residues; + /** A list of the atoms in the molecule */ + tng_atom_t atoms; + /** A list of the bonds in the molecule */ + tng_bond_t bonds; +}; + +struct tng_gen_block { + /** The size of the block header in bytes */ + int64_t header_contents_size; + /** The size of the block contents in bytes */ + int64_t block_contents_size; + /** The ID of the block to determine its type */ + int64_t id; + /** The MD5 hash of the block to verify integrity */ + char md5_hash[TNG_MD5_HASH_LEN]; + /** The name of the block */ + char *name; + /** The library version used to write the block */ + int64_t block_version; + int64_t alt_hash_type; + int64_t alt_hash_len; + char *alt_hash; + int64_t signature_type; + int64_t signature_len; + char *signature; + /** The full block header contents */ + char *header_contents; + /** The full block contents */ + char *block_contents; +}; + +struct tng_particle_mapping { + /** The index number of the first particle in this mapping block */ + int64_t num_first_particle; + /** The number of particles list in this mapping block */ + int64_t n_particles; + /** the mapping of index numbers to the real particle numbers in the + * trajectory. real_particle_numbers[0] is the real particle number + * (as it is numbered in the molecular system) of the first particle + * in the data blocks covered by this particle mapping block */ + int64_t *real_particle_numbers; +}; + +struct tng_trajectory_frame_set { + /** The number of different particle mapping blocks present. */ + int64_t n_mapping_blocks; + /** The atom mappings of this frame set */ + struct tng_particle_mapping *mappings; + /** The first frame of this frame set */ + int64_t first_frame; + /** The number of frames in this frame set */ + int64_t n_frames; + /** The number of written frames in this frame set (used when writing one + * frame at a time). */ + int64_t n_written_frames; + /** The number of frames not yet written to file in this frame set + * (used from the utility functions to finish the writing properly. */ + int64_t n_unwritten_frames; + + + /** A list of the number of each molecule type - only used when using + * variable number of atoms */ + int64_t *molecule_cnt_list; + /** The number of particles/atoms - only used when using variable number + * of atoms */ + int64_t n_particles; + /** The file position of the next frame set */ + int64_t next_frame_set_file_pos; + /** The file position of the previous frame set */ + int64_t prev_frame_set_file_pos; + /** The file position of the frame set one long stride step ahead */ + int64_t medium_stride_next_frame_set_file_pos; + /** The file position of the frame set one long stride step behind */ + int64_t medium_stride_prev_frame_set_file_pos; + /** The file position of the frame set one long stride step ahead */ + int64_t long_stride_next_frame_set_file_pos; + /** The file position of the frame set one long stride step behind */ + int64_t long_stride_prev_frame_set_file_pos; + /** Time stamp (in seconds) of first frame in frame set */ + double first_frame_time; + + /* The data blocks in a frame set are trajectory data blocks */ + /** The number of trajectory data blocks of particle dependent data */ + int n_particle_data_blocks; + /** A list of data blocks containing particle dependent data */ + struct tng_data *tr_particle_data; + /** The number of trajectory data blocks independent of particles */ + int n_data_blocks; + /** A list of data blocks containing particle indepdendent data */ + struct tng_data *tr_data; +}; + +/* FIXME: Should there be a pointer to a tng_gen_block from each data block? */ +struct tng_data { + /** The block ID of the data block containing this particle data. + * This is used to determine the kind of data that is stored */ + int64_t block_id; + /** The name of the data block. This is used to determine the kind of + * data that is stored */ + char *block_name; + /** The type of data stored. */ + char datatype; + /** A flag to indicate if this data block contains frame and/or particle dependent + * data */ + char dependency; + /** The frame number of the first data value */ + int64_t first_frame_with_data; + /** The number of frames in this frame set */ + int64_t n_frames; + /** The number of values stored per frame */ + int64_t n_values_per_frame; + /** The number of frames between each data point - e.g. when + * storing sparse data. */ + int64_t stride_length; + /** ID of the CODEC used for compression 0 == no compression. */ + int64_t codec_id; + /** If reading one frame at a time this is the last read frame */ + int64_t last_retrieved_frame; + /** The multiplier used for getting integer values for compression */ + double compression_multiplier; + /** A 1-dimensional array of values of length + * [sizeof (datatype)] * n_frames * n_particles * n_values_per_frame */ + void *values; + /** If storing character data store it in a 3-dimensional array */ + char ****strings; +}; + + +struct tng_trajectory { + /** The path of the input trajectory file */ + char *input_file_path; + /** A handle to the input file */ + FILE *input_file; + /** The length of the input file */ + int64_t input_file_len; + /** The path of the output trajectory file */ + char *output_file_path; + /** A handle to the output file */ + FILE *output_file; + /** Function to swap 32 bit values to and from the endianness of the + * input file */ + tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, uint32_t *); + /** Function to swap 64 bit values to and from the endianness of the + * input file */ + tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, uint64_t *); + /** Function to swap 32 bit values to and from the endianness of the + * input file */ + tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, uint32_t *); + /** Function to swap 64 bit values to and from the endianness of the + * input file */ + tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, uint64_t *); + /** The endianness of 32 bit values of the current computer */ + char endianness_32; + /** The endianness of 64 bit values of the current computer */ + char endianness_64; + + /** The name of the program producing this trajectory */ + char *first_program_name; + /** The forcefield used in the simulations */ + char *forcefield_name; + /** The name of the user running the simulations */ + char *first_user_name; + /** The name of the computer on which the simulations were performed */ + char *first_computer_name; + /** The PGP signature of the user creating the file. */ + char *first_pgp_signature; + /** The name of the program used when making last modifications to the + * file */ + char *last_program_name; + /** The name of the user making the last modifications to the file */ + char *last_user_name; + /** The name of the computer on which the last modifications were made */ + char *last_computer_name; + /** The PGP signature of the user making the last modifications to the + * file. */ + char *last_pgp_signature; + /** The time (n seconds since 1970) when the file was created */ + int64_t time; + /** The exponential of the value of the distance unit used. The default + * distance unit is nm (1e-9), i.e. distance_unit_exponential = -9. If + * the measurements are in Å the distance_unit_exponential = -10. */ + int64_t distance_unit_exponential; + + /** A flag indicating if the number of atoms can vary throughout the + * simulation, e.g. using a grand canonical ensemble */ + char var_num_atoms_flag; + /** The number of frames in a frame set. It is allowed to have frame sets + * with fewer frames, but this will help searching for specific frames */ + int64_t frame_set_n_frames; + /** The number of frame sets in a medium stride step */ + int64_t medium_stride_length; + /** The number of frame sets in a long stride step */ + int64_t long_stride_length; + /** The current (can change from one frame set to another) time length + * (in seconds) of one frame */ + double time_per_frame; + + /** The number of different kinds of molecules in the trajectory */ + int64_t n_molecules; + /** A list of molecules in the trajectory */ + tng_molecule_t molecules; + /** A list of the count of each molecule - if using variable number of + * particles this will be specified in each frame set */ + int64_t *molecule_cnt_list; + /** The total number of particles/atoms. If using variable number of + * particles this will be specified in each frame set */ + int64_t n_particles; + + /** The pos in the src file of the first frame set */ + int64_t first_trajectory_frame_set_input_file_pos; + /** The pos in the dest file of the first frame set */ + int64_t first_trajectory_frame_set_output_file_pos; + /** The pos in the src file of the last frame set */ + int64_t last_trajectory_frame_set_input_file_pos; + /** The pos in the dest file of the last frame set */ + int64_t last_trajectory_frame_set_output_file_pos; + /** The currently active frame set */ + struct tng_trajectory_frame_set current_trajectory_frame_set; + /** The pos in the src file of the current frame set */ + int64_t current_trajectory_frame_set_input_file_pos; + /** The pos in the dest file of the current frame set */ + int64_t current_trajectory_frame_set_output_file_pos; + /** The number of frame sets in the trajectory N.B. Not saved in file and + * cannot be trusted to be up-to-date */ + int64_t n_trajectory_frame_sets; + + /* These data blocks are non-trajectory data blocks */ + /** The number of non-frame dependent particle dependent data blocks */ + int n_particle_data_blocks; + /** A list of data blocks containing particle dependent data */ + struct tng_data *non_tr_particle_data; + + /** The number of frame and particle independent data blocks */ + int n_data_blocks; + /** A list of frame and particle indepdendent data blocks */ + struct tng_data *non_tr_data; + + /** TNG compression algorithm for compressing positions */ + int *compress_algo_pos; + /** TNG compression algorithm for compressing velocities */ + int *compress_algo_vel; + /** The precision used for lossy compression */ + double compression_precision; +}; + +#ifndef USE_WINDOWS +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +#define USE_WINDOWS +#endif /* win32... */ +#endif /* not defined USE_WINDOWS */ + +#ifdef USE_WINDOWS +#define TNG_INLINE __inline +#define TNG_SNPRINTF _snprintf +#else +#define TNG_INLINE inline +#define TNG_SNPRINTF snprintf +#endif + +static TNG_INLINE size_t tng_min_size(const size_t a, const size_t b) +{ + return (a < b ? a : b); +} + +static TNG_INLINE int64_t tng_min_i64(const int64_t a, const int64_t b) +{ + return (a < b ? a : b); +} + +static TNG_INLINE int64_t tng_max_i64(const int64_t a, const int64_t b) +{ + return (a > b ? a : b); +} + +/** + * @brief This function swaps the byte order of a 32 bit numerical variable + * to big endian. + * @param tng_data is a trajectory data container. + * @param v is a pointer to a 32 bit numerical value (float or integer). + * @details The function does not only work with integer, but e.g. floats need casting. + * If the byte order is already big endian no change is needed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current + * byte order is not recognised. + */ +static tng_function_status tng_swap_byte_order_big_endian_32 + (const tng_trajectory_t tng_data, uint32_t *v) +{ + switch(tng_data->endianness_32) + { + case TNG_LITTLE_ENDIAN_32: /* Byte order is reversed. */ + *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */ + ((*v & 0x00FF0000) >> 8) | /* Move 2nd byte to pos 3 */ + ((*v & 0x0000FF00) << 8) | /* Move 3rd byte to pos 2 */ + ((*v & 0x000000FF) << 24); /* Move last byte to first */ + + return(TNG_SUCCESS); + + case TNG_BYTE_PAIR_SWAP_32: /* byte pair swap */ + *v = ((*v & 0xFFFF0000) >> 16) | + ((*v & 0x0000FFFF) << 16); + + return(TNG_SUCCESS); + + case TNG_BIG_ENDIAN_32: /* Already correct */ + return(TNG_SUCCESS); + + default: + return(TNG_FAILURE); + } +} + +/** + * @brief This function swaps the byte order of a 64 bit numerical variable + * to big endian. + * @param tng_data is a trajectory data container. + * @param v is a pointer to a 64 bit numerical value (double or integer). + * @details The function does not only work with integer, but e.g. floats need casting. + * The byte order swapping routine can convert four different byte + * orders to big endian. + * If the byte order is already big endian no change is needed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current + * byte order is not recognised. + */ +static tng_function_status tng_swap_byte_order_big_endian_64 + (const tng_trajectory_t tng_data, uint64_t *v) +{ + switch(tng_data->endianness_64) + { + case TNG_LITTLE_ENDIAN_64: /* Byte order is reversed. */ + *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */ + ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */ + ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */ + ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */ + ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */ + ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */ + ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */ + ((*v & 0x00000000000000FFLL) << 56); /* Move last byte to first */ + + return(TNG_SUCCESS); + + case TNG_QUAD_SWAP_64: /* Byte quad swap */ + *v = ((*v & 0xFFFFFFFF00000000LL) >> 32) | + ((*v & 0x00000000FFFFFFFFLL) << 32); + + return(TNG_SUCCESS); + + case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swap */ + *v = ((*v & 0xFFFF0000FFFF0000LL) >> 16) | + ((*v & 0x0000FFFF0000FFFFLL) << 16); + + return(TNG_SUCCESS); + + case TNG_BYTE_SWAP_64: /* Byte swap */ + *v = ((*v & 0xFF00FF00FF00FF00LL) >> 8) | + ((*v & 0x00FF00FF00FF00FFLL) << 8); + + return(TNG_SUCCESS); + + case TNG_BIG_ENDIAN_64: /* Already correct */ + return(TNG_SUCCESS); + + default: + return(TNG_FAILURE); + } +} + +/** + * @brief This function swaps the byte order of a 32 bit numerical variable + * to little endian. + * @param tng_data is a trajectory data container. + * @param v is a pointer to a 32 bit numerical value (float or integer). + * @details The function does not only work with integer, but e.g. floats need casting. + * If the byte order is already little endian no change is needed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current + * byte order is not recognised. + */ +static tng_function_status tng_swap_byte_order_little_endian_32 + (const tng_trajectory_t tng_data, uint32_t *v) +{ + switch(tng_data->endianness_32) + { + case TNG_LITTLE_ENDIAN_32: /* Already correct */ + return(TNG_SUCCESS); + + case TNG_BYTE_PAIR_SWAP_32: /* byte pair swapped big endian to little endian */ + *v = ((*v & 0xFF00FF00) >> 8) | + ((*v & 0x00FF00FF) << 8); + + return(TNG_SUCCESS); + + case TNG_BIG_ENDIAN_32: /* Byte order is reversed. */ + *v = ((*v & 0xFF000000) >> 24) | /* Move first byte to end */ + ((*v & 0x00FF0000) >> 8) | /* Move 2nd byte to pos 3 */ + ((*v & 0x0000FF00) << 8) | /* Move 3rd byte to pos 2 */ + ((*v & 0x000000FF) << 24); /* Move last byte to first */ + + return(TNG_SUCCESS); + + default: + return(TNG_FAILURE); + } +} + +/** + * @brief This function swaps the byte order of a 64 bit numerical variable + * to little endian. + * @param tng_data is a trajectory data container. + * @param v is a pointer to a 64 bit numerical value (double or integer). + * @details The function does not only work with integer, but e.g. floats need casting. + * The byte order swapping routine can convert four different byte + * orders to little endian. + * If the byte order is already little endian no change is needed. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the current + * byte order is not recognised. + */ +static tng_function_status tng_swap_byte_order_little_endian_64 + (const tng_trajectory_t tng_data, uint64_t *v) +{ + switch(tng_data->endianness_64) + { + case TNG_LITTLE_ENDIAN_64: /* Already correct */ + return(TNG_SUCCESS); + + case TNG_QUAD_SWAP_64: /* Byte quad swapped big endian to little endian */ + *v = ((*v & 0xFF000000FF000000LL) >> 24) | + ((*v & 0x00FF000000FF0000LL) >> 8) | + ((*v & 0x0000FF000000FF00LL) << 8) | + ((*v & 0x000000FF000000FFLL) << 24); + + return(TNG_SUCCESS); + + case TNG_BYTE_PAIR_SWAP_64: /* Byte pair swapped big endian to little endian */ + *v = ((*v & 0xFF00FF0000000000LL) >> 40) | + ((*v & 0x00FF00FF00000000LL) >> 24) | + ((*v & 0x00000000FF00FF00LL) << 24) | + ((*v & 0x0000000000FF00FFLL) << 40); + + return(TNG_SUCCESS); + + case TNG_BYTE_SWAP_64: /* Byte swapped big endian to little endian */ + *v = ((*v & 0xFFFF000000000000LL) >> 48) | + ((*v & 0x0000FFFF00000000LL) >> 16) | + ((*v & 0x00000000FFFF0000LL) << 16) | + ((*v & 0x000000000000FFFFLL) << 48); + + return(TNG_SUCCESS); + + case TNG_BIG_ENDIAN_64: /* Byte order is reversed. */ + *v = ((*v & 0xFF00000000000000LL) >> 56) | /* Move first byte to end */ + ((*v & 0x00FF000000000000LL) >> 40) | /* Move 2nd byte to pos 7 */ + ((*v & 0x0000FF0000000000LL) >> 24) | /* Move 3rd byte to pos 6 */ + ((*v & 0x000000FF00000000LL) >> 8 ) | /* Move 4th byte to pos 5 */ + ((*v & 0x00000000FF000000LL) << 8 ) | /* Move 5th byte to pos 4 */ + ((*v & 0x0000000000FF0000LL) << 24) | /* Move 6th byte to pos 3 */ + ((*v & 0x000000000000FF00LL) << 40) | /* Move 7th byte to pos 2 */ + ((*v & 0x00000000000000FFLL) << 56); /* Move last byte to first */ + + return(TNG_SUCCESS); + + default: + return(TNG_FAILURE); + } +} + +/** + * @brief Read a NULL terminated string from a file. + * @param tng_data is a trajectory data container + * @param str is a pointer to the character string that will + * contain the read string. *str is reallocated in the function + * and must be NULL or pointing at already allocated memory. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * @param md5_state is a pointer to the current md5 storage, which will be + * appended with str if hash_mode == TNG_USE_HASH. + * @param line_nr is the line number where this function was called, to be + * able to give more useful error messages. + */ +static tng_function_status tng_freadstr(const tng_trajectory_t tng_data, + char **str, + const char hash_mode, + md5_state_t *md5_state, + const int line_nr) +{ + char temp[TNG_MAX_STR_LEN], *temp_alloc; + int c, count = 0; + + do + { + c = fgetc(tng_data->input_file); + + if (c == EOF) + { + /* Clear file error flag and return -1 if EOF is read.*/ + clearerr(tng_data->input_file); + return TNG_FAILURE; + } + else + { + /* Cast c to char */ + temp[count++] = (char) c; + } + } while ((temp[count-1] != '\0') && (count < TNG_MAX_STR_LEN)); + + temp_alloc = (char *)realloc(*str, count); + if(!temp_alloc) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, line_nr); + free(*str); + *str = 0; + return TNG_FAILURE; + } + *str = temp_alloc; + + strncpy(*str, temp, count); + + if(hash_mode == TNG_USE_HASH) + { + md5_append(md5_state, (md5_byte_t *)*str, count); + } + + return TNG_SUCCESS; +} + +/** + * @brief Write a NULL terminated string to a file. + * @param tng_data is a trajectory data container + * @param str is a pointer to the character string should be written. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * @param md5_state is a pointer to the current md5 storage, which will be + * appended with str if hash_mode == TNG_USE_HASH. + * @param line_nr is the line number where this function was called, to be + * able to give more useful error messages. + */ +static TNG_INLINE tng_function_status tng_fwritestr(tng_trajectory_t tng_data, + const char *str, + const char hash_mode, + md5_state_t *md5_state, + const int line_nr) +{ + size_t len; + + len = tng_min_size(strlen(str) + 1, TNG_MAX_STR_LEN); + + if(fwrite(str, len, 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write block data. %s: %d\n", __FILE__, line_nr); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + md5_append(md5_state, (md5_byte_t *)str, len); + } + + return(TNG_SUCCESS); +} + +/** + * @brief Read a numerical value from file. + * The byte order will be swapped if need be. + * @param tng_data is a trajectory data container + * @param dest is a pointer to where to store the read data. + * @param len is the length (in bytes) of the numerical data type. Should + * be 8 for 64 bit, 4 for 32 bit or 1 for a single byte flag. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * @param md5_state is a pointer to the current md5 storage, which will be + * appended with str if hash_mode == TNG_USE_HASH. + * @param line_nr is the line number where this function was called, to be + * able to give more useful error messages. + */ +static TNG_INLINE tng_function_status tng_file_input_numerical + (const tng_trajectory_t tng_data, + void *dest, + const size_t len, + const char hash_mode, + md5_state_t *md5_state, + const int line_nr) +{ + if(fread(dest, len, 1, tng_data->input_file) == 0) + { + fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, line_nr); + return(TNG_CRITICAL); + } + if(hash_mode == TNG_USE_HASH) + { + md5_append(md5_state, (md5_byte_t *)dest, len); + } + switch(len) + { + case 8: + if(tng_data->input_endianness_swap_func_64 && + tng_data->input_endianness_swap_func_64(tng_data, (uint64_t *)dest) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, line_nr); + } + break; + case 4: + if(tng_data->input_endianness_swap_func_32 && + tng_data->input_endianness_swap_func_32(tng_data, (uint32_t *)dest) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, line_nr); + } + break; + default: + break; + } + + return(TNG_SUCCESS); +} + +/** + * @brief Write a numerical value to file. + * The byte order will be swapped if need be. + * @param tng_data is a trajectory data container + * @param src is a pointer to the data to write. + * @param len is the length (in bytes) of the numerical data type. Should + * be 8 for 64 bit, 4 for 32 bit or 1 for a single byte flag. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * @param md5_state is a pointer to the current md5 storage, which will be + * appended with str if hash_mode == TNG_USE_HASH. + * @param line_nr is the line number where this function was called, to be + * able to give more useful error messages. + */ +static TNG_INLINE tng_function_status tng_file_output_numerical + (const tng_trajectory_t tng_data, + const void *src, + const size_t len, + const char hash_mode, + md5_state_t *md5_state, + const int line_nr) +{ + uint32_t temp_i32; + uint64_t temp_i64; + + switch(len) + { + case 8: + temp_i64 = *((uint64_t *)src); + if(tng_data->output_endianness_swap_func_64 && + tng_data->output_endianness_swap_func_64(tng_data, &temp_i64) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, line_nr); + } + if(fwrite(&temp_i64, len, 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write data. %s: %d\n", __FILE__, line_nr); + return(TNG_CRITICAL); + } + if(hash_mode == TNG_USE_HASH) + { + md5_append(md5_state, (md5_byte_t *)&temp_i64, len); + } + break; + case 4: + temp_i32 = *((uint32_t *)src); + if(tng_data->output_endianness_swap_func_32 && + tng_data->output_endianness_swap_func_32(tng_data, &temp_i32) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, line_nr); + } + if(fwrite(&temp_i32, len, 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write data. %s: %d\n", __FILE__, line_nr); + return(TNG_CRITICAL); + } + if(hash_mode == TNG_USE_HASH) + { + md5_append(md5_state, (md5_byte_t *)&temp_i32, len); + } + break; + default: + if(fwrite(src, len, 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write data. %s: %d\n", __FILE__, line_nr); + return(TNG_CRITICAL); + } + if(hash_mode == TNG_USE_HASH) + { + md5_append(md5_state, (md5_byte_t *)src, len); + } + break; + } + + return(TNG_SUCCESS); +} + +/** + * @brief Generate the md5 hash of a block. + * The hash is created based on the actual block contents. + * @param block is a general block container. + * @return TNG_SUCCESS (0) if successful. + */ +static tng_function_status tng_block_md5_hash_generate(const tng_gen_block_t block) +{ + md5_state_t md5_state; + + md5_init(&md5_state); + md5_append(&md5_state, (md5_byte_t *)block->block_contents, + (int)block->block_contents_size); + md5_finish(&md5_state, (md5_byte_t *)block->md5_hash); + + return(TNG_SUCCESS); +} + +/** + * @brief If there is data left in the block read that to append that to the MD5 hash. + * @param tng_data is a trajectory data container. + * @param block is the data block that is being read. + * @param start_pos is the file position where the block started. + * @param md5_state is the md5 to which the md5 of the remaining block + * will be appended. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_md5_remaining_append(const tng_trajectory_t tng_data, + const tng_gen_block_t block, + const int64_t start_pos, + md5_state_t *md5_state) +{ + int64_t curr_file_pos; + char *temp_data; + + curr_file_pos = ftello(tng_data->input_file); + if(curr_file_pos < start_pos + block->block_contents_size) + { + temp_data = (char *)malloc(start_pos + block->block_contents_size - curr_file_pos); + if(!temp_data) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + if(fread(temp_data, start_pos + block->block_contents_size - curr_file_pos, + 1, tng_data->input_file) == 0) + { + fprintf(stderr, "TNG library: Cannot read remaining part of block to generate MD5 sum. %s: %d\n", __FILE__, __LINE__); + free(temp_data); + return(TNG_CRITICAL); + } + md5_append(md5_state, (md5_byte_t *)temp_data, + start_pos + block->block_contents_size - curr_file_pos); + free(temp_data); + } + + return(TNG_SUCCESS); +} + +/** + * @brief Open the input file if it is not already opened. + * @param tng_data is a trajectory data container. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_input_file_init(const tng_trajectory_t tng_data) +{ + int64_t file_pos; + + if(!tng_data->input_file) + { + if(!tng_data->input_file_path) + { + fprintf(stderr, "TNG library: No file specified for reading. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + tng_data->input_file = fopen(tng_data->input_file_path, "rb"); + if(!tng_data->input_file) + { + fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n", + tng_data->input_file_path, __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + if(!tng_data->input_file_len) + { + file_pos = ftello(tng_data->input_file); + fseeko(tng_data->input_file, 0, SEEK_END); + tng_data->input_file_len = ftello(tng_data->input_file); + fseeko(tng_data->input_file, file_pos, SEEK_SET); + } + + return(TNG_SUCCESS); +} + +/** + * @brief Open the output file if it is not already opened + * @param tng_data is a trajectory data container. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_output_file_init(const tng_trajectory_t tng_data) +{ + if(!tng_data->output_file) + { + if(!tng_data->output_file_path) + { + fprintf(stderr, "TNG library: No file specified for writing. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + tng_data->output_file = fopen(tng_data->output_file_path, "wb+"); + + if(!tng_data->output_file) + { + fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n", + tng_data->output_file_path, __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + return(TNG_SUCCESS); +} + +/** + * @brief Setup a file block container. + * @param block_p a pointer to memory to initialise as a file block container. + * @details Memory is allocated during initialisation. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_block_init(struct tng_gen_block **block_p) +{ + tng_gen_block_t block; + + *block_p = (struct tng_gen_block *)malloc(sizeof(struct tng_gen_block)); + if(!*block_p) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + block = *block_p; + + block->id = -1; + /* Reset the md5_hash */ + memset(block->md5_hash, '\0', TNG_MD5_HASH_LEN); + block->name = 0; + block->block_version = TNG_API_VERSION; + block->header_contents = 0; + block->header_contents_size = 0; + block->block_contents = 0; + block->block_contents_size = 0; + + return(TNG_SUCCESS); +} + +/** + * @brief Clean up a file block container. + * @param block_p a pointer to the file block container to destroy. + * @details All allocated memory in the data structure is freed, as well as + * block_p itself. + * @return TNG_SUCCESS (0) if successful. + */ +static tng_function_status tng_block_destroy(struct tng_gen_block **block_p) +{ + tng_gen_block_t block = *block_p; + + if(!*block_p) + { + return(TNG_SUCCESS); + } + +/* fprintf(stderr, "TNG library: Destroying block\n"); */ + if(block->name) + { + free(block->name); + block->name = 0; + } + if(block->header_contents) + { + free(block->header_contents); + block->header_contents = 0; + } + if(block->block_contents) + { + free(block->block_contents); + block->block_contents = 0; + } + + free(*block_p); + *block_p = 0; + + return(TNG_SUCCESS); +} + +/** + * @brief Read the header of a data block, regardless of its type + * @param tng_data is a trajectory data container. + * @param block is a general block container. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE(1) if a minor + * error has occured (not able to read the header size, thus skipping + * the block) or TNG_CRITICAL (2) if a major error has occured. + */ +static tng_function_status tng_block_header_read + (const tng_trajectory_t tng_data, const tng_gen_block_t block) +{ + int64_t start_pos; + + TNG_ASSERT(block != 0, "TNG library: Trying to read to uninitialized block (NULL pointer)."); + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + start_pos = ftello(tng_data->input_file); + + /* First read the header size to be able to read the whole header. */ + if(fread(&block->header_contents_size, sizeof(block->header_contents_size), + 1, tng_data->input_file) == 0) + { + fprintf(stderr, "TNG library: Cannot read header size. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(block->header_contents_size == 0) + { + block->id = -1; + return(TNG_FAILURE); + } + + /* If this was the size of the general info block check the endianness */ + if(ftello(tng_data->input_file) < 9) + { + /* File is little endian */ + if ( *((const char*)&block->header_contents_size) != 0x00 && + *((const char*)(&block->header_contents_size) + 7) == 0x00) + { + /* If the architecture endianness is little endian no byte swap + * will be needed. Otherwise use the functions to swap to little + * endian */ + if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32) + { + tng_data->input_endianness_swap_func_32 = 0; + } + else + { + tng_data->input_endianness_swap_func_32 = + &tng_swap_byte_order_little_endian_32; + } + if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64) + { + tng_data->input_endianness_swap_func_64 = 0; + } + else + { + tng_data->input_endianness_swap_func_64 = + &tng_swap_byte_order_little_endian_64; + } + } + /* File is big endian */ + else + { + /* If the architecture endianness is big endian no byte swap + * will be needed. Otherwise use the functions to swap to big + * endian */ + if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32) + { + tng_data->input_endianness_swap_func_32 = 0; + } + else + { + tng_data->input_endianness_swap_func_32 = + &tng_swap_byte_order_big_endian_32; + } + if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64) + { + tng_data->input_endianness_swap_func_64 = 0; + } + else + { + tng_data->input_endianness_swap_func_64 = + &tng_swap_byte_order_big_endian_64; + } + } + } + + if(tng_data->input_endianness_swap_func_64 && + tng_data->input_endianness_swap_func_64(tng_data, (uint64_t *)&block->header_contents_size) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + + if(tng_file_input_numerical(tng_data, &block->block_contents_size, + sizeof(block->block_contents_size), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &block->id, + sizeof(block->id), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(fread(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->input_file) == 0) + { + fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + tng_freadstr(tng_data, &block->name, TNG_SKIP_HASH, 0, __LINE__); + + if(tng_file_input_numerical(tng_data, &block->block_version, + sizeof(block->block_version), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + fseeko(tng_data->input_file, start_pos + block->header_contents_size, SEEK_SET); + + return(TNG_SUCCESS); +} + +/** + * @brief Write a whole block, both header and contents, regardless of it type + * @param tng_data is a trajectory data container. + * @param block is a general block container. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +/* Disabled until it is used.*/ +/* +// static tng_function_status tng_block_verbatim_write(tng_trajectory_t tng_data, +// tng_gen_block_t block) +// { +// if(!block->header_contents) +// { +// fprintf(stderr, "TNG library: No contents to write. %s: %d\n", __FILE__, __LINE__); +// return(TNG_FAILURE); +// } +// if(fwrite(block->header_contents, block->header_contents_size, 1, +// tng_data->output_file) != 1) +// { +// fprintf(stderr, "TNG library: Could not write all header data. %s: %d\n", +// __FILE__, __LINE__); +// return(TNG_CRITICAL); +// } +// +// if(!block->block_contents) +// { +// fprintf(stderr, "TNG library: No block data to write. %s: %d\n", +// __FILE__, __LINE__); +// return(TNG_FAILURE); +// } +// if(fwrite(block->block_contents, block->block_contents_size, 1, +// tng_data->output_file) != 1) +// { +// fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", +// __FILE__, __LINE__); +// return(TNG_CRITICAL); +// } +// return(TNG_SUCCESS); +// } +*/ + +/** + * @brief Update the md5 hash of a block already written to the file + * @param tng_data is a trajectory data container. + * @param block is the block, of which to update the md5 hash. + * @param header_start_pos is the file position where the block header starts. + * @param contents_start_pos is the file position where the block contents + * start. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_md5_hash_update(const tng_trajectory_t tng_data, + const tng_gen_block_t block, + const int64_t header_start_pos, + const int64_t contents_start_pos) +{ + if(block->block_contents) + { + free(block->block_contents); + } + + block->block_contents = (char *)malloc(block->block_contents_size); + if(!block->block_contents) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + fseeko(tng_data->output_file, contents_start_pos, SEEK_SET); + if(fread(block->block_contents, block->block_contents_size, 1, + tng_data->output_file) == 0) + { + fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + tng_block_md5_hash_generate(block); + + fseeko(tng_data->output_file, header_start_pos + 3 * sizeof(int64_t), + SEEK_SET); + fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file); + + return(TNG_SUCCESS); +} + +/** + * @brief Update the frame set pointers in the file header (general info block), + * already written to disk + * @param tng_data is a trajectory data container. + * @param hash_mode specifies whether to update the block md5 hash when + * updating the pointers. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_header_pointers_update + (const tng_trajectory_t tng_data, const char hash_mode) +{ + tng_gen_block_t block; + FILE *temp = tng_data->input_file; + uint64_t output_file_pos, pos, contents_start_pos; + + if(tng_output_file_init(tng_data) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + tng_data->input_file = tng_data->output_file; + + tng_block_init(&block); + + output_file_pos = ftello(tng_data->output_file); + fseeko(tng_data->output_file, 0, SEEK_SET); + + if(tng_block_header_read(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read general info header. %s: %d\n", + __FILE__, __LINE__); + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + contents_start_pos = ftello(tng_data->output_file); + + fseeko(tng_data->output_file, block->block_contents_size - 5 * + sizeof(int64_t), SEEK_CUR); + + tng_data->input_file = temp; + + pos = tng_data->first_trajectory_frame_set_output_file_pos; + + if(tng_data->input_endianness_swap_func_64) + { + if(tng_data->input_endianness_swap_func_64(tng_data, + &pos) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + + if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + pos = tng_data->last_trajectory_frame_set_output_file_pos; + + if(tng_data->input_endianness_swap_func_64) + { + if(tng_data->input_endianness_swap_func_64(tng_data, + &pos) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + + if(fwrite(&pos, + sizeof(int64_t), 1, tng_data->output_file) != 1) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + tng_md5_hash_update(tng_data, block, 0, contents_start_pos); + } + + tng_block_destroy(&block); + + fseeko(tng_data->output_file, output_file_pos, SEEK_SET); + + return(TNG_SUCCESS); +} + +/** + * @brief Update the frame set pointers in the current frame set block, already + * written to disk. It also updates the pointers of the blocks pointing to + * the current frame set block. + * @param tng_data is a trajectory data container. + * @param hash_mode specifies whether to update the block md5 hash when + * updating the pointers. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_frame_set_pointers_update + (const tng_trajectory_t tng_data, const char hash_mode) +{ + tng_gen_block_t block; + tng_trajectory_frame_set_t frame_set; + FILE *temp = tng_data->input_file; + uint64_t pos, output_file_pos, contents_start_pos; + + if(tng_output_file_init(tng_data) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + tng_block_init(&block); + output_file_pos = ftello(tng_data->output_file); + + tng_data->input_file = tng_data->output_file; + + frame_set = &tng_data->current_trajectory_frame_set; + + pos = tng_data->current_trajectory_frame_set_output_file_pos; + + /* Update next frame set */ + if(frame_set->next_frame_set_file_pos > 0) + { + fseeko(tng_data->output_file, frame_set->next_frame_set_file_pos, SEEK_SET); + + if(tng_block_header_read(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n", + __FILE__, __LINE__); + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + contents_start_pos = ftello(tng_data->output_file); + + fseeko(tng_data->output_file, block->block_contents_size - (5 * + sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR); + + if(tng_data->input_endianness_swap_func_64) + { + if(tng_data->input_endianness_swap_func_64(tng_data, + &pos) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + + if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1) + { + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + tng_md5_hash_update(tng_data, block, frame_set->next_frame_set_file_pos, + contents_start_pos); + } + } + /* Update previous frame set */ + if(frame_set->prev_frame_set_file_pos > 0) + { + fseeko(tng_data->output_file, frame_set->prev_frame_set_file_pos, + SEEK_SET); + + if(tng_block_header_read(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read frame header. %s: %d\n", + __FILE__, __LINE__); + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + contents_start_pos = ftello(tng_data->output_file); + + fseeko(tng_data->output_file, block->block_contents_size - (6 * + sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR); + + if(tng_data->input_endianness_swap_func_64) + { + if(tng_data->input_endianness_swap_func_64(tng_data, + &pos) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + + if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1) + { + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + tng_md5_hash_update(tng_data, block, frame_set->prev_frame_set_file_pos, + contents_start_pos); + } + } + + /* Update the frame set one medium stride step after */ + if(frame_set->medium_stride_next_frame_set_file_pos > 0) + { + fseeko(tng_data->output_file, + frame_set->medium_stride_next_frame_set_file_pos, + SEEK_SET); + + if(tng_block_header_read(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n", + __FILE__, __LINE__); + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + contents_start_pos = ftello(tng_data->output_file); + + fseeko(tng_data->output_file, block->block_contents_size - (3 * + sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR); + + if(tng_data->input_endianness_swap_func_64) + { + if(tng_data->input_endianness_swap_func_64(tng_data, + &pos) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + + if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1) + { + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + tng_md5_hash_update(tng_data, block, + frame_set->medium_stride_next_frame_set_file_pos, + contents_start_pos); + } + } + /* Update the frame set one medium stride step before */ + if(frame_set->medium_stride_prev_frame_set_file_pos > 0) + { + fseeko(tng_data->output_file, + frame_set->medium_stride_prev_frame_set_file_pos, + SEEK_SET); + + if(tng_block_header_read(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n", + __FILE__, __LINE__); + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + contents_start_pos = ftello(tng_data->output_file); + + fseeko(tng_data->output_file, block->block_contents_size - (4 * + sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR); + + if(tng_data->input_endianness_swap_func_64) + { + if(tng_data->input_endianness_swap_func_64(tng_data, + &pos) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + + if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1) + { + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + tng_md5_hash_update(tng_data, block, + frame_set->medium_stride_prev_frame_set_file_pos, + contents_start_pos); + } + } + + /* Update the frame set one long stride step after */ + if(frame_set->long_stride_next_frame_set_file_pos > 0) + { + fseeko(tng_data->output_file, + frame_set->long_stride_next_frame_set_file_pos, + SEEK_SET); + + if(tng_block_header_read(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n", + __FILE__, __LINE__); + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + contents_start_pos = ftello(tng_data->output_file); + + fseeko(tng_data->output_file, block->block_contents_size - (1 * + sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR); + + if(tng_data->input_endianness_swap_func_64) + { + if(tng_data->input_endianness_swap_func_64(tng_data, + &pos) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + + if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1) + { + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + tng_md5_hash_update(tng_data, block, + frame_set->long_stride_next_frame_set_file_pos, + contents_start_pos); + } + } + /* Update the frame set one long stride step before */ + if(frame_set->long_stride_prev_frame_set_file_pos > 0) + { + fseeko(tng_data->output_file, + frame_set->long_stride_prev_frame_set_file_pos, + SEEK_SET); + + if(tng_block_header_read(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n", + __FILE__, __LINE__); + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + contents_start_pos = ftello(tng_data->output_file); + + fseeko(tng_data->output_file, block->block_contents_size - (2 * + sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR); + + if(tng_data->input_endianness_swap_func_64) + { + if(tng_data->input_endianness_swap_func_64(tng_data, + &pos) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + + if(fwrite(&pos, sizeof(int64_t), 1, tng_data->output_file) != 1) + { + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + tng_md5_hash_update(tng_data, block, + frame_set->long_stride_prev_frame_set_file_pos, + contents_start_pos); + } + } + + fseeko(tng_data->output_file, output_file_pos, SEEK_SET); + + tng_data->input_file = temp; + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +static tng_function_status tng_reread_frame_set_at_file_pos + (const tng_trajectory_t tng_data, + const int64_t pos) +{ + tng_gen_block_t block; + tng_function_status stat; + + tng_block_init(&block); + + fseeko(tng_data->input_file, pos, SEEK_SET); + if(pos > 0) + { + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", pos, + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_FAILURE); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +static tng_function_status tng_file_pos_of_subsequent_trajectory_block_get + (const tng_trajectory_t tng_data, + int64_t *pos) +{ + int64_t orig_pos, curr_frame_set_pos; + tng_gen_block_t block; + tng_function_status stat; + tng_trajectory_frame_set_t frame_set = + &tng_data->current_trajectory_frame_set; + + orig_pos = ftello(tng_data->input_file); + curr_frame_set_pos = tng_data->current_trajectory_frame_set_input_file_pos; + + *pos = tng_data->first_trajectory_frame_set_input_file_pos; + + if(*pos <= 0) + { + return(TNG_SUCCESS); + } + + fseeko(tng_data->input_file, *pos, SEEK_SET); + + tng_block_init(&block); + /* Read block headers first to see that a frame set block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", *pos, + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_FAILURE); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + /* Read all frame set blocks (not the blocks between them) */ + while(frame_set->next_frame_set_file_pos > 0) + { + fseeko(tng_data->input_file, frame_set->next_frame_set_file_pos, SEEK_SET); + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", *pos, + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET) + { + return(TNG_FAILURE); + } + + stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH); + if(stat != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(stat); + } + /* Update *pos if this is the earliest frame set so far (after orig_pos) */ + if(tng_data->current_trajectory_frame_set_input_file_pos < *pos && + tng_data->current_trajectory_frame_set_input_file_pos > orig_pos) + { + *pos = tng_data->current_trajectory_frame_set_input_file_pos; + } + } + + /* Re-read the frame set that used to be the current one */ + tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos); + + fseeko(tng_data->input_file, orig_pos, SEEK_SET); + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +/** + * @brief Migrate a whole frame set from one position in the file to another. + * @param tng_data is a trajectory data container. + * @param block_start_pos is the starting position in the file of the frame set. + * @param block_len is the length of the whole frame set (including all data blocks etc). + * @param new_pos is the new position in the file of the frame set. + * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes. + */ +static tng_function_status tng_frame_set_complete_migrate + (const tng_trajectory_t tng_data, + const int64_t block_start_pos, + const int64_t block_len, + const int64_t new_pos, + const char hash_mode) +{ + tng_bool updated = TNG_FALSE; + + char *contents; + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + fseeko(tng_data->input_file, block_start_pos, SEEK_SET); + + contents = (char *)malloc(block_len); + if(!contents) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(fread(contents, block_len, 1, tng_data->input_file) == 0) + { + fprintf(stderr, "TNG library: Cannot read data from file when migrating data. %s: %d\n", + __FILE__, __LINE__); + free(contents); + return(TNG_CRITICAL); + } + fseeko(tng_data->output_file, new_pos, SEEK_SET); + + if(fwrite(contents, block_len, 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write data to file when migrating data. %s: %d\n", + __FILE__, __LINE__); + free(contents); + return(TNG_CRITICAL); + } + + tng_data->current_trajectory_frame_set_output_file_pos = new_pos; + if(tng_data->input_file == tng_data->output_file) + { + tng_data->current_trajectory_frame_set_input_file_pos = new_pos; + } + + tng_frame_set_pointers_update(tng_data, hash_mode); + + /* Update the general info block if needed */ + if(block_start_pos == tng_data->first_trajectory_frame_set_output_file_pos) + { + tng_data->first_trajectory_frame_set_output_file_pos = new_pos; + updated = TNG_TRUE; + } + if(block_start_pos == tng_data->last_trajectory_frame_set_output_file_pos) + { + tng_data->last_trajectory_frame_set_output_file_pos = new_pos; + updated = TNG_TRUE; + } + if(updated) + { + tng_header_pointers_update(tng_data, hash_mode); + } + + /* Fill the block with NULL to avoid confusion. */ + memset(contents, '\0', block_len); + fseeko(tng_data->output_file, block_start_pos, SEEK_SET); + + /* FIXME: casting block_len to size_t is dangerous */ + fwrite(contents, 1, block_len, tng_data->output_file); + + free(contents); + + return(TNG_SUCCESS); +} + +static tng_function_status tng_length_of_current_frame_set_contents_get + (const tng_trajectory_t tng_data, + int64_t *len) +{ + int64_t orig_pos, pos, curr_frame_set_pos; + tng_gen_block_t block; + tng_function_status stat; + + orig_pos = ftello(tng_data->input_file); + curr_frame_set_pos = pos = tng_data->current_trajectory_frame_set_input_file_pos; + + *len = 0; + + fseeko(tng_data->input_file, curr_frame_set_pos, SEEK_SET); + + tng_block_init(&block); + /* Read block headers first to see that a frame set block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + curr_frame_set_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_FAILURE); + } + + /* Read the headers of all blocks in the frame set (not the actual contents of them) */ + while(stat == TNG_SUCCESS) + { + fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR); + *len += block->header_contents_size + block->block_contents_size; + pos += block->header_contents_size + block->block_contents_size; + if(pos >= tng_data->input_file_len) + { + break; + } + stat = tng_block_header_read(tng_data, block); + if(block->id == TNG_TRAJECTORY_FRAME_SET) + { + break; + } + } + + /* Re-read the frame set that used to be the current one */ + tng_reread_frame_set_at_file_pos(tng_data, curr_frame_set_pos); + + fseeko(tng_data->input_file, orig_pos, SEEK_SET); + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +/** + * @brief Migrate blocks in the file to make room for new data in a block. This + * is required e.g. when adding data to a block or extending strings in a + * block. + * @param tng_data is a trajectory data container. + * @param start_pos is the position from which to start moving data, usually + * the byte after the end of the block to which data was added. + * @param offset is the number of bytes that were inserted. + * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes. + * @details Trajectory blocks (frame sets and their related blocks) are moved + * to the end of the file (if needed) in order to make room for non-trajectory + * data. + */ +static tng_function_status tng_migrate_data_in_file + (const tng_trajectory_t tng_data, + const int64_t start_pos, + const int64_t offset, + const char hash_mode) +{ + int64_t traj_start_pos, empty_space, orig_file_pos, frame_set_length; + tng_gen_block_t block; + tng_function_status stat; + + if(offset <= 0) + { + return(TNG_SUCCESS); + } + + stat = tng_file_pos_of_subsequent_trajectory_block_get(tng_data, &traj_start_pos); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + tng_data->current_trajectory_frame_set_input_file_pos = traj_start_pos; + + empty_space = traj_start_pos - (start_pos - 1); + + if(empty_space >= offset) + { + return(TNG_SUCCESS); + } + + orig_file_pos = ftello(tng_data->input_file); + tng_block_init(&block); + + while(empty_space < offset) + { + fseeko(tng_data->input_file, traj_start_pos, SEEK_SET); + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n", + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + if(stat != TNG_SUCCESS || block->id != TNG_TRAJECTORY_FRAME_SET) + { + tng_block_destroy(&block); + return(TNG_FAILURE); + } + stat = tng_length_of_current_frame_set_contents_get(tng_data, &frame_set_length); + if(stat != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(stat); + } + stat = tng_frame_set_complete_migrate(tng_data, traj_start_pos, + frame_set_length, tng_data->input_file_len, + hash_mode); + if(stat != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(stat); + } + + empty_space += frame_set_length; + } + fseeko(tng_data->input_file, orig_file_pos, SEEK_SET); + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +static tng_function_status tng_block_header_len_calculate + (const tng_trajectory_t tng_data, + const tng_gen_block_t block, + int64_t *len) +{ + int name_len; + (void)tng_data; + + /* If the string is unallocated allocate memory for just string + * termination */ + if(!block->name) + { + block->name = (char *)malloc(1); + if(!block->name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + block->name[0] = 0; + } + + name_len = tng_min_size(strlen(block->name) + 1, TNG_MAX_STR_LEN); + + /* Calculate the size of the header to write */ + *len = sizeof(block->header_contents_size) + + sizeof(block->block_contents_size) + + sizeof(block->id) + + sizeof(block->block_version) + + TNG_MD5_HASH_LEN + + name_len; + + return (TNG_SUCCESS); +} + +/** + * @brief Write the header of a data block, regardless of its type + * @param tng_data is a trajectory data container. + * @param block is a general block container. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_block_header_write + (const tng_trajectory_t tng_data, + const tng_gen_block_t block) +{ + TNG_ASSERT(block != 0, "TNG library: Trying to write uninitialized block (NULL pointer)."); + + if(tng_output_file_init(tng_data) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(tng_block_header_len_calculate(tng_data, block, &block->header_contents_size) != + TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot calculate length of block header. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &block->header_contents_size, + sizeof(block->header_contents_size), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &block->block_contents_size, + sizeof(block->block_contents_size), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &block->id, + sizeof(block->id), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write header data. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, block->name, TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &block->block_version, + sizeof(block->block_version), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + return(TNG_SUCCESS); +} + +static tng_function_status tng_general_info_block_len_calculate + (const tng_trajectory_t tng_data, + int64_t *len) +{ + size_t first_program_name_len, first_user_name_len; + size_t first_computer_name_len, first_pgp_signature_len; + size_t last_program_name_len, last_user_name_len; + size_t last_computer_name_len, last_pgp_signature_len; + size_t forcefield_name_len; + + /* If the strings are unallocated allocate memory for just string + * termination */ + if(!tng_data->first_program_name) + { + tng_data->first_program_name = (char *)malloc(1); + if(!tng_data->first_program_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + tng_data->first_program_name[0] = 0; + } + if(!tng_data->last_program_name) + { + tng_data->last_program_name = (char *)malloc(1); + if(!tng_data->last_program_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + tng_data->last_program_name[0] = 0; + } + if(!tng_data->first_user_name) + { + tng_data->first_user_name = (char *)malloc(1); + if(!tng_data->first_user_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + tng_data->first_user_name[0] = 0; + } + if(!tng_data->last_user_name) + { + tng_data->last_user_name = (char *)malloc(1); + if(!tng_data->last_user_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + tng_data->last_user_name[0] = 0; + } + if(!tng_data->first_computer_name) + { + tng_data->first_computer_name = (char *)malloc(1); + if(!tng_data->first_computer_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + tng_data->first_computer_name[0] = 0; + } + if(!tng_data->last_computer_name) + { + tng_data->last_computer_name = (char *)malloc(1); + if(!tng_data->last_computer_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + tng_data->last_computer_name[0] = 0; + } + if(!tng_data->first_pgp_signature) + { + tng_data->first_pgp_signature = (char *)malloc(1); + if(!tng_data->first_pgp_signature) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + tng_data->first_pgp_signature[0] = 0; + } + if(!tng_data->last_pgp_signature) + { + tng_data->last_pgp_signature = (char *)malloc(1); + if(!tng_data->last_pgp_signature) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + tng_data->last_pgp_signature[0] = 0; + } + if(!tng_data->forcefield_name) + { + tng_data->forcefield_name = (char *)malloc(1); + if(!tng_data->forcefield_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + tng_data->forcefield_name[0] = 0; + } + + first_program_name_len = tng_min_size(strlen(tng_data->first_program_name) + 1, + TNG_MAX_STR_LEN); + last_program_name_len = tng_min_size(strlen(tng_data->last_program_name) + 1, + TNG_MAX_STR_LEN); + first_user_name_len = tng_min_size(strlen(tng_data->first_user_name) + 1, + TNG_MAX_STR_LEN); + last_user_name_len = tng_min_size(strlen(tng_data->last_user_name) + 1, + TNG_MAX_STR_LEN); + first_computer_name_len = tng_min_size(strlen(tng_data->first_computer_name) + 1, + TNG_MAX_STR_LEN); + last_computer_name_len = tng_min_size(strlen(tng_data->last_computer_name) + 1, + TNG_MAX_STR_LEN); + first_pgp_signature_len = tng_min_size(strlen(tng_data->first_pgp_signature) + 1, + TNG_MAX_STR_LEN); + last_pgp_signature_len = tng_min_size(strlen(tng_data->last_pgp_signature) + 1, + TNG_MAX_STR_LEN); + forcefield_name_len = tng_min_size(strlen(tng_data->forcefield_name) + 1, + TNG_MAX_STR_LEN); + + *len = sizeof(tng_data->time) + + sizeof(tng_data->var_num_atoms_flag) + + sizeof(tng_data->frame_set_n_frames) + + sizeof(tng_data->first_trajectory_frame_set_input_file_pos) + + sizeof(tng_data->last_trajectory_frame_set_input_file_pos) + + sizeof(tng_data->medium_stride_length) + + sizeof(tng_data->long_stride_length) + + sizeof(tng_data->distance_unit_exponential) + + first_program_name_len + + last_program_name_len + + first_user_name_len + + last_user_name_len + + first_computer_name_len + + last_computer_name_len + + first_pgp_signature_len + + last_pgp_signature_len + + forcefield_name_len; + + return(TNG_SUCCESS); +} + +/** + * @brief Read a general info block. This is the first block of a TNG file. + * Populate the fields in tng_data. + * @param tng_data is a trajectory data container. + * @param block is a general block container. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_general_info_block_read + (const tng_trajectory_t tng_data, + const tng_gen_block_t block, + const char hash_mode) +{ + int64_t start_pos; + char hash[TNG_MD5_HASH_LEN]; + md5_state_t md5_state; + + TNG_ASSERT(block != 0, "TNG library: Trying to read data to an uninitialized block (NULL pointer)"); + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + start_pos = ftello(tng_data->input_file); + + if(hash_mode == TNG_USE_HASH) + { + md5_init(&md5_state); + } + + tng_freadstr(tng_data, &tng_data->first_program_name, hash_mode, &md5_state, __LINE__); + + tng_freadstr(tng_data, &tng_data->last_program_name, hash_mode, &md5_state, __LINE__); + + tng_freadstr(tng_data, &tng_data->first_user_name, hash_mode, &md5_state, __LINE__); + + tng_freadstr(tng_data, &tng_data->last_user_name, hash_mode, &md5_state, __LINE__); + + tng_freadstr(tng_data, &tng_data->first_computer_name, hash_mode, &md5_state, __LINE__); + + tng_freadstr(tng_data, &tng_data->last_computer_name, hash_mode, &md5_state, __LINE__); + + tng_freadstr(tng_data, &tng_data->first_pgp_signature, hash_mode, &md5_state, __LINE__); + + tng_freadstr(tng_data, &tng_data->last_pgp_signature, hash_mode, &md5_state, __LINE__); + + tng_freadstr(tng_data, &tng_data->forcefield_name, hash_mode, &md5_state, __LINE__); + + if(tng_file_input_numerical(tng_data, &tng_data->time, sizeof(tng_data->time), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + + if(tng_file_input_numerical(tng_data, &tng_data->var_num_atoms_flag, + sizeof(tng_data->var_num_atoms_flag), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &tng_data->frame_set_n_frames, + sizeof(tng_data->frame_set_n_frames), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, + &tng_data->first_trajectory_frame_set_input_file_pos, + sizeof(tng_data->first_trajectory_frame_set_input_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + tng_data->current_trajectory_frame_set.next_frame_set_file_pos = + tng_data->first_trajectory_frame_set_input_file_pos; + + if(tng_file_input_numerical(tng_data, + &tng_data->last_trajectory_frame_set_input_file_pos, + sizeof(tng_data->last_trajectory_frame_set_input_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, + &tng_data->medium_stride_length, + sizeof(tng_data->medium_stride_length), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, + &tng_data->long_stride_length, + sizeof(tng_data->long_stride_length), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(block->block_version >= 3) + { + if(tng_file_input_numerical(tng_data, + &tng_data->distance_unit_exponential, + sizeof(tng_data->distance_unit_exponential), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + + if(hash_mode == TNG_USE_HASH) + { + /* If there is data left in the block that the current version of the library + * cannot interpret still read that to generate the MD5 hash. */ + tng_md5_remaining_append(tng_data, block, start_pos, &md5_state); + + md5_finish(&md5_state, (md5_byte_t *)hash); + if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0) + { + if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0) + { + fprintf(stderr, "TNG library: General info block contents corrupt. Hashes do not match. " + "%s: %d\n", __FILE__, __LINE__); + } + } + } + else + { + /* Seek to the end of the block */ + fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET); + } + + return(TNG_SUCCESS); +} + +/** + * @brief Write a general info block. This is the first block of a TNG file. + * @param tng_data is a trajectory data container. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_general_info_block_write + (const tng_trajectory_t tng_data, + const char hash_mode) +{ + int64_t header_file_pos, curr_file_pos; + size_t name_len; + tng_gen_block_t block; + md5_state_t md5_state; + + if(tng_output_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + fseeko(tng_data->output_file, 0, SEEK_SET); + + tng_block_init(&block); + + name_len = strlen("GENERAL INFO"); + + block->name = (char *)malloc(name_len + 1); + if(!block->name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + strcpy(block->name, "GENERAL INFO"); + block->id = TNG_GENERAL_INFO; + + if(tng_general_info_block_len_calculate(tng_data, &block->block_contents_size) != + TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot calculate length of general info block. %s: %d\n", + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + header_file_pos = 0; + + if(tng_block_header_write(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n", + tng_data->output_file_path, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + md5_init(&md5_state); + } + + if(tng_fwritestr(tng_data, tng_data->first_program_name, + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, tng_data->last_program_name, + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, tng_data->first_user_name, + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, tng_data->last_user_name, + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, tng_data->first_computer_name, + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, tng_data->last_computer_name, + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, tng_data->first_pgp_signature, + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, tng_data->last_pgp_signature, + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, tng_data->forcefield_name, + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + + if(tng_file_output_numerical(tng_data, &tng_data->time, sizeof(tng_data->time), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &tng_data->var_num_atoms_flag, + sizeof(tng_data->var_num_atoms_flag), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &tng_data->frame_set_n_frames, + sizeof(tng_data->frame_set_n_frames), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &tng_data->first_trajectory_frame_set_output_file_pos, + sizeof(tng_data->first_trajectory_frame_set_output_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &tng_data->last_trajectory_frame_set_output_file_pos, + sizeof(tng_data->last_trajectory_frame_set_output_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &tng_data->medium_stride_length, + sizeof(tng_data->medium_stride_length), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &tng_data->long_stride_length, + sizeof(tng_data->long_stride_length), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &tng_data->distance_unit_exponential, + sizeof(tng_data->distance_unit_exponential), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + if(hash_mode == TNG_USE_HASH) + { + md5_finish(&md5_state, (md5_byte_t *)block->md5_hash); + curr_file_pos = ftello(tng_data->output_file); + fseeko(tng_data->output_file, header_file_pos + + 3 * sizeof(int64_t), SEEK_SET); + if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__, + __LINE__); + return(TNG_CRITICAL); + } + fseeko(tng_data->output_file, curr_file_pos, SEEK_SET); + } + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +/** + * @brief Read the chain data of a molecules block. + * @param tng_data is a trajectory data container. + * @param chain is the chain data container. + * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes. + * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately + * if hash_mode == TNG_USE_HASH. + * @return TNG_SUCCESS(0) is successful. + */ +static tng_function_status tng_chain_data_read(const tng_trajectory_t tng_data, + const tng_chain_t chain, + const char hash_mode, + md5_state_t *md5_state) +{ + if(tng_file_input_numerical(tng_data, &chain->id, + sizeof(chain->id), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + tng_freadstr(tng_data, &chain->name, hash_mode, md5_state, __LINE__); + + if(tng_file_input_numerical(tng_data, &chain->n_residues, + sizeof(chain->n_residues), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + return(TNG_SUCCESS); +} + +/** + * @brief Write the chain data of a molecules block. + * @param tng_data is a trajectory data container. + * @param chain is the chain data container. + * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes. + * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately + * if hash_mode == TNG_USE_HASH. + * @return TNG_SUCCESS(0) is successful. + */ +static tng_function_status tng_chain_data_write(const tng_trajectory_t tng_data, + const tng_chain_t chain, + const char hash_mode, + md5_state_t *md5_state) +{ + if(tng_file_output_numerical(tng_data, &chain->id, + sizeof(chain->id), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, chain->name, hash_mode, + md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &chain->n_residues, + sizeof(chain->n_residues), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + return(TNG_SUCCESS); +} + +/** + * @brief Read the residue data of a molecules block. + * @param tng_data is a trajectory data container. + * @param residue is the residue data container. + * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes. + * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately + * if hash_mode == TNG_USE_HASH. + * @return TNG_SUCCESS(0) is successful. + */ +static tng_function_status tng_residue_data_read(const tng_trajectory_t tng_data, + const tng_residue_t residue, + const char hash_mode, + md5_state_t *md5_state) +{ + if(tng_file_input_numerical(tng_data, &residue->id, + sizeof(residue->id), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + tng_freadstr(tng_data, &residue->name, hash_mode, md5_state, __LINE__); + + if(tng_file_input_numerical(tng_data, &residue->n_atoms, + sizeof(residue->n_atoms), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + return(TNG_SUCCESS); +} + +/** + * @brief Write the residue data of a molecules block. + * @param tng_data is a trajectory data container. + * @param residue is the residue data container. + * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes. + * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately + * if hash_mode == TNG_USE_HASH. + * @return TNG_SUCCESS(0) is successful. + */ +static tng_function_status tng_residue_data_write(const tng_trajectory_t tng_data, + const tng_residue_t residue, + const char hash_mode, + md5_state_t *md5_state) +{ + if(tng_file_output_numerical(tng_data, &residue->id, + sizeof(residue->id), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, residue->name, hash_mode, + md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &residue->n_atoms, + sizeof(residue->n_atoms), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + return(TNG_SUCCESS); +} + +/** + * @brief Read the atom data of a molecules block. + * @param tng_data is a trajectory data container. + * @param atom is the atom data container. + * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes. + * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately + * if hash_mode == TNG_USE_HASH. + * @return TNG_SUCCESS(0) is successful. + */ +static tng_function_status tng_atom_data_read(const tng_trajectory_t tng_data, + const tng_atom_t atom, + const char hash_mode, + md5_state_t *md5_state) +{ + if(tng_file_input_numerical(tng_data, &atom->id, + sizeof(atom->id), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + tng_freadstr(tng_data, &atom->name, hash_mode, md5_state, __LINE__); + + tng_freadstr(tng_data, &atom->atom_type, hash_mode, md5_state, __LINE__); + + return(TNG_SUCCESS); +} + +/** + * @brief Write the atom data of a molecules block. + * @param tng_data is a trajectory data container. + * @param atom is the atom data container. + * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes. + * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately + * if hash_mode == TNG_USE_HASH. + * @return TNG_SUCCESS(0) is successful. + */ +static tng_function_status tng_atom_data_write(const tng_trajectory_t tng_data, + const tng_atom_t atom, + const char hash_mode, + md5_state_t *md5_state) +{ + if(tng_file_output_numerical(tng_data, &atom->id, + sizeof(atom->id), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, atom->name, hash_mode, + md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, atom->atom_type, hash_mode, + md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + return(TNG_SUCCESS); +} + +static tng_function_status tng_molecules_block_len_calculate + (const tng_trajectory_t tng_data, + int64_t *len) +{ + int64_t i, j; + tng_molecule_t molecule; + tng_chain_t chain; + tng_residue_t residue; + tng_atom_t atom; + tng_bond_t bond; + + *len = 0; + + for(i = 0; i < tng_data->n_molecules; i++) + { + molecule = &tng_data->molecules[i]; + if(!molecule->name) + { + molecule->name = (char *)malloc(1); + if(!molecule->name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + molecule->name[0] = 0; + } + *len += tng_min_size(strlen(molecule->name) + 1, TNG_MAX_STR_LEN); + + chain = molecule->chains; + for(j = 0; j < molecule->n_chains; j++) + { + *len += sizeof(chain->id); + + if(!chain->name) + { + chain->name = (char *)malloc(1); + if(!chain->name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + chain->name[0] = 0; + } + *len += tng_min_size(strlen(chain->name) + 1, TNG_MAX_STR_LEN); + + *len += sizeof(chain->n_residues); + + chain++; + } + + residue = molecule->residues; + for(j = 0; j < molecule->n_residues; j++) + { + *len += sizeof(residue->id); + + if(!residue->name) + { + residue->name = (char *)malloc(1); + if(!residue->name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + residue->name[0] = 0; + } + *len += tng_min_size(strlen(residue->name) + 1, TNG_MAX_STR_LEN); + + *len += sizeof(residue->n_atoms); + + residue++; + } + + atom = molecule->atoms; + for(j = 0; j < molecule->n_atoms; j++) + { + *len += sizeof(atom->id); + if(!atom->name) + { + atom->name = (char *)malloc(1); + if(!atom->name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + atom->name[0] = 0; + } + *len += tng_min_size(strlen(atom->name) + 1, TNG_MAX_STR_LEN); + + if(!atom->atom_type) + { + atom->atom_type = (char *)malloc(1); + if(!atom->atom_type) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + atom->atom_type[0] = 0; + } + *len += tng_min_size(strlen(atom->atom_type) + 1, TNG_MAX_STR_LEN); + + atom++; + } + + for(j = 0; j < molecule->n_bonds; j++) + { + *len += sizeof(bond->from_atom_id) + sizeof(bond->to_atom_id); + } + } + *len += sizeof(tng_data->n_molecules) + + (sizeof(molecule->id) + + sizeof(molecule->quaternary_str) + + sizeof(molecule->n_chains) + + sizeof(molecule->n_residues) + + sizeof(molecule->n_atoms) + + sizeof(molecule->n_bonds)) * + tng_data->n_molecules; + + if(!tng_data->var_num_atoms_flag) + { + *len += tng_data->n_molecules * sizeof(int64_t); + } + + return(TNG_SUCCESS); +} + +/** + * @brief Read a molecules block. Contains chain, residue and atom data + * @param tng_data is a trajectory data container. + * @param block is a general block container. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_molecules_block_read + (const tng_trajectory_t tng_data, + const tng_gen_block_t block, + const char hash_mode) +{ + int64_t start_pos, i, j, k, l; + tng_molecule_t molecule; + tng_chain_t chain; + tng_residue_t residue; + tng_atom_t atom; + tng_bond_t bond; + char hash[TNG_MD5_HASH_LEN]; + md5_state_t md5_state; + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + start_pos = ftello(tng_data->input_file); + + /* FIXME: Does not check if the size of the contents matches the expected + * size or if the contents can be read. */ + + if(tng_data->molecules) + { + for(i=0; in_molecules; i++) + { + tng_molecule_destroy(tng_data, &tng_data->molecules[i]); + } + free(tng_data->molecules); + tng_data->molecules = 0; + tng_data->n_molecules = 0; + } + + if(hash_mode == TNG_USE_HASH) + { + md5_init(&md5_state); + } + + if(tng_file_input_numerical(tng_data, &tng_data->n_molecules, + sizeof(tng_data->n_molecules), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_data->molecules) + { + free(tng_data->molecules); + } + + tng_data->n_particles = 0; + + tng_data->molecules = (struct tng_molecule *)malloc(tng_data->n_molecules * + sizeof(struct tng_molecule)); + if(!tng_data->molecules) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(!tng_data->var_num_atoms_flag) + { + if(tng_data->molecule_cnt_list) + { + free(tng_data->molecule_cnt_list); + } + tng_data->molecule_cnt_list = (int64_t *)malloc(sizeof(int64_t) * + tng_data->n_molecules); + if(!tng_data->molecule_cnt_list) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + /* Read each molecule from file */ + for(i=0; i < tng_data->n_molecules; i++) + { + molecule = &tng_data->molecules[i]; + + molecule->name = 0; + + if(tng_file_input_numerical(tng_data, &molecule->id, + sizeof(molecule->id), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + +/* fprintf(stderr, "TNG library: Read id: %" PRId64 " offset: %d\n", molecule->id, offset);*/ + tng_freadstr(tng_data, &molecule->name, hash_mode, &md5_state, __LINE__); + + if(tng_file_input_numerical(tng_data, &molecule->quaternary_str, + sizeof(molecule->quaternary_str), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(!tng_data->var_num_atoms_flag) + { + if(tng_file_input_numerical(tng_data, &tng_data->molecule_cnt_list[i], + sizeof(int64_t), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + + if(tng_file_input_numerical(tng_data, &molecule->n_chains, + sizeof(molecule->n_chains), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &molecule->n_residues, + sizeof(molecule->n_residues), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &molecule->n_atoms, + sizeof(molecule->n_atoms), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + tng_data->n_particles += molecule->n_atoms * + tng_data->molecule_cnt_list[i]; + + if(molecule->n_chains > 0) + { + molecule->chains = (struct tng_chain *)malloc(molecule->n_chains * + sizeof(struct tng_chain)); + if(!molecule->chains) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + chain = molecule->chains; + } + else + { + chain = 0; + } + + if(molecule->n_residues > 0) + { + molecule->residues = (struct tng_residue *)malloc(molecule->n_residues * + sizeof(struct tng_residue)); + if(!molecule->residues) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + if(molecule->chains) + { + free(molecule->chains); + molecule->chains = 0; + } + return(TNG_CRITICAL); + } + + residue = molecule->residues; + } + else + { + residue = 0; + } + + molecule->atoms = (struct tng_atom *)malloc(molecule->n_atoms * + sizeof(struct tng_atom)); + if(!molecule->atoms) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + if(molecule->chains) + { + free(molecule->chains); + molecule->chains = 0; + } + if(molecule->residues) + { + free(molecule->residues); + molecule->residues = 0; + } + return(TNG_CRITICAL); + } + + atom = molecule->atoms; + + if(molecule->n_chains > 0) + { + /* Read the chains of the molecule */ + for(j=0; jn_chains; j++) + { + chain->molecule = molecule; + + chain->name = 0; + + tng_chain_data_read(tng_data, chain, hash_mode, &md5_state); + + if(j==0) + { + chain->residues = molecule->residues; + residue = chain->residues; + } + else + { + chain->residues = residue; + } + + /* Read the residues of the chain */ + for(k=0; kn_residues; k++) + { + residue->chain = chain; + + residue->name = 0; + + tng_residue_data_read(tng_data, residue, hash_mode, &md5_state); + + residue->atoms_offset = atom - molecule->atoms; + /* Read the atoms of the residue */ + for(l=0; ln_atoms; l++) + { + atom->residue = residue; + + atom->name = 0; + atom->atom_type = 0; + + tng_atom_data_read(tng_data,atom, hash_mode, &md5_state); + + atom++; + } + residue++; + } + chain++; + } + } + else + { + if(molecule->n_residues > 0) + { + for(k=0; kn_residues; k++) + { + residue->chain = 0; + + residue->name = 0; + + tng_residue_data_read(tng_data, residue, hash_mode, &md5_state); + + residue->atoms_offset = atom - molecule->atoms; + /* Read the atoms of the residue */ + for(l=0; ln_atoms; l++) + { + atom->residue = residue; + + tng_atom_data_read(tng_data, atom, hash_mode, &md5_state); + + atom++; + } + residue++; + } + } + else + { + for(l=0; ln_atoms; l++) + { + atom->residue = 0; + + atom->name = 0; + atom->atom_type = 0; + + tng_atom_data_read(tng_data, atom, hash_mode, &md5_state); + + atom++; + } + } + } + + if(tng_file_input_numerical(tng_data, &molecule->n_bonds, + sizeof(molecule->n_bonds), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(molecule->n_bonds > 0) + { + tng_data->molecules[i].bonds = (struct tng_bond *)malloc(molecule->n_bonds * + sizeof(struct tng_bond)); + if(!molecule->bonds) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + if(molecule->chains) + { + free(molecule->chains); + molecule->chains = 0; + } + if(molecule->residues) + { + free(molecule->residues); + molecule->residues = 0; + } + if(molecule->atoms) + { + free(molecule->atoms); + molecule->atoms = 0; + } + return(TNG_CRITICAL); + } + + bond = molecule->bonds; + + for(j=0; jn_bonds; j++) + { + if(tng_file_input_numerical(tng_data, &bond->from_atom_id, + sizeof(bond->from_atom_id), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &bond->to_atom_id, + sizeof(bond->to_atom_id), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + bond++; + } + } + else + { + molecule->bonds = 0; + } + } + + if(hash_mode == TNG_USE_HASH) + { + /* If there is data left in the block that the current version of the library + * cannot interpret still read that to generate the MD5 hash. */ + tng_md5_remaining_append(tng_data, block, start_pos, &md5_state); + + md5_finish(&md5_state, (md5_byte_t *)hash); + if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0) + { + if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0) + { + fprintf(stderr, "TNG library: Molecules block contents corrupt. Hashes do not match. " + "%s: %d\n", __FILE__, __LINE__); + } + } + } + + else + { + /* Seek to the end of the block */ + fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET); + } + + return(TNG_SUCCESS); +} + +/** + * @brief Write a molecules block. + * @param tng_data is a trajectory data container. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_molecules_block_write + (const tng_trajectory_t tng_data, + const char hash_mode) +{ + int name_len; + int64_t i, j, k, l, header_file_pos, curr_file_pos; + tng_molecule_t molecule; + tng_chain_t chain; + tng_residue_t residue; + tng_atom_t atom; + tng_bond_t bond; + tng_gen_block_t block; + md5_state_t md5_state; + + if(tng_output_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + tng_block_init(&block); + + name_len = (unsigned int)strlen("MOLECULES"); + + block->name = (char *)malloc(name_len + 1); + if(!block->name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + strcpy(block->name, "MOLECULES"); + block->id = TNG_MOLECULES; + + if(tng_molecules_block_len_calculate(tng_data, &block->block_contents_size) != + TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot calculate length of molecules block. %s: %d\n", + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + header_file_pos = ftello(tng_data->output_file); + + if(tng_block_header_write(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n", + tng_data->output_file_path, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + md5_init(&md5_state); + } + + if(tng_file_output_numerical(tng_data, &tng_data->n_molecules, + sizeof(tng_data->n_molecules), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + for(i = 0; i < tng_data->n_molecules; i++) + { + molecule = &tng_data->molecules[i]; + + if(tng_file_output_numerical(tng_data, &molecule->id, + sizeof(molecule->id), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_fwritestr(tng_data, molecule->name, hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &molecule->quaternary_str, + sizeof(molecule->quaternary_str), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(!tng_data->var_num_atoms_flag) + { + if(tng_file_output_numerical(tng_data, &tng_data->molecule_cnt_list[i], + sizeof(int64_t), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + + if(tng_file_output_numerical(tng_data, &molecule->n_chains, + sizeof(molecule->n_chains), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &molecule->n_residues, + sizeof(molecule->n_residues), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &molecule->n_atoms, + sizeof(molecule->n_atoms), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(molecule->n_chains > 0) + { + chain = molecule->chains; + for(j = 0; j < molecule->n_chains; j++) + { + tng_chain_data_write(tng_data, chain, hash_mode, &md5_state); + + residue = chain->residues; + for(k = 0; k < chain->n_residues; k++) + { + tng_residue_data_write(tng_data, residue, hash_mode, &md5_state); + + atom = molecule->atoms + residue->atoms_offset; + for(l = 0; l < residue->n_atoms; l++) + { + tng_atom_data_write(tng_data, atom, hash_mode, &md5_state); + + atom++; + } + residue++; + } + chain++; + } + } + else + { + if(molecule->n_residues > 0) + { + residue = molecule->residues; + for(k = 0; k < molecule->n_residues; k++) + { + tng_residue_data_write(tng_data, residue, hash_mode, &md5_state); + + atom = molecule->atoms + residue->atoms_offset; + for(l = 0; l < residue->n_atoms; l++) + { + tng_atom_data_write(tng_data, atom, hash_mode, &md5_state); + + atom++; + } + residue++; + } + } + else + { + atom = molecule->atoms; + for(l = 0; l < molecule->n_atoms; l++) + { + tng_atom_data_write(tng_data, atom, hash_mode, &md5_state); + + atom++; + } + } + } + + if(tng_file_output_numerical(tng_data, &molecule->n_bonds, + sizeof(molecule->n_bonds), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + bond = molecule->bonds; + for(j = 0; j < molecule->n_bonds; j++) + { + if(tng_file_output_numerical(tng_data, &bond->from_atom_id, + sizeof(bond->from_atom_id), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &bond->to_atom_id, + sizeof(bond->to_atom_id), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + bond++; + } + } + if(hash_mode == TNG_USE_HASH) + { + md5_finish(&md5_state, (md5_byte_t *)block->md5_hash); + curr_file_pos = ftello(tng_data->output_file); + fseeko(tng_data->output_file, header_file_pos + + 3 * sizeof(int64_t), SEEK_SET); + if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__, + __LINE__); + return(TNG_CRITICAL); + } + fseeko(tng_data->output_file, curr_file_pos, SEEK_SET); + } + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +static tng_function_status tng_frame_set_block_len_calculate + (const tng_trajectory_t tng_data, + int64_t *len) +{ + *len = sizeof(int64_t) * 8; + *len += sizeof(double) * 2; + + if(tng_data->var_num_atoms_flag) + { + *len += sizeof(int64_t) * tng_data->n_molecules; + } + return(TNG_SUCCESS); +} + +/** + * @brief Read a frame set block. Update tng_data->current_trajectory_frame_set + * @param tng_data is a trajectory data container. + * @param block is a general block container. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_frame_set_block_read + (tng_trajectory_t tng_data, + tng_gen_block_t block, + const char hash_mode) +{ + int64_t file_pos, start_pos, i, prev_n_particles; + tng_trajectory_frame_set_t frame_set = + &tng_data->current_trajectory_frame_set; + char hash[TNG_MD5_HASH_LEN]; + md5_state_t md5_state; + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + start_pos = ftello(tng_data->input_file); + + /* FIXME: Does not check if the size of the contents matches the expected + * size or if the contents can be read. */ + + file_pos = start_pos - block->header_contents_size; + + tng_data->current_trajectory_frame_set_input_file_pos = file_pos; + + tng_frame_set_particle_mapping_free(tng_data); + + if(hash_mode == TNG_USE_HASH) + { + md5_init(&md5_state); + } + if(tng_file_input_numerical(tng_data, &frame_set->first_frame, + sizeof(frame_set->first_frame), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &frame_set->n_frames, + sizeof(frame_set->n_frames), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_data->var_num_atoms_flag) + { + prev_n_particles = frame_set->n_particles; + frame_set->n_particles = 0; + /* If the list of molecule counts has already been created assume that + * it is of correct size. */ + if(!frame_set->molecule_cnt_list) + { + frame_set->molecule_cnt_list = + (int64_t *)malloc(sizeof(int64_t) * tng_data->n_molecules); + + if(!frame_set->molecule_cnt_list) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + for(i = 0; i < tng_data->n_molecules; i++) + { + if(tng_file_input_numerical(tng_data, &frame_set->molecule_cnt_list[i], + sizeof(int64_t), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + frame_set->n_particles += tng_data->molecules[i].n_atoms * + frame_set->molecule_cnt_list[i]; + } + if(prev_n_particles && frame_set->n_particles != prev_n_particles) + { + /* FIXME: Particle dependent data memory management */ + } + } + + if(tng_file_input_numerical(tng_data, &frame_set->next_frame_set_file_pos, + sizeof(frame_set->next_frame_set_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &frame_set->prev_frame_set_file_pos, + sizeof(frame_set->prev_frame_set_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &frame_set->medium_stride_next_frame_set_file_pos, + sizeof(frame_set->medium_stride_next_frame_set_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &frame_set->medium_stride_prev_frame_set_file_pos, + sizeof(frame_set->medium_stride_prev_frame_set_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &frame_set->long_stride_next_frame_set_file_pos, + sizeof(frame_set->long_stride_next_frame_set_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &frame_set->long_stride_prev_frame_set_file_pos, + sizeof(frame_set->long_stride_prev_frame_set_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(block->block_version >= 3) + { + if(tng_file_input_numerical(tng_data, &frame_set->first_frame_time, + sizeof(frame_set->first_frame_time), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &tng_data->time_per_frame, + sizeof(tng_data->time_per_frame), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + else + { + frame_set->first_frame_time = -1; + tng_data->time_per_frame = -1; + } + + if(hash_mode == TNG_USE_HASH) + { + /* If there is data left in the block that the current version of the library + * cannot interpret still read that to generate the MD5 hash. */ + tng_md5_remaining_append(tng_data, block, start_pos, &md5_state); + + md5_finish(&md5_state, (md5_byte_t *)hash); + if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0) + { + if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0) + { + fprintf(stderr, "TNG library: Frame set block contents corrupt (first frame %" PRId64 "). Hashes do not match. " + "%s: %d\n", frame_set->first_frame, __FILE__, __LINE__); + } + } + } + else + { + /* Seek to the end of the block */ + fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET); + } + + /* If the output file and the input files are the same the number of + * frames in the file are the same number as has just been read. + * This is updated here to later on see if there have been new frames + * added and thereby the frame set needs to be rewritten. */ + if(tng_data->output_file == tng_data->input_file) + { + frame_set->n_written_frames = frame_set->n_frames; + } + + return(TNG_SUCCESS); +} + +/** + * @brief Write tng_data->current_trajectory_frame_set to file + * @param tng_data is a trajectory data container. + * @param block is a general block container. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_frame_set_block_write + (const tng_trajectory_t tng_data, + const tng_gen_block_t block, + const char hash_mode) +{ + char *temp_name; + int64_t i, header_file_pos, curr_file_pos; + unsigned int name_len; + tng_trajectory_frame_set_t frame_set = + &tng_data->current_trajectory_frame_set; + md5_state_t md5_state; + + if(tng_output_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + name_len = (unsigned int)strlen("TRAJECTORY FRAME SET"); + + if(!block->name || strlen(block->name) < name_len) + { + temp_name = (char *)realloc(block->name, name_len + 1); + if(!temp_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(block->name); + block->name = 0; + return(TNG_CRITICAL); + } + block->name = temp_name; + } + strcpy(block->name, "TRAJECTORY FRAME SET"); + block->id = TNG_TRAJECTORY_FRAME_SET; + + if(tng_frame_set_block_len_calculate(tng_data, &block->block_contents_size) != + TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot calculate length of frame set block. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + header_file_pos = ftello(tng_data->output_file); + + if(tng_block_header_write(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n", + tng_data->output_file_path, __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + md5_init(&md5_state); + } + if(tng_file_output_numerical(tng_data, &frame_set->first_frame, + sizeof(frame_set->first_frame), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &frame_set->n_frames, + sizeof(frame_set->n_frames), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_data->var_num_atoms_flag) + { + for(i = 0; i < tng_data->n_molecules; i++) + { + if(tng_file_output_numerical(tng_data, &frame_set->molecule_cnt_list[i], + sizeof(int64_t), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + } + + if(tng_file_output_numerical(tng_data, &frame_set->next_frame_set_file_pos, + sizeof(frame_set->next_frame_set_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &frame_set->prev_frame_set_file_pos, + sizeof(frame_set->prev_frame_set_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &frame_set->medium_stride_next_frame_set_file_pos, + sizeof(frame_set->medium_stride_next_frame_set_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &frame_set->medium_stride_prev_frame_set_file_pos, + sizeof(frame_set->medium_stride_prev_frame_set_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &frame_set->long_stride_next_frame_set_file_pos, + sizeof(frame_set->long_stride_next_frame_set_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &frame_set->long_stride_prev_frame_set_file_pos, + sizeof(frame_set->long_stride_prev_frame_set_file_pos), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &frame_set->first_frame_time, + sizeof(frame_set->first_frame_time), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &tng_data->time_per_frame, + sizeof(tng_data->time_per_frame), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + if(hash_mode == TNG_USE_HASH) + { + md5_finish(&md5_state, (md5_byte_t *)block->md5_hash); + curr_file_pos = ftello(tng_data->output_file); + fseeko(tng_data->output_file, header_file_pos + + 3 * sizeof(int64_t), SEEK_SET); + if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__, + __LINE__); + return(TNG_CRITICAL); + } + fseeko(tng_data->output_file, curr_file_pos, SEEK_SET); + } + + return(TNG_SUCCESS); +} + +static tng_function_status tng_trajectory_mapping_block_len_calculate + (const tng_trajectory_t tng_data, + const int64_t n_particles, + int64_t *len) +{ + (void)tng_data; + *len = sizeof(int64_t) * (2 + n_particles); + + return(TNG_SUCCESS); +} + +/** + * @brief Read an atom mappings block (translating between real atom indexes and how + * the atom info is written in this frame set). + * @param tng_data is a trajectory data container. + * @param block is a general block container. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_trajectory_mapping_block_read + (const tng_trajectory_t tng_data, + const tng_gen_block_t block, + const char hash_mode) +{ + int64_t start_pos, i; + tng_trajectory_frame_set_t frame_set = + &tng_data->current_trajectory_frame_set; + tng_particle_mapping_t mapping, mappings; + char hash[TNG_MD5_HASH_LEN]; + md5_state_t md5_state; + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + start_pos = ftello(tng_data->input_file); + + /* FIXME: Does not check if the size of the contents matches the expected + * size or if the contents can be read. */ + + frame_set->n_mapping_blocks++; + mappings = (tng_particle_mapping_t)realloc(frame_set->mappings, + sizeof(struct tng_particle_mapping) * + frame_set->n_mapping_blocks); + if(!mappings) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(frame_set->mappings); + frame_set->mappings = 0; + return(TNG_CRITICAL); + } + frame_set->mappings = mappings; + mapping = &mappings[frame_set->n_mapping_blocks - 1]; + + + if(hash_mode == TNG_USE_HASH) + { + md5_init(&md5_state); + } + + if(tng_file_input_numerical(tng_data, &mapping->num_first_particle, + sizeof(mapping->num_first_particle), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &mapping->n_particles, + sizeof(mapping->n_particles), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + mapping->real_particle_numbers = (int64_t *)malloc(mapping->n_particles * + sizeof(int64_t)); + if(!mapping->real_particle_numbers) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + /* If the byte order needs to be swapped the data must be read one value at + * a time and swapped */ + if(tng_data->input_endianness_swap_func_64) + { + for(i = 0; i < mapping->n_particles; i++) + { + if(tng_file_input_numerical(tng_data, &mapping->real_particle_numbers[i], + sizeof(int64_t), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + } + /* Otherwise the data can be read all at once */ + else + { + if(fread(mapping->real_particle_numbers, mapping->n_particles * sizeof(int64_t), + 1, tng_data->input_file) == 0) + { + fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + if(hash_mode == TNG_USE_HASH) + { + md5_append(&md5_state, (md5_byte_t *)mapping->real_particle_numbers, mapping->n_particles * sizeof(int64_t)); + } + } + + if(hash_mode == TNG_USE_HASH) + { + /* If there is data left in the block that the current version of the library + * cannot interpret still read that to generate the MD5 hash. */ + tng_md5_remaining_append(tng_data, block, start_pos, &md5_state); + + md5_finish(&md5_state, (md5_byte_t *)hash); + if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0) + { + if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0) + { + fprintf(stderr, "TNG library: Particle mapping block contents corrupt. Hashes do not match. " + "%s: %d\n", __FILE__, __LINE__); + } + } + } + else + { + /* Seek to the end of the block */ + fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET); + } + + return(TNG_SUCCESS); +} + +/** + * @brief Write the atom mappings of the current trajectory frame set + * @param tng_data is a trajectory data container. + * @param block is a general block container. + * @param mapping_block_nr is the index of the mapping block to write. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written. + * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if a minor error + * has occurred or TNG_CRITICAL (2) if a major error has occured. + */ +static tng_function_status tng_trajectory_mapping_block_write + (const tng_trajectory_t tng_data, + const tng_gen_block_t block, + const int mapping_block_nr, + const char hash_mode) +{ + int64_t header_file_pos, curr_file_pos; + char *temp_name; + int i; + unsigned int name_len; + md5_state_t md5_state; + tng_particle_mapping_t mapping = + &tng_data->current_trajectory_frame_set.mappings[mapping_block_nr]; + + if(mapping_block_nr >= + tng_data->current_trajectory_frame_set.n_mapping_blocks) + { + fprintf(stderr, "TNG library: Mapping block index out of bounds. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + if(tng_output_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + name_len = (unsigned int)strlen("PARTICLE MAPPING"); + + if(!block->name || strlen(block->name) < name_len) + { + temp_name = (char *)realloc(block->name, name_len + 1); + if(!temp_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(block->name); + block->name = 0; + return(TNG_CRITICAL); + } + block->name = temp_name; + } + strcpy(block->name, "PARTICLE MAPPING"); + block->id = TNG_PARTICLE_MAPPING; + + if(tng_trajectory_mapping_block_len_calculate(tng_data, + mapping->n_particles, + &block->block_contents_size) != + TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot calculate length of atom mapping block. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + header_file_pos = ftello(tng_data->output_file); + + if(tng_block_header_write(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n", + tng_data->output_file_path, __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + md5_init(&md5_state); + } + if(tng_file_output_numerical(tng_data, &mapping->num_first_particle, + sizeof(mapping->num_first_particle), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &mapping->n_particles, + sizeof(mapping->n_particles), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_data->output_endianness_swap_func_64) + { + for(i = 0; i < mapping->n_particles; i++) + { + if(tng_file_output_numerical(tng_data, &mapping->real_particle_numbers[i], + sizeof(int64_t), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + } + else + { + if(fwrite(mapping->real_particle_numbers, + mapping->n_particles * sizeof(int64_t), + 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write block data. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + if(hash_mode == TNG_USE_HASH) + { + md5_append(&md5_state, (md5_byte_t *)mapping->real_particle_numbers, + mapping->n_particles * sizeof(int64_t)); + } + } + + if(hash_mode == TNG_USE_HASH) + { + md5_finish(&md5_state, (md5_byte_t *)block->md5_hash); + curr_file_pos = ftello(tng_data->output_file); + fseeko(tng_data->output_file, header_file_pos + + 3 * sizeof(int64_t), SEEK_SET); + if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__, + __LINE__); + return(TNG_CRITICAL); + } + fseeko(tng_data->output_file, curr_file_pos, SEEK_SET); + } + + return(TNG_SUCCESS); +} + +/** + * @brief Prepare a block for storing particle data + * @param tng_data is a trajectory data container. + * @param block_type_flag specifies if this is a trajectory block or a + * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK) + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_particle_data_block_create + (const tng_trajectory_t tng_data, + const char block_type_flag) +{ + tng_trajectory_frame_set_t frame_set = + &tng_data->current_trajectory_frame_set; + + tng_data_t data; + + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + frame_set->n_particle_data_blocks++; + data = (tng_data_t)realloc(frame_set->tr_particle_data, + sizeof(struct tng_data) * + frame_set->n_particle_data_blocks); + if(!data) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(frame_set->tr_particle_data); + frame_set->tr_particle_data = 0; + return(TNG_CRITICAL); + } + frame_set->tr_particle_data = data; + } + else + { + tng_data->n_particle_data_blocks++; + data = (tng_data_t)realloc(tng_data->non_tr_particle_data, + sizeof(struct tng_data) * + tng_data->n_particle_data_blocks); + if(!data) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(tng_data->non_tr_particle_data); + tng_data->non_tr_particle_data = 0; + return(TNG_CRITICAL); + } + tng_data->non_tr_particle_data = data; + } + + return(TNG_SUCCESS); +} + +static tng_function_status tng_compress(const tng_trajectory_t tng_data, + const tng_gen_block_t block, + const int64_t n_frames, + const int64_t n_particles, + const char type, + char **data, + int64_t *new_len) +{ + int nalgo; + int compressed_len; + int *alt_algo = 0; + char *dest; + int64_t algo_find_n_frames = -1; + float f_precision; + double d_precision; + + if(block->id != TNG_TRAJ_POSITIONS && + block->id != TNG_TRAJ_VELOCITIES) + { + fprintf(stderr, "TNG library: Can only compress positions and velocities with the " + "TNG method. %s: %d\n", __FILE__, __LINE__); + return(TNG_FAILURE); + } + if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA) + { + fprintf(stderr, "TNG library: Data type not supported. %s: %d\n", __FILE__, __LINE__); + return(TNG_FAILURE); + } + + if(n_frames <= 0 || n_particles <= 0) + { + fprintf(stderr, "TNG library: Missing frames or particles. Cannot compress data " + "with the TNG method. %s: %d\n", __FILE__, __LINE__); + return(TNG_FAILURE); + } + + f_precision = 1/(float)tng_data->compression_precision; + d_precision = 1/tng_data->compression_precision; + + if(block->id == TNG_TRAJ_POSITIONS) + { + /* If there is only one frame in this frame set and there might be more + * do not store the algorithm as the compression algorithm, but find + * the best one without storing it */ + if(n_frames == 1 && tng_data->frame_set_n_frames > 1) + { + nalgo = tng_compress_nalgo(); + alt_algo = (int *)malloc(nalgo * sizeof *tng_data->compress_algo_pos); + + /* If we have already determined the initial coding and + * initial coding parameter do not determine them again. */ + if(tng_data->compress_algo_pos) + { + alt_algo[0] = tng_data->compress_algo_pos[0]; + alt_algo[1] = tng_data->compress_algo_pos[1]; + alt_algo[2] = tng_data->compress_algo_pos[2]; + alt_algo[3] = tng_data->compress_algo_pos[3]; + } + else + { + alt_algo[0] = -1; + alt_algo[1] = -1; + alt_algo[2] = -1; + alt_algo[3] = -1; + } + + /* If the initial coding and initial coding parameter are -1 + * they will be determined in tng_compress_pos/_float/. */ + if(type == TNG_FLOAT_DATA) + { + dest = tng_compress_pos_float((float *)*data, (int)n_particles, + (int)n_frames, + f_precision, + 0, alt_algo, + &compressed_len); + + } + else + { + dest = tng_compress_pos((double *)*data, (int)n_particles, + (int)n_frames, + d_precision, + 0, alt_algo, + &compressed_len); + } + /* If there had been no algorithm determined before keep the initial coding + * and initial coding parameter so that they won't have to be determined again. */ + if(!tng_data->compress_algo_pos) + { + nalgo = tng_compress_nalgo(); + tng_data->compress_algo_pos = (int *)malloc(nalgo * + sizeof *tng_data->compress_algo_pos); + tng_data->compress_algo_pos[0] = alt_algo[0]; + tng_data->compress_algo_pos[1] = alt_algo[1]; + tng_data->compress_algo_pos[2] = -1; + tng_data->compress_algo_pos[3] = -1; + } + } + else if(!tng_data->compress_algo_pos || tng_data->compress_algo_pos[2] == -1 || + tng_data->compress_algo_pos[2] == -1) + { + if(n_frames > 6) + { + algo_find_n_frames = 5; + } + else + { + algo_find_n_frames = n_frames; + } + + /* If the algorithm parameters are -1 they will be determined during the + * compression. */ + if(!tng_data->compress_algo_pos) + { + nalgo = tng_compress_nalgo(); + tng_data->compress_algo_pos = (int *)malloc(nalgo * + sizeof *tng_data->compress_algo_pos); + tng_data->compress_algo_pos[0] = -1; + tng_data->compress_algo_pos[1] = -1; + tng_data->compress_algo_pos[2] = -1; + tng_data->compress_algo_pos[3] = -1; + } + if(type == TNG_FLOAT_DATA) + { + dest = tng_compress_pos_float((float *)*data, (int)n_particles, + (int)algo_find_n_frames, + f_precision, + 0, tng_data-> + compress_algo_pos, + &compressed_len); + + if(algo_find_n_frames < n_frames) + { + free(dest); + dest = tng_compress_pos_float((float *)*data, (int)n_particles, + (int)n_frames, + f_precision, + 0, tng_data->compress_algo_pos, + &compressed_len); + } + } + else + { + dest = tng_compress_pos((double *)*data, (int)n_particles, + (int)algo_find_n_frames, + d_precision, + 0, tng_data-> + compress_algo_pos, + &compressed_len); + + if(algo_find_n_frames < n_frames) + { + free(dest); + dest = tng_compress_pos((double *)*data, (int)n_particles, + (int)n_frames, + d_precision, 0, + tng_data->compress_algo_pos, + &compressed_len); + } + } + } + else + { + if(type == TNG_FLOAT_DATA) + { + dest = tng_compress_pos_float((float *)*data, (int)n_particles, + (int)n_frames, + f_precision, 0, + tng_data->compress_algo_pos, &compressed_len); + } + else + { + dest = tng_compress_pos((double *)*data, (int)n_particles, + (int)n_frames, + d_precision, 0, + tng_data->compress_algo_pos, + &compressed_len); + } + } + } + else if(block->id == TNG_TRAJ_VELOCITIES) + { + /* If there is only one frame in this frame set and there might be more + * do not store the algorithm as the compression algorithm, but find + * the best one without storing it */ + if(n_frames == 1 && tng_data->frame_set_n_frames > 1) + { + nalgo = tng_compress_nalgo(); + alt_algo = (int *)malloc(nalgo * sizeof *tng_data->compress_algo_vel); + + /* If we have already determined the initial coding and + * initial coding parameter do not determine them again. */ + if(tng_data->compress_algo_vel) + { + alt_algo[0] = tng_data->compress_algo_vel[0]; + alt_algo[1] = tng_data->compress_algo_vel[1]; + alt_algo[2] = tng_data->compress_algo_vel[2]; + alt_algo[3] = tng_data->compress_algo_vel[3]; + } + else + { + alt_algo[0] = -1; + alt_algo[1] = -1; + alt_algo[2] = -1; + alt_algo[3] = -1; + } + + /* If the initial coding and initial coding parameter are -1 + * they will be determined in tng_compress_pos/_float/. */ + if(type == TNG_FLOAT_DATA) + { + dest = tng_compress_vel_float((float *)*data, (int)n_particles, + (int)n_frames, + f_precision, + 0, alt_algo, + &compressed_len); + + } + else + { + dest = tng_compress_vel((double *)*data, (int)n_particles, + (int)n_frames, + d_precision, + 0, alt_algo, + &compressed_len); + } + /* If there had been no algorithm determined before keep the initial coding + * and initial coding parameter so that they won't have to be determined again. */ + if(!tng_data->compress_algo_vel) + { + nalgo = tng_compress_nalgo(); + tng_data->compress_algo_vel = (int *)malloc(nalgo * + sizeof *tng_data->compress_algo_vel); + tng_data->compress_algo_vel[0] = alt_algo[0]; + tng_data->compress_algo_vel[1] = alt_algo[1]; + tng_data->compress_algo_vel[2] = -1; + tng_data->compress_algo_vel[3] = -1; + } + } + else if(!tng_data->compress_algo_vel || tng_data->compress_algo_vel[2] == -1 || + tng_data->compress_algo_vel[2] == -1) + { + if(n_frames > 6) + { + algo_find_n_frames = 5; + } + else + { + algo_find_n_frames = n_frames; + } + + /* If the algorithm parameters are -1 they will be determined during the + * compression. */ + if(!tng_data->compress_algo_vel) + { + nalgo = tng_compress_nalgo(); + tng_data->compress_algo_vel = (int *)malloc(nalgo * + sizeof *tng_data->compress_algo_vel); + tng_data->compress_algo_vel[0] = -1; + tng_data->compress_algo_vel[1] = -1; + tng_data->compress_algo_vel[2] = -1; + tng_data->compress_algo_vel[3] = -1; + } + if(type == TNG_FLOAT_DATA) + { + dest = tng_compress_vel_float((float *)*data, (int)n_particles, + (int)algo_find_n_frames, + f_precision, + 0, tng_data-> + compress_algo_vel, + &compressed_len); + if(algo_find_n_frames < n_frames) + { + free(dest); + dest = tng_compress_vel_float((float *)*data, (int)n_particles, + (int)n_frames, + f_precision, + 0, tng_data->compress_algo_vel, + &compressed_len); + } + } + else + { + dest = tng_compress_vel((double *)*data, (int)n_particles, + (int)algo_find_n_frames, + d_precision, + 0, tng_data-> + compress_algo_vel, + &compressed_len); + if(algo_find_n_frames < n_frames) + { + free(dest); + dest = tng_compress_vel((double *)*data, (int)n_particles, + (int)n_frames, + d_precision, + 0, tng_data->compress_algo_vel, + &compressed_len); + } + } + } + else + { + if(type == TNG_FLOAT_DATA) + { + dest = tng_compress_vel_float((float *)*data, (int)n_particles, + (int)n_frames, + f_precision, + 0, tng_data-> + compress_algo_vel, + &compressed_len); + } + else + { + dest = tng_compress_vel((double *)*data, (int)n_particles, + (int)n_frames, + d_precision, + 0, tng_data-> + compress_algo_vel, + &compressed_len); + } + } + } + else + { + fprintf(stderr, "TNG library: Can only compress positions and velocities using TNG-MF1 algorithms.\n"); + return(TNG_FAILURE); + } + + if(alt_algo) + { + free(alt_algo); + } + + free(*data); + + *data = (char *)dest; + + *new_len = compressed_len; + + return(TNG_SUCCESS); +} + +static tng_function_status tng_uncompress(const tng_trajectory_t tng_data, + const tng_gen_block_t block, + const char type, + char **data, + const int64_t uncompressed_len) +{ + double *d_dest = 0; + float *f_dest = 0; + int result; + (void)tng_data; + + TNG_ASSERT(uncompressed_len, "TNG library: The full length of the uncompressed data must be > 0."); + + if(block->id != TNG_TRAJ_POSITIONS && + block->id != TNG_TRAJ_VELOCITIES) + { + fprintf(stderr, "TNG library: Can only uncompress positions and velocities with the" + "TNG method.\n"); + return(TNG_FAILURE); + } + if(type != TNG_FLOAT_DATA && type != TNG_DOUBLE_DATA) + { + fprintf(stderr, "TNG library: Data type not supported.\n"); + return(TNG_FAILURE); + } + + if(type == TNG_FLOAT_DATA) + { + f_dest = (float *)malloc(uncompressed_len); + if(!f_dest) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + result = tng_compress_uncompress_float(*data, f_dest); + + free(*data); + + *data = (char *)f_dest; + } + else + { + d_dest = (double *)malloc(uncompressed_len); + if(!d_dest) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + result = tng_compress_uncompress(*data, d_dest); + + free(*data); + + *data = (char *)d_dest; + } + + if(result == 1) + { + fprintf(stderr, "TNG library: Cannot uncompress TNG compressed block.\n"); + return(TNG_FAILURE); + } + + return(TNG_SUCCESS); +} + +static tng_function_status tng_gzip_compress(const tng_trajectory_t tng_data, + char **data, const int64_t len, + int64_t *new_len) +{ + Bytef *dest; + uLongf stat, max_len; + (void)tng_data; + + max_len = compressBound(len); + dest = (Bytef *)malloc(max_len); + if(!dest) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + stat = compress(dest, &max_len, (Bytef *)*data, len); + if(stat != (unsigned long)Z_OK) + { + free(dest); + if(stat == (unsigned long)Z_MEM_ERROR) + { + fprintf(stderr, "TNG library: Not enough memory. "); + } + else if(stat == (unsigned long)Z_BUF_ERROR) + { + fprintf(stderr, "TNG library: Destination buffer too small. "); + } + fprintf(stderr, "TNG library: Error gzipping data. %s: %d\n", __FILE__, __LINE__); + return(TNG_FAILURE); + } + + *new_len = max_len; + + free(*data); + + *data = (char *)dest; + + return(TNG_SUCCESS); +} + +static tng_function_status tng_gzip_uncompress(const tng_trajectory_t tng_data, + char **data, + const int64_t compressed_len, + const int64_t uncompressed_len) +{ + Bytef *dest; + unsigned long stat; + (void)tng_data; + uLongf new_len = uncompressed_len; + + dest = (Bytef *)malloc(uncompressed_len); + if(!dest) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + stat = uncompress(dest, &new_len, (Bytef *) *data, + compressed_len); + + if(stat != Z_OK) + { + free(dest); + if(stat == (unsigned long)Z_MEM_ERROR) + { + fprintf(stderr, "TNG library: Not enough memory. "); + } + else if(stat == (unsigned long)Z_BUF_ERROR) + { + fprintf(stderr, "TNG library: Destination buffer too small. "); + } + else if(stat == (unsigned long)Z_DATA_ERROR) + { + fprintf(stderr, "TNG library: Data corrupt. "); + } + fprintf(stderr, "TNG library: Error uncompressing gzipped data. %s: %d\n", __FILE__, + __LINE__); + return(TNG_FAILURE); + } + + free(*data); + + *data = (char *)dest; + + return(TNG_SUCCESS); +} + +/** + * @brief Allocate memory for storing particle data. + * The allocated block will be refered to by data->values. + * @param tng_data is a trajectory data container. + * @param data is the data struct, which will contain the allocated memory in + * data->values. + * @param n_frames is the number of frames of data to store. + * @param n_particles is the number of particles with data. + * @param n_values_per_frame is the number of data values per particle and + * frame. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_allocate_particle_data_mem + (const tng_trajectory_t tng_data, + const tng_data_t data, + int64_t n_frames, + const int64_t stride_length, + const int64_t n_particles, + const int64_t n_values_per_frame) +{ + void ***values; + int64_t i, j, k, size, frame_alloc; + (void)tng_data; + + if(n_particles == 0 || n_values_per_frame == 0) + { + return(TNG_FAILURE); + } + + if(data->strings && data->datatype == TNG_CHAR_DATA) + { + for(i = 0; i < data->n_frames; i++) + { + for(j = 0; j < n_particles; j++) + { + for(k = 0; k < data->n_values_per_frame; k++) + { + if(data->strings[i][j][k]) + { + free(data->strings[i][j][k]); + } + } + free(data->strings[i][j]); + } + free(data->strings[i]); + } + free(data->strings); + } + data->n_frames = n_frames; + n_frames = tng_max_i64(1, n_frames); + data->stride_length = tng_max_i64(1, stride_length); + data->n_values_per_frame = n_values_per_frame; + frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length; + + if(data->datatype == TNG_CHAR_DATA) + { + data->strings = (char ****)malloc(sizeof(char ***) * frame_alloc); + for(i = 0; i < frame_alloc; i++) + { + data->strings[i] = (char ***)malloc(sizeof(char **) * + n_particles); + if(!data->strings[i]) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + for(j = 0; j < n_particles; j++) + { + data->strings[i][j] = (char **)malloc(sizeof(char *) * + n_values_per_frame); + if(!data->strings[i][j]) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + for(k = 0; k < n_values_per_frame; k++) + { + data->strings[i][j][k] = 0; + } + } + } + } + else + { + switch(data->datatype) + { + case TNG_INT_DATA: + size = sizeof(int64_t); + break; + case TNG_FLOAT_DATA: + size = sizeof(float); + break; + case TNG_DOUBLE_DATA: + default: + size = sizeof(double); + } + + values = (void ***)realloc(data->values, + size * frame_alloc * + n_particles * n_values_per_frame); + if(!values) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(data->values); + data->values = 0; + return(TNG_CRITICAL); + } + data->values = values; + } + return(TNG_SUCCESS); +} + +static tng_function_status tng_particle_data_find + (const tng_trajectory_t tng_data, + const int64_t id, + tng_data_t *data) +{ + int64_t block_index, i; + tng_trajectory_frame_set_t frame_set = &tng_data-> + current_trajectory_frame_set; + char block_type_flag; + + if(tng_data->current_trajectory_frame_set_input_file_pos > 0 || + tng_data->current_trajectory_frame_set_output_file_pos > 0) + { + block_type_flag = TNG_TRAJECTORY_BLOCK; + } + else + { + block_type_flag = TNG_NON_TRAJECTORY_BLOCK; + } + + block_index = -1; + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + for(i = 0; i < frame_set->n_particle_data_blocks; i++) + { + *data = &frame_set->tr_particle_data[i]; + if((*data)->block_id == id) + { + block_index = i; + break; + } + } + } + else + { + for(i = 0; i < tng_data->n_particle_data_blocks; i++) + { + *data = &tng_data->non_tr_particle_data[i]; + if((*data)->block_id == id) + { + block_index = i; + break; + } + } + } + if(block_index == -1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +static tng_function_status tng_data_find + (const tng_trajectory_t tng_data, + const int64_t id, + tng_data_t *data) +{ + int64_t block_index, i; + tng_trajectory_frame_set_t frame_set = &tng_data-> + current_trajectory_frame_set; + char block_type_flag; + + if(tng_data->current_trajectory_frame_set_input_file_pos > 0 || + tng_data->current_trajectory_frame_set_output_file_pos > 0) + { + block_type_flag = TNG_TRAJECTORY_BLOCK; + } + else + { + block_type_flag = TNG_NON_TRAJECTORY_BLOCK; + } + + block_index = -1; + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + for(i = 0; i < frame_set->n_data_blocks; i++) + { + *data = &frame_set->tr_data[i]; + if((*data)->block_id == id) + { + block_index = i; + break; + } + } + if(block_index == -1) + { + for(i = 0; i < tng_data->n_data_blocks; i++) + { + *data = &tng_data->non_tr_data[i]; + if((*data)->block_id == id) + { + block_index = i; + break; + } + } + } + } + else + { + for(i = 0; i < tng_data->n_data_blocks; i++) + { + *data = &tng_data->non_tr_data[i]; + if((*data)->block_id == id) + { + block_index = i; + break; + } + } + } + if(block_index == -1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +static tng_function_status tng_data_block_len_calculate + (const tng_trajectory_t tng_data, + const tng_data_t data, + const tng_bool is_particle_data, + const int64_t n_frames, + const int64_t frame_step, + const int64_t stride_length, + const int64_t num_first_particle, + const int64_t n_particles, + int64_t *data_start_pos, + int64_t *len) +{ + int size; + int64_t i, j, k; + char ***first_dim_values, **second_dim_values; + (void)tng_data; + + if(data == 0) + { + return(TNG_SUCCESS); + } + + switch(data->datatype) + { + case TNG_CHAR_DATA: + size = 1; + break; + case TNG_INT_DATA: + size = sizeof(int64_t); + break; + case TNG_FLOAT_DATA: + size = sizeof(float); + break; + case TNG_DOUBLE_DATA: + default: + size = sizeof(double); + } + + *len = sizeof(char) * 2 + sizeof(data->n_values_per_frame) + + sizeof(data->codec_id); + if(is_particle_data) + { + *len += sizeof(num_first_particle) + sizeof(n_particles); + } + + if(stride_length > 1) + { + *len += sizeof(data->first_frame_with_data) + + sizeof(data->stride_length); + } + + if(data->codec_id != TNG_UNCOMPRESSED) + { + *len += sizeof(data->compression_multiplier); + } + + if(data->dependency & TNG_FRAME_DEPENDENT) + { + *len += sizeof(char); + } + + *data_start_pos = *len; + + if(data->datatype == TNG_CHAR_DATA) + { + if(is_particle_data) + { + for(i = 0; i < n_frames; i++) + { + first_dim_values = data->strings[i]; + for(j = num_first_particle; j < num_first_particle + n_particles; + j++) + { + second_dim_values = first_dim_values[j]; + for(k = 0; k < data->n_values_per_frame; k++) + { + *len += strlen(second_dim_values[k]) + 1; + } + } + } + } + else + { + for(i = 0; i < n_frames; i++) + { + second_dim_values = data->strings[0][i]; + for(j = 0; j < data->n_values_per_frame; j++) + { + *len += strlen(second_dim_values[j]) + 1; + } + } + } + } + else + { + *len += size * frame_step * n_particles * data->n_values_per_frame; + } + + return(TNG_SUCCESS); +} + +/* TEST: */ +/** + * @brief Create a non-particle data block + * @param tng_data is a trajectory data container. + * @param block_type_flag specifies if this is a trajectory block or a + * non-trajectory block. (TNG_TRAJECTORY_BLOCK or TNG_NON_TRAJECTORY_BLOCK) + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_data_block_create + (const tng_trajectory_t tng_data, + const char block_type_flag) +{ + tng_trajectory_frame_set_t frame_set = + &tng_data->current_trajectory_frame_set; + + tng_data_t data; + + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + frame_set->n_data_blocks++; + data = (tng_data_t)realloc(frame_set->tr_data, sizeof(struct tng_data) * + frame_set->n_data_blocks); + if(!data) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(frame_set->tr_data); + frame_set->tr_data = 0; + return(TNG_CRITICAL); + } + frame_set->tr_data = data; + } + else + { + tng_data->n_data_blocks++; + data = (tng_data_t)realloc(tng_data->non_tr_data, sizeof(struct tng_data) * + tng_data->n_data_blocks); + if(!data) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(tng_data->non_tr_data); + tng_data->non_tr_data = 0; + return(TNG_CRITICAL); + } + tng_data->non_tr_data = data; + } + + return(TNG_SUCCESS); +} + +/* TEST: */ +/** + * @brief Allocate memory for storing non-particle data. + * The allocated block will be refered to by data->values. + * @param tng_data is a trajectory data container. + * @param data is the data struct, which will contain the allocated memory in + * data->values. + * @param n_frames is the number of frames of data to store. + * @param n_values_per_frame is the number of data values per frame. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_allocate_data_mem + (const tng_trajectory_t tng_data, + const tng_data_t data, + int64_t n_frames, + const int64_t stride_length, + const int64_t n_values_per_frame) +{ + void **values; + int64_t i, j, size, frame_alloc; + (void)tng_data; + + if(n_values_per_frame == 0) + { + return(TNG_FAILURE); + } + + if(data->strings && data->datatype == TNG_CHAR_DATA) + { + for(i = 0; i < data->n_frames; i++) + { + for(j = 0; j < data->n_values_per_frame; j++) + { + if(data->strings[0][i][j]) + { + free(data->strings[0][i][j]); + data->strings[0][i][j] = 0; + } + } + free(data->strings[0][i]); + data->strings[0][i] = 0; + } + free(data->strings[0]); + data->strings[0] = 0; + free(data->strings); + } + data->n_frames = n_frames; + data->stride_length = tng_max_i64(1, stride_length); + n_frames = tng_max_i64(1, n_frames); + data->n_values_per_frame = n_values_per_frame; + frame_alloc = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length; + + if(data->datatype == TNG_CHAR_DATA) + { + data->strings = (char ****)malloc(sizeof(char ***)); + data->strings[0] = (char ***)malloc(sizeof(char **) * frame_alloc); + for(i = 0; i < frame_alloc; i++) + { + data->strings[0][i] = (char **)malloc(sizeof(char *) * n_values_per_frame); + if(!data->strings[0][i]) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + for(j = 0; j < n_values_per_frame; j++) + { + data->strings[0][i][j] = 0; + } + } + } + else + { + switch(data->datatype) + { + case TNG_INT_DATA: + size = sizeof(int64_t); + break; + case TNG_FLOAT_DATA: + size = sizeof(float); + break; + case TNG_DOUBLE_DATA: + default: + size = sizeof(double); + } + + values = (void **)realloc(data->values, + size * frame_alloc * + n_values_per_frame); + if(!values) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(data->values); + data->values = 0; + return(TNG_CRITICAL); + } + data->values = values; + } + + return(TNG_SUCCESS); +} + +/** + * @brief Read the values of a data block + * @param tng_data is a trajectory data container. + * @param block is the block to store the data (should already contain + * the block headers and the block contents). + * @param block_data_len is the length of the data contents of the block. + * @param datatype is the type of data of the data block (char, int, float or + * double). + * @param num_first_particle is the number of the first particle in the data + * block. This should be the same as in the corresponding particle mapping + * block. Only used if reading particle dependent data. + * @param n_particles is the number of particles in the data block. This should + * be the same as in the corresponding particle mapping block. Only used if + * reading particle dependent data. + * @param first_frame_with_data is the frame number of the first frame with data + * in this data block. + * @param stride_length is the number of frames between each data entry. + * @param n_frames is the number of frames in this data block. + * @param n_values is the number of values per frame stored in this data block. + * @param codec_id is the ID of the codec to compress the data. + * @param multiplier is the multiplication factor applied to each data value + * before compression. This factor is applied since some compression algorithms + * work only on integers. + * @param hash_mode is an option to decide whether to generate/update the relevant md5 hashes. + * @param md5_state is a pointer to the current md5 storage, which will be updated appropriately + * if hash_mode == TNG_USE_HASH. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_data_read(const tng_trajectory_t tng_data, + const tng_gen_block_t block, + const int64_t block_data_len, + const char datatype, + const int64_t num_first_particle, + const int64_t n_particles, + const int64_t first_frame_with_data, + const int64_t stride_length, + int64_t n_frames, + const int64_t n_values, + const int64_t codec_id, + const double multiplier, + const char hash_mode, + md5_state_t *md5_state) +{ + int64_t i, j, k, tot_n_particles, n_frames_div, offset; + int64_t full_data_len; + int size, len; + char ***first_dim_values, **second_dim_values; + tng_data_t data; + tng_trajectory_frame_set_t frame_set = + &tng_data->current_trajectory_frame_set; + char block_type_flag, *contents; + tng_bool is_particle_data; + tng_function_status stat; + +/* fprintf(stderr, "TNG library: %s\n", block->name);*/ + + switch(datatype) + { + case TNG_CHAR_DATA: + size = 1; + break; + case TNG_INT_DATA: + size = sizeof(int64_t); + break; + case TNG_FLOAT_DATA: + size = sizeof(float); + break; + case TNG_DOUBLE_DATA: + default: + size = sizeof(double); + } + + if(n_particles > 0) + { + is_particle_data = TNG_TRUE; + } + else + { + if(codec_id == TNG_XTC_COMPRESSION || codec_id == TNG_TNG_COMPRESSION) + { + fprintf(stderr, "TNG library: Cannot uncompress data block. %s: %d\n", __FILE__, + __LINE__); + return(TNG_FAILURE); + } + is_particle_data = TNG_FALSE; + } + + if(is_particle_data == TNG_TRUE) + { + stat = tng_particle_data_find(tng_data, block->id, &data); + } + else + { + stat = tng_data_find(tng_data, block->id, &data); + } + + if(tng_data->current_trajectory_frame_set_input_file_pos > 0) + { + block_type_flag = TNG_TRAJECTORY_BLOCK; + } + else + { + block_type_flag = TNG_NON_TRAJECTORY_BLOCK; + } + + /* If the block does not exist, create it */ + if(stat != TNG_SUCCESS) + { + if(is_particle_data == TNG_TRUE) + { + stat = tng_particle_data_block_create(tng_data, block_type_flag); + } + else + { + stat = tng_data_block_create(tng_data, block_type_flag); + } + + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot create data block. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(is_particle_data == TNG_TRUE) + { + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + data = &frame_set->tr_particle_data[frame_set-> + n_particle_data_blocks - 1]; + } + else + { + data = &tng_data->non_tr_particle_data[tng_data-> + n_particle_data_blocks - 1]; + } + } + else + { + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + data = &frame_set->tr_data[frame_set->n_data_blocks - 1]; + } + else + { + data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1]; + } + } + + data->block_id = block->id; + + data->block_name = (char *)malloc(strlen(block->name) + 1); + if(!data->block_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + strcpy(data->block_name, block->name); + + data->datatype = datatype; + + data->values = 0; + /* FIXME: Memory leak from strings. */ + data->strings = 0; + data->n_frames = 0; + data->dependency = 0; + if(is_particle_data == TNG_TRUE) + { + data->dependency += TNG_PARTICLE_DEPENDENT; + } + if(block_type_flag == TNG_TRAJECTORY_BLOCK && + (n_frames > 1 || + frame_set->n_frames == n_frames || + stride_length > 1)) + { + data->dependency += TNG_FRAME_DEPENDENT; + } + data->codec_id = codec_id; + data->compression_multiplier = multiplier; + data->last_retrieved_frame = -1; + } + + if(is_particle_data == TNG_TRUE) + { + if(block_type_flag == TNG_TRAJECTORY_BLOCK && + tng_data->var_num_atoms_flag) + { + tot_n_particles = frame_set->n_particles; + } + else + { + tot_n_particles = tng_data->n_particles; + } + } + /* If there are no particles in this data block, still set tot_n_particles = 1 + * to calculate block lengths etc properly. */ + else + { + tot_n_particles = 1; + } + + n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length; + + contents = (char *)malloc(block_data_len); + if(!contents) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(fread(contents, block_data_len, 1, tng_data->input_file) == 0) + { + fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + md5_append(md5_state, (md5_byte_t *)contents, block_data_len); + } + + if(codec_id != TNG_UNCOMPRESSED) + { + full_data_len = n_frames_div * size * n_values; + if(is_particle_data == TNG_TRUE) + { + full_data_len *= n_particles; + } + switch(codec_id) + { + case TNG_XTC_COMPRESSION: + fprintf(stderr, "TNG library: XTC compression not implemented yet.\n"); + break; + case TNG_TNG_COMPRESSION: +/* fprintf(stderr, "TNG library: Before TNG uncompression: %" PRId64 "\n", block->block_contents_size);*/ + if(tng_uncompress(tng_data, block, datatype, + &contents, full_data_len) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Could not read tng compressed block data. %s: %d\n", + __FILE__, __LINE__); + free(contents); + return(TNG_CRITICAL); + } +/* fprintf(stderr, "TNG library: After TNG uncompression: %" PRId64 "\n", block->block_contents_size);*/ + break; + case TNG_GZIP_COMPRESSION: + /* fprintf(stderr, "TNG library: Before compression: %" PRId64 "\n", block->block_contents_size); */ + if(tng_gzip_uncompress(tng_data, &contents, + block_data_len, full_data_len) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Could not read gzipped block data. %s: %d\n", __FILE__, + __LINE__); + free(contents); + return(TNG_CRITICAL); + } + /* fprintf(stderr, "TNG library: After compression: %" PRId64 "\n", block->block_contents_size); */ + break; + } + } + else + { + full_data_len = block_data_len; + } + + /* Allocate memory */ + if(!data->values || data->n_frames != n_frames || + data->n_values_per_frame != n_values) + { + if(is_particle_data == TNG_TRUE) + { + stat = tng_allocate_particle_data_mem(tng_data, data, n_frames, + stride_length, + tot_n_particles, n_values); + } + else + { + stat = tng_allocate_data_mem(tng_data, data, n_frames, stride_length, + n_values); + } + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot allocate memory for data. %s: %d\n", + __FILE__, __LINE__); + free(contents); + return(TNG_CRITICAL); + } + } + + data->first_frame_with_data = first_frame_with_data; + + if(datatype == TNG_CHAR_DATA) + { + offset = 0; + /* Strings are stores slightly differently if the data block contains particle + * data (frames * particles * n_values) or not (frames * n_values). */ + if(is_particle_data == TNG_TRUE) + { + for(i = 0; i < n_frames_div; i++) + { + first_dim_values = data->strings[i]; + for(j = num_first_particle; j < num_first_particle + n_particles; + j++) + { + second_dim_values = first_dim_values[j]; + for(k = 0; k < n_values; k++) + { + len = tng_min_size(strlen(contents+offset) + 1, + TNG_MAX_STR_LEN); + if(second_dim_values[k]) + { + free(second_dim_values[k]); + } + second_dim_values[k] = (char *)malloc(len); + if(!second_dim_values[k]) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(contents); + return(TNG_CRITICAL); + } + strncpy(second_dim_values[k], contents+offset, len); + offset += len; + } + } + } + } + else + { + for(i = 0; i < n_frames_div; i++) + { + for(j = 0; j < n_values; j++) + { + len = tng_min_size(strlen(contents+offset) + 1, + TNG_MAX_STR_LEN); + if(data->strings[0][i][j]) + { + free(data->strings[0][i][j]); + } + data->strings[0][i][j] = (char *)malloc(len); + if(!data->strings[0][i][j]) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(contents); + return(TNG_CRITICAL); + } + strncpy(data->strings[0][i][j], contents+offset, len); + offset += len; + } + } + } + } + else + { + if(is_particle_data) + { + memcpy((char *)data->values + n_frames_div * size * n_values * + num_first_particle, contents, full_data_len); + } + else + { + memcpy(data->values, contents, full_data_len); + } + /* Endianness is handled by the TNG compression library. TNG compressed blocks are always written + * as little endian by the compression library. */ + if(codec_id != TNG_TNG_COMPRESSION) + { + switch(datatype) + { + case TNG_FLOAT_DATA: + if(tng_data->input_endianness_swap_func_32) + { + for(i = 0; i < full_data_len; i+=size) + { + if(tng_data->input_endianness_swap_func_32(tng_data, + (uint32_t *)((char *)data->values + i)) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + } + break; + case TNG_INT_DATA: + case TNG_DOUBLE_DATA: + if(tng_data->input_endianness_swap_func_64) + { + for(i = 0; i < full_data_len; i+=size) + { + if(tng_data->input_endianness_swap_func_64(tng_data, + (uint64_t *)((char *)data->values + i)) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + } + break; + case TNG_CHAR_DATA: + break; + } + } + } + + free(contents); + + return(TNG_SUCCESS); +} + +/** + * @brief Write a data block (particle or non-particle data) + * @param tng_data is a trajectory data container. + * @param block is the block to store the data (should already contain + * the block headers and the block contents). + * @param block_index is the index number of the data block in the frame set. + * @param is_particle_data is a flag to specify if the data to write is + * particle dependent or not. + * @param mapping is the particle mapping that is relevant for the data block. + * Only relevant if writing particle dependent data. + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH an md5 hash will be generated and written. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_data_block_write(const tng_trajectory_t tng_data, + const tng_gen_block_t block, + const int64_t block_index, + const tng_bool is_particle_data, + const tng_particle_mapping_t mapping, + const char hash_mode) +{ + int64_t n_particles, num_first_particle, n_frames, stride_length; + int64_t full_data_len, block_data_len, frame_step, data_start_pos; + int64_t i, j, k, curr_file_pos, header_file_pos; + int size; + size_t len; + tng_function_status stat; + char temp, *temp_name, ***first_dim_values, **second_dim_values, *contents; + double multiplier; + tng_trajectory_frame_set_t frame_set = + &tng_data->current_trajectory_frame_set; + tng_data_t data; + char block_type_flag; + md5_state_t md5_state; + + /* If we have already started writing frame sets it is too late to write + * non-trajectory data blocks */ + if(tng_data->current_trajectory_frame_set_output_file_pos > 0) + { + block_type_flag = TNG_TRAJECTORY_BLOCK; + } + else + { + block_type_flag = TNG_NON_TRAJECTORY_BLOCK; + } + + if(tng_output_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + if(is_particle_data == TNG_TRUE) + { + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + data = &frame_set->tr_particle_data[block_index]; + + /* If this data block has not had any data added in this frame set + * do not write it. */ + if(data->first_frame_with_data < frame_set->first_frame) + { + return(TNG_SUCCESS); + } + + stride_length = tng_max_i64(1, data->stride_length); + } + else + { + data = &tng_data->non_tr_particle_data[block_index]; + stride_length = 1; + } + } + else + { + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + data = &frame_set->tr_data[block_index]; + + /* If this data block has not had any data added in this frame set + * do not write it. */ + if(data->first_frame_with_data < frame_set->first_frame) + { + return(TNG_SUCCESS); + } + + stride_length = tng_max_i64(1, data->stride_length); + } + else + { + data = &tng_data->non_tr_data[block_index]; + stride_length = 1; + } + } + + switch(data->datatype) + { + case TNG_CHAR_DATA: + size = 1; + break; + case TNG_INT_DATA: + size = sizeof(int64_t); + break; + case TNG_FLOAT_DATA: + size = sizeof(float); + break; + case TNG_DOUBLE_DATA: + default: + size = sizeof(double); + } + + len = strlen(data->block_name) + 1; + + if(!block->name || strlen(block->name) < len) + { + temp_name = (char *)realloc(block->name, len); + if(!temp_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(block->name); + block->name = 0; + return(TNG_CRITICAL); + } + block->name = temp_name; + } + strncpy(block->name, data->block_name, len); + block->id = data->block_id; + + /* If writing frame independent data data->n_frames is 0, but n_frames + is used for the loop writing the data (and reserving memory) and needs + to be at least 1 */ + n_frames = tng_max_i64(1, data->n_frames); + + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + /* If the frame set is finished before writing the full number of frames + make sure the data block is not longer than the frame set. */ + n_frames = tng_min_i64(n_frames, frame_set->n_frames); + + n_frames -= (data->first_frame_with_data - frame_set->first_frame); + } + + frame_step = (n_frames % stride_length) ? n_frames / stride_length + 1: + n_frames / stride_length; + + /* TNG compression will use compression precision to get integers from + * floating point data. The compression multiplier stores that information + * to be able to return the precision of the compressed data. */ + if(data->codec_id == TNG_TNG_COMPRESSION) + { + data->compression_multiplier = tng_data->compression_precision; + } + /* Uncompressed data blocks do not use compression multipliers at all. + * GZip compression does not need it either. */ + else if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION) + { + data->compression_multiplier = 1.0; + } + + if(data->dependency & TNG_PARTICLE_DEPENDENT) + { + if(mapping && mapping->n_particles != 0) + { + n_particles = mapping->n_particles; + num_first_particle = mapping->num_first_particle; + } + else + { + num_first_particle = 0; + if(tng_data->var_num_atoms_flag) + { + n_particles = frame_set->n_particles; + } + else + { + n_particles = tng_data->n_particles; + } + } + } + else + { + /* This just appeases gcc-7 -Wmaybe-uninitialized. + * FIXME: It would be better to refactor so that + * TNG_PARTICLE_DEPENDENT triggers two distinct code paths. + */ + num_first_particle = -1; + n_particles = -1; + } + + if(data->dependency & TNG_PARTICLE_DEPENDENT) + { + if(tng_data_block_len_calculate(tng_data, data, TNG_TRUE, n_frames, + frame_step, stride_length, num_first_particle, + n_particles, &data_start_pos, + &block->block_contents_size) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot calculate length of particle data block. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + else + { + if(tng_data_block_len_calculate(tng_data, data, TNG_FALSE, n_frames, + frame_step, stride_length, 0, + 1, &data_start_pos, + &block->block_contents_size) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot calculate length of non-particle data block. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + header_file_pos = ftello(tng_data->output_file); + + if(tng_block_header_write(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot write header of file %s. %s: %d\n", + tng_data->output_file_path, __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + md5_init(&md5_state); + } + + if(tng_file_output_numerical(tng_data, &data->datatype, + sizeof(data->datatype), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &data->dependency, + sizeof(data->dependency), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(data->dependency & TNG_FRAME_DEPENDENT) + { + if(stride_length > 1) + { + temp = 1; + } + else + { + temp = 0; + } + if(tng_file_output_numerical(tng_data, &temp, + sizeof(temp), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + + if(tng_file_output_numerical(tng_data, &data->n_values_per_frame, + sizeof(data->n_values_per_frame), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &data->codec_id, + sizeof(data->codec_id), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(data->codec_id != TNG_UNCOMPRESSED) + { + if(tng_file_output_numerical(tng_data, &data->compression_multiplier, + sizeof(data->compression_multiplier), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + + if(data->n_frames > 0 && stride_length > 1) + { + /* FIXME: first_frame_with_data is not reliably set */ + if(data->first_frame_with_data == 0) + { + data->first_frame_with_data = frame_set->first_frame; + } + if(tng_file_output_numerical(tng_data, &data->first_frame_with_data, + sizeof(data->first_frame_with_data), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &stride_length, + sizeof(stride_length), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + + if(data->dependency & TNG_PARTICLE_DEPENDENT) + { + if(tng_file_output_numerical(tng_data, &num_first_particle, + sizeof(num_first_particle), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_output_numerical(tng_data, &n_particles, + sizeof(n_particles), + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + + if(data->datatype == TNG_CHAR_DATA) + { + if(data->strings) + { + if(data->dependency & TNG_PARTICLE_DEPENDENT) + { + for(i = 0; i < frame_step; i++) + { + first_dim_values = data->strings[i]; + for(j = num_first_particle; j < num_first_particle + n_particles; + j++) + { + second_dim_values = first_dim_values[j]; + for(k = 0; k < data->n_values_per_frame; k++) + { + if(tng_fwritestr(tng_data, second_dim_values[k], + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + } + } + } + else + { + for(i = 0; i < frame_step; i++) + { + for(j = 0; j < data->n_values_per_frame; j++) + { + if(tng_fwritestr(tng_data, data->strings[0][i][j], + hash_mode, &md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + } + } + } + } + else + { + if(data->dependency & TNG_PARTICLE_DEPENDENT) + { + full_data_len = size * frame_step * n_particles * data->n_values_per_frame; + } + else + { + full_data_len = size * frame_step * data->n_values_per_frame; + } + contents = (char *)malloc(full_data_len); + if(!contents) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(data->values) + { + memcpy(contents, data->values, full_data_len); + /* If writing TNG compressed data the endianness is taken into account by the compression + * routines. TNG compressed data is always written as little endian. */ + if(data->codec_id != TNG_TNG_COMPRESSION) + { + switch(data->datatype) + { + case TNG_FLOAT_DATA: + if(data->codec_id == TNG_UNCOMPRESSED || data->codec_id == TNG_GZIP_COMPRESSION) + { + if(tng_data->output_endianness_swap_func_32) + { + for(i = 0; i < full_data_len; i+=size) + { + if(tng_data->output_endianness_swap_func_32(tng_data, + (uint32_t *)(contents + i)) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + } + } + else + { + multiplier = data->compression_multiplier; + if(fabs(multiplier - 1.0) > 0.00001 || + tng_data->output_endianness_swap_func_32) + { + for(i = 0; i < full_data_len; i+=size) + { + *(float *)(contents + i) *= (float)multiplier; + if(tng_data->output_endianness_swap_func_32 && + tng_data->output_endianness_swap_func_32(tng_data, + (uint32_t *)(contents + i)) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + } + } + break; + case TNG_INT_DATA: + if(tng_data->output_endianness_swap_func_64) + { + for(i = 0; i < full_data_len; i+=size) + { + if(tng_data->output_endianness_swap_func_64(tng_data, + (uint64_t *)(contents + i)) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + } + break; + case TNG_DOUBLE_DATA: + if(data->codec_id == TNG_UNCOMPRESSED || data-> codec_id == TNG_GZIP_COMPRESSION) + { + if(tng_data->output_endianness_swap_func_64) + { + for(i = 0; i < full_data_len; i+=size) + { + if(tng_data->output_endianness_swap_func_64(tng_data, + (uint64_t *)(contents + i)) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + } + } + else + { + multiplier = data->compression_multiplier; + if(fabs(multiplier - 1.0) > 0.00001 || + tng_data->output_endianness_swap_func_64) + { + for(i = 0; i < full_data_len; i+=size) + { + *(double *)(contents + i) *= multiplier; + if(tng_data->output_endianness_swap_func_64 && + tng_data->output_endianness_swap_func_64(tng_data, + (uint64_t *)(contents + i)) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + } + } + break; + case TNG_CHAR_DATA: + break; + } + } + } + else + { + memset(contents, 0, full_data_len); + } + + block_data_len = full_data_len; + + switch(data->codec_id) + { + case TNG_XTC_COMPRESSION: + fprintf(stderr, "TNG library: XTC compression not implemented yet.\n"); + data->codec_id = TNG_UNCOMPRESSED; + break; + case TNG_TNG_COMPRESSION: + stat = tng_compress(tng_data, block, frame_step, + n_particles, data->datatype, + &contents, &block_data_len); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Could not write TNG compressed block data. %s: %d\n", + __FILE__, __LINE__); + if(stat == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + /* Set the data again, but with no compression (to write only + * the relevant data) */ + data->codec_id = TNG_UNCOMPRESSED; + stat = tng_data_block_write(tng_data, block, + block_index, is_particle_data, mapping, + hash_mode); + free(contents); + return(stat); + } + break; + case TNG_GZIP_COMPRESSION: + /* fprintf(stderr, "TNG library: Before compression: %" PRId64 "\n", block->block_contents_size); */ + stat = tng_gzip_compress(tng_data, + &contents, + full_data_len, + &block_data_len); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Could not write gzipped block data. %s: %d\n", __FILE__, + __LINE__); + if(stat == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + data->codec_id = TNG_UNCOMPRESSED; + } + /* fprintf(stderr, "TNG library: After compression: %" PRId64 "\n", block->block_contents_size); */ + break; + } + if(block_data_len != full_data_len) + { + block->block_contents_size -= full_data_len - block_data_len; + + curr_file_pos = ftello(tng_data->output_file); + fseeko(tng_data->output_file, header_file_pos + sizeof(block->header_contents_size), SEEK_SET); + + if(tng_file_output_numerical(tng_data, &block->block_contents_size, + sizeof(block->block_contents_size), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + fseeko(tng_data->output_file, curr_file_pos, SEEK_SET); + } + if(fwrite(contents, block_data_len, 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write all block data. %s: %d\n", __FILE__, + __LINE__); + return(TNG_CRITICAL); + } + if(hash_mode == TNG_USE_HASH) + { + md5_append(&md5_state, (md5_byte_t *)contents, block_data_len); + } + + free(contents); + } + + if(hash_mode == TNG_USE_HASH) + { + md5_finish(&md5_state, (md5_byte_t *)block->md5_hash); + curr_file_pos = ftello(tng_data->output_file); + fseeko(tng_data->output_file, header_file_pos + + 3 * sizeof(int64_t), SEEK_SET); + if(fwrite(block->md5_hash, TNG_MD5_HASH_LEN, 1, tng_data->output_file) != 1) + { + fprintf(stderr, "TNG library: Could not write MD5 hash. %s: %d\n", __FILE__, + __LINE__); + return(TNG_CRITICAL); + } + fseeko(tng_data->output_file, curr_file_pos, SEEK_SET); + } + + frame_set->n_written_frames += frame_set->n_unwritten_frames; + frame_set->n_unwritten_frames = 0; + + return(TNG_SUCCESS); +} + +/** + * @brief Read the meta information of a data block (particle or non-particle data). + * @param tng_data is a trajectory data container. + * @param datatype is set to the datatype of the data block. + * @param dependency is set to the dependency (particle and/or frame dependent) + * @param sparse_data is set to TRUE if data is not written every frame. + * @param n_values is set to the number of values per frame of the data. + * @param codec_id is set to the ID of the codec used to compress the data. + * @param first_frame_with_data is set to the first frame with data (only relevant if + * sparse_data == TRUE). + * @param stride_length is set to the writing interval of the data (1 if sparse_data + * == FALSE). + * @param num_first_particle is set to the number of the first particle with data written + * in this block. + * @param block_n_particles is set to the number of particles in this data block. + * @param multiplier is set to the compression multiplier. + * @param hash_mode specifies whether to check if the hash matches the contents or not. + * @param md5_state is the md5 hash of the block (only used if hash_mode == TNG_USE_HASH). + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_data_block_meta_information_read + (const tng_trajectory_t tng_data, + char *datatype, + char *dependency, + char *sparse_data, + int64_t *n_values, + int64_t *codec_id, + int64_t *first_frame_with_data, + int64_t *stride_length, + int64_t *n_frames, + int64_t *num_first_particle, + int64_t *block_n_particles, + double *multiplier, + const char hash_mode, + md5_state_t *md5_state) +{ + if(tng_file_input_numerical(tng_data, datatype, + sizeof(*datatype), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, dependency, + sizeof(*dependency), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(*dependency & TNG_FRAME_DEPENDENT) + { + if(tng_file_input_numerical(tng_data, sparse_data, + sizeof(*sparse_data), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + + if(tng_file_input_numerical(tng_data, n_values, + sizeof(*n_values), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, codec_id, + sizeof(*codec_id), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(*codec_id != TNG_UNCOMPRESSED) + { + if(tng_file_input_numerical(tng_data, multiplier, + sizeof(*multiplier), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + else + { + *multiplier = 1; + } + + if(*dependency & TNG_FRAME_DEPENDENT) + { + if(*sparse_data) + { + if(tng_file_input_numerical(tng_data, first_frame_with_data, + sizeof(*first_frame_with_data), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, stride_length, + sizeof(*stride_length), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + *n_frames = tng_data->current_trajectory_frame_set.n_frames - + (*first_frame_with_data - + tng_data->current_trajectory_frame_set.first_frame); + } + else + { + *first_frame_with_data = tng_data->current_trajectory_frame_set.first_frame; + *stride_length = 1; + *n_frames = tng_data->current_trajectory_frame_set.n_frames; + } + } + else + { + *first_frame_with_data = 0; + *stride_length = 1; + *n_frames = 1; + } + + if (*dependency & TNG_PARTICLE_DEPENDENT) + { + if(tng_file_input_numerical(tng_data, num_first_particle, + sizeof(*num_first_particle), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, block_n_particles, + sizeof(*block_n_particles), + hash_mode, md5_state, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + } + else + { + *num_first_particle = -1; + *block_n_particles = 0; + } + + return(TNG_SUCCESS); +} + +/** + * @brief Read the contents of a data block (particle or non-particle data). + * @param tng_data is a trajectory data container. + * @param block is the block to store the data (should already contain + * the block headers). + * @param hash_mode is an option to decide whether to use the md5 hash or not. + * If hash_mode == TNG_USE_HASH the written md5 hash in the file will be + * compared to the md5 hash of the read contents to ensure valid data. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_data_block_contents_read + (const tng_trajectory_t tng_data, + const tng_gen_block_t block, + const char hash_mode) +{ + int64_t start_pos, n_values, codec_id, n_frames, first_frame_with_data; + int64_t remaining_len, stride_length, block_n_particles, num_first_particle; + double multiplier; + char datatype, dependency, sparse_data; + tng_function_status stat = TNG_SUCCESS; + char hash[TNG_MD5_HASH_LEN]; + md5_state_t md5_state; + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + start_pos = ftello(tng_data->input_file); + + if(hash_mode == TNG_USE_HASH) + { + md5_init(&md5_state); + } + + /* FIXME: Does not check if the size of the contents matches the expected + * size or if the contents can be read. */ + + if(tng_data_block_meta_information_read(tng_data, + &datatype, + &dependency, &sparse_data, + &n_values, &codec_id, + &first_frame_with_data, + &stride_length, &n_frames, + &num_first_particle, + &block_n_particles, + &multiplier, + hash_mode, + &md5_state) == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read data block (%s) meta information. %s: %d\n", + block->name, __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + remaining_len = block->block_contents_size - (ftello(tng_data->input_file) - start_pos); + + stat = tng_data_read(tng_data, block, + remaining_len, + datatype, + num_first_particle, + block_n_particles, + first_frame_with_data, + stride_length, + n_frames, n_values, + codec_id, multiplier, + hash_mode, + &md5_state); + + if(hash_mode == TNG_USE_HASH) + { + /* If there is data left in the block that the current version of the library + * cannot interpret still read that to generate the MD5 hash. */ + tng_md5_remaining_append(tng_data, block, start_pos, &md5_state); + + md5_finish(&md5_state, (md5_byte_t *)hash); + if(strncmp(block->md5_hash, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", TNG_MD5_HASH_LEN) != 0) + { + if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0) + { + fprintf(stderr, "TNG library: Data block contents corrupt (%s). Hashes do not match. " + "%s: %d\n", block->name, __FILE__, __LINE__); + } + } + } + else + { + /* Seek to the end of the block */ + fseeko(tng_data->input_file, start_pos + block->block_contents_size, SEEK_SET); + } + + return(stat); +} + +/* +// ** Move the blocks in a frame set so that there is no unused space between +// * them. This can only be done on the last frame set in the file and should +// * be done e.g. if the last frame set in the file has fewer frames than +// * default or after compressing data blocks in a frame set. +// * @param tng_data is a trajectory data container. +// * @details the current_trajectory_frame_set is the one that will be modified. +// * @return TNG_SUCCESS (0) if successful, TNG_FAILURE (1) if the frame set +// * cannot be aligned or TNG_CRITICAL (2) if a major error has occured. +// * FIXME: This function is not finished!!! +// * +// static tng_function_status tng_frame_set_align(tng_trajectory_t tng_data) +// { +// tng_gen_block_t block; +// tng_trajectory_frame_set_t frame_set; +// FILE *temp = tng_data->input_file; +// int64_t pos, contents_start_pos, output_file_len; +// +// frame_set = &tng_data->current_trajectory_frame_set; +// +// if(frame_set->n_written_frames == frame_set->n_frames) +// { +// return(TNG_SUCCESS); +// } +// +// if(tng_data->current_trajectory_frame_set_output_file_pos != +// tng_data->last_trajectory_frame_set_output_file_pos) +// { +// } +// +// if(tng_output_file_init(tng_data) != TNG_SUCCESS) +// { +// fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n", +// __FILE__, __LINE__); +// return(TNG_CRITICAL); +// } +// +// tng_block_init(&block); +// // output_file_pos = ftello(tng_data->output_file); +// +// tng_data->input_file = tng_data->output_file; +// +// pos = tng_data->current_trajectory_frame_set_output_file_pos; +// +// fseeko(tng_data->output_file, pos, SEEK_SET); +// if(tng_block_header_read(tng_data, block) != TNG_SUCCESS) +// { +// fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n", +// __FILE__, __LINE__); +// tng_data->input_file = temp; +// tng_block_destroy(&block); +// return(TNG_CRITICAL); +// } +// +// contents_start_pos = ftello(tng_data->output_file); +// +// fseeko(tng_data->output_file, 0, SEEK_END); +// output_file_len = ftello(tng_data->output_file); +// pos = contents_start_pos + block->block_contents_size; +// fseeko(tng_data->output_file, pos, +// SEEK_SET); +// +// while(pos < output_file_len) +// { +// if(tng_block_header_read(tng_data, block) != TNG_SUCCESS) +// { +// fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", pos, +// __FILE__, __LINE__); +// tng_data->input_file = temp; +// tng_block_destroy(&block); +// return(TNG_CRITICAL); +// } +// pos += block->header_contents_size + block->block_contents_size; +// fseeko(tng_data->output_file, pos, SEEK_SET); +// } +// +// return(TNG_SUCCESS); +// } +*/ +/** + * @brief Finish writing the current frame set. Update the number of frames + * and the hashes of the frame set and all its data blocks (if hash_mode + * == TNG_USE_HASH). + * @param tng_data is a trajectory data container. + * @param hash_mode specifies whether to update the block md5 hash when + * updating the pointers. + * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major + * error has occured. + */ +static tng_function_status tng_frame_set_finalize + (const tng_trajectory_t tng_data, + const char hash_mode) +{ + tng_gen_block_t block; + tng_trajectory_frame_set_t frame_set; + FILE *temp = tng_data->input_file; + int64_t pos, curr_file_pos; + + frame_set = &tng_data->current_trajectory_frame_set; + + if(frame_set->n_written_frames == frame_set->n_frames) + { + return(TNG_SUCCESS); + } + + frame_set->n_written_frames = frame_set->n_frames; + + if(tng_output_file_init(tng_data) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + tng_block_init(&block); +/* output_file_pos = ftello(tng_data->output_file); */ + + tng_data->input_file = tng_data->output_file; + + curr_file_pos = ftello(tng_data->output_file); + + pos = tng_data->current_trajectory_frame_set_output_file_pos; + + fseeko(tng_data->output_file, pos, SEEK_SET); + + if(tng_block_header_read(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n", + __FILE__, __LINE__); + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + +// contents_start_pos = ftello(tng_data->output_file); + + fseeko(tng_data->output_file, sizeof(frame_set->first_frame), SEEK_CUR); + if(fwrite(&frame_set->n_frames, sizeof(frame_set->n_frames), + 1, tng_data->output_file) != 1) + { + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(hash_mode == TNG_USE_HASH) + { + tng_md5_hash_update(tng_data, block, pos, + pos + block->header_contents_size); + } + + fseeko(tng_data->output_file, curr_file_pos, SEEK_SET); + + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_SUCCESS); +} + +/* +// ** Sets the name of a file contents block +// * @param tng_data is a trajectory data container. +// * @param block is the block, of which to change names. +// * @param new_name is the new name of the block. +// * @return TNG_SUCCESS (0) if successful or TNG_CRITICAL (2) if a major +// * error has occured. +// +// static tng_function_status tng_block_name_set(tng_trajectory_t tng_data, +// tng_gen_block_t block, +// const char *new_name) +// { +// int len; +// +// len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN); +// +// * If the currently stored string length is not enough to store the new +// * string it is freed and reallocated. * +// if(block->name && strlen(block->name) < len) +// { +// free(block->name); +// block->name = 0; +// } +// if(!block->name) +// { +// block->name = (char *)malloc(len); +// if(!block->name) +// { +// fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", +// __FILE__, __LINE__); +// return(TNG_CRITICAL); +// } +// } +// +// strncpy(block->name, new_name, len); +// +// return(TNG_SUCCESS); +// } +*/ + +tng_function_status DECLSPECDLLEXPORT tng_atom_residue_get + (const tng_trajectory_t tng_data, + const tng_atom_t atom, + tng_residue_t *residue) +{ + (void) tng_data; + + TNG_ASSERT(atom, "TNG library: atom must not be NULL"); + + *residue = atom->residue; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_atom_name_get + (const tng_trajectory_t tng_data, + const tng_atom_t atom, + char *name, + const int max_len) +{ + (void) tng_data; + TNG_ASSERT(atom, "TNG library: atom must not be NULL"); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer"); + + strncpy(name, atom->name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(atom->name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_atom_name_set + (const tng_trajectory_t tng_data, + const tng_atom_t atom, + const char *new_name) +{ + unsigned int len; + (void)tng_data; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer."); + + len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN); + + /* If the currently stored string length is not enough to store the new + * string it is freed and reallocated. */ + if(atom->name && strlen(atom->name) < len) + { + free(atom->name); + atom->name = 0; + } + if(!atom->name) + { + atom->name = (char *)malloc(len); + if(!atom->name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(atom->name, new_name, len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_atom_type_get + (const tng_trajectory_t tng_data, + const tng_atom_t atom, + char *type, + const int max_len) +{ + (void) tng_data; + TNG_ASSERT(atom, "TNG library: atom must not be NULL"); + TNG_ASSERT(type, "TNG library: type must not be a NULL pointer"); + + strncpy(type, atom->atom_type, max_len - 1); + type[max_len - 1] = 0; + + if(strlen(atom->atom_type) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_atom_type_set + (const tng_trajectory_t tng_data, + const tng_atom_t atom, + const char *new_type) +{ + unsigned int len; + (void)tng_data; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(new_type, "TNG library: new_type must not be a NULL pointer."); + + len = tng_min_size(strlen(new_type) + 1, TNG_MAX_STR_LEN); + + /* If the currently stored string length is not enough to store the new + * string it is freed and reallocated. */ + if(atom->atom_type && strlen(atom->atom_type) < len) + { + free(atom->atom_type); + atom->atom_type = 0; + } + if(!atom->atom_type) + { + atom->atom_type = (char *)malloc(len); + if(!atom->atom_type) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(atom->atom_type, new_type, len); + + return(TNG_SUCCESS); +} + +/** + * @brief Initialise an atom struct + * @param atom is the atom to initialise. + * @return TNG_SUCCESS (0) if successful. + */ +static tng_function_status tng_atom_init(const tng_atom_t atom) +{ + atom->name = 0; + atom->atom_type = 0; + + return(TNG_SUCCESS); +} + +/** + * @brief Free the memory in an atom struct + * @param atom is the atom to destroy. + * @return TNG_SUCCESS (0) if successful. + */ +static tng_function_status tng_atom_destroy(const tng_atom_t atom) +{ + if(atom->name) + { + free(atom->name); + atom->name = 0; + } + if(atom->atom_type) + { + free(atom->atom_type); + atom->atom_type = 0; + } + + return(TNG_SUCCESS); +} + +/** + * @brief Update chain->residue pointers (after new memory for + * molecule->residues has been allocated). + * @param tng_data The trajectory container containing the molecule. + * @param mol The molecule that contains the chains that need to be + * updated. + * @returns TNG_SUCCESS (0) if successful. + */ +static tng_function_status tng_molecule_chains_residue_pointers_update + (const tng_trajectory_t tng_data, + const tng_molecule_t mol) +{ + tng_chain_t chain; + int64_t i, res_cnt = 0; + (void)tng_data; + + for(i = 0; i < mol->n_chains; i++) + { + chain = &mol->chains[i]; + chain->residues = mol->residues + res_cnt; + res_cnt += chain->n_residues; + } + return(TNG_SUCCESS); +} + +/** + * @brief Update atoms->residue pointers (after new memory for + * molecule->residues has been allocated). + * @param tng_data The trajectory container containing the molecule. + * @param mol The molecule that contains the chains that need to be + * updated. + * @returns TNG_SUCCESS (0) if successful. + */ +static tng_function_status tng_molecule_atoms_residue_pointers_update + (const tng_trajectory_t tng_data, + const tng_molecule_t mol) +{ + tng_atom_t atom; + tng_residue_t residue; + int64_t i, j, atom_offset = 0; + (void)tng_data; + + for(i = 0; i < mol->n_residues; i++) + { + residue = &mol->residues[i]; + for(j = 0; j < residue->n_atoms; j++) + { + atom = &mol->atoms[j + atom_offset]; + atom->residue = residue; + } + atom_offset += residue->n_atoms; + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_version_major + (const tng_trajectory_t tng_data, + int *version) +{ + (void)tng_data; + + *version = TNG_VERSION_MAJOR; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_version_minor + (const tng_trajectory_t tng_data, + int *version) +{ + (void)tng_data; + + *version = TNG_VERSION_MINOR; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_version_patchlevel + (const tng_trajectory_t tng_data, + int *patch_level) +{ + (void)tng_data; + + *patch_level = TNG_VERSION_PATCHLEVEL; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_version + (const tng_trajectory_t tng_data, + char *version, + const int max_len) +{ + (void)tng_data; + TNG_ASSERT(version, "TNG library: version must not be a NULL pointer"); + + TNG_SNPRINTF(version, max_len, "%s", TNG_VERSION); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_add + (const tng_trajectory_t tng_data, + const char *name, + tng_molecule_t *molecule) +{ + int64_t id; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + /* Set ID to the ID of the last molecule + 1 */ + if(tng_data->n_molecules) + { + id = tng_data->molecules[tng_data->n_molecules-1].id + 1; + } + else + { + id = 1; + } + + return(tng_molecule_w_id_add(tng_data, name, id, molecule)); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_w_id_add + (const tng_trajectory_t tng_data, + const char *name, + const int64_t id, + tng_molecule_t *molecule) +{ + tng_molecule_t new_molecules; + int64_t *new_molecule_cnt_list; + tng_function_status stat = TNG_SUCCESS; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + new_molecules = (tng_molecule_t)realloc(tng_data->molecules, + sizeof(struct tng_molecule) * + (tng_data->n_molecules + 1)); + + if(!new_molecules) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(tng_data->molecules); + tng_data->molecules = 0; + return(TNG_CRITICAL); + } + + new_molecule_cnt_list = (int64_t *)realloc(tng_data->molecule_cnt_list, + sizeof(int64_t) * + (tng_data->n_molecules + 1)); + + if(!new_molecule_cnt_list) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(tng_data->molecule_cnt_list); + tng_data->molecule_cnt_list = 0; + free(new_molecules); + return(TNG_CRITICAL); + } + + tng_data->molecules = new_molecules; + tng_data->molecule_cnt_list = new_molecule_cnt_list; + + *molecule = &new_molecules[tng_data->n_molecules]; + + tng_molecule_init(tng_data, *molecule); + tng_molecule_name_set(tng_data, *molecule, name); + + /* FIXME: Should this be a function argument instead? */ + tng_data->molecule_cnt_list[tng_data->n_molecules] = 0; + + (*molecule)->id = id; + + tng_data->n_molecules++; + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_existing_add + (const tng_trajectory_t tng_data, + tng_molecule_t *molecule_p) +{ + int64_t *new_molecule_cnt_list, id; + tng_molecule_t new_molecules, molecule; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + /* Set ID to the ID of the last molecule + 1 */ + if(tng_data->n_molecules) + { + id = tng_data->molecules[tng_data->n_molecules-1].id + 1; + } + else + { + id = 1; + } + + new_molecules = (tng_molecule_t)realloc(tng_data->molecules, + sizeof(struct tng_molecule) * + (tng_data->n_molecules + 1)); + + if(!new_molecules) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(tng_data->molecules); + tng_data->molecules = 0; + return(TNG_CRITICAL); + } + + new_molecule_cnt_list = (int64_t *)realloc(tng_data->molecule_cnt_list, + sizeof(int64_t) * + (tng_data->n_molecules + 1)); + + if(!new_molecule_cnt_list) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(tng_data->molecule_cnt_list); + tng_data->molecule_cnt_list = 0; + free(new_molecules); + return(TNG_CRITICAL); + } + + molecule = *molecule_p; + + tng_data->molecules = new_molecules; + tng_data->molecule_cnt_list = new_molecule_cnt_list; + + new_molecules[tng_data->n_molecules] = *molecule; + + tng_data->molecule_cnt_list[tng_data->n_molecules] = 0; + + free(*molecule_p); + + molecule = &new_molecules[tng_data->n_molecules]; + + *molecule_p = molecule; + + molecule->id = id; + + tng_data->n_molecules++; + + return(TNG_SUCCESS); +} + +tng_function_status tng_molecule_name_get(const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + char *name, + const int max_len) +{ + (void) tng_data; + TNG_ASSERT(molecule, "TNG library: molecule must not be NULL"); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer"); + + strncpy(name, molecule->name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(molecule->name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_name_set + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const char *new_name) +{ + unsigned int len; + (void)tng_data; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer."); + + len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN); + + /* If the currently stored string length is not enough to store the new + * string it is freed and reallocated. */ + if(molecule->name && strlen(molecule->name) < len) + { + free(molecule->name); + molecule->name = 0; + } + if(!molecule->name) + { + molecule->name = (char *)malloc(len); + if(!molecule->name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(molecule->name, new_name, len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + int64_t *cnt) +{ + int64_t i, index = -1; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(cnt, "TNG library: cnt must not be a NULL pointer."); + + for(i = 0; i < tng_data->n_molecules; i++) + { + if(&tng_data->molecules[i] == molecule) + { + index = i; + break; + } + } + if(index == -1) + { + return(TNG_FAILURE); + } + *cnt = tng_data->molecule_cnt_list[index]; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_set + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const int64_t cnt) +{ + int64_t i, old_cnt, index = -1; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + for(i = 0; i < tng_data->n_molecules; i++) + { + if(&tng_data->molecules[i] == molecule) + { + index = i; + break; + } + } + if(index == -1) + { + fprintf(stderr, "TNG library: Could not find molecule in TNG trajectory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS) + { + old_cnt = tng_data->molecule_cnt_list[index]; + tng_data->molecule_cnt_list[index] = cnt; + + tng_data->n_particles += (cnt-old_cnt) * + tng_data->molecules[index].n_atoms; + } + else + { + old_cnt = tng_data->current_trajectory_frame_set.molecule_cnt_list[index]; + tng_data->current_trajectory_frame_set.molecule_cnt_list[index] = cnt; + + tng_data->current_trajectory_frame_set.n_particles += (cnt-old_cnt) * + tng_data->molecules[index].n_atoms; + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_find + (const tng_trajectory_t tng_data, + const char *name, + const int64_t nr, + tng_molecule_t *molecule) +{ + int64_t i, n_molecules; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer."); + + n_molecules = tng_data->n_molecules; + + for(i = n_molecules - 1; i >= 0; i--) + { + *molecule = &tng_data->molecules[i]; + if(name[0] == 0 || strcmp(name, (*molecule)->name) == 0) + { + if(nr == -1 || nr == (*molecule)->id) + { + return(TNG_SUCCESS); + } + } + } + + *molecule = 0; + + return(TNG_FAILURE); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_of_index_get + (const tng_trajectory_t tng_data, + const int64_t index, + tng_molecule_t *molecule) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer."); + + if(index >= tng_data->n_molecules) + { + *molecule = 0; + return(TNG_FAILURE); + } + *molecule = &tng_data->molecules[index]; + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_system_copy(const tng_trajectory_t tng_data_src, + const tng_trajectory_t tng_data_dest) +{ + tng_molecule_t molecule, molecule_temp; + tng_chain_t chain, chain_temp; + tng_residue_t residue, residue_temp; + tng_atom_t atom, atom_temp; + tng_bond_t bond_temp; + tng_function_status stat; + int64_t i, j, k, l, *list_temp; + + TNG_ASSERT(tng_data_src, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(tng_data_dest, "TNG library: Trajectory container not properly setup."); + + for(i = 0; i < tng_data_dest->n_molecules; i++) + { + molecule = &tng_data_dest->molecules[i]; + tng_molecule_destroy(tng_data_dest, molecule); + } + + tng_data_dest->n_molecules = 0; + tng_data_dest->n_particles = 0; + + molecule_temp = (tng_molecule_t)realloc(tng_data_dest->molecules, + sizeof(struct tng_molecule) * tng_data_src->n_molecules); + if(!molecule_temp) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(tng_data_dest->molecules); + tng_data_dest->molecules = 0; + return(TNG_CRITICAL); + } + list_temp = (int64_t *)realloc(tng_data_dest->molecule_cnt_list, + sizeof(int64_t) * tng_data_src->n_molecules); + if(!list_temp) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(tng_data_dest->molecule_cnt_list); + tng_data_dest->molecule_cnt_list = 0; + free(molecule_temp); + return(TNG_CRITICAL); + } + + tng_data_dest->molecules = molecule_temp; + tng_data_dest->molecule_cnt_list = list_temp; + + for(i = 0; i < tng_data_src->n_molecules; i++) + { + molecule = &tng_data_src->molecules[i]; + stat = tng_molecule_w_id_add(tng_data_dest, molecule->name, molecule->id, + &molecule_temp); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot create new molecule to make a copy. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + molecule_temp->quaternary_str = molecule->quaternary_str; + for(j = 0; j < molecule->n_chains; j++) + { + chain = &molecule->chains[j]; + stat = tng_molecule_chain_w_id_add(tng_data_dest, molecule_temp, + chain->name, chain->id, + &chain_temp); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot create new chain to make a copy. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + for(k = 0; k < chain->n_residues; k++) + { + residue = &chain->residues[k]; + stat = tng_chain_residue_w_id_add(tng_data_dest, chain_temp, + residue->name, residue->id, + &residue_temp); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot create new residue to make a copy. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + for(l = 0; l < residue->n_atoms; l++) + { + atom = &molecule->atoms[residue->atoms_offset + l]; + stat = tng_residue_atom_w_id_add(tng_data_dest, residue_temp, + atom->name, atom->atom_type, + atom->id, &atom_temp); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot create new atom to make a copy. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + } + } + molecule_temp->n_bonds = molecule->n_bonds; + if(molecule->n_bonds > 0) + { + bond_temp = (tng_bond_t)realloc(molecule_temp->bonds, sizeof(struct tng_bond) * + molecule->n_bonds); + if(!bond_temp) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(molecule_temp->bonds); + molecule_temp->n_bonds = 0; + return(TNG_CRITICAL); + } + molecule_temp->bonds = bond_temp; + for(j = 0; j < molecule->n_bonds; j++) + { + molecule_temp->bonds[j] = molecule->bonds[j]; + } + } + stat = tng_molecule_cnt_set(tng_data_dest, molecule_temp, + tng_data_src->molecule_cnt_list[i]); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot set molecule count. %s: %d.\n", + __FILE__, __LINE__); + return(stat); + } + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_num_chains_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + int64_t *n) +{ + (void) tng_data; + TNG_ASSERT(molecule, "TNG library: molecule must not be NULL"); + TNG_ASSERT(n, "TNG library: n must not be a NULL pointer"); + + *n = molecule->n_chains; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_of_index_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const int64_t index, + tng_chain_t *chain) +{ + (void) tng_data; + TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer."); + TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer."); + + if(index >= molecule->n_chains) + { + *chain = 0; + return(TNG_FAILURE); + } + *chain = &molecule->chains[index]; + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_num_residues_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + int64_t *n) +{ + (void) tng_data; + TNG_ASSERT(molecule, "TNG library: molecule must not be NULL"); + TNG_ASSERT(n, "TNG library: n must not be a NULL pointer"); + + *n = molecule->n_residues; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_residue_of_index_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const int64_t index, + tng_residue_t *residue) +{ + (void) tng_data; + TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer."); + TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer."); + + if(index >= molecule->n_residues) + { + *residue = 0; + return(TNG_FAILURE); + } + *residue = &molecule->residues[index]; + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_num_atoms_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + int64_t *n) +{ + (void) tng_data; + TNG_ASSERT(molecule, "TNG library: molecule must not be NULL"); + TNG_ASSERT(n, "TNG library: n must not be a NULL pointer"); + + *n = molecule->n_atoms; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_of_index_get + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const int64_t index, + tng_atom_t *atom) +{ + (void) tng_data; + TNG_ASSERT(molecule, "TNG library: molecule must not be a NULL pointer."); + TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer."); + + if(index >= molecule->n_atoms) + { + *atom = 0; + return(TNG_FAILURE); + } + *atom = &molecule->atoms[index]; + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_find + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const char *name, + const int64_t nr, + tng_chain_t *chain) +{ + int64_t i, n_chains; + (void)tng_data; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + n_chains = molecule->n_chains; + + for(i = n_chains - 1; i >= 0; i--) + { + *chain = &molecule->chains[i]; + if(name[0] == 0 || strcmp(name, (*chain)->name) == 0) + { + if(nr == -1 || nr == (*chain)->id) + { + return(TNG_SUCCESS); + } + } + } + + *chain = 0; + + return(TNG_FAILURE); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_add + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const char *name, + tng_chain_t *chain) +{ + int64_t id; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + /* Set ID to the ID of the last chain + 1 */ + if(molecule->n_chains) + { + id = molecule->chains[molecule->n_chains-1].id + 1; + } + else + { + id = 1; + } + + return(tng_molecule_chain_w_id_add(tng_data, molecule, name, + id, chain)); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_chain_w_id_add + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const char *name, + const int64_t id, + tng_chain_t *chain) +{ + tng_chain_t new_chains; + tng_function_status stat = TNG_SUCCESS; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + new_chains = (tng_chain_t)realloc(molecule->chains, + sizeof(struct tng_chain) * + (molecule->n_chains + 1)); + + if(!new_chains) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(molecule->chains); + molecule->chains = 0; + return(TNG_CRITICAL); + } + + molecule->chains = new_chains; + + *chain = &new_chains[molecule->n_chains]; + (*chain)->name = 0; + + tng_chain_name_set(tng_data, *chain, name); + + (*chain)->molecule = molecule; + (*chain)->n_residues = 0; + + molecule->n_chains++; + + (*chain)->id = id; + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_bond_add + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const int64_t from_atom_id, + const int64_t to_atom_id, + tng_bond_t *bond) +{ + tng_bond_t new_bonds; + (void)tng_data; + + new_bonds = (tng_bond_t)realloc(molecule->bonds, + sizeof(struct tng_bond) * + (molecule->n_bonds + 1)); + + if(!new_bonds) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + *bond = 0; + free(molecule->bonds); + molecule->bonds = 0; + return(TNG_CRITICAL); + } + + molecule->bonds = new_bonds; + + *bond = &new_bonds[molecule->n_bonds]; + + (*bond)->from_atom_id = from_atom_id; + (*bond)->to_atom_id = to_atom_id; + + molecule->n_bonds++; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_atom_find + (const tng_trajectory_t tng_data, + const tng_molecule_t molecule, + const char *name, + const int64_t id, + tng_atom_t *atom) +{ + int64_t i, n_atoms; + (void)tng_data; + + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + n_atoms = molecule->n_atoms; + + for(i = n_atoms - 1; i >= 0; i--) + { + *atom = &molecule->atoms[i]; + if(name[0] == 0 || strcmp(name, (*atom)->name) == 0) + { + if(id == -1 || id == (*atom)->id) + { + return(TNG_SUCCESS); + } + } + } + + *atom = 0; + + return(TNG_FAILURE); +} + +tng_function_status tng_chain_name_get(const tng_trajectory_t tng_data, + const tng_chain_t chain, + char *name, + const int max_len) +{ + (void) tng_data; + TNG_ASSERT(chain, "TNG library: chain must not be NULL"); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer"); + + strncpy(name, chain->name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(chain->name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_chain_name_set + (const tng_trajectory_t tng_data, + const tng_chain_t chain, + const char *new_name) +{ + unsigned int len; + (void)tng_data; + + TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer."); + + len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN); + + /* If the currently stored string length is not enough to store the new + * string it is freed and reallocated. */ + if(chain->name && strlen(chain->name) < len) + { + free(chain->name); + chain->name = 0; + } + if(!chain->name) + { + chain->name = (char *)malloc(len); + if(!chain->name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(chain->name, new_name, len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_chain_num_residues_get + (const tng_trajectory_t tng_data, + const tng_chain_t chain, + int64_t *n) +{ + (void) tng_data; + TNG_ASSERT(chain, "TNG library: chain must not be NULL"); + TNG_ASSERT(n, "TNG library: n must not be a NULL pointer"); + + *n = chain->n_residues; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_chain_residue_of_index_get + (const tng_trajectory_t tng_data, + const tng_chain_t chain, + const int64_t index, + tng_residue_t *residue) +{ + (void) tng_data; + TNG_ASSERT(chain, "TNG library: chain must not be a NULL pointer."); + TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer."); + + if(index >= chain->n_residues) + { + *residue = 0; + return(TNG_FAILURE); + } + *residue = &chain->residues[index]; + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_chain_residue_find + (const tng_trajectory_t tng_data, + const tng_chain_t chain, + const char *name, + const int64_t id, + tng_residue_t *residue) +{ + int64_t i, n_residues; + (void)tng_data; + + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + n_residues = chain->n_residues; + + for(i = n_residues - 1; i >= 0; i--) + { + *residue = &chain->residues[i]; + if(name[0] == 0 || strcmp(name, (*residue)->name) == 0) + { + if(id == -1 || id == (*residue)->id) + { + return(TNG_SUCCESS); + } + } + } + + *residue = 0; + + return(TNG_FAILURE); +} + +tng_function_status DECLSPECDLLEXPORT tng_chain_residue_add + (const tng_trajectory_t tng_data, + const tng_chain_t chain, + const char *name, + tng_residue_t *residue) +{ + int64_t id; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + /* Set ID to the ID of the last residue + 1 */ + if(chain->n_residues) + { + id = chain->residues[chain->n_residues-1].id + 1; + } + else + { + id = 0; + } + + return(tng_chain_residue_w_id_add(tng_data, chain, name, + id, residue)); +} + +tng_function_status DECLSPECDLLEXPORT tng_chain_residue_w_id_add + (const tng_trajectory_t tng_data, + const tng_chain_t chain, + const char *name, + const int64_t id, + tng_residue_t *residue) +{ + int64_t curr_index; + tng_residue_t new_residues, temp_residue, last_residue; + tng_molecule_t molecule = chain->molecule; + tng_function_status stat = TNG_SUCCESS; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + if(chain->n_residues) + { + curr_index = chain->residues - molecule->residues; + } + else + { + curr_index = -1; + } + + new_residues = (tng_residue_t)realloc(molecule->residues, + sizeof(struct tng_residue) * + (molecule->n_residues + 1)); + + if(!new_residues) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(molecule->residues); + molecule->residues = 0; + return(TNG_CRITICAL); + } + + molecule->residues = new_residues; + + if(curr_index != -1) + { + chain->residues = new_residues + curr_index; + if(molecule->n_residues) + { + last_residue = &new_residues[molecule->n_residues - 1]; + + temp_residue = chain->residues + (chain->n_residues - 1); + /* Make space in list of residues to add the new residues together with the other + * residues of this chain */ + if(temp_residue != last_residue) + { + ++temp_residue; + memmove(temp_residue + 1, temp_residue, + last_residue - temp_residue); + } + } + } + else + { + curr_index = molecule->n_residues; + } + + *residue = &molecule->residues[curr_index + chain->n_residues]; + + tng_molecule_chains_residue_pointers_update(tng_data, molecule); + tng_molecule_atoms_residue_pointers_update(tng_data, molecule); + + (*residue)->name = 0; + tng_residue_name_set(tng_data, *residue, name); + + (*residue)->chain = chain; + (*residue)->n_atoms = 0; + (*residue)->atoms_offset = 0; + + chain->n_residues++; + molecule->n_residues++; + + (*residue)->id = id; + + return(stat); +} + +tng_function_status tng_residue_name_get(const tng_trajectory_t tng_data, + const tng_residue_t residue, + char *name, + const int max_len) +{ + (void) tng_data; + TNG_ASSERT(residue, "TNG library: residue must not be NULL"); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer"); + + strncpy(name, residue->name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(residue->name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_residue_name_set(const tng_trajectory_t tng_data, + const tng_residue_t residue, + const char *new_name) +{ + unsigned int len; + (void)tng_data; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer"); + + len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN); + + /* If the currently stored string length is not enough to store the new + * string it is freed and reallocated. */ + if(residue->name && strlen(residue->name) < len) + { + free(residue->name); + residue->name = 0; + } + if(!residue->name) + { + residue->name = (char *)malloc(len); + if(!residue->name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(residue->name, new_name, len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_residue_num_atoms_get + (const tng_trajectory_t tng_data, + const tng_residue_t residue, + int64_t *n) +{ + (void) tng_data; + TNG_ASSERT(residue, "TNG library: residue must not be NULL"); + TNG_ASSERT(n, "TNG library: n must not be a NULL pointer"); + + *n = residue->n_atoms; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_residue_atom_of_index_get + (const tng_trajectory_t tng_data, + const tng_residue_t residue, + const int64_t index, + tng_atom_t *atom) +{ + tng_chain_t chain; + tng_molecule_t molecule; + + (void) tng_data; + TNG_ASSERT(residue, "TNG library: residue must not be a NULL pointer."); + TNG_ASSERT(atom, "TNG library: atom must not be a NULL pointer."); + + if(index >= residue->n_atoms) + { + *atom = 0; + return(TNG_FAILURE); + } + chain = residue->chain; + molecule = chain->molecule; + + if(index + residue->atoms_offset >= molecule->n_atoms) + { + *atom = 0; + return(TNG_FAILURE); + } + + *atom = &molecule->atoms[residue->atoms_offset + index]; + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_residue_atom_add + (const tng_trajectory_t tng_data, + const tng_residue_t residue, + const char *atom_name, + const char *atom_type, + tng_atom_t *atom) +{ + int64_t id; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer."); + TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer."); + + /* Set ID to the ID of the last atom + 1 */ + if(residue->chain->molecule->n_atoms) + { + id = residue->chain->molecule->atoms[residue->chain->molecule->n_atoms-1].id + 1; + } + else + { + id = 0; + } + + return(tng_residue_atom_w_id_add(tng_data, residue, atom_name, atom_type, + id, atom)); +} + +tng_function_status DECLSPECDLLEXPORT tng_residue_atom_w_id_add + (const tng_trajectory_t tng_data, + const tng_residue_t residue, + const char *atom_name, + const char *atom_type, + const int64_t id, + tng_atom_t *atom) +{ + tng_atom_t new_atoms; + tng_molecule_t molecule = residue->chain->molecule; + tng_function_status stat = TNG_SUCCESS; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(atom_name, "TNG library: atom_name must not be a NULL pointer."); + TNG_ASSERT(atom_type, "TNG library: atom_type must not be a NULL pointer."); + + if(!residue->n_atoms) + { + residue->atoms_offset = molecule->n_atoms; + } + + new_atoms = (tng_atom_t)realloc(molecule->atoms, + sizeof(struct tng_atom) * + (molecule->n_atoms + 1)); + + if(!new_atoms) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(molecule->atoms); + molecule->atoms = 0; + return(TNG_CRITICAL); + } + + molecule->atoms = new_atoms; + + *atom = &new_atoms[molecule->n_atoms]; + + tng_atom_init(*atom); + tng_atom_name_set(tng_data, *atom, atom_name); + tng_atom_type_set(tng_data, *atom, atom_type); + + (*atom)->residue = residue; + + residue->n_atoms++; + molecule->n_atoms++; + + (*atom)->id = id; + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data, + tng_molecule_t *molecule_p) +{ + *molecule_p = (tng_molecule_t)malloc(sizeof(struct tng_molecule)); + if(!*molecule_p) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + tng_molecule_init(tng_data, *molecule_p); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_free(const tng_trajectory_t tng_data, + tng_molecule_t *molecule_p) +{ + if(!*molecule_p) + { + return(TNG_SUCCESS); + } + + tng_molecule_destroy(tng_data, *molecule_p); + + free(*molecule_p); + *molecule_p = 0; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_init(const tng_trajectory_t tng_data, + const tng_molecule_t molecule) +{ + (void)tng_data; + molecule->quaternary_str = 1; + molecule->name = 0; + molecule->n_chains = 0; + molecule->chains = 0; + molecule->n_residues = 0; + molecule->residues = 0; + molecule->n_atoms = 0; + molecule->atoms = 0; + molecule->n_bonds = 0; + molecule->bonds = 0; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_destroy(const tng_trajectory_t tng_data, + const tng_molecule_t molecule) +{ + int64_t i; + (void)tng_data; + + if(molecule->name) + { + free(molecule->name); + molecule->name = 0; + } + + if(molecule->chains) + { + for(i = 0; i < molecule->n_chains; i++) + { + if(molecule->chains[i].name) + { + free(molecule->chains[i].name); + molecule->chains[i].name = 0; + } + } + free(molecule->chains); + molecule->chains = 0; + } + molecule->n_chains = 0; + + if(molecule->residues) + { + for(i = 0; i < molecule->n_residues; i++) + { + if(molecule->residues[i].name) + { + free(molecule->residues[i].name); + molecule->residues[i].name = 0; + } + } + free(molecule->residues); + molecule->residues = 0; + } + molecule->n_residues = 0; + + if(molecule->atoms) + { + for(i = 0; i < molecule->n_atoms; i++) + { + tng_atom_destroy(&molecule->atoms[i]); + } + free(molecule->atoms); + molecule->atoms = 0; + } + molecule->n_atoms = 0; + + if(molecule->bonds) + { + free(molecule->bonds); + molecule->bonds = 0; + } + molecule->n_bonds = 0; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_name_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + char *name, + const int max_len) +{ + int64_t cnt = 0, i, *molecule_cnt_list = 0; + tng_molecule_t mol; + tng_bool found = TNG_FALSE; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list); + + if(!molecule_cnt_list) + { + return(TNG_FAILURE); + } + + for(i = 0; i < tng_data->n_molecules; i++) + { + mol = &tng_data->molecules[i]; + if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr) + { + cnt += mol->n_atoms * molecule_cnt_list[i]; + continue; + } + found = TNG_TRUE; + break; + } + if(!found) + { + return(TNG_FAILURE); + } + + strncpy(name, mol->name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(mol->name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_id_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + int64_t *id) +{ + int64_t cnt = 0, i, *molecule_cnt_list = 0; + tng_molecule_t mol; + tng_bool found = TNG_FALSE; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(id, "TNG library: id must not be a NULL pointer."); + + tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list); + + if(!molecule_cnt_list) + { + return(TNG_FAILURE); + } + + for(i = 0; i < tng_data->n_molecules; i++) + { + mol = &tng_data->molecules[i]; + if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr) + { + cnt += mol->n_atoms * molecule_cnt_list[i]; + continue; + } + found = TNG_TRUE; + break; + } + if(!found) + { + return(TNG_FAILURE); + } + + *id = mol->id; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molsystem_bonds_get + (const tng_trajectory_t tng_data, + int64_t *n_bonds, + int64_t **from_atoms, + int64_t **to_atoms) +{ + int64_t atom_cnt = 0, cnt, mol_cnt, i, j, k; + int64_t from_atom, to_atom, *molecule_cnt_list = 0; + tng_molecule_t mol; + tng_bond_t bond; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(n_bonds, "TNG library: n_bonds must not be a NULL pointer."); + TNG_ASSERT(from_atoms, "TNG library: from_atoms must not be a NULL pointer."); + TNG_ASSERT(to_atoms, "TNG library: to_atoms must not be a NULL pointer."); + + tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list); + + if(!molecule_cnt_list) + { + return(TNG_FAILURE); + } + + *n_bonds = 0; + /* First count the total number of bonds to allocate memory */ + for(i = 0; i < tng_data->n_molecules; i++) + { + mol = &tng_data->molecules[i]; + mol_cnt = molecule_cnt_list[i]; + *n_bonds += mol_cnt * mol->n_bonds; + } + if(*n_bonds == 0) + { + return(TNG_SUCCESS); + } + + *from_atoms = (int64_t *)malloc(sizeof(int64_t) * (*n_bonds)); + if(!*from_atoms) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + *to_atoms = (int64_t *)malloc(sizeof(int64_t) * (*n_bonds)); + if(!*to_atoms) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(*from_atoms); + *from_atoms = 0; + return(TNG_CRITICAL); + } + + cnt = 0; + for(i = 0; i < tng_data->n_molecules; i++) + { + mol = &tng_data->molecules[i]; + mol_cnt = molecule_cnt_list[i]; + for(j = 0; j < mol_cnt; j++) + { + for(k = 0; k < mol->n_bonds; k++) + { + bond = &mol->bonds[k]; + from_atom = atom_cnt + bond->from_atom_id; + to_atom = atom_cnt + bond->to_atom_id; + (*from_atoms)[cnt] = from_atom; + (*to_atoms)[cnt++] = to_atom; + } + atom_cnt += mol->n_atoms; + } + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_chain_name_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + char *name, + const int max_len) +{ + int64_t cnt = 0, i, *molecule_cnt_list = 0; + tng_molecule_t mol; + tng_atom_t atom; + tng_bool found = TNG_FALSE; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list); + + if(!molecule_cnt_list) + { + return(TNG_FAILURE); + } + + for(i = 0; i < tng_data->n_molecules; i++) + { + mol = &tng_data->molecules[i]; + if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr) + { + cnt += mol->n_atoms * molecule_cnt_list[i]; + continue; + } + atom = &mol->atoms[nr % mol->n_atoms]; + found = TNG_TRUE; + break; + } + if(!found) + { + return(TNG_FAILURE); + } + if(!atom->residue || !atom->residue->chain) + { + return(TNG_FAILURE); + } + + strncpy(name, atom->residue->chain->name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(atom->residue->chain->name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_residue_name_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + char *name, + const int max_len) +{ + int64_t cnt = 0, i, *molecule_cnt_list = 0; + tng_molecule_t mol; + tng_atom_t atom; + tng_bool found = TNG_FALSE; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list); + + if(!molecule_cnt_list) + { + return(TNG_FAILURE); + } + + for(i = 0; i < tng_data->n_molecules; i++) + { + mol = &tng_data->molecules[i]; + if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr) + { + cnt += mol->n_atoms * molecule_cnt_list[i]; + continue; + } + atom = &mol->atoms[nr % mol->n_atoms]; + found = TNG_TRUE; + break; + } + if(!found) + { + return(TNG_FAILURE); + } + if(!atom->residue) + { + return(TNG_FAILURE); + } + + strncpy(name, atom->residue->name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(atom->residue->name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_residue_id_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + int64_t *id) +{ + int64_t cnt = 0, i, *molecule_cnt_list = 0; + tng_molecule_t mol; + tng_atom_t atom; + tng_bool found = TNG_FALSE; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(id, "TNG library: id must not be a NULL pointer."); + + tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list); + + if(!molecule_cnt_list) + { + return(TNG_FAILURE); + } + + for(i = 0; i < tng_data->n_molecules; i++) + { + mol = &tng_data->molecules[i]; + if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr) + { + cnt += mol->n_atoms * molecule_cnt_list[i]; + continue; + } + atom = &mol->atoms[nr % mol->n_atoms]; + found = TNG_TRUE; + break; + } + if(!found) + { + return(TNG_FAILURE); + } + if(!atom->residue) + { + return(TNG_FAILURE); + } + + *id = atom->residue->id; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_global_residue_id_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + int64_t *id) +{ + int64_t cnt = 0, i, offset = 0, *molecule_cnt_list = 0; + tng_molecule_t mol; + tng_atom_t atom; + tng_bool found = TNG_FALSE; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(id, "TNG library: id must not be a NULL pointer."); + + tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list); + + if(!molecule_cnt_list) + { + return(TNG_FAILURE); + } + + for(i = 0; i < tng_data->n_molecules; i++) + { + mol = &tng_data->molecules[i]; + if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr) + { + cnt += mol->n_atoms * molecule_cnt_list[i]; + offset += mol->n_residues * molecule_cnt_list[i]; + continue; + } + atom = &mol->atoms[nr % mol->n_atoms]; + found = TNG_TRUE; + break; + } + if(!found) + { + return(TNG_FAILURE); + } + if(!atom->residue) + { + return(TNG_FAILURE); + } + + offset += mol->n_residues * ((nr - cnt) / mol->n_atoms); + + *id = atom->residue->id + offset; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_atom_name_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + char *name, + const int max_len) +{ + int64_t cnt = 0, i, *molecule_cnt_list = 0; + tng_molecule_t mol; + tng_atom_t atom; + tng_bool found = TNG_FALSE; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list); + + if(!molecule_cnt_list) + { + return(TNG_FAILURE); + } + + for(i = 0; i < tng_data->n_molecules; i++) + { + mol = &tng_data->molecules[i]; + if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr) + { + cnt += mol->n_atoms * molecule_cnt_list[i]; + continue; + } + atom = &mol->atoms[nr % mol->n_atoms]; + found = TNG_TRUE; + break; + } + if(!found) + { + return(TNG_FAILURE); + } + + strncpy(name, atom->name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(atom->name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status tng_atom_type_of_particle_nr_get + (const tng_trajectory_t tng_data, + const int64_t nr, + char *type, + const int max_len) +{ + int64_t cnt = 0, i, *molecule_cnt_list = 0; + tng_molecule_t mol; + tng_atom_t atom; + tng_bool found = TNG_FALSE; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(type, "TNG library: type must not be a NULL pointer."); + + tng_molecule_cnt_list_get(tng_data, &molecule_cnt_list); + + if(!molecule_cnt_list) + { + return(TNG_FAILURE); + } + + for(i = 0; i < tng_data->n_molecules; i++) + { + mol = &tng_data->molecules[i]; + if(cnt + mol->n_atoms * molecule_cnt_list[i] - 1 < nr) + { + cnt += mol->n_atoms * molecule_cnt_list[i]; + continue; + } + atom = &mol->atoms[nr % mol->n_atoms]; + found = TNG_TRUE; + break; + } + if(!found) + { + return(TNG_FAILURE); + } + + strncpy(type, atom->atom_type, max_len - 1); + type[max_len - 1] = 0; + + if(strlen(atom->atom_type) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_particle_mapping_add + (const tng_trajectory_t tng_data, + const int64_t num_first_particle, + const int64_t n_particles, + const int64_t *mapping_table) +{ + int64_t i; + tng_particle_mapping_t mapping; + tng_trajectory_frame_set_t frame_set; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + frame_set = &tng_data->current_trajectory_frame_set; + + /* Sanity check of the particle ranges. Split into multiple if + * statements for improved readability */ + for(i = 0; i < frame_set->n_mapping_blocks; i++) + { + mapping = &frame_set->mappings[i]; + if(num_first_particle >= mapping->num_first_particle && + num_first_particle < mapping->num_first_particle + + mapping->n_particles) + { + fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__); + return(TNG_FAILURE); + } + if(num_first_particle + n_particles >= + mapping->num_first_particle && + num_first_particle + n_particles < + mapping->num_first_particle + mapping->n_particles) + { + fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__); + return(TNG_FAILURE); + } + if(mapping->num_first_particle >= num_first_particle && + mapping->num_first_particle < num_first_particle + + n_particles) + { + fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__); + return(TNG_FAILURE); + } + if(mapping->num_first_particle + mapping->n_particles > + num_first_particle && + mapping->num_first_particle + mapping->n_particles < + num_first_particle + n_particles) + { + fprintf(stderr, "TNG library: Particle mapping overlap. %s: %d\n", __FILE__, __LINE__); + return(TNG_FAILURE); + } + } + + frame_set->n_mapping_blocks++; + + mapping = (tng_particle_mapping_t)realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) * + frame_set->n_mapping_blocks); + + if(!mapping) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(frame_set->mappings); + frame_set->mappings = 0; + return(TNG_CRITICAL); + } + frame_set->mappings = mapping; + + frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle; + frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles; + + frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = (int64_t *)malloc(sizeof(int64_t) * n_particles); + if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + for(i=0; imappings[frame_set->n_mapping_blocks - 1].real_particle_numbers[i] = mapping_table[i]; + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_particle_mapping_free(const tng_trajectory_t tng_data) +{ + tng_trajectory_frame_set_t frame_set; + tng_particle_mapping_t mapping; + int64_t i; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + frame_set = &tng_data->current_trajectory_frame_set; + + if(frame_set->n_mapping_blocks && frame_set->mappings) + { + for(i = 0; i < frame_set->n_mapping_blocks; i++) + { + mapping = &frame_set->mappings[i]; + if(mapping->real_particle_numbers) + { + free(mapping->real_particle_numbers); + mapping->real_particle_numbers = 0; + } + } + free(frame_set->mappings); + frame_set->mappings = 0; + frame_set->n_mapping_blocks = 0; + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_trajectory_init(tng_trajectory_t *tng_data_p) +{ + time_t seconds; + tng_trajectory_frame_set_t frame_set; + tng_trajectory_t tng_data; + + *tng_data_p = (tng_trajectory_t)malloc(sizeof(struct tng_trajectory)); + if(!*tng_data_p) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + tng_data = *tng_data_p; + + frame_set = &tng_data->current_trajectory_frame_set; + + tng_data->input_file_path = 0; + tng_data->input_file = 0; + tng_data->input_file_len = 0; + tng_data->output_file_path = 0; + tng_data->output_file = 0; + + tng_data->first_program_name = 0; + tng_data->first_user_name = 0; + tng_data->first_computer_name = 0; + tng_data->first_pgp_signature = 0; + tng_data->last_program_name = 0; + tng_data->last_user_name = 0; + tng_data->last_computer_name = 0; + tng_data->last_pgp_signature = 0; + tng_data->forcefield_name = 0; + + seconds = time(0); + if ( seconds == -1) + { + fprintf(stderr, "TNG library: Cannot get time. %s: %d\n", __FILE__, __LINE__); + } + else + { + tng_data->time = seconds; + } + + tng_data->var_num_atoms_flag = TNG_CONSTANT_N_ATOMS; + tng_data->first_trajectory_frame_set_input_file_pos = -1; + tng_data->last_trajectory_frame_set_input_file_pos = -1; + tng_data->current_trajectory_frame_set_input_file_pos = -1; + tng_data->first_trajectory_frame_set_output_file_pos = -1; + tng_data->last_trajectory_frame_set_output_file_pos = -1; + tng_data->current_trajectory_frame_set_output_file_pos = -1; + tng_data->frame_set_n_frames = 100; + tng_data->n_trajectory_frame_sets = 0; + tng_data->medium_stride_length = 100; + tng_data->long_stride_length = 10000; + + tng_data->time_per_frame = -1; + + tng_data->n_particle_data_blocks = 0; + tng_data->n_data_blocks = 0; + + tng_data->non_tr_particle_data = 0; + tng_data->non_tr_data = 0; + + tng_data->compress_algo_pos = 0; + tng_data->compress_algo_vel = 0; + tng_data->compression_precision = 1000; + tng_data->distance_unit_exponential = -9; + + frame_set->first_frame = -1; + frame_set->n_mapping_blocks = 0; + frame_set->mappings = 0; + frame_set->molecule_cnt_list = 0; + + frame_set->n_particle_data_blocks = 0; + frame_set->n_data_blocks = 0; + + frame_set->tr_particle_data = 0; + frame_set->tr_data = 0; + + frame_set->n_written_frames = 0; + frame_set->n_unwritten_frames = 0; + + frame_set->next_frame_set_file_pos = -1; + frame_set->prev_frame_set_file_pos = -1; + frame_set->medium_stride_next_frame_set_file_pos = -1; + frame_set->medium_stride_prev_frame_set_file_pos = -1; + frame_set->long_stride_next_frame_set_file_pos = -1; + frame_set->long_stride_prev_frame_set_file_pos = -1; + + frame_set->first_frame_time = -1; + + tng_data->n_molecules = 0; + tng_data->molecules = 0; + tng_data->molecule_cnt_list = 0; + tng_data->n_particles = 0; + + { + /* Check the endianness of the computer */ + static int32_t endianness_32 = 0x01234567; + /* 0x01234567 */ + if ( *(const unsigned char*)&endianness_32 == 0x01 ) + { + tng_data->endianness_32 = TNG_BIG_ENDIAN_32; + } + + /* 0x67452301 */ + else if( *(const unsigned char*)&endianness_32 == 0x67 ) + { + tng_data->endianness_32 = TNG_LITTLE_ENDIAN_32; + + } + + /* 0x45670123 */ + else if ( *(const unsigned char*)&endianness_32 == 0x45 ) + { + tng_data->endianness_32 = TNG_BYTE_PAIR_SWAP_32; + } + } + { + static int64_t endianness_64 = 0x0123456789ABCDEFLL; + /* 0x0123456789ABCDEF */ + if ( *(const unsigned char*)&endianness_64 == 0x01 ) + { + tng_data->endianness_64 = TNG_BIG_ENDIAN_64; + } + + /* 0xEFCDAB8967452301 */ + else if ( *(const unsigned char*)&endianness_64 == 0xEF ) + { + tng_data->endianness_64 = TNG_LITTLE_ENDIAN_64; + } + + /* 0x89ABCDEF01234567 */ + else if ( *(const unsigned char*)&endianness_64 == 0x89 ) + { + tng_data->endianness_64 = TNG_QUAD_SWAP_64; + } + + /* 0x45670123CDEF89AB */ + else if ( *(const unsigned char*)&endianness_64 == 0x45 ) + { + tng_data->endianness_64 = TNG_BYTE_PAIR_SWAP_64; + } + + /* 0x23016745AB89EFCD */ + else if ( *(const unsigned char*)&endianness_64 == 0x23 ) + { + tng_data->endianness_64 = TNG_BYTE_SWAP_64; + } + } + + /* By default do not swap the byte order, i.e. keep the byte order of the + * architecture. The input file endianness will be set when reading the + * header. The output endianness can be changed - before the file is + * written. */ + tng_data->input_endianness_swap_func_32 = 0; + tng_data->input_endianness_swap_func_64 = 0; + tng_data->output_endianness_swap_func_32 = 0; + tng_data->output_endianness_swap_func_64 = 0; + + tng_data->current_trajectory_frame_set.next_frame_set_file_pos = -1; + tng_data->current_trajectory_frame_set.prev_frame_set_file_pos = -1; + tng_data->current_trajectory_frame_set.n_frames = 0; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_trajectory_destroy(tng_trajectory_t *tng_data_p) +{ + int64_t i, j, k, l; + int64_t n_particles, n_values_per_frame; + tng_trajectory_t tng_data = *tng_data_p; + tng_trajectory_frame_set_t frame_set; + + if(!*tng_data_p) + { + return(TNG_SUCCESS); + } + + frame_set = &tng_data->current_trajectory_frame_set; + + if(tng_data->input_file) + { + if(tng_data->output_file == tng_data->input_file) + { + tng_frame_set_finalize(tng_data, TNG_USE_HASH); + tng_data->output_file = 0; + } + fclose(tng_data->input_file); + tng_data->input_file = 0; + } + + if(tng_data->input_file_path) + { + free(tng_data->input_file_path); + tng_data->input_file_path = 0; + } + + if(tng_data->output_file) + { + /* FIXME: Do not always write the hash */ + tng_frame_set_finalize(tng_data, TNG_USE_HASH); + fclose(tng_data->output_file); + tng_data->output_file = 0; + } + + if(tng_data->output_file_path) + { + free(tng_data->output_file_path); + tng_data->output_file_path = 0; + } + + if(tng_data->first_program_name) + { + free(tng_data->first_program_name); + tng_data->first_program_name = 0; + } + + if(tng_data->last_program_name) + { + free(tng_data->last_program_name); + tng_data->last_program_name = 0; + } + + if(tng_data->first_user_name) + { + free(tng_data->first_user_name); + tng_data->first_user_name = 0; + } + + if(tng_data->last_user_name) + { + free(tng_data->last_user_name); + tng_data->last_user_name = 0; + } + + if(tng_data->first_computer_name) + { + free(tng_data->first_computer_name); + tng_data->first_computer_name = 0; + } + + if(tng_data->last_computer_name) + { + free(tng_data->last_computer_name); + tng_data->last_computer_name = 0; + } + + if(tng_data->first_pgp_signature) + { + free(tng_data->first_pgp_signature); + tng_data->first_pgp_signature = 0; + } + + if(tng_data->last_pgp_signature) + { + free(tng_data->last_pgp_signature); + tng_data->last_pgp_signature = 0; + } + + if(tng_data->forcefield_name) + { + free(tng_data->forcefield_name); + tng_data->forcefield_name = 0; + } + + tng_frame_set_particle_mapping_free(tng_data); + + if(frame_set->molecule_cnt_list) + { + free(frame_set->molecule_cnt_list); + frame_set->molecule_cnt_list = 0; + } + + if(tng_data->var_num_atoms_flag) + { + n_particles = frame_set->n_particles; + } + else + { + n_particles = tng_data->n_particles; + } + + if(tng_data->non_tr_particle_data) + { + for(i = 0; i < tng_data->n_particle_data_blocks; i++) + { + if(tng_data->non_tr_particle_data[i].values) + { + free(tng_data->non_tr_particle_data[i].values); + tng_data->non_tr_particle_data[i].values = 0; + } + + if(tng_data->non_tr_particle_data[i].strings) + { + n_values_per_frame = tng_data->non_tr_particle_data[i]. + n_values_per_frame; + if(tng_data->non_tr_particle_data[i].strings[0]) + { + for(j = 0; j < n_particles; j++) + { + if(tng_data->non_tr_particle_data[i].strings[0][j]) + { + for(k = 0; k < n_values_per_frame; k++) + { + if(tng_data->non_tr_particle_data[i]. + strings[0][j][k]) + { + free(tng_data->non_tr_particle_data[i]. + strings[0][j][k]); + tng_data->non_tr_particle_data[i]. + strings[0][j][k] = 0; + } + } + free(tng_data->non_tr_particle_data[i]. + strings[0][j]); + tng_data->non_tr_particle_data[i].strings[0][j] = 0; + } + } + free(tng_data->non_tr_particle_data[i].strings[0]); + tng_data->non_tr_particle_data[i].strings[0] = 0; + } + free(tng_data->non_tr_particle_data[i].strings); + tng_data->non_tr_particle_data[i].strings = 0; + } + + if(tng_data->non_tr_particle_data[i].block_name) + { + free(tng_data->non_tr_particle_data[i].block_name); + tng_data->non_tr_particle_data[i].block_name = 0; + } + } + free(tng_data->non_tr_particle_data); + tng_data->non_tr_particle_data = 0; + } + + if(tng_data->non_tr_data) + { + for(i = 0; i < tng_data->n_data_blocks; i++) + { + if(tng_data->non_tr_data[i].values) + { + free(tng_data->non_tr_data[i].values); + tng_data->non_tr_data[i].values = 0; + } + + if(tng_data->non_tr_data[i].strings) + { + n_values_per_frame = tng_data->non_tr_data[i]. + n_values_per_frame; + if(tng_data->non_tr_data[i].strings[0][0]) + { + for(j = 0; j < n_values_per_frame; j++) + { + if(tng_data->non_tr_data[i].strings[0][0][j]) + { + free(tng_data->non_tr_data[i].strings[0][0][j]); + tng_data->non_tr_data[i].strings[0][0][j] = 0; + } + } + free(tng_data->non_tr_data[i].strings[0][0]); + tng_data->non_tr_data[i].strings[0][0] = 0; + } + free(tng_data->non_tr_data[i].strings[0]); + tng_data->non_tr_data[i].strings[0] = 0; + free(tng_data->non_tr_data[i].strings); + tng_data->non_tr_data[i].strings = 0; + } + + if(tng_data->non_tr_data[i].block_name) + { + free(tng_data->non_tr_data[i].block_name); + tng_data->non_tr_data[i].block_name = 0; + } + } + free(tng_data->non_tr_data); + tng_data->non_tr_data = 0; + } + + tng_data->n_particle_data_blocks = 0; + tng_data->n_data_blocks = 0; + + if(tng_data->compress_algo_pos) + { + free(tng_data->compress_algo_pos); + tng_data->compress_algo_pos = 0; + } + if(tng_data->compress_algo_vel) + { + free(tng_data->compress_algo_vel); + tng_data->compress_algo_vel = 0; + } + + if(frame_set->tr_particle_data) + { + for(i = 0; i < frame_set->n_particle_data_blocks; i++) + { + if(frame_set->tr_particle_data[i].values) + { + free(frame_set->tr_particle_data[i].values); + frame_set->tr_particle_data[i].values = 0; + } + + if(frame_set->tr_particle_data[i].strings) + { + n_values_per_frame = frame_set->tr_particle_data[i]. + n_values_per_frame; + for(j = 0; j < frame_set->tr_particle_data[i].n_frames; j++) + { + if(frame_set->tr_particle_data[i].strings[j]) + { + for(k = 0; k < n_particles; k++) + { + if(frame_set->tr_particle_data[i]. + strings[j][k]) + { + for(l = 0; l < n_values_per_frame; l++) + { + if(frame_set->tr_particle_data[i]. + strings[j][k][l]) + { + free(frame_set->tr_particle_data[i]. + strings[j][k][l]); + frame_set->tr_particle_data[i]. + strings[j][k][l] = 0; + } + } + free(frame_set->tr_particle_data[i]. + strings[j][k]); + frame_set->tr_particle_data[i]. + strings[j][k] = 0; + } + } + free(frame_set->tr_particle_data[i].strings[j]); + frame_set->tr_particle_data[i].strings[j] = 0; + } + } + free(frame_set->tr_particle_data[i].strings); + frame_set->tr_particle_data[i].strings = 0; + } + + if(frame_set->tr_particle_data[i].block_name) + { + free(frame_set->tr_particle_data[i].block_name); + frame_set->tr_particle_data[i].block_name = 0; + } + } + free(frame_set->tr_particle_data); + frame_set->tr_particle_data = 0; + } + + if(frame_set->tr_data) + { + for(i = 0; i < frame_set->n_data_blocks; i++) + { + if(frame_set->tr_data[i].values) + { + free(frame_set->tr_data[i].values); + frame_set->tr_data[i].values = 0; + } + + if(frame_set->tr_data[i].strings) + { + n_values_per_frame = frame_set->tr_data[i]. + n_values_per_frame; + for(j = 0; j < frame_set->tr_data[i].n_frames; j++) + { + if(frame_set->tr_data[i].strings[j]) + { + for(k = 0; k < n_values_per_frame; k++) + { + if(frame_set->tr_data[i].strings[j][k]) + { + free(frame_set->tr_data[i].strings[j][k]); + frame_set->tr_data[i].strings[j][k] = 0; + } + } + free(frame_set->tr_data[i].strings[j]); + frame_set->tr_data[i].strings[j] = 0; + } + } + free(frame_set->tr_data[i].strings); + frame_set->tr_data[i].strings = 0; + } + + if(frame_set->tr_data[i].block_name) + { + free(frame_set->tr_data[i].block_name); + frame_set->tr_data[i].block_name = 0; + } + } + free(frame_set->tr_data); + frame_set->tr_data = 0; + } + + frame_set->n_particle_data_blocks = 0; + frame_set->n_data_blocks = 0; + + if(tng_data->molecules) + { + for(i = 0; i < tng_data->n_molecules; i++) + { + tng_molecule_destroy(tng_data, &tng_data->molecules[i]); + } + free(tng_data->molecules); + tng_data->molecules = 0; + tng_data->n_molecules = 0; + } + if(tng_data->molecule_cnt_list) + { + free(tng_data->molecule_cnt_list); + tng_data->molecule_cnt_list = 0; + } + + free(*tng_data_p); + *tng_data_p = 0; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_trajectory_init_from_src + (const tng_trajectory_t src, + tng_trajectory_t *dest_p) +{ + tng_trajectory_frame_set_t frame_set; + tng_trajectory_t dest; + + TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL."); + + *dest_p = (tng_trajectory_t)malloc(sizeof(struct tng_trajectory)); + if(!*dest_p) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + dest = *dest_p; + + frame_set = &dest->current_trajectory_frame_set; + + if(src->input_file_path) + { + dest->input_file_path = (char *)malloc(strlen(src->input_file_path) + 1); + if(!dest->input_file_path) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + strcpy(dest->input_file_path, src->input_file_path); + dest->input_file_len = src->input_file_len; + } + else + { + dest->input_file_path = 0; + } + dest->input_file = 0; + if(src->output_file_path) + { + dest->output_file_path = (char *)malloc(strlen(src->output_file_path) + 1); + if(!dest->output_file_path) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + strcpy(dest->output_file_path, src->output_file_path); + } + else + { + dest->output_file_path = 0; + } + dest->output_file = 0; + + dest->first_program_name = 0; + dest->first_user_name = 0; + dest->first_computer_name = 0; + dest->first_pgp_signature = 0; + dest->last_program_name = 0; + dest->last_user_name = 0; + dest->last_computer_name = 0; + dest->last_pgp_signature = 0; + dest->forcefield_name = 0; + + dest->var_num_atoms_flag = src->var_num_atoms_flag; + dest->first_trajectory_frame_set_input_file_pos = + src->first_trajectory_frame_set_input_file_pos; + dest->last_trajectory_frame_set_input_file_pos = + src->last_trajectory_frame_set_input_file_pos; + dest->current_trajectory_frame_set_input_file_pos = + src->current_trajectory_frame_set_input_file_pos; + dest->first_trajectory_frame_set_output_file_pos = + src->first_trajectory_frame_set_output_file_pos; + dest->last_trajectory_frame_set_output_file_pos = + src->last_trajectory_frame_set_output_file_pos; + dest->current_trajectory_frame_set_output_file_pos = + src->current_trajectory_frame_set_output_file_pos; + dest->frame_set_n_frames = src->frame_set_n_frames; + dest->n_trajectory_frame_sets = src->n_trajectory_frame_sets; + dest->medium_stride_length = src->medium_stride_length; + dest->long_stride_length = src->long_stride_length; + + dest->time_per_frame = src->time_per_frame; + + /* Currently the non trajectory data blocks are not copied since it + * can lead to problems when freeing memory in a parallel block. */ + dest->n_particle_data_blocks = 0; + dest->n_data_blocks = 0; + dest->non_tr_particle_data = 0; + dest->non_tr_data = 0; + + dest->compress_algo_pos = 0; + dest->compress_algo_vel = 0; + dest->distance_unit_exponential = -9; + dest->compression_precision = 1000; + + frame_set->n_mapping_blocks = 0; + frame_set->mappings = 0; + frame_set->molecule_cnt_list = 0; + + frame_set->n_particle_data_blocks = 0; + frame_set->n_data_blocks = 0; + + frame_set->tr_particle_data = 0; + frame_set->tr_data = 0; + + frame_set->n_written_frames = 0; + frame_set->n_unwritten_frames = 0; + + frame_set->next_frame_set_file_pos = -1; + frame_set->prev_frame_set_file_pos = -1; + frame_set->medium_stride_next_frame_set_file_pos = -1; + frame_set->medium_stride_prev_frame_set_file_pos = -1; + frame_set->long_stride_next_frame_set_file_pos = -1; + frame_set->long_stride_prev_frame_set_file_pos = -1; + frame_set->first_frame = -1; + + dest->n_molecules = 0; + dest->molecules = 0; + dest->molecule_cnt_list = 0; + dest->n_particles = src->n_particles; + + dest->endianness_32 = src->endianness_32; + dest->endianness_64 = src->endianness_64; + dest->input_endianness_swap_func_32 = src->input_endianness_swap_func_32; + dest->input_endianness_swap_func_64 = src->input_endianness_swap_func_64; + dest->output_endianness_swap_func_32 = src->output_endianness_swap_func_32; + dest->output_endianness_swap_func_64 = src->output_endianness_swap_func_64; + + dest->current_trajectory_frame_set.next_frame_set_file_pos = -1; + dest->current_trajectory_frame_set.prev_frame_set_file_pos = -1; + dest->current_trajectory_frame_set.n_frames = 0; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_input_file_get + (const tng_trajectory_t tng_data, + char *file_name, + const int max_len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer"); + + strncpy(file_name, tng_data->input_file_path, max_len - 1); + file_name[max_len - 1] = 0; + + if(strlen(tng_data->input_file_path) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_input_file_set + (const tng_trajectory_t tng_data, + const char *file_name) +{ + unsigned int len; + char *temp; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer"); + + + if(tng_data->input_file_path && strcmp(tng_data->input_file_path, + file_name) == 0) + { + return(TNG_SUCCESS); + } + + if(tng_data->input_file) + { + fclose(tng_data->input_file); + } + + len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN); + temp = (char *)realloc(tng_data->input_file_path, len); + if(!temp) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(tng_data->input_file_path); + tng_data->input_file_path = 0; + return(TNG_CRITICAL); + } + tng_data->input_file_path = temp; + + strncpy(tng_data->input_file_path, file_name, len); + + return(tng_input_file_init(tng_data)); +} + +tng_function_status tng_output_file_get + (const tng_trajectory_t tng_data, + char *file_name, + const int max_len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer"); + + strncpy(file_name, tng_data->output_file_path, max_len - 1); + file_name[max_len - 1] = 0; + + if(strlen(tng_data->output_file_path) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_output_file_set + (const tng_trajectory_t tng_data, + const char *file_name) +{ + int len; + char *temp; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer"); + + if(tng_data->output_file_path && + strcmp(tng_data->output_file_path, file_name) == 0) + { + return(TNG_SUCCESS); + } + + if(tng_data->output_file) + { + fclose(tng_data->output_file); + } + + len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN); + temp = (char *)realloc(tng_data->output_file_path, len); + if(!temp) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(tng_data->output_file_path); + tng_data->output_file_path = 0; + return(TNG_CRITICAL); + } + tng_data->output_file_path = temp; + + strncpy(tng_data->output_file_path, file_name, len); + + return(tng_output_file_init(tng_data)); +} + +tng_function_status DECLSPECDLLEXPORT tng_output_append_file_set + (const tng_trajectory_t tng_data, + const char *file_name) +{ + int len; + char *temp; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(file_name, "TNG library: file_name must not be a NULL pointer"); + + if(tng_data->output_file_path && + strcmp(tng_data->output_file_path, file_name) == 0) + { + return(TNG_SUCCESS); + } + + if(tng_data->output_file) + { + fclose(tng_data->output_file); + } + + len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN); + temp = (char *)realloc(tng_data->output_file_path, len); + if(!temp) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(tng_data->output_file_path); + tng_data->output_file_path = 0; + return(TNG_CRITICAL); + } + tng_data->output_file_path = temp; + + strncpy(tng_data->output_file_path, file_name, len); + + tng_data->output_file = fopen(tng_data->output_file_path, "rb+"); + if(!tng_data->output_file) + { + fprintf(stderr, "TNG library: Cannot open file %s. %s: %d\n", + tng_data->output_file_path, __FILE__, __LINE__); + return(TNG_CRITICAL); + } + tng_data->input_file = tng_data->output_file; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_get + (const tng_trajectory_t tng_data, tng_file_endianness *endianness) +{ + tng_endianness_32 end_32; + tng_endianness_64 end_64; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(endianness, "TNG library: endianness must not be a NULL pointer"); + + if(tng_data->output_endianness_swap_func_32) + { + /* If other endianness variants are added they must be added here as well */ + if(tng_data->output_endianness_swap_func_32 == + &tng_swap_byte_order_big_endian_32) + { + end_32 = TNG_BIG_ENDIAN_32; + } + else if(tng_data->output_endianness_swap_func_32 == + &tng_swap_byte_order_little_endian_32) + { + end_32 = TNG_LITTLE_ENDIAN_32; + } + else + { + return(TNG_FAILURE); + } + } + else + { + end_32 = (tng_endianness_32)tng_data->endianness_32; + } + + if(tng_data->output_endianness_swap_func_64) + { + /* If other endianness variants are added they must be added here as well */ + if(tng_data->output_endianness_swap_func_64 == + &tng_swap_byte_order_big_endian_64) + { + end_64 = TNG_BIG_ENDIAN_64; + } + else if(tng_data->output_endianness_swap_func_64 == + &tng_swap_byte_order_little_endian_64) + { + end_64 = TNG_LITTLE_ENDIAN_64; + } + else + { + return(TNG_FAILURE); + } + } + else + { + end_64 = (tng_endianness_64)tng_data->endianness_64; + } + + if((int)end_32 != (int)end_64) + { + return(TNG_FAILURE); + } + + if(end_32 == TNG_LITTLE_ENDIAN_32) + { + *endianness = TNG_LITTLE_ENDIAN; + } + + else if(end_32 == TNG_BIG_ENDIAN_32) + { + *endianness = TNG_BIG_ENDIAN; + } + else + { + return(TNG_FAILURE); + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_output_file_endianness_set + (const tng_trajectory_t tng_data, + const tng_file_endianness endianness) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + /* Tne endianness cannot be changed if the data has already been written + * to the output file. */ + if(ftello(tng_data->output_file) > 0) + { + return(TNG_FAILURE); + } + + if(endianness == TNG_BIG_ENDIAN) + { + if(tng_data->endianness_32 == TNG_BIG_ENDIAN_32) + { + tng_data->output_endianness_swap_func_32 = 0; + } + else + { + tng_data->output_endianness_swap_func_32 = + &tng_swap_byte_order_big_endian_32; + } + if(tng_data->endianness_64 == TNG_BIG_ENDIAN_64) + { + tng_data->output_endianness_swap_func_64 = 0; + } + else + { + tng_data->output_endianness_swap_func_64 = + &tng_swap_byte_order_big_endian_64; + } + return(TNG_SUCCESS); + } + else if(endianness == TNG_LITTLE_ENDIAN) + { + if(tng_data->endianness_32 == TNG_LITTLE_ENDIAN_32) + { + tng_data->output_endianness_swap_func_32 = 0; + } + else + { + tng_data->output_endianness_swap_func_32 = + &tng_swap_byte_order_little_endian_32; + } + if(tng_data->endianness_64 == TNG_LITTLE_ENDIAN_64) + { + tng_data->output_endianness_swap_func_64 = 0; + } + else + { + tng_data->output_endianness_swap_func_64 = + &tng_swap_byte_order_little_endian_64; + } + return(TNG_SUCCESS); + } + + /* If the specified endianness is neither big nor little endian return a + * failure. */ + return(TNG_FAILURE); +} + +tng_function_status DECLSPECDLLEXPORT tng_first_program_name_get + (const tng_trajectory_t tng_data, + char *name, + const int max_len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer"); + + strncpy(name, tng_data->first_program_name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(tng_data->first_program_name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_first_program_name_set + (const tng_trajectory_t tng_data, + const char *new_name) +{ + unsigned int len; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer"); + + len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN); + + if(tng_data->first_program_name && strlen(tng_data->first_program_name) < len) + { + free(tng_data->first_program_name); + tng_data->first_program_name = 0; + } + if(!tng_data->first_program_name) + { + tng_data->first_program_name = (char *)malloc(len); + if(!tng_data->first_program_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(tng_data->first_program_name, new_name, len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_last_program_name_get + (const tng_trajectory_t tng_data, + char *name, const int max_len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer"); + + strncpy(name, tng_data->last_program_name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(tng_data->last_program_name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_last_program_name_set + (const tng_trajectory_t tng_data, + const char *new_name) +{ + unsigned int len; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer"); + + len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN); + + if(tng_data->last_program_name && strlen(tng_data->last_program_name) < len) + { + free(tng_data->last_program_name); + tng_data->last_program_name = 0; + } + if(!tng_data->last_program_name) + { + tng_data->last_program_name = (char *)malloc(len); + if(!tng_data->last_program_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(tng_data->last_program_name, new_name, len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_first_user_name_get + (const tng_trajectory_t tng_data, + char *name, const int max_len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer"); + + strncpy(name, tng_data->first_user_name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(tng_data->first_user_name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_first_user_name_set + (const tng_trajectory_t tng_data, + const char *new_name) +{ + unsigned int len; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer"); + + len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN); + + /* If the currently stored string length is not enough to store the new + * string it is freed and reallocated. */ + if(tng_data->first_user_name && strlen(tng_data->first_user_name) < len) + { + free(tng_data->first_user_name); + tng_data->first_user_name = 0; + } + if(!tng_data->first_user_name) + { + tng_data->first_user_name = (char *)malloc(len); + if(!tng_data->first_user_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(tng_data->first_user_name, new_name, len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_last_user_name_get + (const tng_trajectory_t tng_data, + char *name, const int max_len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer"); + + strncpy(name, tng_data->last_user_name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(tng_data->last_user_name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_last_user_name_set + (const tng_trajectory_t tng_data, + const char *new_name) +{ + unsigned int len; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer"); + + len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN); + + /* If the currently stored string length is not enough to store the new + * string it is freed and reallocated. */ + if(tng_data->last_user_name && strlen(tng_data->last_user_name) < len) + { + free(tng_data->last_user_name); + tng_data->last_user_name = 0; + } + if(!tng_data->last_user_name) + { + tng_data->last_user_name = (char *)malloc(len); + if(!tng_data->last_user_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(tng_data->last_user_name, new_name, len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_get + (const tng_trajectory_t tng_data, + char *name, const int max_len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer"); + + strncpy(name, tng_data->first_computer_name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(tng_data->first_computer_name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_first_computer_name_set + (const tng_trajectory_t tng_data, + const char *new_name) +{ + unsigned int len; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer"); + + len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN); + + /* If the currently stored string length is not enough to store the new + * string it is freed and reallocated. */ + if(tng_data->first_computer_name && strlen(tng_data->first_computer_name) < len) + { + free(tng_data->first_computer_name); + tng_data->first_computer_name = 0; + } + if(!tng_data->first_computer_name) + { + tng_data->first_computer_name = (char *)malloc(len); + if(!tng_data->first_computer_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(tng_data->first_computer_name, new_name, len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_get + (const tng_trajectory_t tng_data, + char *name, const int max_len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer"); + + strncpy(name, tng_data->last_computer_name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(tng_data->last_computer_name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_last_computer_name_set + (const tng_trajectory_t tng_data, + const char *new_name) +{ + unsigned int len; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer"); + + len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN); + + /* If the currently stored string length is not enough to store the new + * string it is freed and reallocated. */ + if(tng_data->last_computer_name && strlen(tng_data->last_computer_name) < + len) + { + free(tng_data->last_computer_name); + tng_data->last_computer_name = 0; + } + if(!tng_data->last_computer_name) + { + tng_data->last_computer_name = (char *)malloc(len); + if(!tng_data->last_computer_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(tng_data->last_computer_name, new_name, len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_first_signature_get + (const tng_trajectory_t tng_data, + char *signature, const int max_len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer"); + + strncpy(signature, tng_data->first_pgp_signature, max_len - 1); + signature[max_len - 1] = 0; + + if(strlen(tng_data->first_pgp_signature) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_first_signature_set + (const tng_trajectory_t tng_data, + const char *signature) +{ + unsigned int len; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer"); + + len = tng_min_size(strlen(signature) + 1, TNG_MAX_STR_LEN); + + /* If the currently stored string length is not enough to store the new + * string it is freed and reallocated. */ + if(tng_data->first_pgp_signature && strlen(tng_data->first_pgp_signature) < + len) + { + free(tng_data->first_pgp_signature); + tng_data->first_pgp_signature = 0; + } + if(!tng_data->first_pgp_signature) + { + tng_data->first_pgp_signature = (char *)malloc(len); + if(!tng_data->first_pgp_signature) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(tng_data->first_pgp_signature, signature, len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_last_signature_get + (const tng_trajectory_t tng_data, + char *signature, const int max_len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer"); + + strncpy(signature, tng_data->last_pgp_signature, max_len - 1); + signature[max_len - 1] = 0; + + if(strlen(tng_data->last_pgp_signature) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_last_signature_set + (const tng_trajectory_t tng_data, + const char *signature) +{ + unsigned int len; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(signature, "TNG library: signature must not be a NULL pointer"); + + len = tng_min_size(strlen(signature) + 1, TNG_MAX_STR_LEN); + + /* If the currently stored string length is not enough to store the new + * string it is freed and reallocated. */ + if(tng_data->last_pgp_signature && strlen(tng_data->last_pgp_signature) < + len) + { + free(tng_data->last_pgp_signature); + tng_data->last_pgp_signature = 0; + } + if(!tng_data->last_pgp_signature) + { + tng_data->last_pgp_signature = (char *)malloc(len); + if(!tng_data->last_pgp_signature) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(tng_data->last_pgp_signature, signature, len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_get + (const tng_trajectory_t tng_data, + char *name, const int max_len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer"); + + strncpy(name, tng_data->forcefield_name, max_len - 1); + name[max_len - 1] = 0; + + if(strlen(tng_data->forcefield_name) > (unsigned int)max_len - 1) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_forcefield_name_set + (const tng_trajectory_t tng_data, + const char *new_name) +{ + unsigned int len; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(new_name, "TNG library: new_name must not be a NULL pointer"); + + len = tng_min_size(strlen(new_name) + 1, TNG_MAX_STR_LEN); + + /* If the currently stored string length is not enough to store the new + * string it is freed and reallocated. */ + if(tng_data->forcefield_name && strlen(tng_data->forcefield_name) < len) + { + free(tng_data->forcefield_name); + tng_data->forcefield_name = 0; + } + if(!tng_data->forcefield_name) + { + tng_data->forcefield_name = (char *)malloc(len); + if(!tng_data->forcefield_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + + strncpy(tng_data->forcefield_name, new_name, len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_get + (const tng_trajectory_t tng_data, + int64_t *len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(len, "TNG library: len must not be a NULL pointer"); + + *len = tng_data->medium_stride_length; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_medium_stride_length_set + (const tng_trajectory_t tng_data, + const int64_t len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + if(len >= tng_data->long_stride_length) + { + return(TNG_FAILURE); + } + tng_data->medium_stride_length = len; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_get + (const tng_trajectory_t tng_data, + int64_t *len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(len, "TNG library: len must not be a NULL pointer"); + + *len = tng_data->long_stride_length; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_long_stride_length_set + (const tng_trajectory_t tng_data, + const int64_t len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + if(len <= tng_data->medium_stride_length) + { + return(TNG_FAILURE); + } + tng_data->long_stride_length = len; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_get + (const tng_trajectory_t tng_data, + double *time) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(time, "TNG library: time must not be a NULL pointer"); + + *time = tng_data->time_per_frame; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_time_per_frame_set + (const tng_trajectory_t tng_data, + const double time) +{ + tng_trajectory_frame_set_t frame_set; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(time >= 0, "TNG library: The time per frame must be >= 0."); + + if(fabs(time - tng_data->time_per_frame) < 0.00001) + { + return(TNG_SUCCESS); + } + + frame_set = &tng_data->current_trajectory_frame_set; + + /* If the current frame set is not finished write it to disk before + changing time per frame. */ + if(tng_data->time_per_frame > 0 && frame_set->n_unwritten_frames > 0) + { + frame_set->n_frames = frame_set->n_unwritten_frames; + tng_frame_set_write(tng_data, TNG_USE_HASH); + } + tng_data->time_per_frame = time; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_input_file_len_get + (const tng_trajectory_t tng_data, + int64_t *len) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(len, "TNG library: len must not be a NULL pointer"); + + *len = tng_data->input_file_len; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_num_frames_get + (const tng_trajectory_t tng_data, + int64_t *n) +{ + tng_gen_block_t block; + tng_function_status stat; + int64_t file_pos, last_file_pos, first_frame, n_frames; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set"); + TNG_ASSERT(n, "TNG library: n must not be a NULL pointer"); + + file_pos = ftello(tng_data->input_file); + last_file_pos = tng_data->last_trajectory_frame_set_input_file_pos; + + if(last_file_pos <= 0) + { + return(TNG_FAILURE); + } + + tng_block_init(&block); + fseeko(tng_data->input_file, + last_file_pos, + SEEK_SET); + /* Read block headers first to see that a frame set block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", last_file_pos, + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_FAILURE); + } + tng_block_destroy(&block); + + if(tng_file_input_numerical(tng_data, &first_frame, + sizeof(first_frame), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &n_frames, + sizeof(n_frames), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + fseeko(tng_data->input_file, file_pos, SEEK_SET); + + *n = first_frame + n_frames; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_compression_precision_get + (const tng_trajectory_t tng_data, + double *precision) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + *precision = tng_data->compression_precision; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_compression_precision_set + (const tng_trajectory_t tng_data, + const double precision) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + tng_data->compression_precision = precision; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_implicit_num_particles_set + (const tng_trajectory_t tng_data, + const int64_t n) +{ + tng_molecule_t mol; + tng_chain_t chain; + tng_residue_t res; + tng_atom_t atom; + tng_function_status stat; + int64_t diff, n_mod, n_impl; + + TNG_ASSERT(n >= 0, "TNG library: The requested number of particles must be >= 0"); + + diff = n - tng_data->n_particles; + + stat = tng_molecule_find(tng_data, "TNG_IMPLICIT_MOL", -1, &mol); + if(stat == TNG_SUCCESS) + { + if(tng_molecule_cnt_get(tng_data, mol, &n_impl) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot get the number of implicit molecules. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + diff -= n_impl * mol->n_atoms; + } + + if(diff == 0) + { + if(stat == TNG_SUCCESS) + { + stat = tng_molecule_cnt_set(tng_data, mol, 0); + return(stat); + } + return(TNG_SUCCESS); + } + else if(diff < 0) + { + fprintf(stderr, "TNG library: Already more actual particles than requested implicit "); + fprintf(stderr, "particle count.\n"); + fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n", + __FILE__, __LINE__); + /* FIXME: Should we set the count of all other molecules to 0 and add + * implicit molecules? */ + return(TNG_FAILURE); + } + if(stat != TNG_SUCCESS) + { + stat = tng_molecule_add(tng_data, + "TNG_IMPLICIT_MOL", + &mol); + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_molecule_chain_add(tng_data, mol, "", &chain); + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_chain_residue_add(tng_data, chain, "", &res); + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_residue_atom_add(tng_data, res, "", "", &atom); + if(stat != TNG_SUCCESS) + { + return(stat); + } + } + else + { + if(mol->n_atoms > 1) + { + n_mod = diff % mol->n_atoms; + if(n_mod != 0) + { + fprintf(stderr, "TNG library: Number of atoms in implicit molecule "); + fprintf(stderr, "not compatible with requested implicit particle cnt.\n"); + fprintf(stderr, "TNG library: Cannot set implicit particle count. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + diff /= mol->n_atoms; + } + } + stat = tng_molecule_cnt_set(tng_data, mol, diff); + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_num_particles_get + (const tng_trajectory_t tng_data, + int64_t *n) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(n, "TNG library: n must not be a NULL pointer"); + + if(tng_data->var_num_atoms_flag == TNG_CONSTANT_N_ATOMS) + { + *n = tng_data->n_particles; + } + else + { + *n = tng_data->current_trajectory_frame_set.n_particles; + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_num_particles_variable_get + (const tng_trajectory_t tng_data, + char *variable) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(variable, "TNG library: variable must not be a NULL pointer"); + + *variable = tng_data->var_num_atoms_flag; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_num_molecule_types_get + (const tng_trajectory_t tng_data, + int64_t *n) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(n, "TNG library: n must not be a NULL pointer"); + + *n = tng_data->n_molecules; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_num_molecules_get + (const tng_trajectory_t tng_data, + int64_t *n) +{ + int64_t *cnt_list = 0, cnt = 0, i; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(n, "TNG library: n must not be a NULL pointer"); + + tng_molecule_cnt_list_get(tng_data, &cnt_list); + + if(!cnt_list) + { + return(TNG_FAILURE); + } + + for(i = 0; i < tng_data->n_molecules; i++) + { + cnt += cnt_list[i]; + } + + *n = cnt; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_molecule_cnt_list_get + (const tng_trajectory_t tng_data, + int64_t **mol_cnt_list) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + if(tng_data->var_num_atoms_flag) + { + *mol_cnt_list = tng_data->current_trajectory_frame_set. + molecule_cnt_list; + } + else + { + *mol_cnt_list = tng_data->molecule_cnt_list; + } + if(*mol_cnt_list == 0) + { + return(TNG_FAILURE); + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_get + (const tng_trajectory_t tng_data, + int64_t *exp) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(exp, "TNG library: exp must not be a NULL pointer"); + + *exp = tng_data->distance_unit_exponential; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_distance_unit_exponential_set + (const tng_trajectory_t tng_data, + const int64_t exp) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + tng_data->distance_unit_exponential = exp; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_get + (const tng_trajectory_t tng_data, + int64_t *n) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(n, "TNG library: n must not be a NULL pointer"); + + *n = tng_data->frame_set_n_frames; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_num_frames_per_frame_set_set + (const tng_trajectory_t tng_data, + const int64_t n) +{ + tng_trajectory_frame_set_t frame_set; + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + tng_data->frame_set_n_frames = n; + frame_set = &tng_data->current_trajectory_frame_set; + if(frame_set) + { + frame_set->n_frames = n; + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_num_frame_sets_get + (const tng_trajectory_t tng_data, + int64_t *n) +{ + int64_t long_stride_length, medium_stride_length; + int64_t file_pos, orig_frame_set_file_pos; + tng_trajectory_frame_set_t frame_set; + struct tng_trajectory_frame_set orig_frame_set; + tng_gen_block_t block; + tng_function_status stat; + int64_t cnt = 0; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(n, "TNG library: n must not be a NULL pointer"); + + orig_frame_set = tng_data->current_trajectory_frame_set; + + frame_set = &tng_data->current_trajectory_frame_set; + + orig_frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos; + file_pos = tng_data->first_trajectory_frame_set_input_file_pos; + + if(file_pos < 0) + { + *n = tng_data->n_trajectory_frame_sets = cnt; + return(TNG_SUCCESS); + } + + tng_block_init(&block); + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + tng_data->current_trajectory_frame_set_input_file_pos = file_pos; + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", file_pos, + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + ++cnt; + + long_stride_length = tng_data->long_stride_length; + medium_stride_length = tng_data->medium_stride_length; + + /* Take long steps forward until a long step forward would be too long or + * the last frame set is found */ + file_pos = frame_set->long_stride_next_frame_set_file_pos; + while(file_pos > 0) + { + if(file_pos > 0) + { + cnt += long_stride_length; + fseeko(tng_data->input_file, file_pos, SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + file_pos = frame_set->long_stride_next_frame_set_file_pos; + } + + /* Take medium steps forward until a medium step forward would be too long + * or the last frame set is found */ + file_pos = frame_set->medium_stride_next_frame_set_file_pos; + while(file_pos > 0) + { + if(file_pos > 0) + { + cnt += medium_stride_length; + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + file_pos = frame_set->medium_stride_next_frame_set_file_pos; + } + + /* Take one step forward until the last frame set is found */ + file_pos = frame_set->next_frame_set_file_pos; + while(file_pos > 0) + { + if(file_pos > 0) + { + ++cnt; + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + file_pos = frame_set->next_frame_set_file_pos; + } + + tng_block_destroy(&block); + + *n = tng_data->n_trajectory_frame_sets = cnt; + + *frame_set = orig_frame_set; + /* The mapping block in the original frame set has been freed when reading + * other frame sets. */ + frame_set->mappings = 0; + frame_set->n_mapping_blocks = 0; + + fseeko(tng_data->input_file, + tng_data->first_trajectory_frame_set_input_file_pos, + SEEK_SET); + + tng_data->current_trajectory_frame_set_input_file_pos = orig_frame_set_file_pos; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_current_frame_set_get + (const tng_trajectory_t tng_data, + tng_trajectory_frame_set_t *frame_set_p) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + *frame_set_p = &tng_data->current_trajectory_frame_set; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_nr_find + (const tng_trajectory_t tng_data, + const int64_t nr) +{ + int64_t long_stride_length, medium_stride_length; + int64_t file_pos, curr_nr = 0, n_frame_sets; + tng_trajectory_frame_set_t frame_set; + tng_gen_block_t block; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(nr >= 0, "The frame set number (nr) must be >= 0"); + + frame_set = &tng_data->current_trajectory_frame_set; + + stat = tng_num_frame_sets_get(tng_data, &n_frame_sets); + + if(stat != TNG_SUCCESS) + { + return(stat); + } + + if(nr >= n_frame_sets) + { + return(TNG_FAILURE); + } + + long_stride_length = tng_data->long_stride_length; + medium_stride_length = tng_data->medium_stride_length; + + /* FIXME: The frame set number of the current frame set is not stored */ + + if(nr < n_frame_sets - 1 - nr) + { + /* Start from the beginning */ + file_pos = tng_data->first_trajectory_frame_set_input_file_pos; + } + else + { + /* Start from the end */ + file_pos = tng_data->last_trajectory_frame_set_input_file_pos; + curr_nr = n_frame_sets - 1; + } + if(file_pos <= 0) + { + return(TNG_FAILURE); + } + + tng_block_init(&block); + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + tng_data->current_trajectory_frame_set_input_file_pos = file_pos; + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", file_pos, + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(curr_nr == nr) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + + file_pos = tng_data->current_trajectory_frame_set_input_file_pos; + + /* Take long steps forward until a long step forward would be too long or + * the right frame set is found */ + while(file_pos > 0 && curr_nr + long_stride_length <= nr) + { + file_pos = frame_set->long_stride_next_frame_set_file_pos; + if(file_pos > 0) + { + curr_nr += long_stride_length; + fseeko(tng_data->input_file, file_pos, SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + if(curr_nr == nr) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + } + + /* Take medium steps forward until a medium step forward would be too long + * or the right frame set is found */ + while(file_pos > 0 && curr_nr + medium_stride_length <= nr) + { + file_pos = frame_set->medium_stride_next_frame_set_file_pos; + if(file_pos > 0) + { + curr_nr += medium_stride_length; + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + if(curr_nr == nr) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + } + + /* Take one step forward until the right frame set is found */ + while(file_pos > 0 && curr_nr < nr) + { + file_pos = frame_set->next_frame_set_file_pos; + + if(file_pos > 0) + { + ++curr_nr; + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + if(curr_nr == nr) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + } + + /* Take long steps backward until a long step backward would be too long + * or the right frame set is found */ + while(file_pos > 0 && curr_nr - long_stride_length >= nr) + { + file_pos = frame_set->long_stride_prev_frame_set_file_pos; + if(file_pos > 0) + { + curr_nr -= long_stride_length; + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + if(curr_nr == nr) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + } + + /* Take medium steps backward until a medium step backward would be too long + * or the right frame set is found */ + while(file_pos > 0 && curr_nr - medium_stride_length >= nr) + { + file_pos = frame_set->medium_stride_prev_frame_set_file_pos; + if(file_pos > 0) + { + curr_nr -= medium_stride_length; + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + if(curr_nr == nr) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + } + + /* Take one step backward until the right frame set is found */ + while(file_pos > 0 && curr_nr > nr) + { + file_pos = frame_set->prev_frame_set_file_pos; + if(file_pos > 0) + { + --curr_nr; + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + if(curr_nr == nr) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + } + + /* If for some reason the current frame set is not yet found, + * take one step forward until the right frame set is found */ + while(file_pos > 0 && curr_nr < nr) + { + file_pos = frame_set->next_frame_set_file_pos; + if(file_pos > 0) + { + ++curr_nr; + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + if(curr_nr == nr) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + } + + tng_block_destroy(&block); + return(TNG_FAILURE); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_of_frame_find + (const tng_trajectory_t tng_data, + const int64_t frame) +{ + int64_t first_frame, last_frame, n_frames_per_frame_set; + int64_t long_stride_length, medium_stride_length; + int64_t file_pos, temp_frame, n_frames; + tng_trajectory_frame_set_t frame_set; + tng_gen_block_t block; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(frame >= 0, "TNG library: frame must be >= 0."); + + frame_set = &tng_data->current_trajectory_frame_set; + + tng_block_init(&block); + + if(tng_data->current_trajectory_frame_set_input_file_pos < 0) + { + file_pos = tng_data->first_trajectory_frame_set_input_file_pos; + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + tng_data->current_trajectory_frame_set_input_file_pos = file_pos; + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + + first_frame = tng_max_i64(frame_set->first_frame, 0); + last_frame = first_frame + frame_set->n_frames - 1; + /* Is this the right frame set? */ + if(first_frame <= frame && frame <= last_frame) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + + n_frames_per_frame_set = tng_data->frame_set_n_frames; + long_stride_length = tng_data->long_stride_length; + medium_stride_length = tng_data->medium_stride_length; + + if(tng_first_frame_nr_of_next_frame_set_get(tng_data, &temp_frame) == + TNG_SUCCESS) + { + if(temp_frame - first_frame > n_frames_per_frame_set) + { + n_frames_per_frame_set = temp_frame - first_frame; + } + } + + tng_num_frames_get(tng_data, &n_frames); + + if(frame >= n_frames) + { + tng_block_destroy(&block); + return(TNG_FAILURE); + } + + if(first_frame - frame >= frame || + frame - last_frame > + tng_data->n_trajectory_frame_sets * n_frames_per_frame_set - frame) + { + /* Start from the beginning */ + if(first_frame - frame >= frame) + { + file_pos = tng_data->first_trajectory_frame_set_input_file_pos; + + if(file_pos <= 0) + { + tng_block_destroy(&block); + return(TNG_FAILURE); + } + } + /* Start from the end */ + else if(frame - first_frame > (n_frames - 1) - frame) + { + file_pos = tng_data->last_trajectory_frame_set_input_file_pos; + + /* If the last frame set position is not set start from the current + * frame set, since it will be closer than the first frame set. */ + } + /* Start from current */ + else + { + file_pos = tng_data->current_trajectory_frame_set_input_file_pos; + } + + if(file_pos > 0) + { + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + tng_data->current_trajectory_frame_set_input_file_pos = file_pos; + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + } + + first_frame = tng_max_i64(frame_set->first_frame, 0); + last_frame = first_frame + frame_set->n_frames - 1; + + if(frame >= first_frame && frame <= last_frame) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + + file_pos = tng_data->current_trajectory_frame_set_input_file_pos; + + /* Take long steps forward until a long step forward would be too long or + * the right frame set is found */ + while(file_pos > 0 && first_frame + long_stride_length * + n_frames_per_frame_set <= frame) + { + file_pos = frame_set->long_stride_next_frame_set_file_pos; + if(file_pos > 0) + { + fseeko(tng_data->input_file, file_pos, SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + first_frame = tng_max_i64(frame_set->first_frame, 0); + last_frame = first_frame + frame_set->n_frames - 1; + if(frame >= first_frame && frame <= last_frame) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + + /* Take medium steps forward until a medium step forward would be too long + * or the right frame set is found */ + while(file_pos > 0 && first_frame + medium_stride_length * + n_frames_per_frame_set <= frame) + { + file_pos = frame_set->medium_stride_next_frame_set_file_pos; + if(file_pos > 0) + { + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + first_frame = tng_max_i64(frame_set->first_frame, 0); + last_frame = first_frame + frame_set->n_frames - 1; + if(frame >= first_frame && frame <= last_frame) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + + /* Take one step forward until the right frame set is found */ + while(file_pos > 0 && first_frame < frame && last_frame < frame) + { + file_pos = frame_set->next_frame_set_file_pos; + if(file_pos > 0) + { + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + first_frame = tng_max_i64(frame_set->first_frame, 0); + last_frame = first_frame + frame_set->n_frames - 1; + if(frame >= first_frame && frame <= last_frame) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + + /* Take long steps backward until a long step backward would be too long + * or the right frame set is found */ + while(file_pos > 0 && first_frame - long_stride_length * + n_frames_per_frame_set >= frame) + { + file_pos = frame_set->long_stride_prev_frame_set_file_pos; + if(file_pos > 0) + { + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + first_frame = tng_max_i64(frame_set->first_frame, 0); + last_frame = first_frame + frame_set->n_frames - 1; + if(frame >= first_frame && frame <= last_frame) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + + /* Take medium steps backward until a medium step backward would be too long + * or the right frame set is found */ + while(file_pos > 0 && first_frame - medium_stride_length * + n_frames_per_frame_set >= frame) + { + file_pos = frame_set->medium_stride_prev_frame_set_file_pos; + if(file_pos > 0) + { + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + first_frame = tng_max_i64(frame_set->first_frame, 0); + last_frame = first_frame + frame_set->n_frames - 1; + if(frame >= first_frame && frame <= last_frame) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + + /* Take one step backward until the right frame set is found */ + while(file_pos > 0 && first_frame > frame && last_frame > frame) + { + file_pos = frame_set->prev_frame_set_file_pos; + if(file_pos > 0) + { + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + first_frame = tng_max_i64(frame_set->first_frame, 0); + last_frame = first_frame + frame_set->n_frames - 1; + if(frame >= first_frame && frame <= last_frame) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + + /* If for some reason the current frame set is not yet found, + * take one step forward until the right frame set is found */ + while(file_pos > 0 && first_frame < frame && last_frame < frame) + { + file_pos = frame_set->next_frame_set_file_pos; + if(file_pos > 0) + { + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_block_read_next(tng_data, block, + TNG_SKIP_HASH) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + first_frame = tng_max_i64(frame_set->first_frame, 0); + last_frame = first_frame + frame_set->n_frames - 1; + if(frame >= first_frame && frame <= last_frame) + { + tng_block_destroy(&block); + return(TNG_SUCCESS); + } + } + + tng_block_destroy(&block); + return(TNG_FAILURE); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_next_frame_set_file_pos_get + (const tng_trajectory_t tng_data, + const tng_trajectory_frame_set_t frame_set, + int64_t *pos) +{ + (void)tng_data; + + TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data."); + TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer"); + + *pos = frame_set->next_frame_set_file_pos; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_prev_frame_set_file_pos_get + (const tng_trajectory_t tng_data, + const tng_trajectory_frame_set_t frame_set, + int64_t *pos) +{ + (void)tng_data; + + TNG_ASSERT(frame_set, "TNG library: frame_set not initialised before accessing data."); + TNG_ASSERT(pos, "TNG library: pos must not be a NULL pointer"); + + *pos = frame_set->prev_frame_set_file_pos; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_frame_range_get + (const tng_trajectory_t tng_data, + const tng_trajectory_frame_set_t frame_set, + int64_t *first_frame, + int64_t *last_frame) +{ + (void)tng_data; + + TNG_ASSERT(first_frame, "TNG library: first_frame must not be a NULL pointer"); + TNG_ASSERT(last_frame, "TNG library: last_frame must not be a NULL pointer"); + TNG_ASSERT(frame_set, "TNG library: frame_set must not be a NULL pointer"); + + *first_frame = frame_set->first_frame; + *last_frame = *first_frame + frame_set->n_frames - 1; + + return(TNG_SUCCESS); +} + +/** + * @brief Translate from the particle numbering used in a frame set to the real + * particle numbering - used in the molecule description. + * @param frame_set is the frame_set containing the mappings to use. + * @param local is the index number of the atom in this frame set + * @param real is set to the index of the atom in the molecular system. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping + * cannot be found. + */ +static TNG_INLINE tng_function_status tng_particle_mapping_get_real_particle + (const tng_trajectory_frame_set_t frame_set, + const int64_t local, + int64_t *real) +{ + int64_t i, n_blocks = frame_set->n_mapping_blocks, first; + tng_particle_mapping_t mapping; + if(n_blocks <= 0) + { + *real = local; + return(TNG_SUCCESS); + } + for(i = 0; i < n_blocks; i++) + { + mapping = &frame_set->mappings[i]; + first = mapping->num_first_particle; + if(local < first || + local >= first + mapping->n_particles) + { + continue; + } + *real = mapping->real_particle_numbers[local-first]; + return(TNG_SUCCESS); + } + *real = local; + return(TNG_FAILURE); +} + +/** + * @brief Translate from the real particle numbering to the particle numbering + * used in a frame set. + * @param frame_set is the frame_set containing the mappings to use. + * @param real is the index number of the atom in the molecular system. + * @param local is set to the index of the atom in this frame set. + * @return TNG_SUCCESS (0) if successful or TNG_FAILURE (1) if the mapping + * cannot be found. + */ +/*static TNG_INLINE tng_function_status tng_particle_mapping_get_local_particle + (const tng_trajectory_frame_set_t frame_set, + const int64_t real, + int64_t *local) +{ + int64_t i, j, n_blocks = frame_set->n_mapping_blocks; + tng_particle_mapping_t mapping; + if(n_blocks <= 0) + { + *local = real; + return(TNG_SUCCESS); + } + for(i = 0; i < n_blocks; i++) + { + mapping = &frame_set->mappings[i]; + for(j = mapping->n_particles; j--;) + { + if(mapping->real_particle_numbers[j] == real) + { + *local = j; + return(TNG_SUCCESS); + } + } + } + return(TNG_FAILURE); +} +*/ + +static tng_function_status tng_file_headers_len_get + (const tng_trajectory_t tng_data, + int64_t *len) +{ + int64_t orig_pos; + tng_gen_block_t block; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + *len = 0; + + orig_pos = ftello(tng_data->input_file); + + fseeko(tng_data->input_file, 0, SEEK_SET); + + tng_block_init(&block); + /* Read through the headers of non-trajectory blocks (they come before the + * trajectory blocks in the file) */ + while (*len < tng_data->input_file_len && + tng_block_header_read(tng_data, block) != TNG_CRITICAL && + block->id != -1 && + block->id != TNG_TRAJECTORY_FRAME_SET) + { + *len += block->header_contents_size + block->block_contents_size; + fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR); + } + + fseeko(tng_data->input_file, orig_pos, SEEK_SET); + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_file_headers_read + (const tng_trajectory_t tng_data, + const char hash_mode) +{ + int64_t prev_pos = 0; + tng_gen_block_t block; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + tng_data->n_trajectory_frame_sets = 0; + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + fseeko(tng_data->input_file, 0, SEEK_SET); + + tng_block_init(&block); + /* Non trajectory blocks (they come before the trajectory + * blocks in the file) */ + while (prev_pos < tng_data->input_file_len && + tng_block_header_read(tng_data, block) != TNG_CRITICAL && + block->id != -1 && + block->id != TNG_TRAJECTORY_FRAME_SET) + { + tng_block_read_next(tng_data, block, hash_mode); + prev_pos = ftello(tng_data->input_file); + } + + /* Go back if a trajectory block was encountered */ + if(block->id == TNG_TRAJECTORY_FRAME_SET) + { + fseeko(tng_data->input_file, prev_pos, SEEK_SET); + } + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_file_headers_write + (const tng_trajectory_t tng_data, + const char hash_mode) +{ + int i; + int64_t len, orig_len, tot_len = 0, data_start_pos, temp_pos = -1; + tng_function_status stat; + tng_gen_block_t block; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + if(tng_output_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + if(tng_data->n_trajectory_frame_sets > 0) + { + stat = tng_file_headers_len_get(tng_data, &orig_len); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + tng_block_init(&block); + block->name = (char *)malloc(TNG_MAX_STR_LEN); + if(!block->name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + strcpy(block->name, "GENERAL INFO"); + tng_block_header_len_calculate(tng_data, block, &len); + tot_len += len; + tng_general_info_block_len_calculate(tng_data, &len); + tot_len += len; + strcpy(block->name, "MOLECULES"); + tng_block_header_len_calculate(tng_data, block, &len); + tot_len += len; + tng_molecules_block_len_calculate(tng_data, &len); + tot_len += len; + + for(i = 0; i < tng_data->n_data_blocks; i++) + { + strcpy(block->name, tng_data->non_tr_data[i].block_name); + tng_block_header_len_calculate(tng_data, block, &len); + tot_len += len; + tng_data_block_len_calculate(tng_data, + (tng_data_t)&tng_data->non_tr_data[i], + TNG_FALSE, 1, 1, 1, 0, 1, + &data_start_pos, + &len); + tot_len += len; + } + for(i = 0; i < tng_data->n_particle_data_blocks; i++) + { + strcpy(block->name, tng_data->non_tr_particle_data[i].block_name); + tng_block_header_len_calculate(tng_data, block, &len); + tot_len += len; + tng_data_block_len_calculate(tng_data, + &tng_data->non_tr_particle_data[i], + TNG_TRUE, 1, 1, 1, 0, + tng_data->n_particles, + &data_start_pos, + &len); + tot_len += len; + } + tng_block_destroy(&block); + + if(tot_len > orig_len) + { + tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len, hash_mode); + tng_data->last_trajectory_frame_set_input_file_pos = tng_data->last_trajectory_frame_set_output_file_pos; + } + + stat = tng_reread_frame_set_at_file_pos(tng_data, tng_data->last_trajectory_frame_set_input_file_pos); + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read frame set. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + /* In order to write non-trajectory data the current_trajectory_frame_set_output_file_pos + * must temporarily be reset */ + temp_pos = tng_data->current_trajectory_frame_set_output_file_pos; + tng_data->current_trajectory_frame_set_output_file_pos = -1; + } + + if(tng_general_info_block_write(tng_data, hash_mode) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error writing general info block of file %s. %s: %d\n", + tng_data->input_file_path, __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(tng_molecules_block_write(tng_data, hash_mode) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error writing atom names block of file %s. %s: %d\n", + tng_data->input_file_path, __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + /* FIXME: Currently writing non-trajectory data blocks here. + * Should perhaps be moved. */ + tng_block_init(&block); + for(i = 0; i < tng_data->n_data_blocks; i++) + { + block->id = tng_data->non_tr_data[i].block_id; + tng_data_block_write(tng_data, block, + i, TNG_FALSE, 0, hash_mode); + } + + for(i = 0; i < tng_data->n_particle_data_blocks; i++) + { + block->id = tng_data->non_tr_particle_data[i].block_id; + tng_data_block_write(tng_data, block, + i, TNG_TRUE, 0, hash_mode); + } + + tng_block_destroy(&block); + + /* Continue writing at the end of the file. */ + fseeko(tng_data->output_file, 0, SEEK_END); + if(temp_pos > 0) + { + tng_data->current_trajectory_frame_set_output_file_pos = temp_pos; + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_block_read_next + (const tng_trajectory_t tng_data, + const tng_gen_block_t block, + const char hash_mode) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(block, "TNG library: block must be initialised and must not be a NULL pointer."); + + switch(block->id) + { + case TNG_TRAJECTORY_FRAME_SET: + return(tng_frame_set_block_read(tng_data, block, hash_mode)); + case TNG_PARTICLE_MAPPING: + return(tng_trajectory_mapping_block_read(tng_data, block, hash_mode)); + case TNG_GENERAL_INFO: + return(tng_general_info_block_read(tng_data, block, hash_mode)); + case TNG_MOLECULES: + return(tng_molecules_block_read(tng_data, block, hash_mode)); + default: + if(block->id >= TNG_TRAJ_BOX_SHAPE) + { + return(tng_data_block_contents_read(tng_data, block, hash_mode)); + } + else + { + /* Skip to the next block */ + fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR); + return(TNG_FAILURE); + } + } +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_read + (const tng_trajectory_t tng_data, + const char hash_mode) +{ + int64_t file_pos; + tng_gen_block_t block; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + file_pos = ftello(tng_data->input_file); + + tng_block_init(&block); + + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET || + block->id == -1) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + tng_data->current_trajectory_frame_set_input_file_pos = file_pos; + + if(tng_block_read_next(tng_data, block, + hash_mode) == TNG_SUCCESS) + { + tng_data->n_trajectory_frame_sets++; + file_pos = ftello(tng_data->input_file); + /* Read all blocks until next frame set block */ + stat = tng_block_header_read(tng_data, block); + while(file_pos < tng_data->input_file_len && + stat != TNG_CRITICAL && + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) + { + stat = tng_block_read_next(tng_data, block, + hash_mode); + if(stat != TNG_CRITICAL) + { + file_pos = ftello(tng_data->input_file); + if(file_pos < tng_data->input_file_len) + { + stat = tng_block_header_read(tng_data, block); + } + } + } + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(stat); + } + + if(block->id == TNG_TRAJECTORY_FRAME_SET) + { + fseeko(tng_data->input_file, file_pos, SEEK_SET); + } + } + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_current_only_data_from_block_id + (const tng_trajectory_t tng_data, + const char hash_mode, + const int64_t block_id) +{ + int64_t file_pos; + tng_gen_block_t block; + tng_function_status stat; + int found_flag = 1; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + file_pos = tng_data->current_trajectory_frame_set_input_file_pos; + + if(file_pos < 0) + { + /* No current frame set. This means that the first frame set must be + * read */ + found_flag = 0; + file_pos = tng_data->first_trajectory_frame_set_input_file_pos; + } + + if(file_pos > 0) + { + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + } + else + { + return(TNG_FAILURE); + } + + tng_block_init(&block); + + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + /* If the current frame set had already been read skip its block contents */ + if(found_flag) + { + fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR); + } + /* Otherwise read the frame set block */ + else + { + stat = tng_block_read_next(tng_data, block, + hash_mode); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read frame set block. %s: %d\n", __FILE__, __LINE__); + tng_block_destroy(&block); + return(stat); + } + } + file_pos = ftello(tng_data->input_file); + + found_flag = 0; + + /* Read only blocks of the requested ID + * until next frame set block */ + stat = tng_block_header_read(tng_data, block); + while(file_pos < tng_data->input_file_len && + stat != TNG_CRITICAL && + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) + { + if(block->id == block_id) + { + stat = tng_block_read_next(tng_data, block, + hash_mode); + if(stat != TNG_CRITICAL) + { + file_pos = ftello(tng_data->input_file); + found_flag = 1; + if(file_pos < tng_data->input_file_len) + { + stat = tng_block_header_read(tng_data, block); + } + } + } + else + { + file_pos += block->block_contents_size + block->header_contents_size; + fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR); + if(file_pos < tng_data->input_file_len) + { + stat = tng_block_header_read(tng_data, block); + } + } + } + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(stat); + } + + if(block->id == TNG_TRAJECTORY_FRAME_SET) + { + fseeko(tng_data->input_file, file_pos, SEEK_SET); + } + + tng_block_destroy(&block); + + if(found_flag) + { + return(TNG_SUCCESS); + } + else + { + return(TNG_FAILURE); + } +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next + (const tng_trajectory_t tng_data, + const char hash_mode) +{ + int64_t file_pos; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos; + + if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0) + { + file_pos = tng_data->first_trajectory_frame_set_input_file_pos; + } + + if(file_pos > 0) + { + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + } + else + { + return(TNG_FAILURE); + } + + return(tng_frame_set_read(tng_data, hash_mode)); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_read_next_only_data_from_block_id + (const tng_trajectory_t tng_data, + const char hash_mode, + const int64_t block_id) +{ + int64_t file_pos; + tng_gen_block_t block; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + file_pos = tng_data->current_trajectory_frame_set.next_frame_set_file_pos; + + if(file_pos < 0 && tng_data->current_trajectory_frame_set_input_file_pos <= 0) + { + file_pos = tng_data->first_trajectory_frame_set_input_file_pos; + } + + if(file_pos > 0) + { + fseeko(tng_data->input_file, + file_pos, + SEEK_SET); + } + else + { + return(TNG_FAILURE); + } + + tng_block_init(&block); + + /* Read block headers first to see what block is found. */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + tng_data->current_trajectory_frame_set_input_file_pos = file_pos; + + if(tng_block_read_next(tng_data, block, + hash_mode) == TNG_SUCCESS) + { + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, hash_mode, block_id); + } + + tng_block_destroy(&block); + + return(stat); +} + +tng_function_status tng_frame_set_write + (const tng_trajectory_t tng_data, + const char hash_mode) +{ + int i, j; + tng_gen_block_t block; + tng_trajectory_frame_set_t frame_set; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + frame_set = &tng_data->current_trajectory_frame_set; + + if(frame_set->n_written_frames == frame_set->n_frames) + { + return(TNG_SUCCESS); + } + + tng_data->current_trajectory_frame_set_output_file_pos = + ftello(tng_data->output_file); + tng_data->last_trajectory_frame_set_output_file_pos = + tng_data->current_trajectory_frame_set_output_file_pos; + + if(tng_data->current_trajectory_frame_set_output_file_pos <= 0) + { + return(TNG_FAILURE); + } + + if(tng_data->first_trajectory_frame_set_output_file_pos == -1) + { + tng_data->first_trajectory_frame_set_output_file_pos = + tng_data->current_trajectory_frame_set_output_file_pos; + } + + tng_block_init(&block); + + if(tng_frame_set_block_write(tng_data, block, hash_mode) != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(TNG_FAILURE); + } + + /* Write non-particle data blocks */ + for(i = 0; in_data_blocks; i++) + { + block->id = frame_set->tr_data[i].block_id; + tng_data_block_write(tng_data, block, i, TNG_FALSE, 0, hash_mode); + } + /* Write the mapping blocks and particle data blocks*/ + if(frame_set->n_mapping_blocks) + { + for(i = 0; i < frame_set->n_mapping_blocks; i++) + { + block->id = TNG_PARTICLE_MAPPING; + if(frame_set->mappings[i].n_particles > 0) + { + tng_trajectory_mapping_block_write(tng_data, block, i, hash_mode); + for(j = 0; jn_particle_data_blocks; j++) + { + block->id = frame_set->tr_particle_data[j].block_id; + tng_data_block_write(tng_data, block, + j, TNG_TRUE, &frame_set->mappings[i], + hash_mode); + } + } + } + } + else + { + for(i = 0; in_particle_data_blocks; i++) + { + block->id = frame_set->tr_particle_data[i].block_id; + tng_data_block_write(tng_data, block, + i, TNG_TRUE, 0, hash_mode); + } + } + + + /* Update pointers in the general info block */ + stat = tng_header_pointers_update(tng_data, hash_mode); + + if(stat == TNG_SUCCESS) + { + stat = tng_frame_set_pointers_update(tng_data, hash_mode); + } + + tng_block_destroy(&block); + + frame_set->n_unwritten_frames = 0; + + fflush(tng_data->output_file); + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_premature_write + (const tng_trajectory_t tng_data, + const char hash_mode) +{ + tng_trajectory_frame_set_t frame_set; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + frame_set = &tng_data->current_trajectory_frame_set; + + if(frame_set->n_unwritten_frames == 0) + { + return(TNG_SUCCESS); + } + frame_set->n_frames = frame_set->n_unwritten_frames; + + return(tng_frame_set_write(tng_data, hash_mode)); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_new + (const tng_trajectory_t tng_data, + const int64_t first_frame, + const int64_t n_frames) +{ + tng_gen_block_t block; + tng_trajectory_frame_set_t frame_set; + FILE *temp = tng_data->input_file; + int64_t curr_file_pos; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0."); + TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0."); + + frame_set = &tng_data->current_trajectory_frame_set; + + curr_file_pos = ftello(tng_data->output_file); + + if(curr_file_pos <= 10) + { + tng_file_headers_write(tng_data, TNG_USE_HASH); + } + + /* Set pointer to previous frame set to the one that was loaded + * before. + * FIXME: This is a bit risky. If they are not added in order + * it will be wrong. */ + if(tng_data->n_trajectory_frame_sets) + { + frame_set->prev_frame_set_file_pos = + tng_data->last_trajectory_frame_set_output_file_pos; + } + + frame_set->next_frame_set_file_pos = -1; + + tng_data->current_trajectory_frame_set_output_file_pos = + ftello(tng_data->output_file); + + tng_data->n_trajectory_frame_sets++; + + /* Set the medium range pointers */ + if(tng_data->n_trajectory_frame_sets == tng_data->medium_stride_length + 1) + { + frame_set->medium_stride_prev_frame_set_file_pos = + tng_data->first_trajectory_frame_set_output_file_pos; + } + else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1) + { + /* FIXME: Currently only working if the previous frame set has its + * medium stride pointer already set. This might need some fixing. */ + if(frame_set->medium_stride_prev_frame_set_file_pos != -1 && + frame_set->medium_stride_prev_frame_set_file_pos != 0) + { + tng_block_init(&block); + tng_data->input_file = tng_data->output_file; + + curr_file_pos = ftello(tng_data->output_file); + fseeko(tng_data->output_file, + frame_set->medium_stride_prev_frame_set_file_pos, + SEEK_SET); + + if(tng_block_header_read(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n", + __FILE__, __LINE__); + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + /* Read the next frame set from the previous frame set and one + * medium stride step back */ + fseeko(tng_data->output_file, block->block_contents_size - (6 * + sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR); + if(fread(&frame_set->medium_stride_prev_frame_set_file_pos, + sizeof(frame_set->medium_stride_prev_frame_set_file_pos), + 1, tng_data->output_file) == 0) + { + fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__); + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_data->input_endianness_swap_func_64) + { + if(tng_data->input_endianness_swap_func_64(tng_data, + (uint64_t *)&frame_set->medium_stride_prev_frame_set_file_pos) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + + tng_block_destroy(&block); + + /* Set the long range pointers */ + if(tng_data->n_trajectory_frame_sets == tng_data->long_stride_length + 1) + { + frame_set->long_stride_prev_frame_set_file_pos = + tng_data->first_trajectory_frame_set_output_file_pos; + } + else if(tng_data->n_trajectory_frame_sets > tng_data->medium_stride_length + 1) + { + /* FIXME: Currently only working if the previous frame set has its + * long stride pointer already set. This might need some fixing. */ + if(frame_set->long_stride_prev_frame_set_file_pos != -1 && + frame_set->long_stride_prev_frame_set_file_pos != 0) + { + tng_block_init(&block); + tng_data->input_file = tng_data->output_file; + + fseeko(tng_data->output_file, + frame_set->long_stride_prev_frame_set_file_pos, + SEEK_SET); + + if(tng_block_header_read(tng_data, block) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read frame set header. %s: %d\n", + __FILE__, __LINE__); + tng_data->input_file = temp; + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + /* Read the next frame set from the previous frame set and one + * long stride step back */ + fseeko(tng_data->output_file, block->block_contents_size - (6 * + sizeof(int64_t) + 2 * sizeof(double)), SEEK_CUR); + + tng_block_destroy(&block); + + if(fread(&frame_set->long_stride_prev_frame_set_file_pos, + sizeof(frame_set->long_stride_prev_frame_set_file_pos), + 1, tng_data->output_file) == 0) + { + fprintf(stderr, "TNG library: Cannot read block. %s: %d\n", __FILE__, __LINE__); + tng_data->input_file = temp; + return(TNG_CRITICAL); + } + + if(tng_data->input_endianness_swap_func_64) + { + if(tng_data->input_endianness_swap_func_64(tng_data, + (uint64_t *)&frame_set->long_stride_prev_frame_set_file_pos) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + + } + } + + tng_data->input_file = temp; + fseeko(tng_data->output_file, curr_file_pos, SEEK_SET); + } + } + + frame_set->first_frame = first_frame; + frame_set->n_frames = n_frames; + frame_set->n_written_frames = 0; + frame_set->n_unwritten_frames = 0; + frame_set->first_frame_time = -1; + + if(tng_data->first_trajectory_frame_set_output_file_pos == -1 || + tng_data->first_trajectory_frame_set_output_file_pos == 0) + { + tng_data->first_trajectory_frame_set_output_file_pos = + tng_data->current_trajectory_frame_set_output_file_pos; + } + /* FIXME: Should check the frame number instead of the file_pos, + * in case frame sets are not in order */ + if(tng_data->last_trajectory_frame_set_output_file_pos == -1 || + tng_data->last_trajectory_frame_set_output_file_pos == 0 || + tng_data->last_trajectory_frame_set_output_file_pos < + tng_data->current_trajectory_frame_set_output_file_pos) + { + tng_data->last_trajectory_frame_set_output_file_pos = + tng_data->current_trajectory_frame_set_output_file_pos; + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_with_time_new + (const tng_trajectory_t tng_data, + const int64_t first_frame, + const int64_t n_frames, + const double first_frame_time) +{ + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(first_frame >= 0, "TNG library: first_frame must be >= 0."); + TNG_ASSERT(n_frames >= 0, "TNG library: n_frames must be >= 0."); + TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0."); + + + stat = tng_frame_set_new(tng_data, first_frame, n_frames); + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_frame_set_first_frame_time_set(tng_data, first_frame_time); + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_first_frame_time_set + (const tng_trajectory_t tng_data, + const double first_frame_time) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(first_frame_time >= 0, "TNG library: first_frame_time must be >= 0."); + + tng_data->current_trajectory_frame_set.first_frame_time = first_frame_time; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_first_frame_nr_of_next_frame_set_get + (const tng_trajectory_t tng_data, + int64_t *frame) +{ + int64_t file_pos, next_frame_set_file_pos; + tng_gen_block_t block; + tng_function_status stat; + + tng_trajectory_frame_set_t frame_set; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(tng_data->input_file, "TNG library: An input file must be open to find the next frame set"); + TNG_ASSERT(frame, "TNG library: frame must not be a NULL pointer"); + + file_pos = ftello(tng_data->input_file); + + if(tng_data->current_trajectory_frame_set_input_file_pos <= 0) + { + next_frame_set_file_pos = tng_data->first_trajectory_frame_set_input_file_pos; + } + else + { + frame_set = &tng_data->current_trajectory_frame_set; + next_frame_set_file_pos = frame_set->next_frame_set_file_pos; + } + + if(next_frame_set_file_pos <= 0) + { + return(TNG_FAILURE); + } + + fseeko(tng_data->input_file, next_frame_set_file_pos, SEEK_SET); + /* Read block headers first to see that a frame set block is found. */ + tng_block_init(&block); + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + return(TNG_CRITICAL); + } +/* if(tng_data->current_trajectory_frame_set_input_file_pos <= 0) + { + tng_block_read_next(tng_data, block, TNG_USE_HASH); + }*/ + tng_block_destroy(&block); + + if(fread(frame, sizeof(int64_t), 1, tng_data->input_file) == 0) + { + fprintf(stderr, "TNG library: Cannot read first frame of next frame set. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + fseeko(tng_data->input_file, file_pos, SEEK_SET); + + return(TNG_SUCCESS); +} + +static tng_function_status tng_gen_data_block_add + (const tng_trajectory_t tng_data, + const int64_t id, + const tng_bool is_particle_data, + const char *block_name, + const char datatype, + const char block_type_flag, + int64_t n_frames, + const int64_t n_values_per_frame, + int64_t stride_length, + const int64_t num_first_particle, + const int64_t n_particles, + const int64_t codec_id, + void *new_data) +{ + int i, size, len; + int64_t j, k; + int64_t tot_n_particles, n_frames_div; + char ***first_dim_values, **second_dim_values; + tng_trajectory_frame_set_t frame_set; + tng_data_t data; + char *new_data_c = (char *)new_data; + tng_function_status stat; + + frame_set = &tng_data->current_trajectory_frame_set; + + if(stride_length <= 0) + { + stride_length = 1; + } + + if(is_particle_data) + { + stat = tng_particle_data_find(tng_data, id, &data); + } + else + { + stat = tng_data_find(tng_data, id, &data); + } + /* If the block does not exist, create it */ + if(stat != TNG_SUCCESS) + { + if(is_particle_data) + { + stat = tng_particle_data_block_create(tng_data, block_type_flag); + } + else + { + stat = tng_data_block_create(tng_data, block_type_flag); + } + + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot create particle data block. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + if(is_particle_data) + { + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + data = &frame_set->tr_particle_data[frame_set-> + n_particle_data_blocks - 1]; + } + else + { + data = &tng_data->non_tr_particle_data[tng_data-> + n_particle_data_blocks - 1]; + } + } + else + { + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + data = &frame_set->tr_data[frame_set->n_data_blocks - 1]; + } + else + { + data = &tng_data->non_tr_data[tng_data->n_data_blocks - 1]; + } + } + data->block_id = id; + + data->block_name = (char *)malloc(strlen(block_name) + 1); + if(!data->block_name) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + strncpy(data->block_name, block_name, strlen(block_name) + 1); + + data->values = 0; + /* FIXME: Memory leak from strings. */ + data->strings = 0; + data->last_retrieved_frame = -1; + } + + data->datatype = datatype; + data->stride_length = tng_max_i64(stride_length, 1); + data->n_values_per_frame = n_values_per_frame; + data->n_frames = n_frames; + if(is_particle_data) + { + data->dependency = TNG_PARTICLE_DEPENDENT; + } + else + { + data->dependency = 0; + } + if(block_type_flag == TNG_TRAJECTORY_BLOCK && + (n_frames > 1 || + frame_set->n_frames == n_frames || + stride_length > 1)) + { + data->dependency += TNG_FRAME_DEPENDENT; + } + data->codec_id = codec_id; + data->compression_multiplier = 1.0; + /* FIXME: This can cause problems. */ + data->first_frame_with_data = frame_set->first_frame; + + if(is_particle_data) + { + if(block_type_flag == TNG_TRAJECTORY_BLOCK && tng_data->var_num_atoms_flag) + { + tot_n_particles = frame_set->n_particles; + } + else + { + tot_n_particles = tng_data->n_particles; + } + } + /* This is just to keep the compiler happy - avoid it considering tot_n_particles + * uninitialized. */ + else + { + tot_n_particles = 0; + } + + /* If data values are supplied add that data to the data block. */ + if(new_data_c) + { + /* Allocate memory */ + if(is_particle_data) + { + stat = tng_allocate_particle_data_mem(tng_data, data, n_frames, + stride_length, tot_n_particles, + n_values_per_frame); + } + else + { + stat = tng_allocate_data_mem(tng_data, data, n_frames, stride_length, + n_values_per_frame); + } + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot allocate particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(n_frames > frame_set->n_unwritten_frames) + { + frame_set->n_unwritten_frames = n_frames; + } + + n_frames_div = (n_frames % stride_length) ? + n_frames / stride_length + 1: + n_frames / stride_length; + + if(datatype == TNG_CHAR_DATA) + { + if(is_particle_data) + { + for(i = 0; i < n_frames_div; i++) + { + first_dim_values = data->strings[i]; + for(j = num_first_particle; j < num_first_particle + n_particles; + j++) + { + second_dim_values = first_dim_values[j]; + for(k = 0; k < n_values_per_frame; k++) + { + len = tng_min_size(strlen(new_data_c) + 1, + TNG_MAX_STR_LEN); + if(second_dim_values[k]) + { + free(second_dim_values[k]); + } + second_dim_values[k] = (char *)malloc(len); + if(!second_dim_values[k]) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + strncpy(second_dim_values[k], + new_data_c, len); + new_data_c += len; + } + } + } + } + else + { + for(i = 0; i < n_frames_div; i++) + { + second_dim_values = data->strings[0][i]; + for(j = 0; j < n_values_per_frame; j++) + { + len = tng_min_size(strlen(new_data_c) + 1, + TNG_MAX_STR_LEN); + if(second_dim_values[j]) + { + free(second_dim_values[j]); + } + second_dim_values[j] = (char *)malloc(len); + if(!second_dim_values[j]) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + strncpy(second_dim_values[j], + new_data_c, len); + new_data_c += len; + } + } + } + } + else + { + switch(datatype) + { + case TNG_INT_DATA: + size = sizeof(int64_t); + break; + case TNG_FLOAT_DATA: + size = sizeof(float); + break; + case TNG_DOUBLE_DATA: + default: + size = sizeof(double); + } + + if(is_particle_data) + { + memcpy(data->values, new_data, size * n_frames_div * + n_particles * n_values_per_frame); + } + else + { + memcpy(data->values, new_data, size * n_frames_div * + n_values_per_frame); + } + } + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_data_block_add + (const tng_trajectory_t tng_data, + const int64_t id, + const char *block_name, + const char datatype, + const char block_type_flag, + int64_t n_frames, + const int64_t n_values_per_frame, + int64_t stride_length, + const int64_t codec_id, + void *new_data) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(block_name, "TNG library: block_name must not be a NULL pointer."); + TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer."); + + return(tng_gen_data_block_add(tng_data, id, TNG_FALSE, block_name, datatype, + block_type_flag, n_frames, n_values_per_frame, + stride_length, 0, 0, codec_id, new_data)); +} + +tng_function_status DECLSPECDLLEXPORT tng_particle_data_block_add + (const tng_trajectory_t tng_data, + const int64_t id, + const char *block_name, + const char datatype, + const char block_type_flag, + int64_t n_frames, + const int64_t n_values_per_frame, + int64_t stride_length, + const int64_t num_first_particle, + const int64_t n_particles, + const int64_t codec_id, + void *new_data) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(block_name, "TNG library: block_name mustnot be a NULL pointer."); + TNG_ASSERT(n_values_per_frame > 0, "TNG library: n_values_per_frame must be a positive integer."); + TNG_ASSERT(num_first_particle >= 0, "TNG library: num_first_particle must be >= 0."); + TNG_ASSERT(n_particles >= 0, "TNG library: n_particles must be >= 0."); + + return(tng_gen_data_block_add(tng_data, id, TNG_TRUE, block_name, datatype, + block_type_flag, n_frames, n_values_per_frame, + stride_length, num_first_particle, n_particles, + codec_id, new_data)); +} + +tng_function_status DECLSPECDLLEXPORT tng_data_block_name_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + char *name, + const int max_len) +{ + int64_t i; + tng_trajectory_frame_set_t frame_set; + tng_function_status stat; + tng_data_t data; + int block_type = -1; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer."); + + for(i = 0; i < tng_data->n_particle_data_blocks; i++) + { + data = &tng_data->non_tr_particle_data[i]; + if(data->block_id == block_id) + { + strncpy(name, data->block_name, max_len); + name[max_len - 1] = '\0'; + return(TNG_SUCCESS); + } + } + for(i = 0; i < tng_data->n_data_blocks; i++) + { + data = &tng_data->non_tr_data[i]; + if(data->block_id == block_id) + { + strncpy(name, data->block_name, max_len); + name[max_len - 1] = '\0'; + return(TNG_SUCCESS); + } + } + + frame_set = &tng_data->current_trajectory_frame_set; + + stat = tng_particle_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + block_type = TNG_PARTICLE_BLOCK_DATA; + } + else + { + stat = tng_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + block_type = TNG_NON_PARTICLE_BLOCK_DATA; + } + else + { + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_particle_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + block_type = TNG_PARTICLE_BLOCK_DATA; + } + else + { + stat = tng_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + block_type = TNG_NON_PARTICLE_BLOCK_DATA; + } + } + } + } + if(block_type == TNG_PARTICLE_BLOCK_DATA) + { + for(i = 0; i < frame_set->n_particle_data_blocks; i++) + { + data = &frame_set->tr_particle_data[i]; + if(data->block_id == block_id) + { + strncpy(name, data->block_name, max_len); + name[max_len - 1] = '\0'; + return(TNG_SUCCESS); + } + } + } + else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA) + { + for(i = 0; i < frame_set->n_data_blocks; i++) + { + data = &frame_set->tr_data[i]; + if(data->block_id == block_id) + { + strncpy(name, data->block_name, max_len); + name[max_len - 1] = '\0'; + return(TNG_SUCCESS); + } + } + } + + return(TNG_FAILURE); +} + +tng_function_status DECLSPECDLLEXPORT tng_data_block_dependency_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + int *block_dependency) +{ + int64_t i; + tng_function_status stat; + tng_data_t data; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(block_dependency, "TNG library: block_dependency must not be a NULL pointer."); + + for(i = 0; i < tng_data->n_particle_data_blocks; i++) + { + data = &tng_data->non_tr_particle_data[i]; + if(data->block_id == block_id) + { + *block_dependency = TNG_PARTICLE_DEPENDENT; + return(TNG_SUCCESS); + } + } + for(i = 0; i < tng_data->n_data_blocks; i++) + { + data = &tng_data->non_tr_data[i]; + if(data->block_id == block_id) + { + *block_dependency = 0; + return(TNG_SUCCESS); + } + } + + stat = tng_particle_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT; + return(TNG_SUCCESS); + } + else + { + stat = tng_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + *block_dependency = TNG_FRAME_DEPENDENT; + return(TNG_SUCCESS); + } + else + { + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_particle_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + *block_dependency = TNG_PARTICLE_DEPENDENT + TNG_FRAME_DEPENDENT; + return(TNG_SUCCESS); + } + else + { + stat = tng_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + *block_dependency = TNG_FRAME_DEPENDENT; + return(TNG_SUCCESS); + } + } + } + } + + return(TNG_FAILURE); +} + +tng_function_status DECLSPECDLLEXPORT tng_data_block_num_values_per_frame_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + int64_t *n_values_per_frame) +{ + int64_t i; + tng_function_status stat; + tng_data_t data; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer."); + + for(i = 0; i < tng_data->n_particle_data_blocks; i++) + { + data = &tng_data->non_tr_particle_data[i]; + if(data->block_id == block_id) + { + *n_values_per_frame = data->n_values_per_frame; + return(TNG_SUCCESS); + } + } + for(i = 0; i < tng_data->n_data_blocks; i++) + { + data = &tng_data->non_tr_data[i]; + if(data->block_id == block_id) + { + *n_values_per_frame = data->n_values_per_frame; + return(TNG_SUCCESS); + } + } + + stat = tng_particle_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + *n_values_per_frame = data->n_values_per_frame; + return(TNG_SUCCESS); + } + else + { + stat = tng_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + *n_values_per_frame = data->n_values_per_frame; + return(TNG_SUCCESS); + } + else + { + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_particle_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + *n_values_per_frame = data->n_values_per_frame; + return(TNG_SUCCESS); + } + else + { + stat = tng_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + *n_values_per_frame = data->n_values_per_frame; + return(TNG_SUCCESS); + } + } + } + } + + return(TNG_FAILURE); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_set_n_frames_of_data_block_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + int64_t *n_frames) +{ + tng_gen_block_t block; + tng_function_status stat; + char datatype, dependency, sparse_data; + int64_t n_values, codec_id, first_frame_with_data, stride_length, curr_n_frames; + int64_t num_first_particle, block_n_particles; + double multiplier; + md5_state_t md5_state; + int found = TNG_FALSE; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + tng_block_init(&block); + + stat = tng_block_header_read(tng_data, block); + /* If the block header could not be read the reading position might not have been + * at the start of a block. Try again from the file position of the current frame + * set. */ + if(stat != TNG_SUCCESS) + { + fseeko(tng_data->input_file, tng_data->current_trajectory_frame_set_input_file_pos, SEEK_SET); + stat = tng_block_header_read(tng_data, block); + if(stat != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(stat); + } + } + if(block->id == TNG_TRAJECTORY_FRAME_SET) + { + stat = tng_block_read_next(tng_data, block, TNG_SKIP_HASH); + if(stat != TNG_SUCCESS) + { + tng_block_destroy(&block); + return(stat); + } + stat = tng_block_header_read(tng_data, block); + } + while(stat == TNG_SUCCESS && block->id != TNG_TRAJECTORY_FRAME_SET && found == TNG_FALSE) + { + if(block->id == block_id) + { + stat = tng_data_block_meta_information_read(tng_data, &datatype, + &dependency, &sparse_data, + &n_values, &codec_id, + &first_frame_with_data, + &stride_length, &curr_n_frames, + &num_first_particle, + &block_n_particles, + &multiplier, TNG_SKIP_HASH, + &md5_state); + if(stat == TNG_SUCCESS) + { + found = TNG_TRUE; + } + } + else + { + fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR); + stat = tng_block_header_read(tng_data, block); + } + } + if(found == TNG_TRUE) + { + *n_frames = (tng_data->current_trajectory_frame_set.n_frames - + (tng_data->current_trajectory_frame_set.first_frame - first_frame_with_data)) / stride_length; + } + else if(stat == TNG_SUCCESS) + { + *n_frames = 0; + } + + tng_block_destroy(&block); + + return(stat); +} + +static tng_function_status tng_frame_gen_data_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const int64_t block_id, + const tng_bool is_particle_data, + const int64_t val_first_particle, + const int64_t val_n_particles, + const void *values, + const char hash_mode) +{ + int64_t header_pos, file_pos, tot_n_particles; + int64_t output_file_len, n_values_per_frame, size, contents_size; + int64_t header_size, temp_first, temp_last; + int64_t mapping_block_end_pos, num_first_particle, block_n_particles; + int64_t i, last_frame, temp_current, write_n_particles; + tng_gen_block_t block; + tng_trajectory_frame_set_t frame_set; + FILE *temp = tng_data->input_file; + struct tng_data data; + tng_function_status stat; + tng_particle_mapping_t mapping; + char dependency, sparse_data, datatype; + void *copy; + + if(tng_output_file_init(tng_data) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot initialise destination file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + temp_first = tng_data->first_trajectory_frame_set_input_file_pos; + temp_last = tng_data->last_trajectory_frame_set_input_file_pos; + temp_current = tng_data->current_trajectory_frame_set_input_file_pos; + tng_data->first_trajectory_frame_set_input_file_pos = + tng_data->first_trajectory_frame_set_output_file_pos; + tng_data->last_trajectory_frame_set_input_file_pos = + tng_data->last_trajectory_frame_set_output_file_pos; + tng_data->current_trajectory_frame_set_input_file_pos = + tng_data->current_trajectory_frame_set_output_file_pos; + + tng_data->input_file = tng_data->output_file; + + stat = tng_frame_set_of_frame_find(tng_data, frame_nr); + + frame_set = &tng_data->current_trajectory_frame_set; + + if(stat != TNG_SUCCESS) + { + last_frame = frame_set->first_frame + + frame_set->n_frames - 1; + /* If the wanted frame would be in the frame set after the last + * frame set create a new frame set. */ + if(stat == TNG_FAILURE && + last_frame < frame_nr) +/* (last_frame < frame_nr && + tng_data->current_trajectory_frame_set.first_frame + + tng_data->frame_set_n_frames >= frame_nr))*/ + { + if(last_frame + tng_data->frame_set_n_frames < frame_nr) + { + last_frame = frame_nr - 1; + } + tng_frame_set_new(tng_data, + last_frame+1, + tng_data->frame_set_n_frames); + file_pos = ftello(tng_data->output_file); + fseeko(tng_data->output_file, 0, SEEK_END); + output_file_len = ftello(tng_data->output_file); + fseeko(tng_data->output_file, file_pos, SEEK_SET); + + /* Read mapping blocks from the last frame set */ + tng_block_init(&block); + + stat = tng_block_header_read(tng_data, block); + while(file_pos < output_file_len && + stat != TNG_CRITICAL && + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) + { + if(block->id == TNG_PARTICLE_MAPPING) + { + tng_trajectory_mapping_block_read(tng_data, block, + hash_mode); + } + else + { + fseeko(tng_data->output_file, block->block_contents_size, + SEEK_CUR); + } + file_pos = ftello(tng_data->output_file); + if(file_pos < output_file_len) + { + stat = tng_block_header_read(tng_data, block); + } + } + + tng_block_destroy(&block); + /* Write the frame set to disk */ + if(tng_frame_set_write(tng_data, hash_mode) != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error writing frame set. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + else + { + tng_data->input_file = temp; + tng_data->first_trajectory_frame_set_input_file_pos = temp_first; + tng_data->last_trajectory_frame_set_input_file_pos = temp_last; + tng_data->current_trajectory_frame_set_input_file_pos = temp_current; + return(stat); + } + } + + tng_block_init(&block); + + file_pos = tng_data->current_trajectory_frame_set_output_file_pos; + + fseeko(tng_data->output_file, 0, SEEK_END); + output_file_len = ftello(tng_data->output_file); + fseeko(tng_data->output_file, file_pos, SEEK_SET); + + /* Read past the frame set block first */ + stat = tng_block_header_read(tng_data, block); + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + tng_data->input_file = temp; + + tng_data->first_trajectory_frame_set_input_file_pos = temp_first; + tng_data->last_trajectory_frame_set_input_file_pos = temp_last; + tng_data->current_trajectory_frame_set_input_file_pos = temp_current; + return(stat); + } + fseeko(tng_data->output_file, block->block_contents_size, + SEEK_CUR); + + if(is_particle_data == TNG_TRUE) + { + if(tng_data->var_num_atoms_flag) + { + tot_n_particles = frame_set->n_particles; + } + else + { + tot_n_particles = tng_data->n_particles; + } + + if(val_n_particles < tot_n_particles) + { + mapping_block_end_pos = -1; + /* Read all mapping blocks to find the right place to put the data */ + stat = tng_block_header_read(tng_data, block); + while(file_pos < output_file_len && + stat != TNG_CRITICAL && + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) + { + if(block->id == TNG_PARTICLE_MAPPING) + { + tng_trajectory_mapping_block_read(tng_data, block, hash_mode); + } + else + { + fseeko(tng_data->output_file, block->block_contents_size, + SEEK_CUR); + } + file_pos = ftello(tng_data->output_file); + if(block->id == TNG_PARTICLE_MAPPING) + { + mapping = &frame_set->mappings[frame_set->n_mapping_blocks - 1]; + if(val_first_particle >= mapping->num_first_particle && + val_first_particle < mapping->num_first_particle + + mapping->n_particles && + val_first_particle + val_n_particles <= + mapping->num_first_particle + mapping->n_particles) + { + mapping_block_end_pos = file_pos; + } + } + if(file_pos < output_file_len) + { + stat = tng_block_header_read(tng_data, block); + } + } + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + tng_data->input_file = temp; + + tng_data->first_trajectory_frame_set_input_file_pos = temp_first; + tng_data->last_trajectory_frame_set_input_file_pos = temp_last; + tng_data->current_trajectory_frame_set_input_file_pos = temp_current; + return(stat); + } + if(mapping_block_end_pos < 0) + { + tng_block_destroy(&block); + tng_data->input_file = temp; + + tng_data->first_trajectory_frame_set_input_file_pos = temp_first; + tng_data->last_trajectory_frame_set_input_file_pos = temp_last; + tng_data->current_trajectory_frame_set_input_file_pos = temp_current; + return(TNG_FAILURE); + } + fseeko(tng_data->output_file, mapping_block_end_pos, SEEK_SET); + } + } + + /* Read all block headers until next frame set block or + * until the wanted block id is found */ + stat = tng_block_header_read(tng_data, block); + while(file_pos < output_file_len && + stat != TNG_CRITICAL && + block->id != block_id && + (is_particle_data != TNG_TRUE || block->id != TNG_PARTICLE_MAPPING) && + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) + { + fseeko(tng_data->output_file, block->block_contents_size, SEEK_CUR); + file_pos = ftello(tng_data->output_file); + if(file_pos < output_file_len) + { + stat = tng_block_header_read(tng_data, block); + } + } + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + tng_block_destroy(&block); + tng_data->input_file = temp; + tng_data->first_trajectory_frame_set_input_file_pos = temp_first; + tng_data->last_trajectory_frame_set_input_file_pos = temp_last; + tng_data->current_trajectory_frame_set_input_file_pos = temp_current; + return(stat); + } + + contents_size = block->block_contents_size; + header_size = block->header_contents_size; + + header_pos = ftello(tng_data->output_file) - header_size; + frame_set = &tng_data->current_trajectory_frame_set; + + if(tng_file_input_numerical(tng_data, &datatype, + sizeof(datatype), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + if(tng_file_input_numerical(tng_data, &dependency, + sizeof(dependency), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + data.datatype = datatype; + + if(!(dependency & TNG_FRAME_DEPENDENT) || + (is_particle_data == TNG_FALSE && dependency & TNG_PARTICLE_DEPENDENT) || + (is_particle_data == TNG_TRUE && !(dependency & TNG_PARTICLE_DEPENDENT))) + { + tng_block_destroy(&block); + tng_data->input_file = temp; + + tng_data->first_trajectory_frame_set_input_file_pos = temp_first; + tng_data->last_trajectory_frame_set_input_file_pos = temp_last; + tng_data->current_trajectory_frame_set_input_file_pos = temp_current; + return(TNG_FAILURE); + } + + if(tng_file_input_numerical(tng_data, &sparse_data, + sizeof(sparse_data), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &data.n_values_per_frame, + sizeof(data.n_values_per_frame), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &data.codec_id, + sizeof(data.codec_id), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(data.codec_id != TNG_UNCOMPRESSED) + { + if(tng_file_input_numerical(tng_data, &data.compression_multiplier, + sizeof(data.compression_multiplier), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + else + { + data.compression_multiplier = 1; + } + + if(sparse_data) + { + if(tng_file_input_numerical(tng_data, &data.first_frame_with_data, + sizeof(data.first_frame_with_data), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &data.stride_length, + sizeof(data.stride_length), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + else + { + data.first_frame_with_data = 0; + data.stride_length = 1; + } + data.n_frames = tng_data->current_trajectory_frame_set.n_frames; + + if(is_particle_data == TNG_TRUE) + { + if(tng_file_input_numerical(tng_data, &num_first_particle, + sizeof(num_first_particle), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + + if(tng_file_input_numerical(tng_data, &block_n_particles, + sizeof(block_n_particles), + TNG_SKIP_HASH, 0, __LINE__) == TNG_CRITICAL) + { + tng_block_destroy(&block); + return(TNG_CRITICAL); + } + } + + tng_data->input_file = temp; + + tng_data->first_trajectory_frame_set_input_file_pos = temp_first; + tng_data->last_trajectory_frame_set_input_file_pos = temp_last; + tng_data->current_trajectory_frame_set_input_file_pos = temp_current; + + switch(data.datatype) + { + case(TNG_INT_DATA): + size = sizeof(int64_t); + break; + case(TNG_FLOAT_DATA): + size = sizeof(float); + break; + case(TNG_DOUBLE_DATA): + size = sizeof(double); + break; + default: + fprintf(stderr, "TNG library: Cannot calculate writing locations. %s: %d.\n", __FILE__, + __LINE__); + tng_block_destroy(&block); + return(TNG_FAILURE); + } + + n_values_per_frame = data.n_values_per_frame; + + file_pos = (frame_nr - tng_max_i64(frame_set->first_frame, + data.first_frame_with_data)) / + data.stride_length; + if(is_particle_data == TNG_TRUE) + { + file_pos *= block_n_particles * size * n_values_per_frame; + } + else + { + file_pos *= size * n_values_per_frame; + } + + if(file_pos > contents_size) + { + fprintf(stderr, "TNG library: Attempting to write outside the block. %s: %d\n", __FILE__, + __LINE__); + tng_block_destroy(&block); + return(TNG_FAILURE); + } + + fseeko(tng_data->output_file, file_pos, SEEK_CUR); + + if(is_particle_data == TNG_TRUE) + { + write_n_particles = val_n_particles; + } + else + { + write_n_particles = 1; + } + + /* If the endianness is not big endian the data needs to be swapped */ + if((data.datatype == TNG_INT_DATA || + data.datatype == TNG_DOUBLE_DATA) && + tng_data->output_endianness_swap_func_64) + { + copy = (char *)malloc(write_n_particles * n_values_per_frame * size); + memcpy(copy, values, write_n_particles * n_values_per_frame * size); + for(i = 0; i < write_n_particles * n_values_per_frame; i++) + { + if(tng_data->output_endianness_swap_func_64(tng_data, + (uint64_t *) copy+i) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + fwrite(copy, write_n_particles * n_values_per_frame, size, + tng_data->output_file); + free(copy); + } + else if(data.datatype == TNG_FLOAT_DATA && + tng_data->output_endianness_swap_func_32) + { + copy = (char *)malloc(write_n_particles * n_values_per_frame * size); + memcpy(copy, values, write_n_particles * n_values_per_frame * size); + for(i = 0; i < write_n_particles * n_values_per_frame; i++) + { + if(tng_data->output_endianness_swap_func_32(tng_data, + (uint32_t *) copy+i) + != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n", + __FILE__, __LINE__); + } + } + fwrite(copy, write_n_particles * n_values_per_frame, size, + tng_data->output_file); + free(copy); + } + + else + { + fwrite(values, write_n_particles * n_values_per_frame, size, tng_data->output_file); + } + + fflush(tng_data->output_file); + + /* Update the number of written frames in the frame set. */ + if(frame_nr - frame_set->first_frame + 1 > frame_set->n_written_frames) + { + frame_set->n_written_frames = frame_nr - frame_set->first_frame + 1; + } + + /* If the last frame has been written update the hash */ + if(hash_mode == TNG_USE_HASH && (frame_nr + data.stride_length - + data.first_frame_with_data) >= + frame_set->n_frames) + { + tng_md5_hash_update(tng_data, block, header_pos, header_pos + + header_size); + } + + tng_block_destroy(&block); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_data_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const int64_t block_id, + const void *values, + const char hash_mode) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0."); + TNG_ASSERT(values, "TNG library: values must not be a NULL pointer."); + + /* This is now just calling the generic data writing function. This + * function must keep its signature to let the API be backwards + * compatible. */ + return(tng_frame_gen_data_write(tng_data, frame_nr, block_id, + TNG_FALSE, 0, 0, values, hash_mode)); +} + +tng_function_status DECLSPECDLLEXPORT tng_frame_particle_data_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const int64_t block_id, + const int64_t val_first_particle, + const int64_t val_n_particles, + const void *values, + const char hash_mode) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0."); + TNG_ASSERT(values, "TNG library: values must not be a NULL pointer."); + TNG_ASSERT(val_first_particle >= 0, "TNG library: val_first_particle must be >= 0."); + TNG_ASSERT(val_n_particles >= 0, "TNG library: val_n_particles must be >= 0."); + + /* This is now just calling the generic data writing function. This + * function must keep its signature to let the API be backwards + * compatible. */ + return(tng_frame_gen_data_write(tng_data, frame_nr, block_id, + TNG_TRUE, val_first_particle, val_n_particles, + values, hash_mode)); +} + +static tng_function_status tng_data_values_alloc + (const tng_trajectory_t tng_data, + union data_values ***values, + const int64_t n_frames, + const int64_t n_values_per_frame, + const char type) +{ + int64_t i; + tng_function_status stat; + + if(n_frames <= 0 || n_values_per_frame <= 0) + { + return(TNG_FAILURE); + } + + if(*values) + { + stat = tng_data_values_free(tng_data, *values, n_frames, + n_values_per_frame, + type); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + *values = (union data_values **)malloc(sizeof(union data_values *) * n_frames); + if(!*values) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + + } + + for(i = 0; i < n_frames; i++) + { + (*values)[i] = (union data_values *)malloc(sizeof(union data_values) * + n_values_per_frame); + if(!(*values)[i]) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(values); + values = 0; + return(TNG_CRITICAL); + } + } + return(TNG_SUCCESS); +} + +/* FIXME: This needs ***values */ +tng_function_status DECLSPECDLLEXPORT tng_data_values_free + (const tng_trajectory_t tng_data, + union data_values **values, + const int64_t n_frames, + const int64_t n_values_per_frame, + const char type) +{ + int64_t i, j; + (void)tng_data; + + if(values) + { + for(i = 0; i < n_frames; i++) + { + if(values[i]) + { + if(type == TNG_CHAR_DATA) + { + for(j = 0; j < n_values_per_frame; j++) + { + if(values[i][j].c) + { + free(values[i][j].c); + values[i][j].c = 0; + } + } + } + free(values[i]); + values[i] = 0; + } + } + free(values); + values = 0; + } + + return(TNG_SUCCESS); +} + +static tng_function_status tng_particle_data_values_alloc + (const tng_trajectory_t tng_data, + union data_values ****values, + const int64_t n_frames, + const int64_t n_particles, + const int64_t n_values_per_frame, + const char type) +{ + int64_t i, j; + tng_function_status stat; + + if(n_particles == 0 || n_values_per_frame == 0) + { + return(TNG_FAILURE); + } + + if(*values) + { + stat = tng_particle_data_values_free(tng_data, *values, n_frames, + n_particles, n_values_per_frame, + type); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot free particle data values. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + *values = (union data_values ***)malloc(sizeof(union data_values **) * n_frames); + if(!*values) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + + } + + for(i = 0; i < n_frames; i++) + { + (*values)[i] = (union data_values **)malloc(sizeof(union data_values *) * + n_particles); + if(!(*values)[i]) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(*values); + *values = 0; + return(TNG_CRITICAL); + } + for(j = 0; j < n_particles; j++) + { + (*values)[i][j] = (union data_values *)malloc(sizeof(union data_values) * + n_values_per_frame); + if(!(*values)[i][j]) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + tng_particle_data_values_free(tng_data, *values, n_frames, + n_particles, n_values_per_frame, + type); + *values = 0; + return(TNG_CRITICAL); + } + } + } + return(TNG_SUCCESS); +} + +/* FIXME: This needs ****values */ +tng_function_status DECLSPECDLLEXPORT tng_particle_data_values_free + (const tng_trajectory_t tng_data, + union data_values ***values, + const int64_t n_frames, + const int64_t n_particles, + const int64_t n_values_per_frame, + const char type) +{ + int64_t i, j, k; + (void)tng_data; + + if(values) + { + for(i = 0; i < n_frames; i++) + { + if(values[i]) + { + for(j = 0; j < n_particles; j++) + { + if(type == TNG_CHAR_DATA) + { + for(k = 0; k < n_values_per_frame; k++) + { + if(values[i][j][k].c) + { + free(values[i][j][k].c); + values[i][j][k].c = 0; + } + } + } + free(values[i][j]); + values[i][j] = 0; + } + free(values[i]); + values[i] = 0; + } + } + free(values); + values = 0; + } + + return(TNG_SUCCESS); +} + +static tng_function_status tng_gen_data_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + const tng_bool is_particle_data, + union data_values ****values, + int64_t *n_frames, + int64_t *n_particles, + int64_t *n_values_per_frame, + char *type) +{ + int64_t i, j, k, mapping, file_pos, i_step, block_index; + int size; + size_t len; + tng_data_t data; + tng_trajectory_frame_set_t frame_set; + tng_gen_block_t block; + char block_type_flag; + tng_function_status stat; + + frame_set = &tng_data->current_trajectory_frame_set; + + block_index = -1; + data = 0; + + if(is_particle_data == TNG_TRUE) + { + stat = tng_particle_data_find(tng_data, block_id, &data); + } + else + { + stat = tng_data_find(tng_data, block_id, &data); + } + + if(tng_data->current_trajectory_frame_set_input_file_pos > 0) + { + block_type_flag = TNG_TRAJECTORY_BLOCK; + } + else + { + block_type_flag = TNG_NON_TRAJECTORY_BLOCK; + } + + if(stat != TNG_SUCCESS) + { + tng_block_init(&block); + file_pos = ftello(tng_data->input_file); + /* Read all blocks until next frame set block */ + stat = tng_block_header_read(tng_data, block); + while(file_pos < tng_data->input_file_len && + stat != TNG_CRITICAL && + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) + { + /* Use hash by default */ + stat = tng_block_read_next(tng_data, block, + TNG_USE_HASH); + if(stat != TNG_CRITICAL) + { + file_pos = ftello(tng_data->input_file); + if(file_pos < tng_data->input_file_len) + { + stat = tng_block_header_read(tng_data, block); + } + } + } + tng_block_destroy(&block); + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + return(stat); + } + + if(is_particle_data == TNG_TRUE) + { + for(i = 0; i < frame_set->n_particle_data_blocks; i++) + { + data = &frame_set->tr_particle_data[i]; + if(data->block_id == block_id) + { + block_index = i; + block_type_flag = TNG_TRAJECTORY_BLOCK; + break; + } + } + } + else + { + for(i = 0; i < frame_set->n_data_blocks; i++) + { + data = &frame_set->tr_data[i]; + if(data->block_id == block_id) + { + block_index = i; + break; + } + } + } + if(block_index < 0) + { + return(TNG_FAILURE); + } + } + + if(is_particle_data == TNG_TRUE) + { + if(block_type_flag == TNG_TRAJECTORY_BLOCK && + tng_data->var_num_atoms_flag) + { + *n_particles = frame_set->n_particles; + } + else + { + *n_particles = tng_data->n_particles; + } + } + + *n_frames = tng_max_i64(1, data->n_frames); + *n_values_per_frame = data->n_values_per_frame; + *type = data->datatype; + + if(is_particle_data == TNG_TRUE) + { + if(*values == 0) + { + if(tng_particle_data_values_alloc(tng_data, values, *n_frames, + *n_particles, *n_values_per_frame, + *type) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + } + + i_step = (*n_particles) * (*n_values_per_frame); + + /* It's not very elegant to reuse so much of the code in the different case + * statements, but it's unnecessarily slow to have the switch-case block + * inside the for loops. */ + switch(*type) + { + case TNG_CHAR_DATA: + for(i = 0; i < *n_frames; i++) + { + for(j = 0; j < *n_particles; j++) + { + tng_particle_mapping_get_real_particle(frame_set, j, &mapping); + for(k = 0; k < *n_values_per_frame; k++) + { + len = strlen(data->strings[i][j][k]) + 1; + (*values)[i][mapping][k].c = (char *)malloc(len); + strncpy((*values)[i][mapping][k].c, + data->strings[i][j][k], len); + } + } + } + break; + case TNG_INT_DATA: + size = sizeof(int); + for(i = 0; i < *n_frames; i++) + { + for(j = 0; j < *n_particles; j++) + { + tng_particle_mapping_get_real_particle(frame_set, j, &mapping); + for(k = 0; k < *n_values_per_frame; k++) + { + (*values)[i][mapping][k].i = *(int *) + ((char *)data->values + size * + (i * i_step + j * + (*n_values_per_frame) + k)); + } + } + } + break; + case TNG_FLOAT_DATA: + size = sizeof(float); + for(i = 0; i < *n_frames; i++) + { + for(j = 0; j < *n_particles; j++) + { + tng_particle_mapping_get_real_particle(frame_set, j, &mapping); + for(k = 0; k < *n_values_per_frame; k++) + { + (*values)[i][mapping][k].f = *(float *) + ((char *)data->values + size * + (i * i_step + j * + (*n_values_per_frame) + k)); + } + } + } + break; + case TNG_DOUBLE_DATA: + default: + size = sizeof(double); + for(i = 0; i < *n_frames; i++) + { + for(j = 0; j < *n_particles; j++) + { + tng_particle_mapping_get_real_particle(frame_set, j, &mapping); + for(k = 0; k < *n_values_per_frame; k++) + { + (*values)[i][mapping][k].d = *(double *) + ((char *)data->values + size * + (i * i_step + j * + (*n_values_per_frame) + k)); + } + } + } + } + } + else + { + if(*(values[0]) == 0) + { + if(tng_data_values_alloc(tng_data, values[0], *n_frames, + *n_values_per_frame, + *type) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + } + switch(*type) + { + case TNG_CHAR_DATA: + for(i = 0; i < *n_frames; i++) + { + for(j = 0; j < *n_values_per_frame; j++) + { + len = strlen(data->strings[0][i][j]) + 1; + (*values)[0][i][j].c = (char *)malloc(len); + strncpy((*values)[0][i][j].c, data->strings[0][i][j], len); + } + } + break; + case TNG_INT_DATA: + size = sizeof(int); + for(i = 0; i < *n_frames; i++) + { + for(j = 0; j < *n_values_per_frame; j++) + { + (*values)[0][i][j].i = *(int *)((char *)data->values + size * + (i*(*n_values_per_frame) + j)); + } + } + break; + case TNG_FLOAT_DATA: + size = sizeof(float); + for(i = 0; i < *n_frames; i++) + { + for(j = 0; j < *n_values_per_frame; j++) + { + (*values)[0][i][j].f = *(float *)((char *)data->values + size * + (i*(*n_values_per_frame) + j)); + } + } + break; + case TNG_DOUBLE_DATA: + default: + size = sizeof(double); + for(i = 0; i < *n_frames; i++) + { + for(j = 0; j < *n_values_per_frame; j++) + { + (*values)[0][i][j].d = *(double *)((char *)data->values + size * + (i*(*n_values_per_frame) + j)); + } + } + } + } + + data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_data_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + union data_values ***values, + int64_t *n_frames, + int64_t *n_values_per_frame, + char *type) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer."); + TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer."); + TNG_ASSERT(type, "TNG library: type must not be a NULL pointer."); + + return(tng_gen_data_get(tng_data, block_id, TNG_FALSE, &values, n_frames, 0, + n_values_per_frame, type)); +} + +static tng_function_status tng_gen_data_vector_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + const tng_bool is_particle_data, + void **values, + int64_t *n_frames, + int64_t *stride_length, + int64_t *n_particles, + int64_t *n_values_per_frame, + char *type) +{ + int64_t i, j, mapping, file_pos, i_step, full_data_len, n_frames_div; + int64_t block_index; + int size; + tng_data_t data; + tng_trajectory_frame_set_t frame_set; + tng_gen_block_t block; + void *temp; + char block_type_flag; + tng_function_status stat; + + frame_set = &tng_data->current_trajectory_frame_set; + + block_index = -1; + data = 0; + + if(is_particle_data == TNG_TRUE) + { + stat = tng_particle_data_find(tng_data, block_id, &data); + } + else + { + stat = tng_data_find(tng_data, block_id, &data); + } + + if(stat != TNG_SUCCESS) + { + tng_block_init(&block); + file_pos = ftello(tng_data->input_file); + /* Read all blocks until next frame set block */ + stat = tng_block_header_read(tng_data, block); + while(file_pos < tng_data->input_file_len && + stat != TNG_CRITICAL && + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) + { + /* Use hash by default */ + stat = tng_block_read_next(tng_data, block, + TNG_USE_HASH); + if(stat != TNG_CRITICAL) + { + file_pos = ftello(tng_data->input_file); + if(file_pos < tng_data->input_file_len) + { + stat = tng_block_header_read(tng_data, block); + } + } + } + tng_block_destroy(&block); + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + return(stat); + } + + for(i = 0; i < frame_set->n_particle_data_blocks; i++) + { + data = &frame_set->tr_particle_data[i]; + if(data->block_id == block_id) + { + block_index = i; + break; + } + } + if(block_index < 0) + { + return(TNG_FAILURE); + } + } + + if(is_particle_data == TNG_TRUE) + { + if(tng_data->current_trajectory_frame_set_input_file_pos > 0) + { + block_type_flag = TNG_TRAJECTORY_BLOCK; + } + else + { + block_type_flag = TNG_NON_TRAJECTORY_BLOCK; + } + + if(block_type_flag == TNG_TRAJECTORY_BLOCK && + tng_data->var_num_atoms_flag) + { + *n_particles = frame_set->n_particles; + } + else + { + *n_particles = tng_data->n_particles; + } + } + + *type = data->datatype; + + switch(*type) + { + case TNG_CHAR_DATA: + return(TNG_FAILURE); + case TNG_INT_DATA: + size = sizeof(int64_t); + break; + case TNG_FLOAT_DATA: + size = sizeof(float); + break; + case TNG_DOUBLE_DATA: + default: + size = sizeof(double); + } + + *n_frames = tng_max_i64(1, data->n_frames); + *n_values_per_frame = data->n_values_per_frame; + *stride_length = data->stride_length; + + n_frames_div = (*n_frames % *stride_length) ? + *n_frames / *stride_length + 1: + *n_frames / *stride_length; + + full_data_len = n_frames_div * size * + (*n_values_per_frame); + if(is_particle_data == TNG_TRUE) + { + full_data_len *= (*n_particles); + } + + temp = (char *)realloc(*values, full_data_len); + if(!temp) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(*values); + *values = 0; + return(TNG_CRITICAL); + } + + *values = temp; + + if(is_particle_data != TNG_TRUE || frame_set->n_mapping_blocks <= 0) + { + memcpy(*values, data->values, full_data_len); + } + else + { + i_step = (*n_particles) * (*n_values_per_frame); + for(i = 0; i < *n_frames; i++) + { + for(j = 0; j < *n_particles; j++) + { + tng_particle_mapping_get_real_particle(frame_set, j, &mapping); + memcpy(((char *)*values) + size * (i * i_step + mapping * + (*n_values_per_frame)), + (char *)data->values + size * + (i * i_step + j * (*n_values_per_frame)), + size * (*n_values_per_frame)); + } + } + } + + data->last_retrieved_frame = frame_set->first_frame + data->n_frames - 1; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_data_vector_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + void **values, + int64_t *n_frames, + int64_t *stride_length, + int64_t *n_values_per_frame, + char *type) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer."); + TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer."); + TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer."); + TNG_ASSERT(type, "TNG library: type must not be a NULL pointer."); + + return(tng_gen_data_vector_get(tng_data, block_id, TNG_FALSE, values, + n_frames, stride_length, 0, n_values_per_frame, + type)); +} + +static tng_function_status tng_gen_data_interval_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + const tng_bool is_particle_data, + const int64_t start_frame_nr, + const int64_t end_frame_nr, + const char hash_mode, + union data_values ****values, + int64_t *n_particles, + int64_t *n_values_per_frame, + char *type) +{ + int64_t i, j, k, mapping, n_frames, file_pos, current_frame_pos, i_step; + int64_t first_frame, block_index; + int size; + size_t len; + tng_data_t data; + tng_trajectory_frame_set_t frame_set; + tng_gen_block_t block; + char block_type_flag; + tng_function_status stat; + + block_index = -1; + + frame_set = &tng_data->current_trajectory_frame_set; + first_frame = frame_set->first_frame; + + stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + /* Do not re-read the frame set. */ + if((is_particle_data == TNG_TRUE && + (first_frame != frame_set->first_frame || + frame_set->n_particle_data_blocks <= 0)) || + (is_particle_data == TNG_FALSE && + (first_frame != frame_set->first_frame || + frame_set->n_data_blocks <= 0))) + { + tng_block_init(&block); + file_pos = ftello(tng_data->input_file); + /* Read all blocks until next frame set block */ + stat = tng_block_header_read(tng_data, block); + while(file_pos < tng_data->input_file_len && + stat != TNG_CRITICAL && + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) + { + stat = tng_block_read_next(tng_data, block, + hash_mode); + if(stat != TNG_CRITICAL) + { + file_pos = ftello(tng_data->input_file); + if(file_pos < tng_data->input_file_len) + { + stat = tng_block_header_read(tng_data, block); + } + } + } + tng_block_destroy(&block); + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + return(stat); + } + } + + /* See if there is already a data block of this ID. + * Start checking the last read frame set */ + if(is_particle_data == TNG_TRUE) + { + for(i = frame_set->n_particle_data_blocks; i-- ;) + { + data = &frame_set->tr_particle_data[i]; + if(data->block_id == block_id) + { + block_index = i; + block_type_flag = TNG_TRAJECTORY_BLOCK; + break; + } + } + } + else + { + for(i = 0; i < frame_set->n_data_blocks; i++) + { + data = &frame_set->tr_data[i]; + if(data->block_id == block_id) + { + block_index = i; + break; + } + } + } + + if(block_index < 0) + { + fprintf(stderr, "TNG library: Could not find particle data block with id %" PRId64 ". %s: %d\n", + block_id, __FILE__, __LINE__); + return(TNG_FAILURE); + } + + if(is_particle_data == TNG_TRUE) + { + if(block_type_flag == TNG_TRAJECTORY_BLOCK && + tng_data->var_num_atoms_flag) + { + *n_particles = frame_set->n_particles; + } + else + { + *n_particles = tng_data->n_particles; + } + } + + n_frames = end_frame_nr - start_frame_nr + 1; + *n_values_per_frame = data->n_values_per_frame; + *type = data->datatype; + + if(*values == 0) + { + if(is_particle_data == TNG_TRUE) + { + if(tng_particle_data_values_alloc(tng_data, values, n_frames, + *n_particles, *n_values_per_frame, + *type) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + } + else + { + if(tng_data_values_alloc(tng_data, *values, n_frames, + *n_values_per_frame, + *type) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + } + } + + current_frame_pos = start_frame_nr - frame_set->first_frame; + + if(is_particle_data == TNG_TRUE) + { + i_step = (*n_particles) * (*n_values_per_frame); + } + else + { + i_step = (*n_values_per_frame); + } + /* It's not very elegant to reuse so much of the code in the different case + * statements, but it's unnecessarily slow to have the switch-case block + * inside the for loops. */ + switch(*type) + { + case TNG_CHAR_DATA: + for(i=0; in_frames) + { + stat = tng_frame_set_read_next(tng_data, hash_mode); + if(stat != TNG_SUCCESS) + { + return(stat); + } + current_frame_pos = 0; + } + if(is_particle_data == TNG_TRUE) + { + for(j = 0; j < *n_particles; j++) + { + tng_particle_mapping_get_real_particle(frame_set, j, &mapping); + for(k = 0; k < *n_values_per_frame; k++) + { + len = strlen(data->strings[current_frame_pos][j][k]) + 1; + (*values)[i][mapping][k].c = (char *)malloc(len); + strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len); + } + } + } + else + { + for(j = 0; j < *n_values_per_frame; j++) + { + len = strlen(data->strings[0][current_frame_pos][j]) + 1; + (*values)[0][i][j].c = (char *)malloc(len); + strncpy((*values)[0][i][j].c, data->strings[0][current_frame_pos][j], len); + } + } + current_frame_pos++; + } + break; + case TNG_INT_DATA: + size = sizeof(int); + for(i=0; in_frames) + { + stat = tng_frame_set_read_next(tng_data, hash_mode); + if(stat != TNG_SUCCESS) + { + return(stat); + } + current_frame_pos = 0; + } + if(is_particle_data == TNG_TRUE) + { + for(j = 0; j < *n_particles; j++) + { + tng_particle_mapping_get_real_particle(frame_set, j, &mapping); + for(k = 0; k < *n_values_per_frame; k++) + { + (*values)[i][mapping][k].i = *(int *) + ((char *)data->values + size * + (current_frame_pos * + i_step + j * + (*n_values_per_frame) + k)); + } + } + current_frame_pos++; + } + else + { + for(j = 0; j < *n_values_per_frame; j++) + { + (*values)[0][i][j].i = *(int *)((char *)data->values + size * + (current_frame_pos * + i_step + j)); + } + } + } + break; + case TNG_FLOAT_DATA: + size = sizeof(float); + for(i=0; in_frames) + { + stat = tng_frame_set_read_next(tng_data, hash_mode); + if(stat != TNG_SUCCESS) + { + return(stat); + } + current_frame_pos = 0; + } + if(is_particle_data == TNG_TRUE) + { + for(j=0; j<*n_particles; j++) + { + tng_particle_mapping_get_real_particle(frame_set, j, &mapping); + for(k=0; k<*n_values_per_frame; k++) + { + (*values)[i][mapping][k].f = *(float *) + ((char *)data->values + size * + (current_frame_pos * + i_step + j * + (*n_values_per_frame) + k)); + } + } + } + else + { + for(j = 0; j < *n_values_per_frame; j++) + { + (*values)[0][i][j].f = *(float *)((char *)data->values + size * + (current_frame_pos * + i_step + j)); + } + } + current_frame_pos++; + } + break; + case TNG_DOUBLE_DATA: + default: + size = sizeof(double); + for(i=0; in_frames) + { + stat = tng_frame_set_read_next(tng_data, hash_mode); + if(stat != TNG_SUCCESS) + { + return(stat); + } + current_frame_pos = 0; + } + if(is_particle_data == TNG_TRUE) + { + for(j=0; j<*n_particles; j++) + { + tng_particle_mapping_get_real_particle(frame_set, j, &mapping); + for(k=0; k<*n_values_per_frame; k++) + { + (*values)[i][mapping][k].d = *(double *) + ((char *)data->values + size * + (current_frame_pos * + i_step + j * + (*n_values_per_frame) + k)); + } + } + } + else + { + for(j = 0; j < *n_values_per_frame; j++) + { + (*values)[0][i][j].d = *(double *)((char *)data->values + size * + (current_frame_pos * + i_step + j)); + } + } + current_frame_pos++; + } + } + + data->last_retrieved_frame = end_frame_nr; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_data_interval_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + const int64_t start_frame_nr, + const int64_t end_frame_nr, + const char hash_mode, + union data_values ***values, + int64_t *n_values_per_frame, + char *type) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr."); + TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer."); + TNG_ASSERT(type, "TNG library: type must not be a NULL pointer."); + + return(tng_gen_data_interval_get(tng_data, block_id, TNG_FALSE, start_frame_nr, + end_frame_nr, hash_mode, &values, 0, + n_values_per_frame, type)); +} + +static tng_function_status tng_gen_data_vector_interval_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + const tng_bool is_particle_data, + const int64_t start_frame_nr, + const int64_t end_frame_nr, + const char hash_mode, + void **values, + int64_t *n_particles, + int64_t *stride_length, + int64_t *n_values_per_frame, + char *type) +{ + int64_t n_frames, tot_n_frames, n_frames_div, n_frames_div_2, first_frame; + int64_t file_pos, current_frame_pos, last_frame_pos, full_data_len, frame_size; + int size; + tng_trajectory_frame_set_t frame_set; + tng_data_t data; + tng_gen_block_t block; + void *current_values = 0, *temp; + tng_function_status stat; + + frame_set = &tng_data->current_trajectory_frame_set; + first_frame = frame_set->first_frame; + + stat = tng_frame_set_of_frame_find(tng_data, start_frame_nr); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + /* Do not re-read the frame set and only need the requested block + particle mapping blocks. */ + /* TODO: Test that blocks are read correctly now that now all of them are read at the same time. */ + if(is_particle_data == TNG_TRUE) + { + stat = tng_particle_data_find(tng_data, block_id, &data); + } + else + { + stat = tng_data_find(tng_data, block_id, &data); + } + + if(first_frame != frame_set->first_frame || + stat != TNG_SUCCESS) + { + tng_block_init(&block); + if(stat != TNG_SUCCESS) + { + fseeko(tng_data->input_file, + tng_data->current_trajectory_frame_set_input_file_pos, + SEEK_SET); + stat = tng_block_header_read(tng_data, block); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read block header. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR); + } + file_pos = ftello(tng_data->input_file); + /* Read until next frame set block */ + stat = tng_block_header_read(tng_data, block); + while(file_pos < tng_data->input_file_len && + stat != TNG_CRITICAL && + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) + { + if(block->id == block_id || block->id == TNG_PARTICLE_MAPPING) + { + stat = tng_block_read_next(tng_data, block, + hash_mode); + if(stat != TNG_CRITICAL) + { + file_pos = ftello(tng_data->input_file); + if(file_pos < tng_data->input_file_len) + { + stat = tng_block_header_read(tng_data, block); + } + } + } + else + { + file_pos += block->block_contents_size + block->header_contents_size; + fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR); + if(file_pos < tng_data->input_file_len) + { + stat = tng_block_header_read(tng_data, block); + } + } + } + tng_block_destroy(&block); + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + return(stat); + } + } + if(is_particle_data == TNG_TRUE) + { + stat = tng_particle_data_find(tng_data, block_id, &data); + } + else + { + stat = tng_data_find(tng_data, block_id, &data); + } + if(stat != TNG_SUCCESS) + { + return(stat); + } + + stat = tng_gen_data_vector_get(tng_data, block_id, is_particle_data, + ¤t_values, &n_frames, stride_length, + n_particles, n_values_per_frame, type); + + if(stat != TNG_SUCCESS || (is_particle_data && *n_particles == 0)) + { + if(current_values) + { + free(current_values); + } + return(stat); + } + + if(n_frames == 1 && n_frames < frame_set->n_frames) + { + tot_n_frames = 1; + } + else + { + tot_n_frames = end_frame_nr - start_frame_nr + 1; + } + + switch(*type) + { + case TNG_CHAR_DATA: + return(TNG_FAILURE); + case TNG_INT_DATA: + size = sizeof(int64_t); + break; + case TNG_FLOAT_DATA: + size = sizeof(float); + break; + case TNG_DOUBLE_DATA: + default: + size = sizeof(double); + } + + n_frames_div = (tot_n_frames % *stride_length) ? + tot_n_frames / *stride_length + 1: + tot_n_frames / *stride_length; + + full_data_len = n_frames_div * size * (*n_values_per_frame); + if(is_particle_data) + { + full_data_len *= (*n_particles); + } + + temp = (char *)realloc(*values, full_data_len); + if(!temp) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(*values); + *values = 0; + return(TNG_CRITICAL); + } + + *values = temp; + + if( n_frames == 1 && n_frames < frame_set->n_frames) + { + if(is_particle_data) + { + memcpy(*values, current_values, size * (*n_particles) * + (*n_values_per_frame)); + } + else + { + memcpy(*values, current_values, size * (*n_values_per_frame)); + } + } + else + { + current_frame_pos = start_frame_nr - frame_set->first_frame; + + frame_size = size * (*n_values_per_frame); + if(is_particle_data) + { + frame_size *= (*n_particles); + } + + last_frame_pos = tng_min_i64(n_frames, + end_frame_nr - start_frame_nr); + + n_frames_div = current_frame_pos / *stride_length; + n_frames_div_2 = (last_frame_pos % *stride_length) ? + last_frame_pos / *stride_length + 1: + last_frame_pos / *stride_length; + n_frames_div_2 = tng_max_i64(1, n_frames_div_2 + 1); + + memcpy(*values, (char *)current_values + n_frames_div * frame_size, + n_frames_div_2 * frame_size); + + current_frame_pos += n_frames - current_frame_pos; + + while(current_frame_pos <= end_frame_nr - start_frame_nr) + { + stat = tng_frame_set_read_next(tng_data, hash_mode); + if(stat != TNG_SUCCESS) + { + if(current_values) + { + free(current_values); + } + free(*values); + *values = 0; + return(stat); + } + + stat = tng_gen_data_vector_get(tng_data, block_id, is_particle_data, + ¤t_values, &n_frames, + stride_length, n_particles, + n_values_per_frame, type); + + if(stat != TNG_SUCCESS) + { + if(current_values) + { + free(current_values); + } + free(*values); + *values = 0; + return(stat); + } + + last_frame_pos = tng_min_i64(n_frames, + end_frame_nr - current_frame_pos); + + n_frames_div = current_frame_pos / *stride_length; + n_frames_div_2 = (last_frame_pos % *stride_length) ? + last_frame_pos / *stride_length + 1: + last_frame_pos / *stride_length; + n_frames_div_2 = tng_max_i64(1, n_frames_div_2); + + memcpy(((char *)*values) + n_frames_div * frame_size, + current_values, + n_frames_div_2 * frame_size); + + current_frame_pos += n_frames; + } + } + + if(current_values) + { + free(current_values); + } + + data->last_retrieved_frame = end_frame_nr; + + return(TNG_SUCCESS); +} + + +tng_function_status DECLSPECDLLEXPORT tng_data_vector_interval_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + const int64_t start_frame_nr, + const int64_t end_frame_nr, + const char hash_mode, + void **values, + int64_t *stride_length, + int64_t *n_values_per_frame, + char *type) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than the end_frame_nr."); + TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer."); + TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer."); + TNG_ASSERT(type, "TNG library: type must not be a NULL pointer."); + + return(tng_gen_data_vector_interval_get(tng_data, block_id, TNG_FALSE, + start_frame_nr, end_frame_nr, + hash_mode, values, 0, stride_length, + n_values_per_frame, type)); +} + +tng_function_status DECLSPECDLLEXPORT tng_particle_data_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + union data_values ****values, + int64_t *n_frames, + int64_t *n_particles, + int64_t *n_values_per_frame, + char *type) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(n_frames, "TNG library: n_frames must not be a NULL pointer."); + TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer."); + TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer."); + TNG_ASSERT(type, "TNG library: type must not be a NULL pointer."); + + return(tng_gen_data_get(tng_data, block_id, TNG_TRUE, values, n_frames, n_particles, + n_values_per_frame, type)); +} + +tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + void **values, + int64_t *n_frames, + int64_t *stride_length, + int64_t *n_particles, + int64_t *n_values_per_frame, + char *type) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer."); + TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer."); + TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer."); + TNG_ASSERT(type, "TNG library: type must not be a NULL pointer."); + + return(tng_gen_data_vector_get(tng_data, block_id, TNG_TRUE, values, + n_frames, stride_length, n_particles, + n_values_per_frame, type)); +} + +tng_function_status DECLSPECDLLEXPORT tng_particle_data_interval_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + const int64_t start_frame_nr, + const int64_t end_frame_nr, + const char hash_mode, + union data_values ****values, + int64_t *n_particles, + int64_t *n_values_per_frame, + char *type) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr."); + TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer."); + TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer."); + TNG_ASSERT(type, "TNG library: type must not be a NULL pointer."); + + return(tng_gen_data_interval_get(tng_data, block_id, TNG_TRUE, start_frame_nr, + end_frame_nr, hash_mode, values, n_particles, + n_values_per_frame, type)); +} + +tng_function_status DECLSPECDLLEXPORT tng_particle_data_vector_interval_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + const int64_t start_frame_nr, + const int64_t end_frame_nr, + const char hash_mode, + void **values, + int64_t *n_particles, + int64_t *stride_length, + int64_t *n_values_per_frame, + char *type) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(start_frame_nr <= end_frame_nr, "TNG library: start_frame_nr must not be higher than tne end_frame_nr."); + TNG_ASSERT(n_particles, "TNG library: n_particles must not be a NULL pointer."); + TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer."); + TNG_ASSERT(n_values_per_frame, "TNG library: n_values_per_frame must not be a NULL pointer."); + TNG_ASSERT(type, "TNG library: type must not be a NULL pointer."); + + return(tng_gen_data_vector_interval_get(tng_data, block_id, TNG_TRUE, + start_frame_nr, end_frame_nr, + hash_mode, values, n_particles, + stride_length, n_values_per_frame, + type)); +} + +tng_function_status DECLSPECDLLEXPORT tng_data_get_stride_length + (const tng_trajectory_t tng_data, + const int64_t block_id, + int64_t frame, + int64_t *stride_length) +{ + tng_function_status stat; + tng_data_t data; + int64_t orig_file_pos, file_pos; + int is_particle_data; + + if(tng_data->current_trajectory_frame_set_input_file_pos <= 0) + { + frame = 0; + } + + if(frame >= 0) + { + stat = tng_frame_set_of_frame_find(tng_data, frame); + if(stat != TNG_SUCCESS) + { + return(stat); + } + } + orig_file_pos = tng_data->current_trajectory_frame_set_input_file_pos; + stat = tng_data_find(tng_data, block_id, &data); + if(stat != TNG_SUCCESS) + { + stat = tng_particle_data_find(tng_data, block_id, &data); + if(stat != TNG_SUCCESS) + { + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + /* If no specific frame was required read until this data block is found */ + if(frame < 0) + { + file_pos = ftello(tng_data->input_file); + while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len) + { + stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + file_pos = ftello(tng_data->input_file); + } + } + if(stat != TNG_SUCCESS) + { + tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos); + + return(stat); + } + stat = tng_data_find(tng_data, block_id, &data); + if(stat != TNG_SUCCESS) + { + stat = tng_particle_data_find(tng_data, block_id, &data); + if(stat != TNG_SUCCESS) + { + tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos); + + return(stat); + } + else + { + is_particle_data = 1; + } + } + else + { + is_particle_data = 0; + } + } + else + { + is_particle_data = 1; + } + } + else + { + is_particle_data = 0; + } + if(is_particle_data) + { + *stride_length = data->stride_length; + } + else + { + *stride_length = data->stride_length; + } + tng_reread_frame_set_at_file_pos(tng_data, orig_file_pos); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_time_get_str + (const tng_trajectory_t tng_data, + char *time) +{ + struct tm *time_data; + time_t secs; + int retval; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(time, "TNG library: time must not be a NULL pointer"); + + secs = tng_data->time; + + time_data = localtime(&secs); /* Returns a statically allocated variable. */ + retval = TNG_SNPRINTF(time, TNG_MAX_DATE_STR_LEN, + "%4d-%02d-%02d %02d:%02d:%02d", + time_data->tm_year+1900, time_data->tm_mon+1, time_data->tm_mday, + time_data->tm_hour, time_data->tm_min, time_data->tm_sec); + + /* handle return value (also) to quiet a -Wformat-truncation warning */ + return( (retval < 0) ? TNG_SUCCESS : TNG_FAILURE ); +} + + +tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_open + (const char *filename, + const char mode, + tng_trajectory_t *tng_data_p) +{ + tng_function_status stat; + + TNG_ASSERT(filename, "TNG library: filename must not be a NULL pointer."); + + if(mode != 'r' && mode != 'w' && mode != 'a') + { + return(TNG_FAILURE); + } + + if(tng_trajectory_init(tng_data_p) != TNG_SUCCESS) + { + tng_trajectory_destroy(tng_data_p); + return(TNG_CRITICAL); + } + + if(mode == 'w') + { + stat = tng_output_file_set(*tng_data_p, filename); + return(stat); + } + tng_input_file_set(*tng_data_p, filename); + + /* Read the file headers */ + tng_file_headers_read(*tng_data_p, TNG_USE_HASH); + + stat = tng_num_frame_sets_get(*tng_data_p, &(*tng_data_p)->n_trajectory_frame_sets); + + if(stat != TNG_SUCCESS) + { + return(stat); + } + + if(mode == 'a') + { + if((*tng_data_p)->output_file) + { + fclose((*tng_data_p)->output_file); + } + (*tng_data_p)->output_file = (*tng_data_p)->input_file; + fseeko((*tng_data_p)->input_file, + (*tng_data_p)->last_trajectory_frame_set_input_file_pos, + SEEK_SET); + + stat = tng_frame_set_read(*tng_data_p, TNG_USE_HASH); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read frame set and related blocks. %s: %d\n", + __FILE__, __LINE__); + } + (*tng_data_p)->output_file = 0; + + (*tng_data_p)->first_trajectory_frame_set_output_file_pos = + (*tng_data_p)->first_trajectory_frame_set_input_file_pos; + (*tng_data_p)->last_trajectory_frame_set_output_file_pos = + (*tng_data_p)->last_trajectory_frame_set_input_file_pos; + (*tng_data_p)->current_trajectory_frame_set_output_file_pos = + (*tng_data_p)->current_trajectory_frame_set_input_file_pos; + if((*tng_data_p)->input_file) + { + fclose((*tng_data_p)->input_file); + (*tng_data_p)->input_file = 0; + } + if((*tng_data_p)->input_file_path) + { + free((*tng_data_p)->input_file_path); + (*tng_data_p)->input_file_path = 0; + } + tng_output_append_file_set(*tng_data_p, filename); + + fseeko((*tng_data_p)->output_file, 0, SEEK_END); + + (*tng_data_p)->output_endianness_swap_func_32 = (*tng_data_p)->input_endianness_swap_func_32; + (*tng_data_p)->output_endianness_swap_func_64 = (*tng_data_p)->input_endianness_swap_func_64; + } + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_close + (tng_trajectory_t *tng_data_p) +{ + tng_trajectory_frame_set_t frame_set; + + if(tng_data_p == 0) + { + fprintf(stderr, "TNG library: Empty pointer to trajectory when attempting to close. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + if(*tng_data_p == 0) + { + return(TNG_SUCCESS); + } + + frame_set = &(*tng_data_p)->current_trajectory_frame_set; + + if(frame_set->n_unwritten_frames > 0) + { + frame_set->n_frames = frame_set->n_unwritten_frames; + tng_frame_set_write(*tng_data_p, TNG_USE_HASH); + } + + return(tng_trajectory_destroy(tng_data_p)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_time_of_frame_get + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + double *time) +{ + int64_t first_frame; + tng_trajectory_frame_set_t frame_set; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(time, "TNG library: time must not be a NULL pointer"); + + stat = tng_frame_set_of_frame_find(tng_data, frame_nr); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot find frame nr %" PRId64 ". %s: %d\n", + frame_nr, __FILE__, __LINE__); + return(stat); + } + + frame_set = &tng_data->current_trajectory_frame_set; + first_frame = frame_set->first_frame; + + if(tng_data->time_per_frame <= 0) + { + return(TNG_FAILURE); + } + + *time = frame_set->first_frame_time + (tng_data->time_per_frame * (frame_nr - first_frame)); + + return(TNG_SUCCESS); +} + +/* +tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecules_get + (const tng_trajectory_t tng_data, + int64_t *n_mols, + int64_t **molecule_cnt_list, + tng_molecule_t *mols) +{ + tng_trajectory_frame_set_t frame_set; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(n_mols, "TNG library: n_mols must not be a NULL pointer."); + + *n_mols = tng_data->n_molecules; + + frame_set = &tng_data->current_trajectory_frame_set; + if(tng_data->var_num_atoms_flag && frame_set && frame_set->molecule_cnt_list) + { + *molecule_cnt_list = frame_set->molecule_cnt_list; + } + else + { + *molecule_cnt_list = tng_data->molecule_cnt_list; + } + + *mols = tng_data->molecules; + + return(TNG_SUCCESS); +} +*/ +/* +tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_molecule_add + (const tng_trajectory_t tng_data, + const char *name, + const int64_t cnt, + tng_molecule_t *mol) +{ + tng_function_status stat; + + TNG_ASSERT(name, "TNG library: name must not be a NULL pointer"); + TNG_ASSERT(cnt>=0, "TNG library: cnt must be >= 0"); + + stat = tng_molecule_add(tng_data, name, mol); + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_molecule_cnt_set(tng_data, *mol, cnt); + + return(stat); +} +*/ +tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_get + (const tng_trajectory_t tng_data, + const tng_molecule_t mol, + int64_t *n_particles, + char ***names, + char ***types, + char ***res_names, + int64_t **res_ids, + char ***chain_names, + int64_t **chain_ids) +{ + tng_atom_t atom; + tng_residue_t res; + tng_chain_t chain; + int64_t i; + (void)tng_data; + + *n_particles = mol->n_atoms; + + *names = (char **)malloc(sizeof(char *) * *n_particles); + *types = (char **)malloc(sizeof(char *) * *n_particles); + *res_names = (char **)malloc(sizeof(char *) * *n_particles); + *chain_names = (char **)malloc(sizeof(char *) * *n_particles); + *res_ids = (int64_t *)malloc(sizeof(int64_t) * *n_particles); + *chain_ids = (int64_t *)malloc(sizeof(int64_t) * *n_particles); + + for(i = 0; i < *n_particles; i++) + { + atom = &mol->atoms[i]; + res = atom->residue; + chain = res->chain; + (*names)[i] = (char *)malloc(strlen(atom->name)); + strcpy(*names[i], atom->name); + (*types)[i] = (char *)malloc(strlen(atom->atom_type)); + strcpy(*types[i], atom->atom_type); + (*res_names)[i] = (char *)malloc(strlen(res->name)); + strcpy(*res_names[i], res->name); + (*chain_names)[i] = (char *)malloc(strlen(chain->name)); + strcpy(*chain_names[i], chain->name); + (*res_ids)[i] = res->id; + (*chain_ids)[i] = chain->id; + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_molecule_particles_set + (const tng_trajectory_t tng_data, + const tng_molecule_t mol, + const int64_t n_particles, + const char **names, + const char **types, + const char **res_names, + const int64_t *res_ids, + const char **chain_names, + const int64_t *chain_ids) +{ + int64_t i; + tng_chain_t chain; + tng_residue_t residue; + tng_atom_t atom; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(names, "TNG library: names must not be a NULL pointer"); + TNG_ASSERT(types, "TNG library: types must not be a NULL pointer"); + TNG_ASSERT(res_names, "TNG library: res_names must not be a NULL pointer"); + TNG_ASSERT(res_ids, "TNG library: res_ids must not be a NULL pointer"); + TNG_ASSERT(chain_names, "TNG library: chain_names must not be a NULL pointer"); + TNG_ASSERT(chain_ids, "TNG library: chain_ids must not be a NULL pointer"); + + for(i = 0; i < n_particles; i++) + { + if(tng_molecule_chain_find(tng_data, mol, chain_names[i], chain_ids[i], + &chain) == TNG_FAILURE) + { + stat = tng_molecule_chain_add(tng_data, mol, chain_names[i], + &chain); + if(stat != TNG_SUCCESS) + { + return(stat); + } + } + if(tng_chain_residue_find(tng_data, chain, res_names[i], res_ids[i], + &residue) == TNG_FAILURE) + { + stat = tng_chain_residue_add(tng_data, chain, res_names[i], + &residue); + if(stat != TNG_SUCCESS) + { + return(stat); + } + } + stat = tng_residue_atom_add(tng_data, residue, names[i], types[i], &atom); + if(stat != TNG_SUCCESS) + { + return(stat); + } + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_pos_read + (const tng_trajectory_t tng_data, + float **positions, int64_t *stride_length) +{ + int64_t n_frames, n_particles, n_values_per_frame; + char type; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer"); + TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer"); + + stat = tng_num_frames_get(tng_data, &n_frames); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS, + 0, n_frames - 1, TNG_USE_HASH, + (void **)positions, + &n_particles, + stride_length, + &n_values_per_frame, + &type); + + if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA) + { + return(TNG_FAILURE); + } + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_vel_read + (const tng_trajectory_t tng_data, + float **velocities, int64_t *stride_length) +{ + int64_t n_frames, n_particles, n_values_per_frame; + char type; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer"); + TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer"); + + stat = tng_num_frames_get(tng_data, &n_frames); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES, + 0, n_frames - 1, TNG_USE_HASH, + (void **)velocities, + &n_particles, + stride_length, + &n_values_per_frame, + &type); + + if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA) + { + return(TNG_FAILURE); + } + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_force_read + (const tng_trajectory_t tng_data, + float **forces, int64_t *stride_length) +{ + int64_t n_frames, n_particles, n_values_per_frame; + char type; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer"); + TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer"); + + stat = tng_num_frames_get(tng_data, &n_frames); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES, + 0, n_frames - 1, TNG_USE_HASH, + (void **)forces, + &n_particles, + stride_length, + &n_values_per_frame, + &type); + + if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA) + { + return(TNG_FAILURE); + } + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read + (const tng_trajectory_t tng_data, + float **box_shape, + int64_t *stride_length) +{ + int64_t n_frames, n_values_per_frame; + char type; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer"); + TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer"); + + stat = tng_num_frames_get(tng_data, &n_frames); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE, + 0, n_frames - 1, TNG_USE_HASH, + (void **)box_shape, + stride_length, + &n_values_per_frame, + &type); + + if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA) + { + return(TNG_FAILURE); + } + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_particle_data_next_frame_read + (const tng_trajectory_t tng_data, + const int64_t block_id, + void **values, + char *data_type, + int64_t *retrieved_frame_number, + double *retrieved_time) +{ + tng_trajectory_frame_set_t frame_set; + tng_data_t data = 0; + tng_function_status stat; + int size; + int64_t i, full_data_len, n_particles; + void *temp; + int64_t file_pos; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer"); + TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer"); + TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer"); + TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer"); + + frame_set = &tng_data->current_trajectory_frame_set; + + stat = tng_particle_data_find(tng_data, block_id, &data); + if(stat != TNG_SUCCESS) + { + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + file_pos = ftello(tng_data->input_file); + while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len) + { + stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + file_pos = ftello(tng_data->input_file); + } + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_particle_data_find(tng_data, block_id, &data); + if(stat != TNG_SUCCESS) + { + return(stat); + } + } + if(data->last_retrieved_frame < 0) + { + fseeko(tng_data->input_file, + tng_data->first_trajectory_frame_set_input_file_pos, + SEEK_SET); + stat = tng_frame_set_read(tng_data, TNG_USE_HASH); + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + i = data->first_frame_with_data; + } + else + { + if(data->n_frames == 1 && frame_set->n_frames == 1) + { + i = data->last_retrieved_frame + 1; + } + else + { + i = data->last_retrieved_frame + data->stride_length; + } + if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames) + { + stat = tng_frame_set_of_frame_find(tng_data, i); + if(stat != TNG_SUCCESS) + { + /* If the frame set search found the frame set after the starting + * frame set there is a gap in the frame sets. So, even if the frame + * was not found the next frame with data is still in the found + * frame set. */ + if(stat == TNG_CRITICAL) + { + return(stat); + } + if(frame_set->first_frame + frame_set->n_frames - 1 < i) + { + return(TNG_FAILURE); + } + i = frame_set->first_frame; + } + } + if(data->last_retrieved_frame < frame_set->first_frame) + { + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + if(stat != TNG_SUCCESS) + { + return(stat); + } + } + } + data->last_retrieved_frame = i; + *retrieved_frame_number = i; + if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0) + { + *retrieved_time = frame_set->first_frame_time + + (i - frame_set->first_frame) * + tng_data->time_per_frame; + } + else + { + *retrieved_time = 0; + } + + if(data->stride_length > 1) + { + i = (i - data->first_frame_with_data) / data->stride_length; + } + else + { + i = (i - frame_set->first_frame); + } + + tng_num_particles_get(tng_data, &n_particles); + + *data_type = data->datatype; + + switch(*data_type) + { + case TNG_CHAR_DATA: + return(TNG_FAILURE); + case TNG_INT_DATA: + size = sizeof(int64_t); + break; + case TNG_FLOAT_DATA: + size = sizeof(float); + break; + case TNG_DOUBLE_DATA: + default: + size = sizeof(double); + } + + full_data_len = size * n_particles * data->n_values_per_frame; + +// fprintf(stderr, "TNG library: TEMP: i = %" PRId64 ", full_data_len = %" PRId64 ", size = %d, n_particles = %" PRId64 ", n_values_per_frame = %" PRId64 "\n", +// i, full_data_len, size, n_particles, data->n_values_per_frame); + + temp = (char *)realloc(*values, full_data_len); + if(!temp) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(*values); + *values = 0; + return(TNG_CRITICAL); + } + + *values = temp; + + memcpy(*values, (char *)data->values + i * full_data_len, full_data_len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_non_particle_data_next_frame_read + (const tng_trajectory_t tng_data, + const int64_t block_id, + void **values, + char *data_type, + int64_t *retrieved_frame_number, + double *retrieved_time) +{ + tng_trajectory_frame_set_t frame_set; + tng_data_t data = 0; + tng_function_status stat; + int size; + int64_t i, full_data_len; + void *temp; + int64_t file_pos; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(values, "TNG library: The pointer to the values array must not be a NULL pointer"); + TNG_ASSERT(data_type, "TNG library: The pointer to the data type of the returned data must not be a NULL pointer"); + TNG_ASSERT(retrieved_frame_number, "TNG library: The pointer to the frame number of the returned data must not be a NULL pointer"); + TNG_ASSERT(retrieved_time, "TNG library: The pointer to the time of the returned data must not be a NULL pointer"); + + frame_set = &tng_data->current_trajectory_frame_set; + + stat = tng_data_find(tng_data, block_id, &data); + if(stat != TNG_SUCCESS) + { + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + file_pos = ftello(tng_data->input_file); + while(stat != TNG_SUCCESS && file_pos < tng_data->input_file_len) + { + stat = tng_frame_set_read_next_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + file_pos = ftello(tng_data->input_file); + } + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_data_find(tng_data, block_id, &data); + if(stat != TNG_SUCCESS) + { + return(stat); + } + } + if(data->last_retrieved_frame < 0) + { + fseeko(tng_data->input_file, + tng_data->first_trajectory_frame_set_input_file_pos, + SEEK_SET); + stat = tng_frame_set_read(tng_data, TNG_USE_HASH); + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + i = data->first_frame_with_data; + } + else + { + if(data->n_frames == 1 && frame_set->n_frames == 1) + { + i = data->last_retrieved_frame + 1; + } + else + { + i = data->last_retrieved_frame + data->stride_length; + } + if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames) + { + stat = tng_frame_set_of_frame_find(tng_data, i); + if(stat != TNG_SUCCESS) + { + /* If the frame set search found the frame set after the starting + * frame set there is a gap in the frame sets. So, even if the frame + * was not found the next frame with data is still in the found + * frame set. */ + if(stat == TNG_CRITICAL) + { + return(stat); + } + if(frame_set->first_frame + frame_set->n_frames - 1 < i) + { + return(TNG_FAILURE); + } + i = frame_set->first_frame; + } + } + if(data->last_retrieved_frame < frame_set->first_frame) + { + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + if(stat != TNG_SUCCESS) + { + return(stat); + } + } + } + data->last_retrieved_frame = i; + *retrieved_frame_number = i; + if(frame_set->first_frame_time >= 0 && tng_data->time_per_frame >= 0) + { + *retrieved_time = frame_set->first_frame_time + + (i - frame_set->first_frame) * + tng_data->time_per_frame; + } + else + { + *retrieved_time = 0; + } + + if(data->stride_length > 1) + { + i = (i - data->first_frame_with_data) / data->stride_length; + } + else + { + i = (i - frame_set->first_frame); + } + + *data_type = data->datatype; + + switch(*data_type) + { + case TNG_CHAR_DATA: + return(TNG_FAILURE); + case TNG_INT_DATA: + size = sizeof(int64_t); + break; + case TNG_FLOAT_DATA: + size = sizeof(float); + break; + case TNG_DOUBLE_DATA: + default: + size = sizeof(double); + } + + full_data_len = size * data->n_values_per_frame; + + temp = (char *)realloc(*values, full_data_len); + if(!temp) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(*values); + *values = 0; + return(TNG_CRITICAL); + } + + *values = temp; + + memcpy(*values, (char *)data->values + i * full_data_len, full_data_len); + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_pos_read_range + (const tng_trajectory_t tng_data, + const int64_t first_frame, + const int64_t last_frame, + float **positions, + int64_t *stride_length) +{ + int64_t n_particles, n_values_per_frame; + char type; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer"); + TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame."); + TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer"); + + stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_POSITIONS, + first_frame, last_frame, + TNG_USE_HASH, + (void **)positions, + &n_particles, + stride_length, + &n_values_per_frame, + &type); + + if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA) + { + return(TNG_FAILURE); + } + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_vel_read_range + (const tng_trajectory_t tng_data, + const int64_t first_frame, + const int64_t last_frame, + float **velocities, + int64_t *stride_length) +{ + int64_t n_particles, n_values_per_frame; + char type; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer"); + TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame."); + TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer"); + + stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_VELOCITIES, + first_frame, last_frame, + TNG_USE_HASH, + (void **)velocities, + &n_particles, + stride_length, + &n_values_per_frame, + &type); + + if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA) + { + return(TNG_FAILURE); + } + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_force_read_range + (const tng_trajectory_t tng_data, + const int64_t first_frame, + const int64_t last_frame, + float **forces, + int64_t *stride_length) +{ + int64_t n_particles, n_values_per_frame; + char type; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer"); + TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame."); + TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer"); + + stat = tng_particle_data_vector_interval_get(tng_data, TNG_TRAJ_FORCES, + first_frame, last_frame, + TNG_USE_HASH, + (void **)forces, + &n_particles, + stride_length, + &n_values_per_frame, + &type); + + if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA) + { + return(TNG_FAILURE); + } + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_read_range + (const tng_trajectory_t tng_data, + const int64_t first_frame, + const int64_t last_frame, + float **box_shape, + int64_t *stride_length) +{ + int64_t n_values_per_frame; + char type; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer"); + TNG_ASSERT(first_frame <= last_frame, "TNG library: first_frame must be lower or equal to last_frame."); + TNG_ASSERT(stride_length, "TNG library: stride_length must not be a NULL pointer"); + + stat = tng_data_vector_interval_get(tng_data, TNG_TRAJ_BOX_SHAPE, + first_frame, last_frame, + TNG_USE_HASH, + (void **)box_shape, + stride_length, + &n_values_per_frame, + &type); + + if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA) + { + return(TNG_FAILURE); + } + + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_set + (const tng_trajectory_t tng_data, + const int64_t i, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression) +{ + tng_trajectory_frame_set_t frame_set; + tng_data_t data; + int64_t n_particles, n_frames; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0."); + + if(i <= 0) + { + fprintf(stderr, "TNG library: Cannot set writing frequency to %" PRId64 ". %s: %d\n", + i, __FILE__, __LINE__); + return(TNG_FAILURE); + } + + frame_set = &tng_data->current_trajectory_frame_set; + + if(!frame_set || tng_data->n_trajectory_frame_sets <= 0) + { + n_frames = tng_data->frame_set_n_frames; + + stat = tng_frame_set_new(tng_data, 0, n_frames); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__, + __LINE__); + return(stat); + } + } + else + { + n_frames = frame_set->n_frames; + } + + if(particle_dependency == TNG_PARTICLE_BLOCK_DATA) + { + tng_num_particles_get(tng_data, &n_particles); + if(n_particles <= 0) + { + return(TNG_FAILURE); + } + + if(tng_particle_data_find(tng_data, block_id, &data) + != TNG_SUCCESS) + { + stat = tng_particle_data_block_add(tng_data, block_id, + block_name, + TNG_FLOAT_DATA, + TNG_TRAJECTORY_BLOCK, + n_frames, n_values_per_frame, i, + 0, n_particles, + compression, 0); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name, + __FILE__, __LINE__); + return(stat); + } + data = &frame_set->tr_particle_data[frame_set-> + n_particle_data_blocks - 1]; + stat = tng_allocate_particle_data_mem(tng_data, data, n_frames, + i, n_particles, + n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + else + { + if(data->stride_length != i) + { + data->stride_length = i; + stat = tng_allocate_particle_data_mem(tng_data, data, n_frames, + i, n_particles, + n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + } + } + else + { + if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS) + { + stat = tng_data_block_add(tng_data, block_id, block_name, + TNG_FLOAT_DATA, TNG_TRAJECTORY_BLOCK, + n_frames, n_values_per_frame, + i, compression, 0); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name, + __FILE__, __LINE__); + return(stat); + } + data = &frame_set->tr_data[frame_set-> + n_data_blocks - 1]; + stat = tng_allocate_data_mem(tng_data, data, n_frames, + i, n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + else + { + if(data->stride_length != i) + { + data->stride_length = i; + stat = tng_allocate_data_mem(tng_data, data, n_frames, + i, n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + } + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_interval_double_set + (const tng_trajectory_t tng_data, + const int64_t i, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression) +{ + tng_trajectory_frame_set_t frame_set; + tng_data_t data; + int64_t n_particles, n_frames; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(i >= 0, "TNG library: i (writing interval) must be >= 0."); + + if(i <= 0) + { + fprintf(stderr, "TNG library: Cannot set writing frequency to %" PRId64 ". %s: %d\n", + i, __FILE__, __LINE__); + return(TNG_FAILURE); + } + + frame_set = &tng_data->current_trajectory_frame_set; + + if(!frame_set || tng_data->n_trajectory_frame_sets <= 0) + { + n_frames = tng_data->frame_set_n_frames; + + stat = tng_frame_set_new(tng_data, 0, n_frames); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__, + __LINE__); + return(stat); + } + } + else + { + n_frames = frame_set->n_frames; + } + + if(particle_dependency == TNG_PARTICLE_BLOCK_DATA) + { + tng_num_particles_get(tng_data, &n_particles); + + if(n_particles <= 0) + { + return(TNG_FAILURE); + } + + if(tng_particle_data_find(tng_data, block_id, &data) + != TNG_SUCCESS) + { + stat = tng_particle_data_block_add(tng_data, block_id, + block_name, + TNG_DOUBLE_DATA, + TNG_TRAJECTORY_BLOCK, + n_frames, n_values_per_frame, i, + 0, n_particles, + compression, 0); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name, + __FILE__, __LINE__); + return(stat); + } + data = &frame_set->tr_particle_data[frame_set-> + n_particle_data_blocks - 1]; + stat = tng_allocate_particle_data_mem(tng_data, data, n_frames, + i, n_particles, + n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + else + { + data->stride_length = i; + } + } + else + { + if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS) + { + stat = tng_data_block_add(tng_data, block_id, block_name, + TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK, + n_frames, n_values_per_frame, + i, compression, 0); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name, + __FILE__, __LINE__); + return(stat); + } + data = &frame_set->tr_data[frame_set-> + n_data_blocks - 1]; + stat = tng_allocate_data_mem(tng_data, data, n_frames, + i, n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + else + { + data->stride_length = i; + } + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_generic_write_frequency_set + (const tng_trajectory_t tng_data, + const int64_t i, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression) +{ + fprintf(stderr, "TNG library: Using obsolete function tng_util_generic_write_frequency_set(). " + "See documentation. %s: %d", __FILE__, __LINE__); + return(tng_util_generic_write_interval_set(tng_data, i, n_values_per_frame, + block_id, block_name, + particle_dependency, + compression)); +} +tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_set + (const tng_trajectory_t tng_data, + const int64_t i) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0."); + + return(tng_util_generic_write_interval_set(tng_data, i, 3, + TNG_TRAJ_POSITIONS, + "POSITIONS", + TNG_PARTICLE_BLOCK_DATA, + TNG_TNG_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_interval_double_set + (const tng_trajectory_t tng_data, + const int64_t i) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0."); + + return(tng_util_generic_write_interval_double_set(tng_data, i, 3, + TNG_TRAJ_POSITIONS, + "POSITIONS", + TNG_PARTICLE_BLOCK_DATA, + TNG_TNG_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_pos_write_frequency_set + (const tng_trajectory_t tng_data, + const int64_t i) +{ + fprintf(stderr, "TNG library: Using obsolete function tng_util_pos_write_frequency_set(). " + "See documentation. %s: %d", __FILE__, __LINE__); + return(tng_util_pos_write_interval_set(tng_data, i)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_set + (const tng_trajectory_t tng_data, + const int64_t i) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0."); + + return(tng_util_generic_write_interval_set(tng_data, i, 3, + TNG_TRAJ_VELOCITIES, + "VELOCITIES", + TNG_PARTICLE_BLOCK_DATA, + TNG_TNG_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_interval_double_set + (const tng_trajectory_t tng_data, + const int64_t i) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0."); + + return(tng_util_generic_write_interval_double_set(tng_data, i, 3, + TNG_TRAJ_VELOCITIES, + "VELOCITIES", + TNG_PARTICLE_BLOCK_DATA, + TNG_TNG_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_vel_write_frequency_set + (const tng_trajectory_t tng_data, + const int64_t i) +{ + fprintf(stderr, "TNG library: Using obsolete function tng_util_vel_write_frequency_set(). " + "See documentation. %s: %d", __FILE__, __LINE__); + return(tng_util_vel_write_interval_set(tng_data, i)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_set + (const tng_trajectory_t tng_data, + const int64_t i) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0."); + + return(tng_util_generic_write_interval_set(tng_data, i, 3, + TNG_TRAJ_FORCES, + "FORCES", + TNG_PARTICLE_BLOCK_DATA, + TNG_GZIP_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_force_write_interval_double_set + (const tng_trajectory_t tng_data, + const int64_t i) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0."); + + return(tng_util_generic_write_interval_double_set(tng_data, i, 3, + TNG_TRAJ_FORCES, + "FORCES", + TNG_PARTICLE_BLOCK_DATA, + TNG_GZIP_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_force_write_frequency_set + (const tng_trajectory_t tng_data, + const int64_t i) +{ + fprintf(stderr, "TNG library: Using obsolete function tng_util_force_write_frequency_set(). " + "See documentation. %s: %d", __FILE__, __LINE__); + return(tng_util_force_write_interval_set(tng_data, i)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_set + (const tng_trajectory_t tng_data, + const int64_t i) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0."); + + return(tng_util_generic_write_interval_set(tng_data, i, 9, + TNG_TRAJ_BOX_SHAPE, + "BOX SHAPE", + TNG_NON_PARTICLE_BLOCK_DATA, + TNG_GZIP_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_interval_double_set + (const tng_trajectory_t tng_data, + const int64_t i) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(i > 0, "TNG library: i (writing interval) must be >= 0."); + + return(tng_util_generic_write_interval_double_set(tng_data, i, 9, + TNG_TRAJ_BOX_SHAPE, + "BOX SHAPE", + TNG_NON_PARTICLE_BLOCK_DATA, + TNG_GZIP_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write_frequency_set + (const tng_trajectory_t tng_data, + const int64_t i) +{ + fprintf(stderr, "TNG library: Using obsolete function tng_util_box_shape_write_frequency_set(). " + "See documentation. %s: %d", __FILE__, __LINE__); + return(tng_util_box_shape_write_interval_set(tng_data, i)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_generic_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const float *values, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression) +{ + tng_trajectory_frame_set_t frame_set; + tng_data_t data; + int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos; + int64_t last_frame; + int is_first_frame_flag = 0; + char block_type_flag; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(values, "TNG library: values must not be a NULL pointer"); + + if(particle_dependency == TNG_PARTICLE_BLOCK_DATA) + { + tng_num_particles_get(tng_data, &n_particles); + TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data."); + } + + if(values == 0) + { + return(TNG_FAILURE); + } + + frame_set = &tng_data->current_trajectory_frame_set; + + if(frame_nr < 0) + { + block_type_flag = TNG_NON_TRAJECTORY_BLOCK; + n_frames = stride_length = 1; + } + else + { + block_type_flag = TNG_TRAJECTORY_BLOCK; + + if(!frame_set || tng_data->n_trajectory_frame_sets <= 0) + { + stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__, + __LINE__); + return(stat); + } + } + last_frame = frame_set->first_frame + + frame_set->n_frames - 1; + if(frame_nr > last_frame) + { + stat = tng_frame_set_write(tng_data, TNG_USE_HASH); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot write frame set. %s: %d\n", __FILE__, + __LINE__); + return(stat); + } + if(last_frame + tng_data->frame_set_n_frames < frame_nr) + { + last_frame = frame_nr - 1; + } + stat = tng_frame_set_new(tng_data, last_frame + 1, + tng_data->frame_set_n_frames); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__, + __LINE__); + return(stat); + } + } + if(frame_set->n_unwritten_frames == 0) + { + is_first_frame_flag = 1; + } + frame_set->n_unwritten_frames = frame_nr - + frame_set->first_frame + 1; + + n_frames = frame_set->n_frames; + } + + if(particle_dependency == TNG_PARTICLE_BLOCK_DATA) + { + if(tng_particle_data_find(tng_data, block_id, &data) + != TNG_SUCCESS) + { + stat = tng_particle_data_block_add(tng_data, block_id, + block_name, + TNG_FLOAT_DATA, + block_type_flag, + n_frames, n_values_per_frame, + stride_length, + 0, n_particles, + compression, 0); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name, + __FILE__, __LINE__); + return(stat); + } + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + data = &frame_set->tr_particle_data[frame_set-> + n_particle_data_blocks - 1]; + } + else + { + data = &tng_data->non_tr_particle_data[tng_data-> + n_particle_data_blocks - 1]; + } + stat = tng_allocate_particle_data_mem(tng_data, data, n_frames, + stride_length, n_particles, + n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + /* FIXME: Here we must be able to handle modified n_particles as well. */ + else if(n_frames > data->n_frames) + { + stat = tng_allocate_particle_data_mem(tng_data, data, n_frames, + data->stride_length, n_particles, + n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + stride_length = data->stride_length; + + if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame) + { + data->first_frame_with_data = frame_nr; + frame_pos = 0; + } + else + { + frame_pos = (frame_nr - frame_set->first_frame) / stride_length; + } + + memcpy((char *)data->values + sizeof(float) * frame_pos * n_particles * + n_values_per_frame, values, sizeof(float) * + n_particles * n_values_per_frame); + } + else + { + memcpy(data->values, values, sizeof(float) * n_particles * + n_values_per_frame); + } + } + else + { + if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS) + { + stat = tng_data_block_add(tng_data, block_id, block_name, + TNG_FLOAT_DATA, block_type_flag, + n_frames, n_values_per_frame, + stride_length, compression, 0); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name, + __FILE__, __LINE__); + return(stat); + } + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + data = &frame_set->tr_data[frame_set-> + n_data_blocks - 1]; + } + else + { + data = &tng_data->non_tr_data[tng_data-> + n_data_blocks - 1]; + } + stat = tng_allocate_data_mem(tng_data, data, n_frames, + stride_length, n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + /* FIXME: Here we must be able to handle modified n_particles as well. */ + else if(n_frames > data->n_frames) + { + stat = tng_allocate_data_mem(tng_data, data, n_frames, + data->stride_length, n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + stride_length = data->stride_length; + + if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame) + { + data->first_frame_with_data = frame_nr; + frame_pos = 0; + } + else + { + frame_pos = (frame_nr - frame_set->first_frame) / stride_length; + } + + memcpy((char *)data->values + sizeof(float) * frame_pos * + n_values_per_frame, values, sizeof(float) * + n_values_per_frame); + } + else + { + memcpy(data->values, values, sizeof(float) * n_values_per_frame); + } + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_generic_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double *values, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression) +{ + tng_trajectory_frame_set_t frame_set; + tng_data_t data; + int64_t n_particles = 0, n_frames, stride_length = 100, frame_pos; + int64_t last_frame; + int is_first_frame_flag = 0; + char block_type_flag; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(values, "TNG library: values must not be a NULL pointer"); + + if(particle_dependency == TNG_PARTICLE_BLOCK_DATA) + { + tng_num_particles_get(tng_data, &n_particles); + TNG_ASSERT(n_particles > 0, "TNG library: There must be particles in the system to write particle data."); + } + + if(values == 0) + { + return(TNG_FAILURE); + } + + frame_set = &tng_data->current_trajectory_frame_set; + + if(frame_nr < 0) + { + block_type_flag = TNG_NON_TRAJECTORY_BLOCK; + n_frames = stride_length = 1; + } + else + { + block_type_flag = TNG_TRAJECTORY_BLOCK; + + if(!frame_set || tng_data->n_trajectory_frame_sets <= 0) + { + stat = tng_frame_set_new(tng_data, 0, tng_data->frame_set_n_frames); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__, + __LINE__); + return(stat); + } + } + last_frame = frame_set->first_frame + + frame_set->n_frames - 1; + if(frame_nr > last_frame) + { + stat = tng_frame_set_write(tng_data, TNG_USE_HASH); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot write frame set. %s: %d\n", __FILE__, + __LINE__); + return(stat); + } + if(last_frame + tng_data->frame_set_n_frames < frame_nr) + { + last_frame = frame_nr - 1; + } + stat = tng_frame_set_new(tng_data, last_frame + 1, + tng_data->frame_set_n_frames); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot create frame set. %s: %d\n", __FILE__, + __LINE__); + return(stat); + } + } + if(frame_set->n_unwritten_frames == 0) + { + is_first_frame_flag = 1; + } + frame_set->n_unwritten_frames = frame_nr - + frame_set->first_frame + 1; + + n_frames = frame_set->n_frames; + } + + + if(particle_dependency == TNG_PARTICLE_BLOCK_DATA) + { + if(tng_particle_data_find(tng_data, block_id, &data) + != TNG_SUCCESS) + { + stat = tng_particle_data_block_add(tng_data, block_id, + block_name, + TNG_DOUBLE_DATA, + block_type_flag, + n_frames, n_values_per_frame, + stride_length, + 0, n_particles, + compression, 0); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name, + __FILE__, __LINE__); + return(stat); + } + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + data = &frame_set->tr_particle_data[frame_set-> + n_particle_data_blocks - 1]; + } + else + { + data = &tng_data->non_tr_particle_data[tng_data-> + n_particle_data_blocks - 1]; + } + stat = tng_allocate_particle_data_mem(tng_data, data, n_frames, + stride_length, n_particles, + n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + /* FIXME: Here we must be able to handle modified n_particles as well. */ + else if(n_frames > data->n_frames) + { + stat = tng_allocate_particle_data_mem(tng_data, data, n_frames, + data->stride_length, n_particles, + n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + stride_length = data->stride_length; + + if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame) + { + data->first_frame_with_data = frame_nr; + frame_pos = 0; + } + else + { + frame_pos = (frame_nr - frame_set->first_frame) / stride_length; + } + + memcpy((char *)data->values + sizeof(double) * frame_pos * n_particles * + n_values_per_frame, values, sizeof(double) * + n_particles * n_values_per_frame); + } + else + { + memcpy(data->values, values, sizeof(double) * n_particles * + n_values_per_frame); + } + } + else + { + if(tng_data_find(tng_data, block_id, &data) != TNG_SUCCESS) + { + stat = tng_data_block_add(tng_data, block_id, block_name, + TNG_DOUBLE_DATA, block_type_flag, + n_frames, n_values_per_frame, + stride_length, compression, 0); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error %s adding data block. %s: %d\n", block_name, + __FILE__, __LINE__); + return(stat); + } + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + data = &frame_set->tr_data[frame_set-> + n_data_blocks - 1]; + } + else + { + data = &tng_data->non_tr_data[tng_data-> + n_data_blocks - 1]; + } + stat = tng_allocate_data_mem(tng_data, data, n_frames, + stride_length, n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + /* FIXME: Here we must be able to handle modified n_particles as well. */ + else if(n_frames > data->n_frames) + { + stat = tng_allocate_data_mem(tng_data, data, n_frames, + data->stride_length, n_values_per_frame); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Error allocating particle data memory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + + if(block_type_flag == TNG_TRAJECTORY_BLOCK) + { + stride_length = data->stride_length; + + if(is_first_frame_flag || data->first_frame_with_data < frame_set->first_frame) + { + data->first_frame_with_data = frame_nr; + frame_pos = 0; + } + else + { + frame_pos = (frame_nr - frame_set->first_frame) / stride_length; + } + + memcpy((char *)data->values + sizeof(double) * frame_pos * + n_values_per_frame, values, sizeof(double) * + n_values_per_frame); + } + else + { + memcpy(data->values, values, sizeof(double) * n_values_per_frame); + } + } + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_pos_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const float *positions) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer"); + + return(tng_util_generic_write(tng_data, frame_nr, positions, 3, + TNG_TRAJ_POSITIONS, "POSITIONS", + TNG_PARTICLE_BLOCK_DATA, + TNG_TNG_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_pos_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double *positions) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer"); + + return(tng_util_generic_double_write(tng_data, frame_nr, positions, 3, + TNG_TRAJ_POSITIONS, "POSITIONS", + TNG_PARTICLE_BLOCK_DATA, + TNG_TNG_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_vel_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const float *velocities) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer"); + + return(tng_util_generic_write(tng_data, frame_nr, velocities, 3, + TNG_TRAJ_VELOCITIES, "VELOCITIES", + TNG_PARTICLE_BLOCK_DATA, + TNG_TNG_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_vel_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double *velocities) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer"); + + return(tng_util_generic_double_write(tng_data, frame_nr, velocities, 3, + TNG_TRAJ_VELOCITIES, "VELOCITIES", + TNG_PARTICLE_BLOCK_DATA, + TNG_TNG_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_force_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const float *forces) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer"); + + return(tng_util_generic_write(tng_data, frame_nr, forces, 3, + TNG_TRAJ_FORCES, "FORCES", + TNG_PARTICLE_BLOCK_DATA, + TNG_GZIP_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_force_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double *forces) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer"); + + return(tng_util_generic_double_write(tng_data, frame_nr, forces, 3, + TNG_TRAJ_FORCES, "FORCES", + TNG_PARTICLE_BLOCK_DATA, + TNG_GZIP_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const float *box_shape) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer"); + + return(tng_util_generic_write(tng_data, frame_nr, box_shape, 9, + TNG_TRAJ_BOX_SHAPE, "BOX SHAPE", + TNG_NON_PARTICLE_BLOCK_DATA, + TNG_GZIP_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double *box_shape) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer"); + + return(tng_util_generic_double_write(tng_data, frame_nr, box_shape, 9, + TNG_TRAJ_BOX_SHAPE, "BOX SHAPE", + TNG_NON_PARTICLE_BLOCK_DATA, + TNG_GZIP_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const float *values, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression) +{ + tng_trajectory_frame_set_t frame_set; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0."); + TNG_ASSERT(time >= 0, "TNG library: time must be >= 0."); + TNG_ASSERT(values, "TNG library: values must not be a NULL pointer"); + + stat = tng_util_generic_write(tng_data, frame_nr, values, n_values_per_frame, + block_id, block_name, + particle_dependency, + compression); + + if(stat != TNG_SUCCESS) + { + return(stat); + } + + frame_set = &tng_data->current_trajectory_frame_set; + + /* first_frame_time is -1 when it is not yet set. */ + if(frame_set->first_frame_time < -0.1) + { + if(frame_nr > frame_set->first_frame) + { + stat = tng_frame_set_first_frame_time_set(tng_data, + time - + (frame_nr - + frame_set->first_frame) * + tng_data->time_per_frame); + } + else + { + stat = tng_frame_set_first_frame_time_set(tng_data, time); + } + } + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_generic_with_time_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const double *values, + const int64_t n_values_per_frame, + const int64_t block_id, + const char *block_name, + const char particle_dependency, + const char compression) +{ + tng_trajectory_frame_set_t frame_set; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0."); + TNG_ASSERT(time >= 0, "TNG library: time must be >= 0."); + TNG_ASSERT(values, "TNG library: values must not be a NULL pointer"); + + stat = tng_util_generic_double_write(tng_data, frame_nr, values, n_values_per_frame, + block_id, block_name, + particle_dependency, + compression); + + if(stat != TNG_SUCCESS) + { + return(stat); + } + + frame_set = &tng_data->current_trajectory_frame_set; + + /* first_frame_time is -1 when it is not yet set. */ + if(frame_set->first_frame_time < -0.1) + { + if(frame_nr > frame_set->first_frame) + { + stat = tng_frame_set_first_frame_time_set(tng_data, + time - + (frame_nr - + frame_set->first_frame) * + tng_data->time_per_frame); + } + else + { + stat = tng_frame_set_first_frame_time_set(tng_data, time); + } + } + return(stat); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const float *positions) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0."); + TNG_ASSERT(time >= 0, "TNG library: time must be >= 0."); + TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer"); + + return(tng_util_generic_with_time_write(tng_data, frame_nr, time, positions, + 3, TNG_TRAJ_POSITIONS, "POSITIONS", + TNG_PARTICLE_BLOCK_DATA, + TNG_TNG_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_pos_with_time_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const double *positions) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0."); + TNG_ASSERT(time >= 0, "TNG library: time must be >= 0."); + TNG_ASSERT(positions, "TNG library: positions must not be a NULL pointer"); + + return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time, + positions, 3, + TNG_TRAJ_POSITIONS, + "POSITIONS", + TNG_PARTICLE_BLOCK_DATA, + TNG_TNG_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const float *velocities) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0."); + TNG_ASSERT(time >= 0, "TNG library: time must be >= 0."); + TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer"); + + return(tng_util_generic_with_time_write(tng_data, frame_nr, time, + velocities, 3, + TNG_TRAJ_VELOCITIES, + "VELOCITIES", + TNG_PARTICLE_BLOCK_DATA, + TNG_TNG_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_vel_with_time_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const double *velocities) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0."); + TNG_ASSERT(time >= 0, "TNG library: time must be >= 0."); + TNG_ASSERT(velocities, "TNG library: velocities must not be a NULL pointer"); + + return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time, + velocities, 3, + TNG_TRAJ_VELOCITIES, + "VELOCITIES", + TNG_PARTICLE_BLOCK_DATA, + TNG_TNG_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const float *forces) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0."); + TNG_ASSERT(time >= 0, "TNG library: time must be >= 0."); + TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer"); + + return(tng_util_generic_with_time_write(tng_data, frame_nr, time, forces, + 3, TNG_TRAJ_FORCES, "FORCES", + TNG_PARTICLE_BLOCK_DATA, + TNG_GZIP_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_force_with_time_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const double *forces) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0."); + TNG_ASSERT(time >= 0, "TNG library: time must be >= 0."); + TNG_ASSERT(forces, "TNG library: forces must not be a NULL pointer"); + + return(tng_util_generic_with_time_double_write(tng_data, frame_nr, time, + forces, 3, + TNG_TRAJ_FORCES, "FORCES", + TNG_PARTICLE_BLOCK_DATA, + TNG_GZIP_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const float *box_shape) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0."); + TNG_ASSERT(time >= 0, "TNG library: time must be >= 0."); + TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer"); + + return(tng_util_generic_with_time_write(tng_data, frame_nr, time, box_shape, + 9, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE", + TNG_NON_PARTICLE_BLOCK_DATA, + TNG_GZIP_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_box_shape_with_time_double_write + (const tng_trajectory_t tng_data, + const int64_t frame_nr, + const double time, + const double *box_shape) +{ + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(frame_nr >= 0, "TNG library: frame_nr must be >= 0."); + TNG_ASSERT(time >= 0, "TNG library: time must be >= 0."); + TNG_ASSERT(box_shape, "TNG library: box_shape must not be a NULL pointer"); + + return(tng_util_generic_with_time_double_write(tng_data, frame_nr, + time, box_shape, 9, + TNG_TRAJ_BOX_SHAPE, + "BOX SHAPE", + TNG_NON_PARTICLE_BLOCK_DATA, + TNG_GZIP_COMPRESSION)); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_frame_current_compression_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + int64_t *codec_id, + double *factor) +{ + tng_trajectory_frame_set_t frame_set; + tng_data_t data = 0; + tng_function_status stat; + int64_t i; + int block_type = -1; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(codec_id, "TNG library: The pointer to the returned codec id must not be a NULL pointer."); + TNG_ASSERT(factor, "TNG library: The pointer to the returned multiplication factor must not be a NULL pointer."); + + frame_set = &tng_data->current_trajectory_frame_set; + + stat = tng_particle_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + block_type = TNG_PARTICLE_BLOCK_DATA; + } + else + { + stat = tng_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + block_type = TNG_NON_PARTICLE_BLOCK_DATA; + } + else + { + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_particle_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + block_type = TNG_PARTICLE_BLOCK_DATA; + } + else + { + stat = tng_data_find(tng_data, block_id, &data); + if(stat == TNG_SUCCESS) + { + block_type = TNG_NON_PARTICLE_BLOCK_DATA; + } + else + { + return(stat); + } + } + } + } + if(block_type == TNG_PARTICLE_BLOCK_DATA) + { + if(data->last_retrieved_frame < 0) + { + i = data->first_frame_with_data; + } + else + { + i = data->last_retrieved_frame; + } + } + else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA) + { + if(data->last_retrieved_frame < 0) + { + i = data->first_frame_with_data; + } + else + { + i = data->last_retrieved_frame; + } + } + else + { + return(TNG_FAILURE); + } + if(i < frame_set->first_frame || i >= frame_set->first_frame + frame_set->n_frames) + { + stat = tng_frame_set_of_frame_find(tng_data, i); + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, TNG_USE_HASH, block_id); + if(stat != TNG_SUCCESS) + { + fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + } + if(block_type == TNG_PARTICLE_BLOCK_DATA) + { + *codec_id = data->codec_id; + *factor = data->compression_multiplier; + } + else if(block_type == TNG_NON_PARTICLE_BLOCK_DATA) + { + *codec_id = data->codec_id; + *factor = data->compression_multiplier; + } + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_next_frame_present_data_blocks_find + (const tng_trajectory_t tng_data, + int64_t current_frame, + const int64_t n_requested_data_block_ids, + const int64_t *requested_data_block_ids, + int64_t *next_frame, + int64_t *n_data_blocks_in_next_frame, + int64_t **data_block_ids_in_next_frame) +{ + tng_trajectory_frame_set_t frame_set; + tng_function_status stat; + tng_data_t data; + tng_gen_block_t block; + int64_t i, j, block_id, *temp; + int64_t data_frame, frame_diff, min_diff; + int64_t size, frame_set_file_pos; + int found, read_all = 0; + int64_t file_pos; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(next_frame, "TNG library: The pointer to the next frame must not be NULL."); + TNG_ASSERT(n_data_blocks_in_next_frame, "TNG library: The pointer to n_data_blocks_in_next_frame must not be NULL."); + TNG_ASSERT(data_block_ids_in_next_frame, "TNG library: The pointer to the list of data block IDs must not be NULL."); + + if(n_requested_data_block_ids) + { + TNG_ASSERT(requested_data_block_ids, "TNG library: If the number of requested data blocks is > 0 then the array of data block IDs must not be NULL."); + size = sizeof(int64_t) * n_requested_data_block_ids; + temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size); + if(!temp) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(*data_block_ids_in_next_frame); + *data_block_ids_in_next_frame = 0; + return(TNG_CRITICAL); + } + *data_block_ids_in_next_frame = temp; + } + + frame_set = &tng_data->current_trajectory_frame_set; + + current_frame += 1; + + if(current_frame < frame_set->first_frame || + current_frame >= frame_set->first_frame + frame_set->n_frames) + { + frame_set_file_pos = tng_data->current_trajectory_frame_set_input_file_pos; + stat = tng_frame_set_of_frame_find(tng_data, current_frame); + if(stat != TNG_SUCCESS) + { + /* If the frame set search found the frame set after the starting + * frame set there is a gap in the frame sets. So, even if the frame + * was not found the next frame with data is still in the found + * frame set. */ + if(stat == TNG_CRITICAL || frame_set->prev_frame_set_file_pos != + frame_set_file_pos) + { + return(stat); + } + current_frame = frame_set->first_frame; + } + } + + /* Check for data blocks only if they have not already been found. */ + if(frame_set->n_particle_data_blocks <= 0 && frame_set->n_data_blocks <= 0) + { + file_pos = ftello(tng_data->input_file); + if(file_pos < tng_data->input_file_len) + { + tng_block_init(&block); + stat = tng_block_header_read(tng_data, block); + while(file_pos < tng_data->input_file_len && + stat != TNG_CRITICAL && + block->id != TNG_TRAJECTORY_FRAME_SET && + block->id != -1) + { + stat = tng_block_read_next(tng_data, block, + TNG_USE_HASH); + if(stat != TNG_CRITICAL) + { + file_pos = ftello(tng_data->input_file); + if(file_pos < tng_data->input_file_len) + { + stat = tng_block_header_read(tng_data, block); + } + } + } + tng_block_destroy(&block); + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", + file_pos, __FILE__, __LINE__); + return(stat); + } + } + read_all = 1; + } + + min_diff = -1; + + *n_data_blocks_in_next_frame = 0; + + for(i = 0; i < frame_set->n_particle_data_blocks; i++) + { + data = &frame_set->tr_particle_data[i]; + block_id = data->block_id; + + if(n_requested_data_block_ids > 0) + { + found = 0; + for(j = 0; j < n_requested_data_block_ids; j++) + { + if(block_id == requested_data_block_ids[j]) + { + found = 1; + break; + } + } + if(!found) + { + continue; + } + } + + if(!read_all && (data->last_retrieved_frame < frame_set->first_frame || + data->last_retrieved_frame >= + frame_set->first_frame + frame_set->n_frames)) + { + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, + TNG_USE_HASH, block_id); + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + if(stat == TNG_FAILURE) + { + continue; + } + } + if(frame_set->first_frame != current_frame && + data->last_retrieved_frame >= 0) + { + data_frame = data->last_retrieved_frame + data->stride_length; + } + else + { + data_frame = data->first_frame_with_data; + } + frame_diff = data_frame - current_frame; + if(frame_diff < 0) + { + continue; + } + if(min_diff == -1 || frame_diff <= min_diff) + { + if(frame_diff < min_diff) + { + *n_data_blocks_in_next_frame = 1; + } + else + { + *n_data_blocks_in_next_frame += 1; + } + if(n_requested_data_block_ids <= 0) + { + size = sizeof(int64_t) * (*n_data_blocks_in_next_frame); + temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size); + if(!temp) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(*data_block_ids_in_next_frame); + *data_block_ids_in_next_frame = 0; + return(TNG_CRITICAL); + } + *data_block_ids_in_next_frame = temp; + } + else + { + TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds"); + } + (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id; + + min_diff = frame_diff; + } + } + for(i = 0; i < frame_set->n_data_blocks; i++) + { + data = &frame_set->tr_data[i]; + block_id = data->block_id; + + if(n_requested_data_block_ids > 0) + { + found = 0; + for(j = 0; j < n_requested_data_block_ids; j++) + { + if(block_id == requested_data_block_ids[j]) + { + found = 1; + break; + } + } + if(!found) + { + continue; + } + } + + if(!read_all && (data->last_retrieved_frame < frame_set->first_frame || + data->last_retrieved_frame >= + frame_set->first_frame + frame_set->n_frames)) + { + stat = tng_frame_set_read_current_only_data_from_block_id(tng_data, + TNG_USE_HASH, block_id); + if(stat == TNG_CRITICAL) + { + fprintf(stderr, "TNG library: Cannot read data block of frame set. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + if(stat == TNG_FAILURE) + { + continue; + } + } + if(frame_set->first_frame != current_frame && + data->last_retrieved_frame >= 0) + { + data_frame = data->last_retrieved_frame + data->stride_length; + } + else + { + data_frame = data->first_frame_with_data; + } + frame_diff = data_frame - current_frame; + if(frame_diff < 0) + { + continue; + } + if(min_diff == -1 || frame_diff <= min_diff) + { + if(frame_diff < min_diff) + { + *n_data_blocks_in_next_frame = 1; + } + else + { + *n_data_blocks_in_next_frame += 1; + } + if(n_requested_data_block_ids <= 0) + { + size = sizeof(int64_t) * (*n_data_blocks_in_next_frame); + temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size); + if(!temp) + { + fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + free(*data_block_ids_in_next_frame); + *data_block_ids_in_next_frame = 0; + return(TNG_CRITICAL); + } + *data_block_ids_in_next_frame = temp; + } + else + { + TNG_ASSERT(*n_data_blocks_in_next_frame <= n_requested_data_block_ids, "TNG library: Array of data block IDs out of bounds"); + } + (*data_block_ids_in_next_frame)[(*n_data_blocks_in_next_frame) - 1] = block_id; + + min_diff = frame_diff; + } + } + if(min_diff < 0) + { + return(TNG_FAILURE); + } + *next_frame = current_frame + min_diff; + + return(TNG_SUCCESS); +} + +/* +tng_function_status DECLSPECDLLEXPORT tng_util_trajectory_all_data_block_types_get + (const tng_trajectory_t tng_data, + int64_t *n_data_blocks, + int64_t **data_block_ids, + char ***data_block_names, + int64_t **stride_lengths, + int64_t **n_values_per_frame, + char **block_types, + char **dependencies, + char **compressions) +{ + tng_gen_block_t block; + int64_t orig_file_pos, file_pos; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(n_data_blocks, "TNG library: The pointer to n_data_blocks must not be NULL."); + TNG_ASSERT(data_block_ids, "TNG library: The pointer to the list of data block IDs must not be NULL."); + TNG_ASSERT(data_block_names, "TNG library: The pointer to the list of data block names must not be NULL."); + TNG_ASSERT(stride_lengths, "TNG library: The pointer to the list of stride lengths must not be NULL."); + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + orig_file_pos = ftello(tng_data->input_file); + + fseeko(tng_data->input_file, 0, SEEK_SET); + file_pos = 0; + + *n_data_blocks = 0; + + tng_block_init(&block); + + while(file_pos < tng_data->input_file_len && + tng_block_header_read(tng_data, block) != TNG_CRITICAL) + { + if(block->id > TNG_TRAJECTORY_FRAME_SET) + { + + } + file_pos += (block->block_contents_size + block->header_contents_size); + fseeko(tng_data->input_file, block->block_contents_size, SEEK_CUR); + } + + fseeko(tng_data->input_file, orig_file_pos, SEEK_SET); + + return(TNG_SUCCESS); +} +*/ +tng_function_status DECLSPECDLLEXPORT tng_util_prepare_append_after_frame + (const tng_trajectory_t tng_data, + const int64_t prev_frame) +{ + tng_function_status stat; + FILE *temp = tng_data->input_file; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + TNG_ASSERT(prev_frame >= 0, "TNG library: The previous frame must not be negative."); + + tng_data->input_file = tng_data->output_file; + + stat = tng_frame_set_of_frame_find(tng_data, prev_frame); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + tng_data->current_trajectory_frame_set_output_file_pos = + tng_data->current_trajectory_frame_set_input_file_pos; + + tng_data->input_file = temp; + + return(TNG_SUCCESS); +} + +tng_function_status DECLSPECDLLEXPORT tng_util_num_frames_with_data_of_block_id_get + (const tng_trajectory_t tng_data, + const int64_t block_id, + int64_t *n_frames) +{ + int64_t curr_file_pos, first_frame_set_file_pos, curr_n_frames; + tng_function_status stat; + + TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup."); + + *n_frames = 0; + + if(tng_input_file_init(tng_data) != TNG_SUCCESS) + { + return(TNG_CRITICAL); + } + + first_frame_set_file_pos = tng_data->first_trajectory_frame_set_input_file_pos; + curr_file_pos = ftello(tng_data->input_file); + fseeko(tng_data->input_file, first_frame_set_file_pos, SEEK_SET); + + stat = tng_frame_set_n_frames_of_data_block_get(tng_data, block_id, &curr_n_frames); + + while(stat == TNG_SUCCESS && tng_data->current_trajectory_frame_set.next_frame_set_file_pos != -1) + { + *n_frames += curr_n_frames; + fseeko(tng_data->input_file, + tng_data->current_trajectory_frame_set.next_frame_set_file_pos, + SEEK_SET); + stat = tng_frame_set_n_frames_of_data_block_get(tng_data, block_id, &curr_n_frames); + } + if(stat == TNG_SUCCESS) + { + *n_frames += curr_n_frames; + } + fseeko(tng_data->input_file, curr_file_pos, SEEK_SET); + if(stat == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + return(TNG_SUCCESS); +} diff --git a/src/tng/tng_io_testing.c b/src/tng/tng_io_testing.c new file mode 100644 index 0000000000..70d2e5a6c5 --- /dev/null +++ b/src/tng/tng_io_testing.c @@ -0,0 +1,1496 @@ +/* This code is part of the tng binary trajectory format. + * + * Written by Magnus Lundborg + * Copyright (c) 2012-2014, The GROMACS development team. + * Check out http://www.gromacs.org for more information. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + +#include "tng/tng_io.h" + +#ifdef USE_STD_INTTYPES_H +#include +#endif + +#include +#include +#include +#include "tng/version.h" + +#define BOX_SHAPE_X 150.0 +#define BOX_SHAPE_Y 145.5 +#define BOX_SHAPE_Z 155.5 +#define N_FRAME_SETS 100 +#define MEDIUM_STRIDE_LEN 5 +#define LONG_STRIDE_LEN 25 +#define TIME_PER_FRAME 2e-15 +#define COMPRESSION_PRECISION 1000 +#define USER_NAME "USER 1" +#define PROGRAM_NAME "tng_testing" +#define COMPUTER_NAME "Unknown computer" +#define FORCEFIELD_NAME "No forcefield" + +static tng_function_status tng_test_setup_molecules(tng_trajectory_t traj) +{ + tng_molecule_t molecule; + tng_chain_t chain; + tng_residue_t residue; + tng_atom_t atom; + tng_bond_t bond; + int64_t cnt; + + tng_molecule_add(traj, "water", &molecule); + tng_molecule_chain_add(traj, molecule, "W", &chain); + tng_chain_residue_add(traj, chain, "WAT", &residue); + if(tng_residue_atom_add(traj, residue, "O", "O", &atom) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + if(tng_residue_atom_add(traj, residue, "HO1", "H", &atom) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + if(tng_residue_atom_add(traj, residue, "HO2", "H", &atom) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + tng_molecule_bond_add(traj, molecule, 0, 1, &bond); + tng_molecule_bond_add(traj, molecule, 0, 2, &bond); + tng_molecule_cnt_set(traj, molecule, 200); + tng_molecule_cnt_get(traj, molecule, &cnt); + + if(cnt != 200) + { + return(TNG_CRITICAL); + } +/* printf("Created %"PRId64" %s molecules.\n", cnt, molecule->name); */ + +/* traj->molecule_cnt_list[traj->n_molecules-1] = 5; +// tng_molecule_name_set(traj, &traj->molecules[1], "ligand"); +// tng_molecule_name_set(traj, &traj->molecules[2], "water"); +// tng_molecule_name_set(traj, &traj->molecules[3], "dummy"); +// traj->molecules[0].id = 0; +// traj->molecules[1].id = 1; +// traj->molecules[2].id = 2; +// traj->molecules[3].id = 3; + +// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom1", "type1") == TNG_CRITICAL) +// { +// return(TNG_CRITICAL); +// } +// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom2", "type1") == TNG_CRITICAL) +// { +// return(TNG_CRITICAL); +// } +// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom3", "type1") == TNG_CRITICAL) +// { +// return(TNG_CRITICAL); +// } +// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom4", "type2") == TNG_CRITICAL) +// { +// return(TNG_CRITICAL); +// } +// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom5", "type2") == TNG_CRITICAL) +// { +// return(TNG_CRITICAL); +// } +// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom6", "type2") == TNG_CRITICAL) +// { +// return(TNG_CRITICAL); +// } +// if(tng_add_atom_to_molecule(traj, &traj->molecules[0], "atom7", "type3") == TNG_CRITICAL) +// { +// return(TNG_CRITICAL); +// } +// if(tng_add_atom_to_molecule(traj, &traj->molecules[1], "C1", "C") == TNG_CRITICAL) +// { +// return(TNG_CRITICAL); +// } +// if(tng_add_atom_to_molecule(traj, &traj->molecules[1], "O1", "O") == TNG_CRITICAL) +// { +// return(TNG_CRITICAL); +// } +// if(tng_add_atom_to_molecule(traj, &traj->molecules[1], "H11", "H") == TNG_CRITICAL) +// { +// return(TNG_CRITICAL); +// } +// if(tng_add_atom_to_molecule(traj, &traj->molecules[1], "H12", "H") == TNG_CRITICAL) +// { +// return(TNG_CRITICAL); +// } +// if(tng_add_atom_to_molecule(traj, &traj->molecules[1], "H13", "H") == TNG_CRITICAL) +// { +// return(TNG_CRITICAL); +// } +*/ + return(TNG_SUCCESS); +} + +static tng_function_status tng_test_molecules(tng_trajectory_t traj) +{ + tng_molecule_t molecule, molecule_new; + tng_chain_t chain; + tng_residue_t residue; + tng_atom_t atom; + int64_t cnt, *bonds_to, *bonds_from; + char var_atoms, str[TNG_MAX_STR_LEN]; + tng_function_status stat; + + stat = tng_num_molecule_types_get(traj, &cnt); + if(stat != TNG_SUCCESS || cnt != 1) + { + printf("Molecule reading error. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + stat = tng_num_molecules_get(traj, &cnt); + if(stat != TNG_SUCCESS || cnt != 200) + { + printf("Molecule reading error. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + stat = tng_num_particles_variable_get(traj, &var_atoms); + if(stat != TNG_SUCCESS || var_atoms) + { + printf("Molecule reading error. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + stat = tng_molecule_of_index_get(traj, 0, &molecule); + if(stat != TNG_SUCCESS) + { + printf("Cannot find molecule. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_molecule_find(traj, "water", -1, &molecule); + if(stat != TNG_SUCCESS) + { + printf("Cannot find molecule. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat =tng_molecule_name_get(traj, molecule, str, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Cannot get molecule name. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_molecule_num_chains_get(traj, molecule, &cnt); + if(stat != TNG_SUCCESS || cnt != 1) + { + printf("Cannot get number of chains in molecule. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_molecule_chain_of_index_get(traj, molecule, 0, &chain); + if(stat != TNG_SUCCESS) + { + printf("Cannot get chain in molecule. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_molecule_chain_find(traj, molecule, "W", -1, &chain); + if(stat != TNG_SUCCESS) + { + printf("Cannot get chain in molecule. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_molecule_num_residues_get(traj, molecule, &cnt); + if(stat != TNG_SUCCESS || cnt != 1) + { + printf("Cannot get number of residues in molecule. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_molecule_residue_of_index_get(traj, molecule, 0, &residue); + if(stat != TNG_SUCCESS) + { + printf("Cannot get residue in molecule. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_molecule_num_atoms_get(traj, molecule, &cnt); + if(stat != TNG_SUCCESS || cnt != 3) + { + printf("Cannot get number of atoms in molecule. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_molecule_atom_of_index_get(traj, molecule, 0, &atom); + if(stat != TNG_SUCCESS) + { + printf("Cannot get atom in molecule. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_molecule_atom_find(traj, molecule, "O", -1, &atom); + if(stat != TNG_SUCCESS) + { + printf("Cannot get atom in molecule. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + stat =tng_chain_name_get(traj, chain, str, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Cannot get name of chain. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_chain_num_residues_get(traj, chain, &cnt); + if(stat != TNG_SUCCESS || cnt != 1) + { + printf("Cannot get number of residues in chain. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_chain_residue_of_index_get(traj, chain, 0, &residue); + if(stat != TNG_SUCCESS) + { + printf("Cannot get residue in chain. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_chain_residue_find(traj, chain, "WAT", -1, &residue); + if(stat != TNG_SUCCESS) + { + printf("Cannot get residue in chain. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + stat = tng_residue_name_get(traj, residue, str, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Cannot get name of residue. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_residue_num_atoms_get(traj, residue, &cnt); + if(stat != TNG_SUCCESS || cnt != 3) + { + printf("Cannot get number of atoms in residue. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_residue_atom_of_index_get(traj, residue, 0, &atom); + if(stat != TNG_SUCCESS) + { + printf("Cannot get residue of atom. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + stat = tng_atom_name_get(traj, atom, str, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Cannot get name of atom. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_atom_type_get(traj, atom, str, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Cannot get atom type of atom. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + stat = tng_molecule_id_of_particle_nr_get(traj, 0, &cnt); + if(stat != TNG_SUCCESS || cnt != 1) + { + printf("Cannot get molecule id of atom. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_residue_id_of_particle_nr_get(traj, 0, &cnt); + if(stat != TNG_SUCCESS || cnt != 0) + { + printf("Cannot get residue id of atom. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_global_residue_id_of_particle_nr_get(traj, 599, &cnt); + if(stat != TNG_SUCCESS || cnt != 199) + { + printf("Cannot get global residue id of atom. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_molecule_name_of_particle_nr_get(traj, 0, str, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Cannot get molecule name of atom. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_chain_name_of_particle_nr_get(traj, 0, str, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Cannot get chain name of atom. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_residue_name_of_particle_nr_get(traj, 0, str, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Cannot get residue name of atom. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_atom_name_of_particle_nr_get(traj, 0, str, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Cannot get atom name of atom. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + stat = tng_molecule_alloc(traj, &molecule_new); + if(stat != TNG_SUCCESS) + { + printf("Cannot setup new molecule. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_molecule_name_set(traj, molecule_new, "TEST"); + if(stat != TNG_SUCCESS) + { + printf("Cannot set name of new molecule. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_molecule_existing_add(traj, &molecule_new); + if(stat != TNG_SUCCESS) + { + printf("Cannot add new molecule to molecule system. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + stat = tng_molsystem_bonds_get(traj, &cnt, &bonds_from, &bonds_to); + if(stat != TNG_SUCCESS || cnt != 400) + { + printf("Cannot get bonds in molecule system. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + free(bonds_from); + free(bonds_to); + + return(TNG_SUCCESS); +} + +static tng_function_status tng_test_read_and_write_file + (tng_trajectory_t traj, const char hash_mode) +{ + char file_name[TNG_MAX_STR_LEN]; + tng_function_status stat; + + stat = tng_input_file_get(traj, file_name, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Could not get name of input file. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_output_file_get(traj, file_name, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Could not get name of output file. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + stat = tng_file_headers_read(traj, hash_mode); + if(stat != TNG_SUCCESS) + { + printf("Could not read headers. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_file_headers_write(traj, hash_mode); + if(stat != TNG_SUCCESS) + { + printf("Could not write headers. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + while(stat == TNG_SUCCESS) + { + stat = tng_frame_set_read_next(traj, hash_mode); + if(stat == TNG_CRITICAL) + { + printf("Could not read frame set. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + if(stat == TNG_FAILURE) + { + return(TNG_SUCCESS); + } + stat = tng_frame_set_write(traj, hash_mode); + } + + return(stat); +} + +static tng_function_status tng_test_write_and_read_traj(tng_trajectory_t *traj, + const char hash_mode) +{ + int i, j, k, nr, cnt, dependency; + float *data, *molpos, *charges, *masses; + int64_t mapping[300], n_particles; + int64_t read_n_frames, read_stride_length, read_n_particles, read_n_values_per_frame; + int64_t n_frames_per_frame_set, tot_n_mols; + int64_t codec_id; + int64_t dist_exp = -9, temp_int, temp_int2; +// int64_t frame_nr; + double box_shape[9], temp_double; + char atom_type[16], annotation[128]; + char temp_str[TNG_MAX_STR_LEN]; + char read_data_type; + tng_trajectory_frame_set_t frame_set; + tng_function_status stat = TNG_SUCCESS; + + tng_medium_stride_length_set(*traj, MEDIUM_STRIDE_LEN); + tng_long_stride_length_set(*traj, LONG_STRIDE_LEN); + + tng_first_user_name_set(*traj, USER_NAME); + tng_first_program_name_set(*traj, PROGRAM_NAME); + tng_first_computer_name_set(*traj, COMPUTER_NAME); + tng_forcefield_name_set(*traj, FORCEFIELD_NAME); + + tng_compression_precision_set(*traj, COMPRESSION_PRECISION); + + tng_distance_unit_exponential_set(*traj, dist_exp); + + tng_time_per_frame_set(*traj, TIME_PER_FRAME); + + /* Create molecules */ + if(tng_test_setup_molecules(*traj) == TNG_CRITICAL) + { + return(TNG_CRITICAL); + } + + /* Set the box shape */ + box_shape[1] = box_shape[2] = box_shape[3] = box_shape[5] = box_shape[6] = + box_shape[7] = 0; + box_shape[0] = BOX_SHAPE_X; + box_shape[4] = BOX_SHAPE_Y; + box_shape[8] = BOX_SHAPE_Z; + if(tng_data_block_add(*traj, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE", TNG_DOUBLE_DATA, + TNG_NON_TRAJECTORY_BLOCK, 1, 9, 1, TNG_UNCOMPRESSED, + box_shape) == TNG_CRITICAL) + { + tng_trajectory_destroy(traj); + printf("Cannot write trajectory box shape.\n"); + exit(1); + } + + /* Set partial charges (treat the water as TIP3P). */ + tng_num_particles_get(*traj, &n_particles); + charges = malloc(sizeof(float) * n_particles); + for(i = 0; i < n_particles; i++) + { + stat = tng_atom_type_of_particle_nr_get(*traj, i, atom_type, + sizeof(atom_type)); + if(stat == TNG_CRITICAL) + { + break; + } + /* We only have water in the system. If the atom is oxygen set its + * partial charge to -0.834, if it's a hydrogen set its partial charge to + * 0.417. */ + switch(atom_type[0]) + { + case 'O': + charges[i] = -0.834; + break; + case 'H': + charges[i] = 0.417; + break; + default: + printf("Failed setting partial charges. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + if(stat == TNG_CRITICAL) + { + free(charges); + printf("Failed setting partial charges. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + stat = tng_particle_data_block_add(*traj, TNG_TRAJ_PARTIAL_CHARGES, "PARTIAL CHARGES", + TNG_FLOAT_DATA, TNG_NON_TRAJECTORY_BLOCK, + 1, 1, 1, 0, n_particles, + TNG_UNCOMPRESSED, charges); + free(charges); + charges = 0; + if(stat != TNG_SUCCESS) + { + printf("Failed adding partial charges. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + /* Set atom masses. */ + masses = malloc(sizeof(float) * n_particles); + for(i = 0; i < n_particles; i++) + { + stat = tng_atom_type_of_particle_nr_get(*traj, i, atom_type, + sizeof(atom_type)); + if(stat == TNG_CRITICAL) + { + break; + } + /* We only have water in the system. If the atom is oxygen set its + * mass to 16.00000, if it's a hydrogen set its mass to + * 1.00800. */ + switch(atom_type[0]) + { + case 'O': + masses[i] = 16.00000; + break; + case 'H': + masses[i] = 1.00800; + break; + default: + printf("Failed setting atom masses. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + } + if(stat == TNG_CRITICAL) + { + free(masses); + printf("Failed setting atom masses. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + stat = tng_particle_data_block_add(*traj, TNG_TRAJ_MASSES, "ATOM MASSES", + TNG_FLOAT_DATA, TNG_NON_TRAJECTORY_BLOCK, + 1, 1, 1, 0, n_particles, + TNG_GZIP_COMPRESSION, masses); + free(masses); + masses = 0; + if(stat != TNG_SUCCESS) + { + printf("Failed adding atom masses. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + /* Generate a custom annotation data block */ + strcpy(annotation, "This trajectory was generated from tng_io_testing. " + "It is not a real MD trajectory."); + if(tng_data_block_add(*traj, TNG_TRAJ_GENERAL_COMMENTS, "COMMENTS", TNG_CHAR_DATA, + TNG_NON_TRAJECTORY_BLOCK, 1, 1, 1, TNG_UNCOMPRESSED, + annotation) != TNG_SUCCESS) + { + printf("Failed adding details annotation data block. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + /* Write file headers (includes non trajectory data blocks */ + if(tng_file_headers_write(*traj, hash_mode) == TNG_CRITICAL) + { + printf("Cannot write file headers. %s: %d\n", + __FILE__, __LINE__); + } + + + tng_num_frames_per_frame_set_get(*traj, &n_frames_per_frame_set); + + data = malloc(sizeof(float) * n_particles * + n_frames_per_frame_set * 3); + if(!data) + { + printf("Cannot allocate memory. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + tng_num_molecules_get(*traj, &tot_n_mols); + molpos = malloc(sizeof(float) * tot_n_mols * 3); + + /* Set initial coordinates */ + for(i = 0; i < tot_n_mols; i++) + { + nr = i * 3; + /* Somewhat random coordinates (between 0 and 100), + * but not specifying a random seed */ + molpos[nr] = 100.0 * rand() / (RAND_MAX + 1.0); + molpos[nr+1] = 100.0 * rand() / (RAND_MAX + 1.0); + molpos[nr+2] = 100.0 * rand() / (RAND_MAX + 1.0); + } + + /* Generate frame sets - each with 100 frames (by default) */ + for(i = 0; i < N_FRAME_SETS; i++) + { + cnt = 0; + if(i < N_FRAME_SETS/2) + { + codec_id = TNG_GZIP_COMPRESSION; + } + else + { + codec_id = TNG_TNG_COMPRESSION; + } + for(j = 0; j < n_frames_per_frame_set; j++) + { + for(k = 0; k < tot_n_mols; k++) + { + nr = k * 3; + /* Move -1 to 1 */ + molpos[nr] += 2 * (rand() / (RAND_MAX + 1.0)) - 1; + molpos[nr+1] += 2 * (rand() / (RAND_MAX + 1.0)) - 1; + molpos[nr+2] += 2 * (rand() / (RAND_MAX + 1.0)) - 1; + + data[cnt++] = molpos[nr]; + data[cnt++] = molpos[nr + 1]; + data[cnt++] = molpos[nr + 2]; + data[cnt++] = molpos[nr] + 1; + data[cnt++] = molpos[nr + 1] + 1; + data[cnt++] = molpos[nr + 2] + 1; + data[cnt++] = molpos[nr] - 1; + data[cnt++] = molpos[nr + 1] - 1; + data[cnt++] = molpos[nr + 2] - 1; + } + } + if(tng_frame_set_with_time_new(*traj, i * n_frames_per_frame_set, + n_frames_per_frame_set, 2e-15 * (i*n_frames_per_frame_set)) != TNG_SUCCESS) + { + printf("Error creating frame set %d. %s: %d\n", + i, __FILE__, __LINE__); + free(molpos); + free(data); + return(TNG_CRITICAL); + } + + tng_frame_set_particle_mapping_free(*traj); + + /* Setup particle mapping. Use 4 different mapping blocks with arbitrary + * mappings. */ + for(k=0; k<150; k++) + { + mapping[k]=k; + } + if(tng_particle_mapping_add(*traj, 0, 150, mapping) != TNG_SUCCESS) + { + printf("Error creating particle mapping. %s: %d\n", + __FILE__, __LINE__); + free(molpos); + free(data); + return(TNG_CRITICAL); + } + for(k=0; k<150; k++) + { + mapping[k]=599-k; + } + if(tng_particle_mapping_add(*traj, 150, 150, mapping) != TNG_SUCCESS) + { + printf("Error creating particle mapping. %s: %d\n", + __FILE__, __LINE__); + free(molpos); + free(data); + return(TNG_CRITICAL); + } + for(k=0; k<150; k++) + { + mapping[k]=k+150; + } + if(tng_particle_mapping_add(*traj, 300, 150, mapping) != TNG_SUCCESS) + { + printf("Error creating particle mapping. %s: %d\n", + __FILE__, __LINE__); + free(molpos); + free(data); + return(TNG_CRITICAL); + } + for(k=0; k<150; k++) + { + mapping[k]=449-k; + } + if(tng_particle_mapping_add(*traj, 450, 150, mapping) != TNG_SUCCESS) + { + printf("Error creating particle mapping. %s: %d\n", + __FILE__, __LINE__); + free(molpos); + free(data); + return(TNG_CRITICAL); + } + + /* Add the positions in a data block */ + if(tng_particle_data_block_add(*traj, TNG_TRAJ_POSITIONS, + "POSITIONS", + TNG_FLOAT_DATA, + TNG_TRAJECTORY_BLOCK, + n_frames_per_frame_set, 3, + 1, 0, n_particles, +/* TNG_UNCOMPRESSED, */ + codec_id, + data) != TNG_SUCCESS) + { + printf("Error adding data. %s: %d\n", __FILE__, __LINE__); + free(molpos); + free(data); + return(TNG_CRITICAL); + } + /* Write the frame set */ + if(tng_frame_set_write(*traj, hash_mode) != TNG_SUCCESS) + { + printf("Error writing frame set. %s: %d\n", __FILE__, __LINE__); + free(molpos); + free(data); + return(TNG_CRITICAL); + } + } + + free(molpos); + free(data); + + tng_trajectory_destroy(traj); + tng_trajectory_init(traj); + tng_input_file_set(*traj, TNG_EXAMPLE_FILES_DIR "tng_test.tng"); + + stat = tng_file_headers_read(*traj, hash_mode); + + tng_first_user_name_get(*traj, temp_str, TNG_MAX_STR_LEN); + if(strcmp(USER_NAME, temp_str) != 0) + { + printf("User name does not match when reading written file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + tng_first_program_name_get(*traj, temp_str, TNG_MAX_STR_LEN); + if(strcmp(PROGRAM_NAME, temp_str) != 0) + { + printf("Program name does not match when reading written file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + tng_first_computer_name_get(*traj, temp_str, TNG_MAX_STR_LEN); + if(strcmp(COMPUTER_NAME, temp_str) != 0) + { + printf("Computer name does not match when reading written file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + tng_forcefield_name_get(*traj, temp_str, TNG_MAX_STR_LEN); + if(strcmp(FORCEFIELD_NAME, temp_str) != 0) + { + printf("Forcefield name does not match when reading written file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + tng_medium_stride_length_get(*traj, &temp_int); + if(temp_int != MEDIUM_STRIDE_LEN) + { + printf("Stride length does not match when reading written file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + tng_long_stride_length_get(*traj, &temp_int); + if(temp_int != LONG_STRIDE_LEN) + { + printf("Stride length does not match when reading written file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + tng_compression_precision_get(*traj, &temp_double); + if(temp_double != COMPRESSION_PRECISION) + { + printf("Compression precision does not match when reading written file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + tng_distance_unit_exponential_get(*traj, &temp_int); + if(temp_int != dist_exp) + { + printf("Distance unit exponential does not match when reading written file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + stat = tng_test_molecules(*traj); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + stat = tng_particle_data_vector_get(*traj, TNG_TRAJ_MASSES, (void **)&masses, &read_n_frames, + &read_stride_length, &read_n_particles, + &read_n_values_per_frame, &read_data_type); + if(stat != TNG_SUCCESS) + { + free(masses); + return(stat); + } + if(read_n_particles != n_particles) + { + printf("Number of particles does not match when reading atom masses. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + /* Above we have written only water molecules (in the order oxygen, hydrogen, hydrogen ...). + * Test that the first and second as well as the very last atoms (oxygen, hydrogen and hydrogen) + * have the correct atom masses. */ + if(fabs(masses[0] - 16.00000) > 0.0001 || fabs(masses[1] - 1.00800) > 0.0001 || + fabs(masses[read_n_particles-1] - 1.00800) > 0.0001) + { + printf("Atom masses do not match when reading written file. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + free(masses); + + i = 0; + while(stat == TNG_SUCCESS) + { + stat = tng_frame_set_read_next(*traj, hash_mode); + tng_current_frame_set_get(*traj, &frame_set); + tng_frame_set_prev_frame_set_file_pos_get(*traj, frame_set, &temp_int); + tng_frame_set_next_frame_set_file_pos_get(*traj, frame_set, &temp_int2); + if(i > 0) + { + if(temp_int == -1) + { + printf("File position of previous frame set not correct. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + } + else if(temp_int != -1) + { + printf("File position of previous frame set not correct. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + if(i < N_FRAME_SETS -1) + { + if(temp_int2 == -1) + { + printf("File position of next frame set not correct. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + } + else if(temp_int2 != -1) + { + printf("File position of previous next set not correct. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + i++; + } + if(stat == TNG_CRITICAL) + { + return(stat); + } + + tng_time_per_frame_get(*traj, &temp_double); + if(fabs(TIME_PER_FRAME - temp_double) > 0.000001) + { + printf("Time per frame does not match when reading written file. %s: %d\n", + __FILE__, __LINE__); + printf("Value: %e, expected value: %e\n", temp_double, TIME_PER_FRAME); + return(TNG_FAILURE); + } + + stat = tng_frame_set_nr_find(*traj, (int64_t)(0.30*N_FRAME_SETS)); + if(stat != TNG_SUCCESS) + { + printf("Could not find frame set %"PRId64". %s: %d\n", (int64_t)0.30*N_FRAME_SETS, + __FILE__, __LINE__); + return(stat); + } + + stat = tng_frame_set_nr_find(*traj, (int64_t)(0.75*N_FRAME_SETS)); + if(stat != TNG_SUCCESS) + { + printf("Could not find frame set %"PRId64". %s: %d\n", (int64_t)0.75*N_FRAME_SETS, + __FILE__, __LINE__); + return(stat); + } + + tng_current_frame_set_get(*traj, &frame_set); + tng_frame_set_frame_range_get(*traj, frame_set, &temp_int, &temp_int2); + if(temp_int != 75 * n_frames_per_frame_set) + { + printf("Unexpected first frame in frame set. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + stat = tng_frame_set_read_current_only_data_from_block_id(*traj, hash_mode, TNG_TRAJ_POSITIONS); + if(stat != TNG_SUCCESS) + { + printf("Cannot read positions in current frame set. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_frame_set_read_next_only_data_from_block_id(*traj, hash_mode, TNG_TRAJ_POSITIONS); + if(stat != TNG_SUCCESS) + { + printf("Cannot read positions in next frame set. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_data_block_name_get(*traj, TNG_TRAJ_POSITIONS, temp_str, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS || strcmp("POSITIONS", temp_str) != 0) + { + printf("Cannot get name of data block or unexpected name. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_data_block_name_get(*traj, TNG_TRAJ_FORCES, temp_str, TNG_MAX_STR_LEN); + if(stat != TNG_FAILURE) + { + printf("Trying to retrieve name of non-existent data block did not return failure. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_data_block_dependency_get(*traj, TNG_TRAJ_POSITIONS, &dependency); + if(stat != TNG_SUCCESS || dependency != TNG_FRAME_DEPENDENT + TNG_PARTICLE_DEPENDENT) + { + printf("Cannot get dependency of data block or unexpected dependency. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_data_block_num_values_per_frame_get(*traj, TNG_TRAJ_POSITIONS, &temp_int); + if(stat != TNG_SUCCESS || temp_int != 3) + { + printf("Cannot get number of values per frame of data block or unexpected value. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_data_get_stride_length(*traj, TNG_TRAJ_POSITIONS, 100, &temp_int); + if(stat != TNG_SUCCESS || temp_int != 1) + { + printf("Cannot get stride length of data block or unexpected value. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + return(TNG_SUCCESS); +} + +/* This test relies on knowing that the box shape is stored as double */ +tng_function_status tng_test_get_box_data(tng_trajectory_t traj) +{ + int64_t n_frames, n_values_per_frame; + union data_values **values = 0; + char type; + + if(tng_data_get(traj, TNG_TRAJ_BOX_SHAPE, &values, &n_frames, + &n_values_per_frame, &type) != TNG_SUCCESS) + { + printf("Failed getting box shape. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + /* The X dimension in the example file is 50 */ + if(fabs(values[0][0].d - 50) > 0.000001) + { + printf("Unexpected value in box shape. %s: %d\n", __FILE__, __LINE__); + return(TNG_FAILURE); + } + + tng_data_values_free(traj, values, n_frames, n_values_per_frame, type); + + return(TNG_SUCCESS); +} + +/* This test relies on knowing that the positions are stored as float + * and that the data is not sparse (i.e. as many frames in the data + * as in the frame set */ +tng_function_status tng_test_get_positions_data(tng_trajectory_t traj, + const char hash_mode) +{ + int64_t i, j, k, n_frames, n_particles, n_values_per_frame; + union data_values ***values = 0; + char type; + + if(tng_particle_data_get(traj, TNG_TRAJ_POSITIONS, &values, &n_frames, + &n_particles, &n_values_per_frame, &type) != + TNG_SUCCESS) + { + printf("Failed getting particle positions. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(n_values_per_frame != 3) + { + printf("Number of values per frame does not match expected value. %s: %d\n", + __FILE__, __LINE__); + tng_particle_data_values_free(traj, values, n_frames, n_particles, + n_values_per_frame, type); + return(TNG_FAILURE); + } + + for(i = 0; i < n_frames; i++) + { +// printf("%"PRId64"\n", i); + for(j = 0; j < n_particles; j++) + { + for(k = 0; k < n_values_per_frame; k++) + { +// printf("%f ", values[i][j][k].f); + if(values[i][j][k].f < -500 || values[i][j][k].f > 500) + { + printf("Coordinates not in range. %s: %d\n", + __FILE__, __LINE__); + tng_particle_data_values_free(traj, values, n_frames, n_particles, + n_values_per_frame, type); + return(TNG_FAILURE); + } + } +// printf("\n"); + } + } + + if(tng_particle_data_interval_get(traj, TNG_TRAJ_POSITIONS, 111000, 111499, + hash_mode, &values, &n_particles, + &n_values_per_frame, &type) == TNG_SUCCESS) + { + printf("Getting particle positions succeeded when it should have failed. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + if(tng_particle_data_interval_get(traj, TNG_TRAJ_POSITIONS, 1000, 1050, + hash_mode, &values, &n_particles, + &n_values_per_frame, &type) != TNG_SUCCESS) + { + printf("Failed getting particle positions. %s: %d\n", __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + for(i = 0; i < 50; i++) + { +// printf("%"PRId64"\n", i); + for(j = 0; j < n_particles; j++) + { + for(k = 0; k < n_values_per_frame; k++) + { +// printf("%f ", values[i][j][k].f); + if(values[i][j][k].f < -500 || values[i][j][k].f > 500) + { + printf("Coordinates not in range. %s: %d\n", + __FILE__, __LINE__); + tng_particle_data_values_free(traj, values, n_frames, n_particles, + n_values_per_frame, type); + return(TNG_FAILURE); + } + } +// printf("\n"); + } + } + + tng_particle_data_values_free(traj, values, n_frames, n_particles, + n_values_per_frame, type); + + return(TNG_SUCCESS); +} + +tng_function_status tng_test_utility_functions(tng_trajectory_t traj, const char hash_mode) +{ + tng_function_status stat; + int64_t n_particles, i, j, k, codec_id, n_frames, n_frames_per_frame_set; + int64_t n_frames_to_read=30, stride_len, next_frame, n_blocks, *block_ids = 0; + double time, multiplier; + float *positions = 0; + + stat = tng_util_trajectory_open(TNG_EXAMPLE_FILES_DIR "tng_test.tng", 'r', &traj); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + stat = tng_util_time_of_frame_get(traj, 50, &time); + if(stat != TNG_SUCCESS || fabs(time - 100e-13) > 0.000001) + { + printf("Unexpected time at frame 50. %s: %d\n", __FILE__, __LINE__); + printf("Value: %e, expected value: %e\n", time, 100e-13); + return(stat); + } + stat = tng_util_time_of_frame_get(traj, 100, &time); + if(stat != TNG_SUCCESS || fabs(time - 200e-13) > 0.000001) + { + printf("Unexpected time at frame 100. %s: %d\n", __FILE__, __LINE__); + printf("Value: %e, expected value: %e\n", time, 100e-13); + return(stat); + } + + tng_num_frames_per_frame_set_get(traj, &n_frames_per_frame_set); + + stat = tng_util_num_frames_with_data_of_block_id_get(traj, TNG_TRAJ_POSITIONS, &n_frames); + if(stat != TNG_SUCCESS || n_frames != n_frames_per_frame_set * N_FRAME_SETS) + { + printf("Unexpected number of frames with positions data. %s: %d\n", + __FILE__, __LINE__); + printf("Value: %"PRId64", expected value: %"PRId64"\n", n_frames, + n_frames_per_frame_set * N_FRAME_SETS); + return(stat); + } + + tng_num_frames_per_frame_set_get(traj, &n_frames_per_frame_set); + + stat = tng_util_num_frames_with_data_of_block_id_get(traj, TNG_TRAJ_POSITIONS, &n_frames); + if(stat != TNG_SUCCESS || n_frames != n_frames_per_frame_set * N_FRAME_SETS) + { + return(stat); + } + + tng_num_particles_get(traj, &n_particles); + + stat = tng_util_pos_read_range(traj, 1, n_frames_to_read, &positions, &stride_len); + if(stat != TNG_SUCCESS) + { + if(positions) + { + free(positions); + } + return(stat); + } + + for(i = 0; i < n_frames_to_read / stride_len; i++) + { + for(j = 0; j < n_particles; j++) + { + for(k = 0; k < 3; k++) + { + if(positions[i*n_particles + j*3 + k] < -500 || positions[i*n_particles + j*3 + k] > 500) + { + printf("Coordinates not in range. %s: %d\n", + __FILE__, __LINE__); + free(positions); + return(TNG_FAILURE); + } + } + } + } + + free(positions); + + stat=tng_util_trajectory_next_frame_present_data_blocks_find(traj, n_frames_to_read, + 0, 0, &next_frame, + &n_blocks, &block_ids); + if(block_ids) + { + free(block_ids); + } + if(stat != TNG_SUCCESS || n_blocks != 1 || next_frame != n_frames_to_read + stride_len) + { + printf("Unexpected data blocks in next frame. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + + stat = tng_util_frame_current_compression_get(traj, TNG_TRAJ_POSITIONS, &codec_id, &multiplier); + if(stat != TNG_SUCCESS || codec_id != TNG_GZIP_COMPRESSION) + { + printf("Could not get compression. %s: %d\n", + __FILE__, __LINE__); + return(TNG_FAILURE); + } + stat = tng_util_trajectory_close(&traj); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + return(TNG_SUCCESS); +} + + +tng_function_status tng_test_append(tng_trajectory_t traj, const char hash_mode) +{ + char str[TNG_MAX_STR_LEN]; + int64_t n_frames, n_particles, i; + double time, *velocities; + tng_function_status stat; + + stat = tng_util_trajectory_open(TNG_EXAMPLE_FILES_DIR "tng_test.tng", 'a', &traj); + if(stat != TNG_SUCCESS) + { + printf("Cannot open trajectory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + stat = tng_last_user_name_set(traj, USER_NAME); + if(stat != TNG_SUCCESS) + { + printf("Cannot set last user name. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_last_user_name_get(traj, str, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Cannot get last user name. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_last_program_name_set(traj, PROGRAM_NAME); + if(stat != TNG_SUCCESS) + { + printf("Cannot set last program name. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_last_program_name_get(traj, str, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Cannot get last program name. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_last_computer_name_set(traj, "Still " COMPUTER_NAME); + if(stat != TNG_SUCCESS) + { + printf("Cannot set last computer name. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + stat = tng_last_computer_name_get(traj, str, TNG_MAX_STR_LEN); + if(stat != TNG_SUCCESS) + { + printf("Cannot get last computer name. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + stat = tng_file_headers_write(traj, hash_mode); + if(stat != TNG_SUCCESS) + { + printf("Cannot write file headers. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + tng_num_frames_get(traj, &n_frames); + tng_frame_set_of_frame_find(traj, n_frames - 1); + tng_util_time_of_frame_get(traj, n_frames - 1, &time); + time += TIME_PER_FRAME; + tng_num_particles_get(traj, &n_particles); + + velocities = malloc(sizeof(double) * n_particles * 3); + if(!velocities) + { + printf("Cannot allocate memory. %s: %d\n", + __FILE__, __LINE__); + return(TNG_CRITICAL); + } + + for(i = 0; i < n_particles * 3; i++) + { + velocities[i] = i; + } + + stat = tng_util_vel_with_time_double_write(traj, n_frames, time, velocities); + + free(velocities); + + stat = tng_util_trajectory_close(&traj); + + return(stat); +} + +tng_function_status tng_test_copy_container(tng_trajectory_t traj, const char hash_mode) +{ + tng_trajectory_t dest; + tng_function_status stat; + + stat = tng_util_trajectory_open(TNG_EXAMPLE_FILES_DIR "tng_test.tng", 'r', &traj); + if(stat != TNG_SUCCESS) + { + printf("Cannot open trajectory. %s: %d\n", + __FILE__, __LINE__); + return(stat); + } + + stat = tng_trajectory_init_from_src(traj, &dest); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + stat = tng_molecule_system_copy(traj, dest); + if(stat != TNG_SUCCESS) + { + return(stat); + } + + stat = tng_util_trajectory_close(&traj); + if(stat != TNG_SUCCESS) + { + return(stat); + } + stat = tng_util_trajectory_close(&dest); + + return(stat); +} + +int main() +{ + tng_trajectory_t traj = 0; + char time_str[TNG_MAX_DATE_STR_LEN]; + char version_str[TNG_MAX_STR_LEN]; + char hash_mode = TNG_USE_HASH; + + tng_version(traj, version_str, TNG_MAX_STR_LEN); + printf("Test version control:\t\t\t\t"); + if(strncmp(TNG_VERSION, version_str, TNG_MAX_STR_LEN) == 0) + { + printf("Succeeded.\n"); + } + else + { + printf("Failed.\n"); + } + + printf("Test Init trajectory:\t\t\t\t"); + if(tng_trajectory_init(&traj) != TNG_SUCCESS) + { + tng_trajectory_destroy(&traj); + printf("Failed. %s: %d.\n", __FILE__, __LINE__); + exit(1); + } + printf("Succeeded.\n"); + + tng_time_get_str(traj, time_str); + + printf("Creation time: %s\n", time_str); + + tng_input_file_set(traj, TNG_EXAMPLE_FILES_DIR "tng_example.tng"); + tng_output_file_set(traj, TNG_EXAMPLE_FILES_DIR "tng_example_out.tng"); + + printf("Test Read and write file:\t\t\t"); + if(tng_test_read_and_write_file(traj, hash_mode) != TNG_SUCCESS) + { + printf("Failed. %s: %d\n", __FILE__, __LINE__); + } + else + { + printf("Succeeded.\n"); + } + + printf("Test Get data:\t\t\t\t\t"); + if(tng_test_get_box_data(traj) != TNG_SUCCESS) + { + printf("Failed. %s: %d\n", __FILE__, __LINE__); + } + else + { + printf("Succeeded.\n"); + } + + printf("Test Destroy and init trajectory:\t\t"); + if(tng_trajectory_destroy(&traj) != TNG_SUCCESS || + tng_trajectory_init(&traj) != TNG_SUCCESS) + { + printf("Failed. %s: %d\n", __FILE__, __LINE__); + } + else + { + printf("Succeeded.\n"); + } + + + tng_output_file_set(traj, TNG_EXAMPLE_FILES_DIR "tng_test.tng"); + + printf("Test Write and read file:\t\t\t"); + if(tng_test_write_and_read_traj(&traj, hash_mode) != TNG_SUCCESS) + { + printf("Failed. %s: %d\n", __FILE__, __LINE__); + } + else + { + printf("Succeeded.\n"); + } + + printf("Test Get particle data:\t\t\t\t"); + if(tng_test_get_positions_data(traj, hash_mode) != TNG_SUCCESS) + { + printf("Failed. %s: %d\n", + __FILE__, __LINE__); + } + else + { + printf("Succeeded.\n"); + } + + printf("Test Destroy trajectory:\t\t\t"); + if(tng_trajectory_destroy(&traj) != TNG_SUCCESS) + { + printf("Failed. %s: %d.\n", __FILE__, __LINE__); + exit(1); + } + else + { + printf("Succeeded.\n"); + } + + printf("Test Utility functions:\t\t\t\t"); + if(tng_test_utility_functions(traj, hash_mode) != TNG_SUCCESS) + { + printf("Failed. %s: %d.\n", __FILE__, __LINE__); + exit(1); + } + else + { + printf("Succeeded.\n"); + } + + printf("Test Append:\t\t\t\t\t"); + if(tng_test_append(traj, hash_mode) != TNG_SUCCESS) + { + printf("Failed. %s: %d.\n", __FILE__, __LINE__); + } + else + { + printf("Succeeded.\n"); + } + + printf("Test Copy trajectory container:\t\t\t"); + if(tng_test_copy_container(traj, hash_mode) != TNG_SUCCESS) + { + printf("Failed. %s: %d.\n", __FILE__, __LINE__); + } + else + { + printf("Succeeded.\n"); + } + + printf("Tests finished\n"); + + exit(0); +} From 4f18d30abd60b6a61f4936e7691f1e4d09ed96ca Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 13:55:05 -0400 Subject: [PATCH 02/77] DRR - Cpptraj: Add ZLIB to external config for TNG --- configure | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure b/configure index ebe6d64b75..46dd549250 100755 --- a/configure +++ b/configure @@ -2114,6 +2114,9 @@ cat > $external_config <> $external_config +fi # ----- Create directories if necessary ---------- if [ ! -e "$CPPTRAJBIN" ] ; then From 3afae0c7348086af21b486d4045fafa65f901c0d Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 13:56:17 -0400 Subject: [PATCH 03/77] DRR - Cpptraj: Remove tng example dir placeholder --- src/tng/tng_io_testing.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tng/tng_io_testing.c b/src/tng/tng_io_testing.c index 70d2e5a6c5..095b008347 100644 --- a/src/tng/tng_io_testing.c +++ b/src/tng/tng_io_testing.c @@ -769,7 +769,7 @@ static tng_function_status tng_test_write_and_read_traj(tng_trajectory_t *traj, tng_trajectory_destroy(traj); tng_trajectory_init(traj); - tng_input_file_set(*traj, TNG_EXAMPLE_FILES_DIR "tng_test.tng"); + tng_input_file_set(*traj, "tng_test.tng"); stat = tng_file_headers_read(*traj, hash_mode); @@ -1127,7 +1127,7 @@ tng_function_status tng_test_utility_functions(tng_trajectory_t traj, const char double time, multiplier; float *positions = 0; - stat = tng_util_trajectory_open(TNG_EXAMPLE_FILES_DIR "tng_test.tng", 'r', &traj); + stat = tng_util_trajectory_open("tng_test.tng", 'r', &traj); if(stat != TNG_SUCCESS) { return(stat); @@ -1237,7 +1237,7 @@ tng_function_status tng_test_append(tng_trajectory_t traj, const char hash_mode) double time, *velocities; tng_function_status stat; - stat = tng_util_trajectory_open(TNG_EXAMPLE_FILES_DIR "tng_test.tng", 'a', &traj); + stat = tng_util_trajectory_open("tng_test.tng", 'a', &traj); if(stat != TNG_SUCCESS) { printf("Cannot open trajectory. %s: %d\n", @@ -1329,7 +1329,7 @@ tng_function_status tng_test_copy_container(tng_trajectory_t traj, const char ha tng_trajectory_t dest; tng_function_status stat; - stat = tng_util_trajectory_open(TNG_EXAMPLE_FILES_DIR "tng_test.tng", 'r', &traj); + stat = tng_util_trajectory_open("tng_test.tng", 'r', &traj); if(stat != TNG_SUCCESS) { printf("Cannot open trajectory. %s: %d\n", @@ -1390,8 +1390,8 @@ int main() printf("Creation time: %s\n", time_str); - tng_input_file_set(traj, TNG_EXAMPLE_FILES_DIR "tng_example.tng"); - tng_output_file_set(traj, TNG_EXAMPLE_FILES_DIR "tng_example_out.tng"); + tng_input_file_set(traj, "tng_example.tng"); + tng_output_file_set(traj, "tng_example_out.tng"); printf("Test Read and write file:\t\t\t"); if(tng_test_read_and_write_file(traj, hash_mode) != TNG_SUCCESS) @@ -1425,7 +1425,7 @@ int main() } - tng_output_file_set(traj, TNG_EXAMPLE_FILES_DIR "tng_test.tng"); + tng_output_file_set(traj, "tng_test.tng"); printf("Test Write and read file:\t\t\t"); if(tng_test_write_and_read_traj(&traj, hash_mode) != TNG_SUCCESS) From 343b1cfeca9166325c024773118d01863d0adc3e Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 13:56:48 -0400 Subject: [PATCH 04/77] Add some more sources. --- src/tng/Makefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tng/Makefile b/src/tng/Makefile index 58db3c3997..820d31e370 100644 --- a/src/tng/Makefile +++ b/src/tng/Makefile @@ -9,7 +9,7 @@ AR = ar cqs TARGET = libtngfile.a # Source files -SOURCES=md5.c tng_io.c +SOURCES=md5.c tng_io.c tng_compress.c # Objects OBJECTS=$(SOURCES:.c=.o) @@ -23,7 +23,7 @@ $(TARGET): $(OBJECTS) $(AR) $(TARGET) $(OBJECTS) test: $(TARGET) tng_io_testing.o - $(CC) -o a.out tng_io_testing.c $(TARGET) -lm + $(CC) -o a.out tng_io_testing.c $(TARGET) -lm $(ZLIB_FLAG) ./a.out clean: @@ -35,3 +35,5 @@ uninstall: clean md5.o : md5.c tng/md5.h tng_io.o : tng_io.c tng/tng_io.h tng/tng_io_fwd.h compression/tng_compress.h tng/version.h + +tng_compress.o : tng_compress.c compression/tng_compress.h From b0d68aa95769e3a8eba64988cce19bcf9b2889e5 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 13:58:16 -0400 Subject: [PATCH 05/77] Add more missing files. --- src/tng/coder.c | 512 +++++++++ src/tng/compression/coder.h | 48 + src/tng/compression/fixpoint.h | 39 + src/tng/compression/my64bit.h | 33 + src/tng/tng_compress.c | 1894 ++++++++++++++++++++++++++++++++ 5 files changed, 2526 insertions(+) create mode 100644 src/tng/coder.c create mode 100644 src/tng/compression/coder.h create mode 100644 src/tng/compression/fixpoint.h create mode 100644 src/tng/compression/my64bit.h create mode 100644 src/tng/tng_compress.c diff --git a/src/tng/coder.c b/src/tng/coder.c new file mode 100644 index 0000000000..d0a0d99f66 --- /dev/null +++ b/src/tng/coder.c @@ -0,0 +1,512 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg and Magnus Lundborg + * Copyright (c) 2010, 2013-2014 The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#include +#include +#include "../../include/compression/tng_compress.h" +#include "../../include/compression/bwlzh.h" +#include "../../include/compression/coder.h" +#include "../../include/compression/warnmalloc.h" + +#ifndef USE_WINDOWS +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +#define USE_WINDOWS +#endif /* win32... */ +#endif /* not defined USE_WINDOWS */ + +#ifdef USE_WINDOWS +#define TNG_INLINE __inline +#define TNG_SNPRINTF _snprintf +#else +#define TNG_INLINE inline +#define TNG_SNPRINTF snprintf +#endif + +struct coder DECLSPECDLLEXPORT *Ptngc_coder_init(void) +{ + struct coder *coder_inst=warnmalloc(sizeof *coder_inst); + coder_inst->pack_temporary_bits=0; + return coder_inst; +} + +void DECLSPECDLLEXPORT Ptngc_coder_deinit(struct coder *coder_inst) +{ + free(coder_inst); +} + +TNG_INLINE void DECLSPECDLLEXPORT Ptngc_out8bits(struct coder *coder_inst, unsigned char **output) +{ + while (coder_inst->pack_temporary_bits>=8) + { + unsigned int mask; + unsigned char out; + coder_inst->pack_temporary_bits-=8; + mask=~(0xFFU<<(coder_inst->pack_temporary_bits)); + out=(unsigned char)(coder_inst->pack_temporary>>(coder_inst->pack_temporary_bits)); + **output=out; + (*output)++; + coder_inst->pack_temporary&=mask; + } +} + +void DECLSPECDLLEXPORT Ptngc_write_pattern(struct coder *coder_inst, unsigned int pattern, + int nbits, unsigned char **output) +{ + unsigned int mask1,mask2; + mask1=1; + mask2=1<<(nbits-1); + coder_inst->pack_temporary<<=nbits; /* Make room for new data. */ + coder_inst->pack_temporary_bits+=nbits; + while (nbits) + { + if (pattern & mask1) + coder_inst->pack_temporary|=mask2; + nbits--; + mask1<<=1; + mask2>>=1; + } + Ptngc_out8bits(coder_inst,output); +} + +/* Write up to 24 bits */ +TNG_INLINE void DECLSPECDLLEXPORT Ptngc_writebits(struct coder *coder_inst, + unsigned int value, const int nbits, + unsigned char **output_ptr) +{ + /* Make room for the bits. */ + coder_inst->pack_temporary<<=nbits; + coder_inst->pack_temporary_bits+=nbits; + coder_inst->pack_temporary|=value; + Ptngc_out8bits(coder_inst,output_ptr); +} + +/* Write up to 32 bits */ +void DECLSPECDLLEXPORT Ptngc_write32bits(struct coder *coder_inst, unsigned int value, + int nbits, unsigned char **output_ptr) +{ + unsigned int mask; + if (nbits>=8) + mask=0xFFU<<(nbits-8); + else + mask=0xFFU>>(8-nbits); + while (nbits>8) + { + /* Make room for the bits. */ + nbits-=8; + coder_inst->pack_temporary<<=8; + coder_inst->pack_temporary_bits+=8; + coder_inst->pack_temporary|=(value&mask)>>(nbits); + Ptngc_out8bits(coder_inst,output_ptr); + mask>>=8; + } + if (nbits) + Ptngc_writebits(coder_inst,value&mask,nbits,output_ptr); +} + +/* Write "arbitrary" number of bits */ +void DECLSPECDLLEXPORT Ptngc_writemanybits(struct coder *coder_inst, unsigned char *value, + int nbits, unsigned char **output_ptr) +{ + int vptr=0; + while (nbits>=24) + { + unsigned int v=((((unsigned int)value[vptr])<<16)| + (((unsigned int)value[vptr+1])<<8)| + (((unsigned int)value[vptr+2]))); + Ptngc_writebits(coder_inst,v,24,output_ptr); + vptr+=3; + nbits-=24; + } + while (nbits>=8) + { + Ptngc_writebits(coder_inst,(unsigned int)value[vptr],8,output_ptr); + vptr++; + nbits-=8; + } + if (nbits) + { + Ptngc_writebits(coder_inst,(unsigned int)value[vptr],nbits,output_ptr); + } +} + +static int write_stop_bit_code(struct coder *coder_inst, unsigned int s, + unsigned int coding_parameter, + unsigned char **output) +{ + do { + unsigned int extract=~(0xffffffffU<>=coding_parameter; + if (s) + { + this|=1U; + coder_inst->stat_overflow++; + } + coder_inst->pack_temporary<<=(coding_parameter+1); + coder_inst->pack_temporary_bits+=coding_parameter+1; + coder_inst->pack_temporary|=this; + Ptngc_out8bits(coder_inst,output); + if (s) + { + coding_parameter>>=1; + if (coding_parameter<1) + coding_parameter=1; + } + } while (s); + coder_inst->stat_numval++; + return 0; +} + +static int pack_stopbits_item(struct coder *coder_inst, const int item, + unsigned char **output, const int coding_parameter) +{ + /* Find this symbol in table. */ + int s=0; + if (item>0) + s=1+(item-1)*2; + else if (item<0) + s=2+(-item-1)*2; + return write_stop_bit_code(coder_inst,s,coding_parameter,output); +} + +static int pack_triplet(struct coder *coder_inst, unsigned int *s, + unsigned char **output, const int coding_parameter, + const unsigned int max_base, const int maxbits) +{ + /* Determine base for this triplet. */ + unsigned int min_base=1U<=this_base) + { + this_base*=2; + jbase++; + } + bits_per_value=coding_parameter+jbase; + if (jbase>=3) + { + if (this_base>max_base) + return 1; + bits_per_value=maxbits; + jbase=3; + } + /* 2 bits selects the base */ + coder_inst->pack_temporary<<=2; + coder_inst->pack_temporary_bits+=2; + coder_inst->pack_temporary|=jbase; + Ptngc_out8bits(coder_inst,output); + for (i=0; i<3; i++) + Ptngc_write32bits(coder_inst,s[i],bits_per_value,output); + return 0; +} + +void DECLSPECDLLEXPORT Ptngc_pack_flush(struct coder *coder_inst, unsigned char **output) +{ + /* Zero-fill just enough. */ + if (coder_inst->pack_temporary_bits>0) + Ptngc_write_pattern(coder_inst,0,8-coder_inst->pack_temporary_bits,output); +} + +unsigned char DECLSPECDLLEXPORT *Ptngc_pack_array(struct coder *coder_inst, + int *input, int *length, const int coding, + const int coding_parameter, const int natoms, const int speed) +{ + if ((coding==TNG_COMPRESS_ALGO_BWLZH1) || (coding==TNG_COMPRESS_ALGO_BWLZH2)) + { + unsigned char *output=warnmalloc(4+bwlzh_get_buflen(*length)); + int i,j,k,n=*length; + unsigned int *pval=warnmalloc(n*sizeof *pval); + int nframes=n/natoms/3; + int cnt=0; + int most_negative=2147483647; + for (i=0; i>8)&0xFFU; + output[2]=(((unsigned int)most_negative)>>16)&0xFFU; + output[3]=(((unsigned int)most_negative)>>24)&0xFFU; + for (i=0; i=5) + bwlzh_compress(pval,n,output+4,length); + else + bwlzh_compress_no_lz77(pval,n,output+4,length); + (*length)+=4; + free(pval); + return output; + } + else if (coding==TNG_COMPRESS_ALGO_POS_XTC3) + return Ptngc_pack_array_xtc3(input,length,natoms,speed); + else if (coding==TNG_COMPRESS_ALGO_POS_XTC2) + return Ptngc_pack_array_xtc2(coder_inst,input,length); + else + { + unsigned char *output=NULL; + unsigned char *output_ptr=NULL; + int i; + int output_length=0; + + coder_inst->stat_numval=0; + coder_inst->stat_overflow=0; + /* Allocate enough memory for output */ + output=warnmalloc(8* *length*sizeof *output); + output_ptr=output; + if ((coding==TNG_COMPRESS_ALGO_TRIPLET) || + (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA) || + (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE)) + { + /* Pack triplets. */ + int ntriplets=*length/3; + /* Determine max base and maxbits */ + unsigned int max_base=1U<0) + s=1+(item-1)*2; + else if (item<0) + s=2+(-item-1)*2; + if (s>intmax) + intmax=s; + } + /* Store intmax */ + coder_inst->pack_temporary_bits=32; + coder_inst->pack_temporary=intmax; + Ptngc_out8bits(coder_inst,&output_ptr); + while (intmax>=max_base) + { + max_base*=2; + maxbits++; + } + for (i=0; i0) + s[j]=1+(item-1)*2; + else if (item<0) + s[j]=2+(-item-1)*2; + } + if (pack_triplet(coder_inst, s, &output_ptr, + coding_parameter, max_base,maxbits)) + { + free(output); + return NULL; + } + } + } + else + for (i=0; i<*length; i++) + if (pack_stopbits_item(coder_inst,input[i],&output_ptr,coding_parameter)) + { + free(output); + return NULL; + } + Ptngc_pack_flush(coder_inst,&output_ptr); + output_length=(int)(output_ptr-output); + *length=output_length; + return output; + } +} + +static int unpack_array_stop_bits(struct coder *coder_inst, + unsigned char *packed,int *output, + const int length, const int coding_parameter) +{ + int i,j; + unsigned int extract_mask=0x80; + unsigned char *ptr=packed; + (void) coder_inst; + for (i=0; i>=1; + extract_mask>>=1; + if (!extract_mask) + { + extract_mask=0x80; + ptr++; + } + } + /* Check stop bit */ + bit=*ptr & extract_mask; + extract_mask>>=1; + if (!extract_mask) + { + extract_mask=0x80; + ptr++; + } + if (bit) + { + numbits>>=1; + if (numbits<1) + numbits=1; + inserted_bits+=numbits; + insert_mask=1U<<(inserted_bits-1); + } + } while (bit); + s=(pattern+1)/2; + if ((pattern%2)==0) + s=-s; + output[i]=s; + } + return 0; +} + +static int unpack_array_triplet(struct coder *coder_inst, + unsigned char *packed, int *output, + int length, const int coding_parameter) +{ + int i,j; + unsigned int extract_mask=0x80; + unsigned char *ptr=packed; + /* Determine max base and maxbits */ + unsigned int max_base=1U<=max_base) + { + max_base*=2; + maxbits++; + } + length/=3; + for (i=0; i>=1; + if (!extract_mask) + { + extract_mask=0x80; + ptr++; + } + } + if (jbase==3) + numbits=maxbits; + else + numbits=coding_parameter+jbase; + for (j=0; j<3; j++) + { + int s; + unsigned int jbit; + unsigned int pattern=0; + for (jbit=0; jbit>=1; + if (!extract_mask) + { + extract_mask=0x80; + ptr++; + } + } + s=(pattern+1)/2; + if ((pattern%2)==0) + s=-s; + output[i*3+j]=s; + } + } + return 0; +} + +static int unpack_array_bwlzh(struct coder *coder_inst, + unsigned char *packed, int *output, + const int length, const int natoms) +{ + int i,j,k,n=length; + unsigned int *pval=warnmalloc(n*sizeof *pval); + int nframes=n/natoms/3; + int cnt=0; + int most_negative=(int)(((unsigned int)packed[0]) | + (((unsigned int)packed[1])<<8) | + (((unsigned int)packed[2])<<16) | + (((unsigned int)packed[3])<<24)); + (void) coder_inst; + bwlzh_decompress(packed+4,length,pval); + for (i=0; i +typedef int64_t my_int64_t; +typedef uint64_t my_uint64_t; +#define HAVE64BIT +#else /* USE_STD_INTTYPES */ +/* The USE_WINDOWS symbol should be automatically defined in tng_compress.h */ +#include "../compression/tng_compress.h" +#ifdef USE_WINDOWS +typedef __int64 my_int64_t; +typedef unsigned __int64 my_uint64_t; +#define HAVE64BIT +#else /* USE_WINDOWS */ +/* Fall back to assume that we have unsigned long long */ +typedef unsigned long long my_uint64_t; +#define HAVE64BIT +#endif /* USE_WINDOWS */ +#endif /* USE_STD_INTTYPES */ + +#endif diff --git a/src/tng/tng_compress.c b/src/tng/tng_compress.c new file mode 100644 index 0000000000..2a28479ab2 --- /dev/null +++ b/src/tng/tng_compress.c @@ -0,0 +1,1894 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + +#include +#include +#include +#include "compression/tng_compress.h" +#include "compression/coder.h" +#include "compression/fixpoint.h" + +/* Please see tng_compress.h for info on how to call these routines. */ + +/* This becomes TNGP for positions (little endian) and TNGV for velocities. In ASCII. */ +#define MAGIC_INT_POS 0x50474E54 +#define MAGIC_INT_VEL 0x56474E54 + +#define SPEED_DEFAULT 2 /* Default to relatively fast compression. For very good compression it makes sense to + choose speed=4 or speed=5 */ + +#define PRECISION(hi,lo) (Ptngc_i32x2_to_d(hi,lo)) + +#define MAX_FVAL 2147483647. + +static int verify_input_data(double *x, const int natoms, const int nframes, const double precision) +{ + int iframe, i, j; + for (iframe=0; iframe=MAX_FVAL) + goto error; + return 0; + error: +#if 0 + for (iframe=0; iframe=MAX_FVAL) + printf("ERROR. Too large value: %d %d %d: %g %g %g\n",iframe,i,j,x[iframe*natoms*3+i*3+j],precision,x[iframe*natoms*3+i*3+j]/precision/MAX_FVAL); +#endif + return 1; +} + +static int verify_input_data_float(float *x, const int natoms, const int nframes, const float precision) +{ + int iframe, i, j; + for (iframe=0; iframe=MAX_FVAL) + goto error; + return 0; + error: +#if 0 + for (iframe=0; iframe=MAX_FVAL) + printf("ERROR. Too large value: %d %d %d: %g %g %g\n",iframe,i,j,x[iframe*natoms*3+i*3+j],precision,x[iframe*natoms*3+i*3+j]/precision/MAX_FVAL); +#endif + return 1; +} + +static int quantize(double *x, const int natoms, const int nframes, + const double precision, + int *quant) +{ + int iframe, i, j; + for (iframe=0; iframe>= 8; + c=(unsigned char)(v & 0xFFU); + } +} + +static fix_t readbufferfix(unsigned char *buf, int num) +{ + unsigned char b; + int shift=0; + fix_t f=0UL; + int cnt=0; + do + { + b=buf[cnt++]; + f |= ((fix_t)b & 0xFF)<1) + { + datablock=NULL; + /* Inter-frame compression? */ + if ((coding==TNG_COMPRESS_ALGO_POS_STOPBIT_INTER) || + (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTER) || + (coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTER)) + { + struct coder *coder=Ptngc_coder_init(); + length=natoms*3*(nframes-1); + datablock=(char*)Ptngc_pack_array(coder,quant_inter+natoms*3,&length, + coding,coding_parameter,natoms,speed); + Ptngc_coder_deinit(coder); + } + /* One-to-one compression? */ + else if ((coding==TNG_COMPRESS_ALGO_POS_XTC2) || + (coding==TNG_COMPRESS_ALGO_POS_XTC3) || + (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE)) + { + struct coder *coder=Ptngc_coder_init(); + length=natoms*3*(nframes-1); + datablock=(char*)Ptngc_pack_array(coder,quant+natoms*3,&length, + coding,coding_parameter,natoms,speed); + Ptngc_coder_deinit(coder); + } + /* Intra-frame compression? */ + else if ((coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA) || + (coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTRA)) + { + struct coder *coder=Ptngc_coder_init(); + length=natoms*3*(nframes-1); + datablock=(char*)Ptngc_pack_array(coder,quant_intra+natoms*3,&length, + coding,coding_parameter,natoms,speed); + Ptngc_coder_deinit(coder); + } + /* Block length. */ + if (data) + bufferfix((unsigned char*)data+bufloc,(fix_t)length,4); + bufloc+=4; + if (datablock) + { + if (data) + memcpy(data+bufloc,datablock,length); + free(datablock); + } + bufloc+=length; + } + *nitems=bufloc; +} + +/* Perform velocity compression from vel into the data block */ +static void compress_quantized_vel(int *quant, int *quant_inter, + const int natoms, const int nframes, + const int speed, + const int initial_coding, const int initial_coding_parameter, + const int coding, const int coding_parameter, + const fix_t prec_hi, const fix_t prec_lo, + int *nitems, + char *data) +{ + int bufloc=0; + char *datablock=NULL; + int length; + /* Information needed for decompression. */ + if (data) + bufferfix((unsigned char*)data+bufloc,(fix_t)MAGIC_INT_VEL,4); + bufloc+=4; + /* Number of atoms. */ + if (data) + bufferfix((unsigned char*)data+bufloc,(fix_t)natoms,4); + bufloc+=4; + /* Number of frames. */ + if (data) + bufferfix((unsigned char*)data+bufloc,(fix_t)nframes,4); + bufloc+=4; + /* Initial coding. */ + if (data) + bufferfix((unsigned char*)data+bufloc,(fix_t)initial_coding,4); + bufloc+=4; + /* Initial coding parameter. */ + if (data) + bufferfix((unsigned char*)data+bufloc,(fix_t)initial_coding_parameter,4); + bufloc+=4; + /* Coding. */ + if (data) + bufferfix((unsigned char*)data+bufloc,(fix_t)coding,4); + bufloc+=4; + /* Coding parameter. */ + if (data) + bufferfix((unsigned char*)data+bufloc,(fix_t)coding_parameter,4); + bufloc+=4; + /* Precision. */ + if (data) + bufferfix((unsigned char*)data+bufloc,prec_lo,4); + bufloc+=4; + if (data) + bufferfix((unsigned char*)data+bufloc,prec_hi,4); + bufloc+=4; + + length=natoms*3; + /* The initial frame */ + if ((initial_coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE) || + (initial_coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE) || + (initial_coding==TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE)) + { + struct coder *coder=Ptngc_coder_init(); + datablock=(char*)Ptngc_pack_array(coder,quant,&length, + initial_coding,initial_coding_parameter,natoms,speed); + Ptngc_coder_deinit(coder); + } + /* Block length. */ + if (data) + bufferfix((unsigned char*)data+bufloc,(fix_t)length,4); + bufloc+=4; + /* The actual data block. */ + if (data && datablock) + { + memcpy(data+bufloc,datablock,length); + free(datablock); + bufloc+=length; + } + /* The remaining frames */ + if (nframes>1) + { + datablock=NULL; + /* Inter-frame compression? */ + if ((coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_INTER) || + (coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_INTER) || + (coding==TNG_COMPRESS_ALGO_VEL_BWLZH_INTER)) + { + struct coder *coder=Ptngc_coder_init(); + length=natoms*3*(nframes-1); + datablock=(char*)Ptngc_pack_array(coder,quant_inter+natoms*3,&length, + coding,coding_parameter,natoms,speed); + Ptngc_coder_deinit(coder); + } + /* One-to-one compression? */ + else if ((coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE) || + (coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE) || + (coding==TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE)) + { + struct coder *coder=Ptngc_coder_init(); + length=natoms*3*(nframes-1); + datablock=(char*)Ptngc_pack_array(coder,quant+natoms*3,&length, + coding,coding_parameter,natoms,speed); + Ptngc_coder_deinit(coder); + } + /* Block length. */ + if (data) + bufferfix((unsigned char*)data+bufloc,(fix_t)length,4); + bufloc+=4; + if (data) + memcpy(data+bufloc,datablock,length); + free(datablock); + bufloc+=length; + } + *nitems=bufloc; +} + +static int determine_best_coding_stop_bits(struct coder *coder,int *input, int *length, + int *coding_parameter, const int natoms) +{ + int bits; + unsigned char *packed; + int best_length=0; + int new_parameter=-1; + int io_length; + for (bits=1; bits<20; bits++) + { + io_length=*length; + packed=Ptngc_pack_array(coder,input,&io_length, + TNG_COMPRESS_ALGO_STOPBIT,bits,natoms,0); + if (packed) + { + if ((new_parameter==-1) || (io_length=2) + { + current_coding=TNG_COMPRESS_ALGO_POS_XTC3; + current_coding_parameter=0; + compress_quantized_pos(quant,NULL,quant_intra,natoms,1,speed, + current_coding,current_coding_parameter, + 0,0,prec_hi,prec_lo,¤t_code_size,NULL); + if (current_code_size=6) + { + current_coding=TNG_COMPRESS_ALGO_POS_BWLZH_INTRA; + current_coding_parameter=0; + compress_quantized_pos(quant,NULL,quant_intra,natoms,1,speed, + current_coding,current_coding_parameter, + 0,0,prec_hi,prec_lo,¤t_code_size,NULL); + if (current_code_size=4) + { + current_coding=TNG_COMPRESS_ALGO_POS_BWLZH_INTER; + current_coding_parameter=0; + compress_quantized_pos(quant,quant_inter,quant_intra,natoms,nframes,speed, + TNG_COMPRESS_ALGO_POS_XTC2,0, + current_coding,current_coding_parameter, + prec_hi,prec_lo,¤t_code_size,NULL); + current_code_size-=initial_code_size; /* Correct for the use of XTC2 for the first frame. */ + if (current_code_size=6) + { + current_coding=TNG_COMPRESS_ALGO_POS_BWLZH_INTRA; + current_coding_parameter=0; + compress_quantized_pos(quant,quant_inter,quant_intra,natoms,nframes,speed, + TNG_COMPRESS_ALGO_POS_XTC2,0, + current_coding,current_coding_parameter, + prec_hi,prec_lo,¤t_code_size,NULL); + current_code_size-=initial_code_size; /* Correct for the use of XTC2 for the first frame. */ + if (current_code_size=4) + { + current_coding=TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE; + current_coding_parameter=0; + compress_quantized_vel(quant,NULL,natoms,1,speed, + current_coding,current_coding_parameter, + 0,0,prec_hi,prec_lo,¤t_code_size,NULL); + if ((best_coding==-1) || (current_code_size=4) + { + /* Test BWLZH inter */ + current_coding=TNG_COMPRESS_ALGO_VEL_BWLZH_INTER; + current_coding_parameter=0; + compress_quantized_vel(quant,quant_inter,natoms,nframes,speed, + TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE,initial_numbits, + current_coding,current_coding_parameter, + prec_hi,prec_lo,¤t_code_size,NULL); + current_code_size-=initial_code_size; /* Correct for the initial frame */ + if (current_code_size6) + speed=6; + initial_coding=algo[0]; + initial_coding_parameter=algo[1]; + coding=algo[2]; + coding_parameter=algo[3]; + + quant_inter_differences(quant,natoms,nframes,quant_inter); + quant_intra_differences(quant,natoms,nframes,quant_intra); + + /* If any of the above codings / coding parameters are == -1, the optimal parameters must be found */ + if (initial_coding==-1) + { + initial_coding_parameter=-1; + determine_best_pos_initial_coding(quant,quant_intra,natoms,speed,prec_hi,prec_lo, + &initial_coding,&initial_coding_parameter); + } + else if (initial_coding_parameter==-1) + { + determine_best_pos_initial_coding(quant,quant_intra,natoms,speed,prec_hi,prec_lo, + &initial_coding,&initial_coding_parameter); + } + + if (nframes==1) + { + coding=0; + coding_parameter=0; + } + + if (nframes>1) + { + if (coding==-1) + { + coding_parameter=-1; + determine_best_pos_coding(quant,quant_inter,quant_intra,natoms,nframes,speed,prec_hi,prec_lo, + &coding,&coding_parameter); + } + else if (coding_parameter==-1) + { + determine_best_pos_coding(quant,quant_inter,quant_intra,natoms,nframes,speed,prec_hi,prec_lo, + &coding,&coding_parameter); + } + } + + compress_quantized_pos(quant,quant_inter,quant_intra,natoms,nframes,speed, + initial_coding,initial_coding_parameter, + coding,coding_parameter, + prec_hi,prec_lo,nitems,data); + free(quant_inter); + free(quant_intra); + if (algo[0]==-1) + algo[0]=initial_coding; + if (algo[1]==-1) + algo[1]=initial_coding_parameter; + if (algo[2]==-1) + algo[2]=coding; + if (algo[3]==-1) + algo[3]=coding_parameter; + return data; +} + +char DECLSPECDLLEXPORT *tng_compress_pos(double *pos, const int natoms, const int nframes, + const double desired_precision, + const int speed,int *algo, + int *nitems) +{ + int *quant=malloc(natoms*nframes*3*sizeof *quant); + char *data; + fix_t prec_hi, prec_lo; + Ptngc_d_to_i32x2(desired_precision,&prec_hi,&prec_lo); + + if (quantize(pos,natoms,nframes,PRECISION(prec_hi,prec_lo),quant)) + data=NULL; /* Error occured. Too large input values. */ + else + data=tng_compress_pos_int(quant,natoms,nframes,prec_hi,prec_lo,speed,algo,nitems); + free(quant); + return data; +} + +char DECLSPECDLLEXPORT *tng_compress_pos_float(float *pos, const int natoms, const int nframes, + const float desired_precision, + const int speed, int *algo, + int *nitems) +{ + int *quant=malloc(natoms*nframes*3*sizeof *quant); + char *data; + fix_t prec_hi, prec_lo; + Ptngc_d_to_i32x2((double)desired_precision,&prec_hi,&prec_lo); + + if (quantize_float(pos,natoms,nframes,(float)PRECISION(prec_hi,prec_lo),quant)) + data=NULL; /* Error occured. Too large input values. */ + else + data=tng_compress_pos_int(quant,natoms,nframes,prec_hi,prec_lo,speed,algo,nitems); + free(quant); + return data; +} + +char DECLSPECDLLEXPORT *tng_compress_pos_find_algo(double *pos, const int natoms, const int nframes, + const double desired_precision, + const int speed, + int *algo, + int *nitems) +{ + algo[0]=-1; + algo[1]=-1; + algo[2]=-1; + algo[3]=-1; + return tng_compress_pos(pos,natoms,nframes,desired_precision,speed,algo,nitems); +} + +char DECLSPECDLLEXPORT *tng_compress_pos_float_find_algo(float *pos, const int natoms, const int nframes, + const float desired_precision, + const int speed, + int *algo, + int *nitems) +{ + algo[0]=-1; + algo[1]=-1; + algo[2]=-1; + algo[3]=-1; + return tng_compress_pos_float(pos,natoms,nframes,desired_precision,speed,algo,nitems); +} + +char DECLSPECDLLEXPORT *tng_compress_pos_int_find_algo(int *pos, const int natoms, const int nframes, + const unsigned long prec_hi, const unsigned long prec_lo, + const int speed, int *algo, + int *nitems) +{ + algo[0]=-1; + algo[1]=-1; + algo[2]=-1; + algo[3]=-1; + return tng_compress_pos_int(pos,natoms,nframes,prec_hi,prec_lo,speed,algo,nitems); +} + + + +int DECLSPECDLLEXPORT tng_compress_nalgo(void) +{ + return 4; /* There are currently four parameters required: + + 1) The compression algorithm for the first frame (initial_coding). + 2) One parameter to the algorithm for the first frame (the initial coding parameter). + 3) The compression algorithm for the remaining frames (coding). + 4) One parameter to the algorithm for the remaining frames (the coding parameter). */ +} + +char DECLSPECDLLEXPORT *tng_compress_vel_int(int *vel, const int natoms, const int nframes, + const unsigned long prec_hi, const unsigned long prec_lo, + int speed, int *algo, + int *nitems) +{ + char *data=malloc(natoms*nframes*14+11*4); /* 12 bytes are required to store 4 32 bit integers + This is 17% extra. The final 11*4 is to store information + needed for decompression. */ + int *quant=vel; + int *quant_inter=malloc(natoms*nframes*3*sizeof *quant_inter); + + int initial_coding, initial_coding_parameter; + int coding, coding_parameter; + if (speed==0) + speed=SPEED_DEFAULT; /* Set the default speed. */ + /* Boundaries of speed. */ + if (speed<1) + speed=1; + if (speed>6) + speed=6; + initial_coding=algo[0]; + initial_coding_parameter=algo[1]; + coding=algo[2]; + coding_parameter=algo[3]; + + quant_inter_differences(quant,natoms,nframes,quant_inter); + + /* If any of the above codings / coding parameters are == -1, the optimal parameters must be found */ + if (initial_coding==-1) + { + initial_coding_parameter=-1; + determine_best_vel_initial_coding(quant,natoms,speed,prec_hi,prec_lo, + &initial_coding,&initial_coding_parameter); + } + else if (initial_coding_parameter==-1) + { + determine_best_vel_initial_coding(quant,natoms,speed,prec_hi,prec_lo, + &initial_coding,&initial_coding_parameter); + } + + if (nframes==1) + { + coding=0; + coding_parameter=0; + } + + if (nframes>1) + { + if (coding==-1) + { + coding_parameter=-1; + determine_best_vel_coding(quant,quant_inter,natoms,nframes,speed,prec_hi,prec_lo, + &coding,&coding_parameter); + } + else if (coding_parameter==-1) + { + determine_best_vel_coding(quant,quant_inter,natoms,nframes,speed,prec_hi,prec_lo, + &coding,&coding_parameter); + } + } + + compress_quantized_vel(quant,quant_inter,natoms,nframes,speed, + initial_coding,initial_coding_parameter, + coding,coding_parameter, + prec_hi,prec_lo,nitems,data); + free(quant_inter); + if (algo[0]==-1) + algo[0]=initial_coding; + if (algo[1]==-1) + algo[1]=initial_coding_parameter; + if (algo[2]==-1) + algo[2]=coding; + if (algo[3]==-1) + algo[3]=coding_parameter; + return data; +} + +char DECLSPECDLLEXPORT *tng_compress_vel(double *vel, const int natoms, const int nframes, + const double desired_precision, + const int speed, int *algo, + int *nitems) +{ + int *quant=malloc(natoms*nframes*3*sizeof *quant); + char *data; + fix_t prec_hi, prec_lo; + Ptngc_d_to_i32x2(desired_precision,&prec_hi,&prec_lo); + if (quantize(vel,natoms,nframes,PRECISION(prec_hi,prec_lo),quant)) + data=NULL; /* Error occured. Too large input values. */ + else + data=tng_compress_vel_int(quant,natoms,nframes,prec_hi,prec_lo,speed,algo,nitems); + free(quant); + return data; +} + +char DECLSPECDLLEXPORT *tng_compress_vel_float(float *vel, const int natoms, const int nframes, + const float desired_precision, + const int speed, int *algo, + int *nitems) +{ + int *quant=malloc(natoms*nframes*3*sizeof *quant); + char *data; + fix_t prec_hi, prec_lo; + Ptngc_d_to_i32x2((double)desired_precision,&prec_hi,&prec_lo); + if (quantize_float(vel,natoms,nframes,(float)PRECISION(prec_hi,prec_lo),quant)) + data=NULL; /* Error occured. Too large input values. */ + else + data=tng_compress_vel_int(quant,natoms,nframes,prec_hi,prec_lo,speed,algo,nitems); + free(quant); + return data; +} + +char DECLSPECDLLEXPORT *tng_compress_vel_find_algo(double *vel, const int natoms, const int nframes, + const double desired_precision, + const int speed, + int *algo, + int *nitems) +{ + algo[0]=-1; + algo[1]=-1; + algo[2]=-1; + algo[3]=-1; + return tng_compress_vel(vel,natoms,nframes,desired_precision,speed,algo,nitems); +} + +char DECLSPECDLLEXPORT *tng_compress_vel_float_find_algo(float *vel, const int natoms, const int nframes, + const float desired_precision, + const int speed, + int *algo, + int *nitems) +{ + algo[0]=-1; + algo[1]=-1; + algo[2]=-1; + algo[3]=-1; + return tng_compress_vel_float(vel,natoms,nframes,desired_precision,speed,algo,nitems); +} + +char DECLSPECDLLEXPORT *tng_compress_vel_int_find_algo(int *vel, const int natoms, const int nframes, + const unsigned long prec_hi, const unsigned long prec_lo, + const int speed, + int *algo, + int *nitems) +{ + algo[0]=-1; + algo[1]=-1; + algo[2]=-1; + algo[3]=-1; + return tng_compress_vel_int(vel,natoms,nframes,prec_hi,prec_lo,speed,algo,nitems); +} + +int DECLSPECDLLEXPORT tng_compress_inquire(char *data,int *vel, int *natoms, + int *nframes, double *precision, + int *algo) +{ + int bufloc=0; + fix_t prec_hi, prec_lo; + int initial_coding, initial_coding_parameter; + int coding, coding_parameter; + int magic_int; + magic_int=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + if (magic_int==MAGIC_INT_POS) + *vel=0; + else if (magic_int==MAGIC_INT_VEL) + *vel=1; + else + return 1; + /* Number of atoms. */ + *natoms=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Number of frames. */ + *nframes=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Initial coding. */ + initial_coding=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Initial coding parameter. */ + initial_coding_parameter=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Coding. */ + coding=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Coding parameter. */ + coding_parameter=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Precision. */ + prec_lo=readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + prec_hi=readbufferfix((unsigned char *)data+bufloc,4); + *precision=PRECISION(prec_hi, prec_lo); + algo[0]=initial_coding; + algo[1]=initial_coding_parameter; + algo[2]=coding; + algo[3]=coding_parameter; + return 0; +} + +static int tng_compress_uncompress_pos_gen(char *data,double *posd,float *posf,int *posi,unsigned long *prec_hi, unsigned long *prec_lo) +{ + int bufloc=0; + int length; + int natoms, nframes; + int initial_coding, initial_coding_parameter; + int coding, coding_parameter; + int *quant=NULL; + struct coder *coder=NULL; + int rval=0; + int magic_int; + /* Magic integer for positions */ + magic_int=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + if (magic_int!=MAGIC_INT_POS) + { + rval=1; + goto error; + } + /* Number of atoms. */ + natoms=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Number of frames. */ + nframes=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Initial coding. */ + initial_coding=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Initial coding parameter. */ + initial_coding_parameter=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Coding. */ + coding=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Coding parameter. */ + coding_parameter=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Precision. */ + *prec_lo=readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + *prec_hi=readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Allocate the memory for the quantized positions */ + quant=malloc(natoms*nframes*3*sizeof *quant); + /* The data block length. */ + length=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* The initial frame */ + coder=Ptngc_coder_init(); + rval=Ptngc_unpack_array(coder,(unsigned char*)data+bufloc,quant,natoms*3, + initial_coding,initial_coding_parameter,natoms); + Ptngc_coder_deinit(coder); + if (rval) + goto error; + /* Skip past the actual data block. */ + bufloc+=length; + /* Obtain the actual positions for the initial block. */ + if ((initial_coding==TNG_COMPRESS_ALGO_POS_XTC2) || + (initial_coding==TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE) || + (initial_coding==TNG_COMPRESS_ALGO_POS_XTC3)) + { + if (posd) + unquantize(posd,natoms,1,PRECISION(*prec_hi,*prec_lo),quant); + else if (posf) + unquantize_float(posf,natoms,1,(float)PRECISION(*prec_hi,*prec_lo),quant); + else if (posi) + memcpy(posi,quant,natoms*3*sizeof *posi); + } + else if ((initial_coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA) || + (initial_coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTRA)) + { + if (posd) + unquantize_intra_differences(posd,natoms,1,PRECISION(*prec_hi,*prec_lo),quant); + else if (posf) + unquantize_intra_differences_float(posf,natoms,1,(float)PRECISION(*prec_hi,*prec_lo),quant); + else if (posi) + unquantize_intra_differences_int(posi,natoms,1,quant); + unquant_intra_differences_first_frame(quant,natoms); + } + /* The remaining frames. */ + if (nframes>1) + { + bufloc+=4; + coder=Ptngc_coder_init(); + rval=Ptngc_unpack_array(coder,(unsigned char *)data+bufloc,quant+natoms*3,(nframes-1)*natoms*3, + coding,coding_parameter,natoms); + Ptngc_coder_deinit(coder); + if (rval) + goto error; + if ((coding==TNG_COMPRESS_ALGO_POS_STOPBIT_INTER) || + (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTER) || + (coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTER)) + { + /* This requires that the first frame is already in one-to-one format, even if intra-frame + compression was done there. Therefore the unquant_intra_differences_first_frame should be called + before to convert it correctly. */ + if (posd) + unquantize_inter_differences(posd,natoms,nframes,PRECISION(*prec_hi,*prec_lo),quant); + else if (posf) + unquantize_inter_differences_float(posf,natoms,nframes,(float)PRECISION(*prec_hi,*prec_lo),quant); + else if (posi) + unquantize_inter_differences_int(posi,natoms,nframes,quant); + } + else if ((coding==TNG_COMPRESS_ALGO_POS_XTC2) || + (coding==TNG_COMPRESS_ALGO_POS_XTC3) || + (coding==TNG_COMPRESS_ALGO_POS_TRIPLET_ONETOONE)) + { + if (posd) + unquantize(posd+natoms*3,natoms,nframes-1,PRECISION(*prec_hi,*prec_lo),quant+natoms*3); + else if (posf) + unquantize_float(posf+natoms*3,natoms,nframes-1,(float)PRECISION(*prec_hi,*prec_lo),quant+natoms*3); + else if (posi) + memcpy(posi+natoms*3,quant+natoms*3,natoms*3*(nframes-1)*sizeof *posi); + } + else if ((coding==TNG_COMPRESS_ALGO_POS_TRIPLET_INTRA) || + (coding==TNG_COMPRESS_ALGO_POS_BWLZH_INTRA)) + { + if (posd) + unquantize_intra_differences(posd+natoms*3,natoms,nframes-1,PRECISION(*prec_hi,*prec_lo),quant+natoms*3); + else if (posf) + unquantize_intra_differences_float(posf+natoms*3,natoms,nframes-1,(float)PRECISION(*prec_hi,*prec_lo),quant+natoms*3); + else if (posi) + unquantize_intra_differences_int(posi+natoms*3,natoms,nframes-1,quant+natoms*3); + } + } + error: + free(quant); + return rval; +} + +static int tng_compress_uncompress_pos(char *data,double *pos) +{ + unsigned long prec_hi, prec_lo; + return tng_compress_uncompress_pos_gen(data,pos,NULL,NULL,&prec_hi,&prec_lo); +} + +static int tng_compress_uncompress_pos_float(char *data,float *pos) +{ + unsigned long prec_hi, prec_lo; + return tng_compress_uncompress_pos_gen(data,NULL,pos,NULL,&prec_hi,&prec_lo); +} + +static int tng_compress_uncompress_pos_int(char *data,int *pos, unsigned long *prec_hi, unsigned long *prec_lo) +{ + return tng_compress_uncompress_pos_gen(data,NULL,NULL,pos,prec_hi,prec_lo); +} + +static int tng_compress_uncompress_vel_gen(char *data,double *veld,float *velf,int *veli,unsigned long *prec_hi, unsigned long *prec_lo) +{ + int bufloc=0; + int length; + int natoms, nframes; + int initial_coding, initial_coding_parameter; + int coding, coding_parameter; + int *quant=NULL; + struct coder *coder=NULL; + int rval=0; + int magic_int; + /* Magic integer for velocities */ + magic_int=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + if (magic_int!=MAGIC_INT_VEL) + { + rval=1; + goto error; + } + /* Number of atoms. */ + natoms=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Number of frames. */ + nframes=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Initial coding. */ + initial_coding=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Initial coding parameter. */ + initial_coding_parameter=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Coding. */ + coding=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Coding parameter. */ + coding_parameter=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Precision. */ + *prec_lo=readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + *prec_hi=readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* Allocate the memory for the quantized positions */ + quant=malloc(natoms*nframes*3*sizeof *quant); + /* The data block length. */ + length=(int)readbufferfix((unsigned char *)data+bufloc,4); + bufloc+=4; + /* The initial frame */ + coder=Ptngc_coder_init(); + rval=Ptngc_unpack_array(coder,(unsigned char*)data+bufloc,quant,natoms*3, + initial_coding,initial_coding_parameter,natoms); + Ptngc_coder_deinit(coder); + if (rval) + goto error; + /* Skip past the actual data block. */ + bufloc+=length; + /* Obtain the actual positions for the initial block. */ + if ((initial_coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE) || + (initial_coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE) || + (initial_coding==TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE)) + { + if (veld) + unquantize(veld,natoms,1,PRECISION(*prec_hi,*prec_lo),quant); + else if (velf) + unquantize_float(velf,natoms,1,(float)PRECISION(*prec_hi,*prec_lo),quant); + else if (veli) + memcpy(veli,quant,natoms*3*sizeof *veli); + } + /* The remaining frames. */ + if (nframes>1) + { + bufloc+=4; + coder=Ptngc_coder_init(); + rval=Ptngc_unpack_array(coder,(unsigned char *)data+bufloc,quant+natoms*3,(nframes-1)*natoms*3, + coding,coding_parameter,natoms); + Ptngc_coder_deinit(coder); + if (rval) + goto error; + /* Inter-frame compression? */ + if ((coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_INTER) || + (coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_INTER) || + (coding==TNG_COMPRESS_ALGO_VEL_BWLZH_INTER)) + { + /* This requires that the first frame is already in one-to-one format. */ + if (veld) + unquantize_inter_differences(veld,natoms,nframes,PRECISION(*prec_hi,*prec_lo),quant); + else if (velf) + unquantize_inter_differences_float(velf,natoms,nframes,(float)PRECISION(*prec_hi,*prec_lo),quant); + else if (veli) + unquantize_inter_differences_int(veli,natoms,nframes,quant); + } + /* One-to-one compression? */ + else if ((coding==TNG_COMPRESS_ALGO_VEL_STOPBIT_ONETOONE) || + (coding==TNG_COMPRESS_ALGO_VEL_TRIPLET_ONETOONE) || + (coding==TNG_COMPRESS_ALGO_VEL_BWLZH_ONETOONE)) + { + if (veld) + unquantize(veld+natoms*3,natoms,nframes-1,PRECISION(*prec_hi,*prec_lo),quant+natoms*3); + else if (velf) + unquantize_float(velf+natoms*3,natoms,nframes-1,(float)PRECISION(*prec_hi,*prec_lo),quant+natoms*3); + else if (veli) + memcpy(veli+natoms*3,quant+natoms*3,natoms*3*(nframes-1)*sizeof *veli); + } + } + error: + free(quant); + return rval; +} + +static int tng_compress_uncompress_vel(char *data,double *vel) +{ + unsigned long prec_hi, prec_lo; + return tng_compress_uncompress_vel_gen(data,vel,NULL,NULL,&prec_hi,&prec_lo); +} + +static int tng_compress_uncompress_vel_float(char *data,float *vel) +{ + unsigned long prec_hi, prec_lo; + return tng_compress_uncompress_vel_gen(data,NULL,vel,NULL,&prec_hi,&prec_lo); +} + +static int tng_compress_uncompress_vel_int(char *data,int *vel, unsigned long *prec_hi, unsigned long *prec_lo) +{ + return tng_compress_uncompress_vel_gen(data,NULL,NULL,vel,prec_hi,prec_lo); +} + +/* Uncompresses any tng compress block, positions or velocities. It determines whether it is positions or velocities from the data buffer. The return value is 0 if ok, and 1 if not. +*/ +int DECLSPECDLLEXPORT tng_compress_uncompress(char *data,double *posvel) +{ + int magic_int; + magic_int=(int)readbufferfix((unsigned char *)data,4); + if (magic_int==MAGIC_INT_POS) + return tng_compress_uncompress_pos(data,posvel); + else if (magic_int==MAGIC_INT_VEL) + return tng_compress_uncompress_vel(data,posvel); + else + return 1; +} + +int DECLSPECDLLEXPORT tng_compress_uncompress_float(char *data,float *posvel) +{ + int magic_int; + magic_int=(int)readbufferfix((unsigned char *)data,4); + if (magic_int==MAGIC_INT_POS) + return tng_compress_uncompress_pos_float(data,posvel); + else if (magic_int==MAGIC_INT_VEL) + return tng_compress_uncompress_vel_float(data,posvel); + else + return 1; +} + +int DECLSPECDLLEXPORT tng_compress_uncompress_int(char *data,int *posvel, unsigned long *prec_hi, unsigned long *prec_lo) +{ + int magic_int; + magic_int=(int)readbufferfix((unsigned char *)data,4); + if (magic_int==MAGIC_INT_POS) + return tng_compress_uncompress_pos_int(data,posvel,prec_hi,prec_lo); + else if (magic_int==MAGIC_INT_VEL) + return tng_compress_uncompress_vel_int(data,posvel,prec_hi,prec_lo); + else + return 1; +} + +void DECLSPECDLLEXPORT tng_compress_int_to_double(int *posvel_int, const unsigned long prec_hi, const unsigned long prec_lo, + const int natoms, const int nframes, + double *posvel_double) +{ + unquantize(posvel_double,natoms,nframes,PRECISION(prec_hi,prec_lo),posvel_int); +} + +void DECLSPECDLLEXPORT tng_compress_int_to_float(int *posvel_int, const unsigned long prec_hi, const unsigned long prec_lo, + const int natoms, const int nframes, + float *posvel_float) +{ + unquantize_float(posvel_float,natoms,nframes,(float)PRECISION(prec_hi,prec_lo),posvel_int); +} + +static char *compress_algo_pos[TNG_COMPRESS_ALGO_MAX]={ + "Positions invalid algorithm", + "Positions stopbits interframe", + "Positions triplet interframe", + "Positions triplet intraframe", + "Positions invalid algorithm", + "Positions XTC2", + "Positions invalid algorithm", + "Positions triplet one to one", + "Positions BWLZH interframe", + "Positions BWLZH intraframe", + "Positions XTC3" +}; + +static char *compress_algo_vel[TNG_COMPRESS_ALGO_MAX]={ + "Velocities invalid algorithm", + "Velocities stopbits one to one", + "Velocities triplet interframe", + "Velocities triplet one to one", + "Velocities invalid algorithm", + "Velocities invalid algorithm", + "Velocities stopbits interframe", + "Velocities invalid algorithm", + "Velocities BWLZH interframe", + "Velocities BWLZH one to one", + "Velocities invalid algorithm" +}; + +char DECLSPECDLLEXPORT *tng_compress_initial_pos_algo(int *algo) +{ + int i=algo[0]; + if (i<0) + i=0; + if (i>=TNG_COMPRESS_ALGO_MAX) + i=0; + return compress_algo_pos[i]; +} + +char DECLSPECDLLEXPORT *tng_compress_pos_algo(int *algo) +{ + int i=algo[2]; + if (i<0) + i=0; + if (i>=TNG_COMPRESS_ALGO_MAX) + i=0; + return compress_algo_pos[i]; +} + +char DECLSPECDLLEXPORT *tng_compress_initial_vel_algo(int *algo) +{ + int i=algo[0]; + if (i<0) + i=0; + if (i>=TNG_COMPRESS_ALGO_MAX) + i=0; + return compress_algo_vel[i]; +} + +char DECLSPECDLLEXPORT *tng_compress_vel_algo(int *algo) +{ + int i=algo[2]; + if (i<0) + i=0; + if (i>=TNG_COMPRESS_ALGO_MAX) + i=0; + return compress_algo_vel[i]; +} From 44590b6ca8a33e5666ed55073e0ac73925df7806 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 14:00:07 -0400 Subject: [PATCH 06/77] Modify some include paths. Add more files. --- src/tng/Makefile | 6 ++- src/tng/coder.c | 8 ++-- src/tng/compression/bwlzh.h | 72 ++++++++++++++++++++++++++++++++ src/tng/compression/warnmalloc.h | 26 ++++++++++++ 4 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 src/tng/compression/bwlzh.h create mode 100644 src/tng/compression/warnmalloc.h diff --git a/src/tng/Makefile b/src/tng/Makefile index 820d31e370..8f62f911d5 100644 --- a/src/tng/Makefile +++ b/src/tng/Makefile @@ -9,7 +9,7 @@ AR = ar cqs TARGET = libtngfile.a # Source files -SOURCES=md5.c tng_io.c tng_compress.c +SOURCES=md5.c tng_io.c tng_compress.c coder.c # Objects OBJECTS=$(SOURCES:.c=.o) @@ -36,4 +36,6 @@ md5.o : md5.c tng/md5.h tng_io.o : tng_io.c tng/tng_io.h tng/tng_io_fwd.h compression/tng_compress.h tng/version.h -tng_compress.o : tng_compress.c compression/tng_compress.h +tng_compress.o : tng_compress.c compression/tng_compress.h compression/coder.h compression/fixpoint.h + +coder.o : coder.c compression/coder.h compression/tng_compress.h compression/bwlzh.h compression/warnmalloc.h diff --git a/src/tng/coder.c b/src/tng/coder.c index d0a0d99f66..cc2001d69c 100644 --- a/src/tng/coder.c +++ b/src/tng/coder.c @@ -11,10 +11,10 @@ #include #include -#include "../../include/compression/tng_compress.h" -#include "../../include/compression/bwlzh.h" -#include "../../include/compression/coder.h" -#include "../../include/compression/warnmalloc.h" +#include "compression/tng_compress.h" +#include "compression/bwlzh.h" +#include "compression/coder.h" +#include "compression/warnmalloc.h" #ifndef USE_WINDOWS #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) diff --git a/src/tng/compression/bwlzh.h b/src/tng/compression/bwlzh.h new file mode 100644 index 0000000000..ce08f69cb8 --- /dev/null +++ b/src/tng/compression/bwlzh.h @@ -0,0 +1,72 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#ifndef BWLZH_H +#define BWLZH_H + +/* Compress the integers (positive, small integers are preferable) + using bwlzh compression. The unsigned char *output should be + allocated to be able to hold worst case. You can obtain this length + conveniently by calling comp_get_buflen() +*/ +void DECLSPECDLLEXPORT bwlzh_compress(unsigned int *vals, const int nvals, + unsigned char *output, int *output_len); + +void DECLSPECDLLEXPORT bwlzh_compress_no_lz77(unsigned int *vals, const int nvals, + unsigned char *output, int *output_len); + +int DECLSPECDLLEXPORT bwlzh_get_buflen(const int nvals); + +void DECLSPECDLLEXPORT bwlzh_decompress(unsigned char *input, const int nvals, + unsigned int *vals); + + +/* The routines below are mostly useful for testing, and for internal + use by the library. */ + +void DECLSPECDLLEXPORT bwlzh_compress_verbose(unsigned int *vals, const int nvals, + unsigned char *output, int *output_len); + +void DECLSPECDLLEXPORT bwlzh_compress_no_lz77_verbose(unsigned int *vals, const int nvals, + unsigned char *output, int *output_len); + +void DECLSPECDLLEXPORT bwlzh_decompress_verbose(unsigned char *input, const int nvals, + unsigned int *vals); + +/* Compress the integers (positive, small integers are preferable) + using huffman coding, with automatic selection of how to handle the + huffman dictionary. The unsigned char *huffman should be allocated + to be able to hold worst case. You can obtain this length + conveniently by calling comp_huff_buflen() +*/ +void Ptngc_comp_huff_compress(unsigned int *vals, const int nvals, + unsigned char *huffman, int *huffman_len); + +int Ptngc_comp_huff_buflen(const int nvals); + +void Ptngc_comp_huff_decompress(unsigned char *huffman, const int huffman_len, + unsigned int *vals); + + +/* the value pointed to by chosen_algo should be + sent as -1 for autodetect. */ +void Ptngc_comp_huff_compress_verbose(unsigned int *vals, int nvals, + unsigned char *huffman, int *huffman_len, + int *huffdatalen, + int *huffman_lengths,int *chosen_algo, + const int isvals16); + +#define N_HUFFMAN_ALGO 3 +char *Ptngc_comp_get_huff_algo_name(const int algo); +char *Ptngc_comp_get_algo_name(const int algo); + + +#endif diff --git a/src/tng/compression/warnmalloc.h b/src/tng/compression/warnmalloc.h new file mode 100644 index 0000000000..aa631117ed --- /dev/null +++ b/src/tng/compression/warnmalloc.h @@ -0,0 +1,26 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#ifndef WARNMALLOC_H +#define WARNMALLOC_H + +#include "../compression/tng_compress.h" + +void DECLSPECDLLEXPORT *Ptngc_warnmalloc_x(const size_t size, char *file, const int line); + +#define warnmalloc(size) Ptngc_warnmalloc_x(size,__FILE__,__LINE__) + +void DECLSPECDLLEXPORT *Ptngc_warnrealloc_x(void *old, const size_t size, char *file, const int line); + +#define warnrealloc(old,size) Ptngc_warnrealloc_x(old,size,__FILE__,__LINE__) + + +#endif From 6fabd4b326020ecb9983a8eb2622618b1b766471 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 14:02:31 -0400 Subject: [PATCH 07/77] More missing files. --- src/tng/Makefile | 4 +++- src/tng/warnmalloc.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/tng/warnmalloc.c diff --git a/src/tng/Makefile b/src/tng/Makefile index 8f62f911d5..2b629b5dd2 100644 --- a/src/tng/Makefile +++ b/src/tng/Makefile @@ -9,7 +9,7 @@ AR = ar cqs TARGET = libtngfile.a # Source files -SOURCES=md5.c tng_io.c tng_compress.c coder.c +SOURCES=md5.c tng_io.c tng_compress.c coder.c warnmalloc.c # Objects OBJECTS=$(SOURCES:.c=.o) @@ -39,3 +39,5 @@ tng_io.o : tng_io.c tng/tng_io.h tng/tng_io_fwd.h compression/tng_compress.h tng tng_compress.o : tng_compress.c compression/tng_compress.h compression/coder.h compression/fixpoint.h coder.o : coder.c compression/coder.h compression/tng_compress.h compression/bwlzh.h compression/warnmalloc.h + +warnmalloc.o : warnmalloc.c compression/warnmalloc.h compression/tng_compress.h diff --git a/src/tng/warnmalloc.c b/src/tng/warnmalloc.c new file mode 100644 index 0000000000..440a03f21d --- /dev/null +++ b/src/tng/warnmalloc.c @@ -0,0 +1,37 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#include +#include +#include "compression/tng_compress.h" +#include "compression/warnmalloc.h" + +void DECLSPECDLLEXPORT *Ptngc_warnmalloc_x(const size_t size, char *file, const int line) +{ + void *mem=malloc(size); + if (!mem) + { + fprintf(stderr,"TRAJNG ERROR: Could not allocate memory of size %lu at %s:%d\n",(unsigned long) size,file,line); + exit(EXIT_FAILURE); + } + return mem; +} + +void DECLSPECDLLEXPORT *Ptngc_warnrealloc_x(void *old, const size_t size, char *file, const int line) +{ + void *mem=realloc(old,size); + if (!mem) + { + fprintf(stderr,"TRAJNG ERROR: Could not allocate memory of size %lu at %s:%d\n",(unsigned long) size,file,line); + exit(EXIT_FAILURE); + } + return mem; +} From 0d0dd8326f26dd1753e423773e704b543ec0244e Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 14:05:34 -0400 Subject: [PATCH 08/77] Another missing file. Trying to get minimal version that works still... --- src/tng/Makefile | 4 +- src/tng/fixpoint.c | 126 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 src/tng/fixpoint.c diff --git a/src/tng/Makefile b/src/tng/Makefile index 2b629b5dd2..90358e1ae5 100644 --- a/src/tng/Makefile +++ b/src/tng/Makefile @@ -9,7 +9,7 @@ AR = ar cqs TARGET = libtngfile.a # Source files -SOURCES=md5.c tng_io.c tng_compress.c coder.c warnmalloc.c +SOURCES=md5.c tng_io.c tng_compress.c coder.c warnmalloc.c fixpoint.c # Objects OBJECTS=$(SOURCES:.c=.o) @@ -41,3 +41,5 @@ tng_compress.o : tng_compress.c compression/tng_compress.h compression/coder.h c coder.o : coder.c compression/coder.h compression/tng_compress.h compression/bwlzh.h compression/warnmalloc.h warnmalloc.o : warnmalloc.c compression/warnmalloc.h compression/tng_compress.h + +fixpoint.o : fixpoint.c compression/fixpoint.h diff --git a/src/tng/fixpoint.c b/src/tng/fixpoint.c new file mode 100644 index 0000000000..fb2f052c4f --- /dev/null +++ b/src/tng/fixpoint.c @@ -0,0 +1,126 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + +#include +#include +#include "compression/fixpoint.h" + +#define MAX32BIT 4294967295UL +#define MAX31BIT 2147483647UL +#define SIGN32BIT 2147483648UL + +/* Conversion routines from / to double precision */ + +/* Positive double to 32 bit fixed point value */ +fix_t Ptngc_ud_to_fix_t(double d, const double max) +{ + fix_t val; + if (d<0.) + d=0.; + if (d>max) + d=max; + val=(fix_t)(MAX32BIT*(d/max)); + if (val>MAX32BIT) + val=MAX32BIT; + return val; +} + +/* double to signed 32 bit fixed point value */ +fix_t Ptngc_d_to_fix_t(double d, const double max) +{ + fix_t val; + int sign=0; + if (d<0.) + { + sign=1; + d=-d; + } + if (d>max) + d=max; + val=(fix_t)(MAX31BIT*(d/max)); + if (val>MAX31BIT) + val=MAX31BIT; + if (sign) + val|=SIGN32BIT; + return val; +} + + +/* 32 bit fixed point value to positive double */ +double Ptngc_fix_t_to_ud(fix_t f, const double max) +{ + return (double)f*(max/MAX32BIT); +} + +/* signed 32 bit fixed point value to double */ +double Ptngc_fix_t_to_d(fix_t f, const double max) +{ + int sign=0; + double d; + if (f&SIGN32BIT) + { + sign=1; + f&=MAX31BIT; + } + d=(double)f*(max/MAX31BIT); + if (sign) + d=-d; + return d; +} + + +/* Convert a floating point variable to two 32 bit integers with range + -2.1e9 to 2.1e9 and precision to somewhere around 1e-9. */ +void Ptngc_d_to_i32x2(double d, fix_t *hi, fix_t *lo) +{ + int sign=0; + double frac; + double ent; + fix_t val,vallo; + if (d<0.) + { + sign=1; + d=-d; + } + /* First the integer part */ + ent=floor(d); + /* Then the fractional part */ + frac=d-ent; + + val=(fix_t)ent; + if (sign) + val|=SIGN32BIT; + + vallo=Ptngc_ud_to_fix_t(frac,1.); + + *hi=val; + *lo=vallo; +} + +/* Convert two 32 bit integers to a floating point variable + -2.1e9 to 2.1e9 and precision to somewhere around 1e-9. */ +double Ptngc_i32x2_to_d(fix_t hi, fix_t lo) +{ + double ent,frac=0.; + double val=0.; + int sign=0; + if (hi&SIGN32BIT) + { + sign=1; + hi&=MAX31BIT; + } + ent=(double)hi; + frac=Ptngc_fix_t_to_ud(lo,1.); + val=ent+frac; + if (sign) + val=-val; + return val; +} + From e918b356decfd4b017068475aef5bb867d876ce2 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 14:32:28 -0400 Subject: [PATCH 09/77] Add remaining files. --- src/tng/Makefile | 28 +- src/tng/bwlzh.c | 799 ++++++++++++ src/tng/bwt.c | 337 +++++ src/tng/compression/bwt.h | 26 + src/tng/compression/dict.h | 21 + src/tng/compression/huffman.h | 33 + src/tng/compression/lz77.h | 25 + src/tng/compression/merge_sort.h | 20 + src/tng/compression/mtf.h | 35 + src/tng/compression/rle.h | 22 + src/tng/compression/vals16.h | 21 + src/tng/compression/widemuldiv.h | 24 + src/tng/dict.c | 45 + src/tng/huffman.c | 581 +++++++++ src/tng/huffmem.c | 356 ++++++ src/tng/lz77.c | 348 ++++++ src/tng/merge_sort.c | 128 ++ src/tng/mtf.c | 258 ++++ src/tng/rle.c | 99 ++ src/tng/vals16.c | 71 ++ src/tng/widemuldiv.c | 240 ++++ src/tng/xtc2.c | 1523 +++++++++++++++++++++++ src/tng/xtc3.c | 1957 ++++++++++++++++++++++++++++++ 23 files changed, 6996 insertions(+), 1 deletion(-) create mode 100644 src/tng/bwlzh.c create mode 100644 src/tng/bwt.c create mode 100644 src/tng/compression/bwt.h create mode 100644 src/tng/compression/dict.h create mode 100644 src/tng/compression/huffman.h create mode 100644 src/tng/compression/lz77.h create mode 100644 src/tng/compression/merge_sort.h create mode 100644 src/tng/compression/mtf.h create mode 100644 src/tng/compression/rle.h create mode 100644 src/tng/compression/vals16.h create mode 100644 src/tng/compression/widemuldiv.h create mode 100644 src/tng/dict.c create mode 100644 src/tng/huffman.c create mode 100644 src/tng/huffmem.c create mode 100644 src/tng/lz77.c create mode 100644 src/tng/merge_sort.c create mode 100644 src/tng/mtf.c create mode 100644 src/tng/rle.c create mode 100644 src/tng/vals16.c create mode 100644 src/tng/widemuldiv.c create mode 100644 src/tng/xtc2.c create mode 100644 src/tng/xtc3.c diff --git a/src/tng/Makefile b/src/tng/Makefile index 90358e1ae5..6b5e3bb3b6 100644 --- a/src/tng/Makefile +++ b/src/tng/Makefile @@ -9,7 +9,7 @@ AR = ar cqs TARGET = libtngfile.a # Source files -SOURCES=md5.c tng_io.c tng_compress.c coder.c warnmalloc.c fixpoint.c +SOURCES=md5.c tng_io.c tng_compress.c coder.c warnmalloc.c fixpoint.c xtc3.c bwlzh.c xtc2.c widemuldiv.c huffmem.c vals16.c bwt.c mtf.c rle.c lz77.c dict.c huffman.c merge_sort.c # Objects OBJECTS=$(SOURCES:.c=.o) @@ -43,3 +43,29 @@ coder.o : coder.c compression/coder.h compression/tng_compress.h compression/bwl warnmalloc.o : warnmalloc.c compression/warnmalloc.h compression/tng_compress.h fixpoint.o : fixpoint.c compression/fixpoint.h + +xtc3.o : xtc3.c compression/warnmalloc.h compression/bwlzh.h compression/widemuldiv.h + +bwlzh.o : bwlzh.c compression/bwlzh.h compression/warnmalloc.h compression/tng_compress.h compression/dict.h compression/vals16.h compression/rle.h compression/mtf.h compression/bwt.h compression/lz77.h + +xtc2.o : xtc2.c compression/coder.h compression/widemuldiv.h compression/warnmalloc.h + +widemuldiv.o : widemuldiv.c compression/widemuldiv.h compression/tng_compress.h compression/my64bit.h + +huffmem.o : huffmem.c compression/huffman.h compression/warnmalloc.h compression/tng_compress.h compression/bwlzh.h compression/dict.h compression/rle.h compression/vals16.h + +vals16.o : vals16.c compression/vals16.h + +bwt.o : bwt.c compression/bwt.h compression/warnmalloc.h + +mtf.o : mtf.c compression/mtf.h compression/warnmalloc.h + +rle.o : rle.c compression/rle.h + +lz77.o : lz77.c compression/lz77.h compression/bwt.h compression/warnmalloc.h + +dict.o : dict.c compression/dict.h + +huffman.o : huffman.c compression/warnmalloc.h compression/merge_sort.h compression/huffman.h + +merge_sort.o : merge_sort.c compression/merge_sort.h compression/warnmalloc.h diff --git a/src/tng/bwlzh.c b/src/tng/bwlzh.c new file mode 100644 index 0000000000..ca115ba084 --- /dev/null +++ b/src/tng/bwlzh.c @@ -0,0 +1,799 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#include +#include +#include +#include "compression/warnmalloc.h" +#include "compression/tng_compress.h" +#include "compression/bwlzh.h" +#include "compression/dict.h" +#include "compression/vals16.h" +#include "compression/rle.h" +#include "compression/mtf.h" +#include "compression/bwt.h" +#include "compression/lz77.h" + +#if 0 +#define SHOWIT +#endif + +#if 0 +#define SHOWTEST +#endif + +#define MAX_VALS_PER_BLOCK 200000 + +#if 1 +#define PARTIAL_MTF3 +#endif + +#if 0 +#define PARTIAL_MTF +#endif + +int bwlzh_get_buflen(const int nvals) +{ + return 132000+nvals*8+12*((nvals+MAX_VALS_PER_BLOCK)/MAX_VALS_PER_BLOCK); +} + +#ifdef SHOWIT +static void printvals(const char *name, unsigned int *vals, const int nvals) +{ + int i; + int nvalsmax=nvals; + if (nvalsmax>99) + nvalsmax=99; +#if 0 + for (i=0; i>8)&0xFFU; + output[outdata++]=(((unsigned int)nvals)>>16)&0xFFU; + output[outdata++]=(((unsigned int)nvals)>>24)&0xFFU; + + valsleft=nvals; + valstart=0; + while (valsleft) + { + int reducealgo=1; /* Reduce algo is LZ77. */ + if (!enable_lz77) + reducealgo=0; + thisvals=valsleft; + if (thisvals>max_vals_per_block) + thisvals=max_vals_per_block; + valsleft-=thisvals; + if (verbose) + fprintf(stderr,"Creating vals16 block from %d values.\n",thisvals); + +#ifdef SHOWIT + printvals("vals",vals+valstart,thisvals); +#endif + + Ptngc_comp_conv_to_vals16(vals+valstart,thisvals,vals16,&nvals16); + valstart+=thisvals; + +#ifdef SHOWTEST + nvals16=99; +#endif + +#ifdef SHOWIT + printvals("vals16",vals16,nvals16); +#endif + + if (verbose) + { + fprintf(stderr,"Resulting vals16 values: %d\n",nvals16); + } + if (verbose) + { + fprintf(stderr,"BWT\n"); + } + Ptngc_comp_to_bwt(vals16,nvals16,bwt,&bwt_index); + +#ifdef SHOWIT + printvals("bwt",bwt,nvals16); + fprintf(stderr,"BWT INDEX is %d\n",bwt_index); +#endif + + /* Store the number of real values in this block. */ + output[outdata++]=((unsigned int)thisvals)&0xFFU; + output[outdata++]=(((unsigned int)thisvals)>>8)&0xFFU; + output[outdata++]=(((unsigned int)thisvals)>>16)&0xFFU; + output[outdata++]=(((unsigned int)thisvals)>>24)&0xFFU; + + /* Store the number of nvals16 values in this block. */ + output[outdata++]=((unsigned int)nvals16)&0xFFU; + output[outdata++]=(((unsigned int)nvals16)>>8)&0xFFU; + output[outdata++]=(((unsigned int)nvals16)>>16)&0xFFU; + output[outdata++]=(((unsigned int)nvals16)>>24)&0xFFU; + + /* Store the BWT index. */ + output[outdata++]=((unsigned int)bwt_index)&0xFFU; + output[outdata++]=(((unsigned int)bwt_index)>>8)&0xFFU; + output[outdata++]=(((unsigned int)bwt_index)>>16)&0xFFU; + output[outdata++]=(((unsigned int)bwt_index)>>24)&0xFFU; + + if (verbose) + fprintf(stderr,"MTF\n"); +#ifdef PARTIAL_MTF3 + Ptngc_comp_conv_to_mtf_partial3(bwt,nvals16, + mtf3); + for (imtfinner=0; imtfinner<3; imtfinner++) + { + int i; + if (verbose) + fprintf(stderr,"Doing partial MTF: %d\n",imtfinner); + for (i=0; i>=1; + } + coarse[numbits-1]+=thist[jj]; + } +#if 1 + for (jj=0; jj>8)&0xFFU; + output[outdata++]=(((unsigned int)nrle)>>16)&0xFFU; + output[outdata++]=(((unsigned int)nrle)>>24)&0xFFU; + + /* Store the size of the huffman block. */ + output[outdata++]=((unsigned int)bwlzhhufflen)&0xFFU; + output[outdata++]=(((unsigned int)bwlzhhufflen)>>8)&0xFFU; + output[outdata++]=(((unsigned int)bwlzhhufflen)>>16)&0xFFU; + output[outdata++]=(((unsigned int)bwlzhhufflen)>>24)&0xFFU; + + /* Store the huffman block. */ + memcpy(output+outdata,bwlzhhuff,bwlzhhufflen); + outdata+=bwlzhhufflen; + + if (reducealgo==1) + { + /* Store the number of values in this block. */ + output[outdata++]=((unsigned int)noffsets)&0xFFU; + output[outdata++]=(((unsigned int)noffsets)>>8)&0xFFU; + output[outdata++]=(((unsigned int)noffsets)>>16)&0xFFU; + output[outdata++]=(((unsigned int)noffsets)>>24)&0xFFU; + + if (noffsets>0) + { + if (verbose) + fprintf(stderr,"Huffman for offsets\n"); + + huffalgo=-1; + Ptngc_comp_huff_compress_verbose(offsets,noffsets,bwlzhhuff,&bwlzhhufflen,&huffdatalen,nhufflen,&huffalgo,1); + if (verbose) + { + int i; + fprintf(stderr,"Huffman data length is %d B.\n",huffdatalen); + for (i=0; i>8)&0xFFU; + output[outdata++]=(((unsigned int)bwlzhhufflen)>>16)&0xFFU; + output[outdata++]=(((unsigned int)bwlzhhufflen)>>24)&0xFFU; + + /* Store the huffman block. */ + memcpy(output+outdata,bwlzhhuff,bwlzhhufflen); + outdata+=bwlzhhufflen; + } + else + { + int i; + output[outdata++]=1; + for (i=0; i>8)&0xFFU; + } + if (verbose) + fprintf(stderr,"Store raw offsets: %d B\n",noffsets*2); + } + } + +#if 0 + { + int i,ndict; + FILE *f=fopen("len.dict","w"); + Ptngc_comp_make_dict_hist(lens,nlens,dict,&ndict,hist); + for (i=0; i>8)&0xFFU; + output[outdata++]=(((unsigned int)nlens)>>16)&0xFFU; + output[outdata++]=(((unsigned int)nlens)>>24)&0xFFU; + + /* Store the size of the huffman block. */ + output[outdata++]=((unsigned int)bwlzhhufflen)&0xFFU; + output[outdata++]=(((unsigned int)bwlzhhufflen)>>8)&0xFFU; + output[outdata++]=(((unsigned int)bwlzhhufflen)>>16)&0xFFU; + output[outdata++]=(((unsigned int)bwlzhhufflen)>>24)&0xFFU; + + /* Store the huffman block. */ + memcpy(output+outdata,bwlzhhuff,bwlzhhufflen); + outdata+=bwlzhhufflen; + } +#ifdef PARTIAL_MTF3 + } +#endif + } + + *output_len=outdata; + free(hist); + free(dict); + free(bwlzhhuff); +#ifdef PARTIAL_MTF3 + free(mtf3); +#endif + free(tmpmem); +} + + +void DECLSPECDLLEXPORT bwlzh_compress(unsigned int *vals, const int nvals, + unsigned char *output, int *output_len) +{ + bwlzh_compress_gen(vals,nvals,output,output_len,1,0); +} + +void DECLSPECDLLEXPORT bwlzh_compress_verbose(unsigned int *vals, const int nvals, + unsigned char *output, int *output_len) +{ + bwlzh_compress_gen(vals,nvals,output,output_len,1,1); +} + + +void DECLSPECDLLEXPORT bwlzh_compress_no_lz77(unsigned int *vals, const int nvals, + unsigned char *output, int *output_len) +{ + bwlzh_compress_gen(vals,nvals,output,output_len,0,0); +} + +void DECLSPECDLLEXPORT bwlzh_compress_no_lz77_verbose(unsigned int *vals, const int nvals, + unsigned char *output, int *output_len) +{ + bwlzh_compress_gen(vals,nvals,output,output_len,0,1); +} + + +static void bwlzh_decompress_gen(unsigned char *input, const int nvals, + unsigned int *vals, + const int verbose) +{ + unsigned int *vals16; + int nvals16; + int bwt_index; + unsigned int *bwt=NULL; + unsigned int *mtf=NULL; +#ifdef PARTIAL_MTF3 + unsigned char *mtf3=NULL; + int imtfinner; +#endif + unsigned int *rle=NULL; + unsigned int *offsets=NULL; + unsigned int *lens=NULL; + unsigned int *dict=warnmalloc(0x20004*sizeof *dict); + unsigned int *hist=warnmalloc(0x20004*sizeof *hist); + int nrle, noffsets, nlens; + unsigned char *bwlzhhuff=NULL; + int bwlzhhufflen; + int max_vals_per_block=MAX_VALS_PER_BLOCK; + int valsleft; + int thisvals; + int valstart; + int inpdata=0; + int nvalsfile; + + unsigned int *tmpmem=warnmalloc(max_vals_per_block*18*sizeof *tmpmem); + +#if 0 + verbose=1; +#endif + + + bwlzhhuff=warnmalloc(Ptngc_comp_huff_buflen(3*nvals)); + vals16=tmpmem; + bwt=tmpmem+max_vals_per_block*3; + mtf=tmpmem+max_vals_per_block*6; + rle=tmpmem+max_vals_per_block*9; + offsets=tmpmem+max_vals_per_block*12; + lens=tmpmem+max_vals_per_block*15; +#ifdef PARTIAL_MTF3 + mtf3=warnmalloc(max_vals_per_block*3*3*sizeof *mtf3); /* 3 due to expansion of 32 bit to 16 bit, 3 due to up to 3 bytes + per 16 value. */ +#endif + + if (verbose) + { + fprintf(stderr,"Number of input values: %d\n",nvals); + } + + /* Read the number of real values in the whole block. */ + nvalsfile=(int)(((unsigned int)input[inpdata]) | + (((unsigned int)input[inpdata+1])<<8) | + (((unsigned int)input[inpdata+2])<<16) | + (((unsigned int)input[inpdata+3])<<24)); + inpdata+=4; + + if (nvalsfile!=nvals) + { + fprintf(stderr,"BWLZH: The number of values found in the file is different from the number of values expected.\n"); + exit(EXIT_FAILURE); + } + + valsleft=nvals; + valstart=0; + while (valsleft) + { + int valsnew; + int reducealgo; + /* Read the number of real values in this block. */ + thisvals=(int)(((unsigned int)input[inpdata]) | + (((unsigned int)input[inpdata+1])<<8) | + (((unsigned int)input[inpdata+2])<<16) | + (((unsigned int)input[inpdata+3])<<24)); + inpdata+=4; + + valsleft-=thisvals; + + /* Read the number of nvals16 values in this block. */ + nvals16=(int)(((unsigned int)input[inpdata]) | + (((unsigned int)input[inpdata+1])<<8) | + (((unsigned int)input[inpdata+2])<<16) | + (((unsigned int)input[inpdata+3])<<24)); + inpdata+=4; + + /* Read the BWT index. */ + bwt_index=(int)(((unsigned int)input[inpdata]) | + (((unsigned int)input[inpdata+1])<<8) | + (((unsigned int)input[inpdata+2])<<16) | + (((unsigned int)input[inpdata+3])<<24)); + inpdata+=4; + + if (thisvals>max_vals_per_block) + { + /* More memory must be allocated for decompression. */ + max_vals_per_block=thisvals; + if (verbose) + fprintf(stderr,"Allocating more memory: %d B\n",(int)(max_vals_per_block*15*sizeof *tmpmem)); + tmpmem=warnrealloc(tmpmem,max_vals_per_block*18*sizeof *tmpmem); + vals16=tmpmem; + bwt=tmpmem+max_vals_per_block*3; + mtf=tmpmem+max_vals_per_block*6; + rle=tmpmem+max_vals_per_block*9; + offsets=tmpmem+max_vals_per_block*12; + lens=tmpmem+max_vals_per_block*15; +#ifdef PARTIAL_MTF3 + mtf3=warnrealloc(mtf3,max_vals_per_block*3*3*sizeof *mtf3); /* 3 due to expansion of 32 bit to 16 bit, 3 due to up to 3 bytes + per 16 value. */ +#endif + } + +#ifdef PARTIAL_MTF3 + for (imtfinner=0; imtfinner<3; imtfinner++) + { + int i; + if (verbose) + fprintf(stderr,"Doing partial MTF: %d\n",imtfinner); +#endif + + reducealgo=(int)input[inpdata]; + inpdata++; + + /* Read the number of huffman values in this block. */ + nrle=(int)(((unsigned int)input[inpdata]) | + (((unsigned int)input[inpdata+1])<<8) | + (((unsigned int)input[inpdata+2])<<16) | + (((unsigned int)input[inpdata+3])<<24)); + inpdata+=4; + + /* Read the size of the huffman block. */ + bwlzhhufflen=(int)(((unsigned int)input[inpdata]) | + (((unsigned int)input[inpdata+1])<<8) | + (((unsigned int)input[inpdata+2])<<16) | + (((unsigned int)input[inpdata+3])<<24)); + inpdata+=4; + + if (verbose) + fprintf(stderr,"Decompressing huffman block of length %d.\n",bwlzhhufflen); + /* Decompress the huffman block. */ + Ptngc_comp_huff_decompress(input+inpdata,bwlzhhufflen,rle); + inpdata+=bwlzhhufflen; + + if (reducealgo==1) /* LZ77 */ + { + int offstore; + /* Read the number of huffman values in this block. */ + noffsets=(int)(((unsigned int)input[inpdata]) | + (((unsigned int)input[inpdata+1])<<8) | + (((unsigned int)input[inpdata+2])<<16) | + (((unsigned int)input[inpdata+3])<<24)); + inpdata+=4; + + if (noffsets>0) + { + /* How are the offsets stored? */ + offstore=(int)input[inpdata++]; + if (offstore==0) + { + /* Read the size of the huffman block. */ + bwlzhhufflen=(int)(((unsigned int)input[inpdata]) | + (((unsigned int)input[inpdata+1])<<8) | + (((unsigned int)input[inpdata+2])<<16) | + (((unsigned int)input[inpdata+3])<<24)); + inpdata+=4; + + if (verbose) + fprintf(stderr,"Decompressing offset huffman block.\n"); + + /* Decompress the huffman block. */ + Ptngc_comp_huff_decompress(input+inpdata,bwlzhhufflen,offsets); + inpdata+=bwlzhhufflen; + } + else + { + int i; + if (verbose) + fprintf(stderr,"Reading offset block.\n"); + for (i=0; i +#include +#include +#include "compression/warnmalloc.h" +#include "compression/bwt.h" + +#if 0 +#define SHOWIT +#endif +#if 0 +#define SHOWIT2 +#endif + +static int compare_index(int i1,int i2, const int nvals, unsigned int *vals, unsigned int *nrepeat) +{ + int i,j; + for (i=0; i>8); + int k1=(int)(nrepeat[i1]&0xFFU); + int repeat2=(int)(nrepeat[i2]>>8); + int k2=(int)(nrepeat[i2]&0xFFU); + + if ((repeat1>1) && (repeat2>1) && (k1==k2)) + { + int maxskip=0; + /* Yes. Compare the repeating patterns. */ + for (j=0; jv2) + return 1; + } + /* The repeating patterns are equal. Skip as far as we can + before continuing. */ + maxskip=repeat1; + if (repeat2vals[i2]) + return 1; + i1++; + if (i1>=nvals) + i1=0; + i2++; + if (i2>=nvals) + i2=0; + } + } + return 0; +} + +void Ptngc_bwt_merge_sort_inner(int *indices, const int nvals,unsigned int *vals, + const int start, const int end, + unsigned int *nrepeat, + int *workarray) +{ + int middle; + if ((end-start)>1) + { + middle=start+(end-start)/2; +#if 0 + printf("For start %d end %d obtained new middle: %d\n",start,end,middle); +#endif + Ptngc_bwt_merge_sort_inner(indices,nvals,vals, + start,middle, + nrepeat, + workarray); + Ptngc_bwt_merge_sort_inner(indices,nvals,vals, + middle,end, + nrepeat, + workarray); +#if 0 + printf("For start %d end %d Before merge: Comparing element %d with %d\n",start,end,middle-1,middle); +#endif + if (compare_index(indices[middle-1],indices[middle],nvals,vals,nrepeat)>0) + { + /* Merge to work array. */ + int i, n=end-start; + int ileft=start; + int iright=middle; + for (i=0; i0) + { + workarray[i]=indices[iright]; + iright++; + } + else + { + workarray[i]=indices[ileft]; + ileft++; + } + } + } + /* Copy result back. */ + memcpy(indices+start,workarray,(end-start)*sizeof(int)); + } + } +} + +/* Burrows-Wheeler transform. */ +void Ptngc_comp_to_bwt(unsigned int *vals, const int nvals, + unsigned int *output, int *index) +{ + int i; + int *indices=warnmalloc(2*nvals*sizeof *indices); + unsigned int *nrepeat=warnmalloc(nvals*sizeof *nrepeat); + int *warr=indices+nvals; + + if (nvals>0xFFFFFF) + { + fprintf(stderr,"BWT cannot pack more than %d values.\n",0xFFFFFF); + exit(1); + } + + /* Also note that repeat pattern k (kmax) cannot be larger than 255. */ +#if 0 + printf("Size of arrays is %.2f M\n",4*nvals*sizeof *indices/1024./1024.); +#endif + for (i=0; i=1; k--) + { + try_next_k: + if (k>=1) + { +#ifdef SHOWIT + printf("Trying k=%d at i=%d\n",k,i); +#endif + for (j=k; jmaxrepeat) + new_j=j; + if ((new_j>good_j) || ((new_j==good_j) && (knvals) + repeat=nvals; + nrepeat[i+m]=((unsigned int) (good_k)) | (((unsigned int) (repeat))<<8); + } + /* If no repetition was found for this value signal that here. */ + if (!nrepeat[i]) + nrepeat[i+m]=257U; /* This is 1<<8 | 1 */ + } + } +#ifdef SHOWIT + for (i=0; i>8)!=1) + printf("String repeats at %d: %d %d\n",i,nrepeat[i]>>8,nrepeat[i]&0xFFU); +#endif + + /* Sort cyclic shift matrix. */ + Ptngc_bwt_merge_sort_inner(indices,nvals,vals,0,nvals,nrepeat,warr); + +#if 0 + /* Test that it really is sorted. */ + for (i=0; i=0; i--) + { + vals[i]=input[index]; + index=p[index]+c[input[index]]; + } + free(p); + free(c); +} + diff --git a/src/tng/compression/bwt.h b/src/tng/compression/bwt.h new file mode 100644 index 0000000000..fedfc3d0ad --- /dev/null +++ b/src/tng/compression/bwt.h @@ -0,0 +1,26 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#ifndef BWT_H +#define BWT_H + +void Ptngc_comp_to_bwt(unsigned int *vals, const int nvals, + unsigned int *output, int *index); + +void Ptngc_comp_from_bwt(unsigned int *input, const int nvals, int index, + unsigned int *vals); + +void Ptngc_bwt_merge_sort_inner(int *indices, const int nvals, unsigned int *vals, + const int start, const int end, + unsigned int *nrepeat, + int *workarray); + +#endif diff --git a/src/tng/compression/dict.h b/src/tng/compression/dict.h new file mode 100644 index 0000000000..26eed2736e --- /dev/null +++ b/src/tng/compression/dict.h @@ -0,0 +1,21 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#ifndef DICT_H +#define DICT_H + +void Ptngc_comp_canonical_dict(unsigned int *dict, int *ndict); + +void Ptngc_comp_make_dict_hist(unsigned int *vals, const int nvals, + unsigned int *dict, int *ndict, + unsigned int *hist); + +#endif diff --git a/src/tng/compression/huffman.h b/src/tng/compression/huffman.h new file mode 100644 index 0000000000..f2ce1875b6 --- /dev/null +++ b/src/tng/compression/huffman.h @@ -0,0 +1,33 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#ifndef HUFFMAN_H +#define HUFFMAN_H + +void Ptngc_comp_conv_to_huffman(unsigned int *vals, const int nvals, + unsigned int *dict, const int ndict, + unsigned int *prob, + unsigned char *huffman, + int *huffman_len, + unsigned char *huffman_dict, + int *huffman_dictlen, + unsigned int *huffman_dict_unpacked, + int *huffman_dict_unpackedlen); + +void Ptngc_comp_conv_from_huffman(unsigned char *huffman, + unsigned int *vals, const int nvals, + const int ndict, + unsigned char *huffman_dict, + const int huffman_dictlen, + unsigned int *huffman_dict_unpacked, + const int huffman_dict_unpackedlen); + +#endif diff --git a/src/tng/compression/lz77.h b/src/tng/compression/lz77.h new file mode 100644 index 0000000000..d4a4beb856 --- /dev/null +++ b/src/tng/compression/lz77.h @@ -0,0 +1,25 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#ifndef LZ77_H +#define LZ77_H + +void Ptngc_comp_to_lz77(unsigned int *vals, const int nvals, + unsigned int *data, int *ndata, + unsigned int *len, int *nlens, + unsigned int *offsets, int *noffsets); + +void Ptngc_comp_from_lz77(unsigned int *data, const int ndata, + unsigned int *len, const int nlens, + unsigned int *offsets, const int noffsets, + unsigned int *vals, const int nvals); + +#endif diff --git a/src/tng/compression/merge_sort.h b/src/tng/compression/merge_sort.h new file mode 100644 index 0000000000..f8aaeb79ba --- /dev/null +++ b/src/tng/compression/merge_sort.h @@ -0,0 +1,20 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#ifndef MERGE_SORT_H +#define MERGE_SORT_H + +void Ptngc_merge_sort(void *base, const size_t nmemb, const size_t size, + int (*compar)(const void *v1,const void *v2,const void *private), + void *private); + + +#endif diff --git a/src/tng/compression/mtf.h b/src/tng/compression/mtf.h new file mode 100644 index 0000000000..3dc9ace1ea --- /dev/null +++ b/src/tng/compression/mtf.h @@ -0,0 +1,35 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#ifndef MTF_H +#define MTF_H + +void Ptngc_comp_conv_to_mtf(unsigned int *vals, const int nvals, + unsigned int *dict, const int ndict, + unsigned int *valsmtf); + +void Ptngc_comp_conv_from_mtf(unsigned int *valsmtf, const int nvals, + unsigned int *dict, const int ndict, + unsigned int *vals); + +void Ptngc_comp_conv_to_mtf_partial(unsigned int *vals, const int nvals, + unsigned int *valsmtf); + +void Ptngc_comp_conv_from_mtf_partial(unsigned int *valsmtf, const int nvals, + unsigned int *vals); + +void Ptngc_comp_conv_to_mtf_partial3(unsigned int *vals, const int nvals, + unsigned char *valsmtf); + +void Ptngc_comp_conv_from_mtf_partial3(unsigned char *valsmtf, const int nvals, + unsigned int *vals); + +#endif diff --git a/src/tng/compression/rle.h b/src/tng/compression/rle.h new file mode 100644 index 0000000000..3665dd0717 --- /dev/null +++ b/src/tng/compression/rle.h @@ -0,0 +1,22 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#ifndef RLE_H +#define RLE_H + +void Ptngc_comp_conv_to_rle(unsigned int *vals, const int nvals, + unsigned int *rle, int *nrle, + const int min_rle); + +void Ptngc_comp_conv_from_rle(unsigned int *rle, + unsigned int *vals, const int nvals); + +#endif diff --git a/src/tng/compression/vals16.h b/src/tng/compression/vals16.h new file mode 100644 index 0000000000..ba1b8fb2e3 --- /dev/null +++ b/src/tng/compression/vals16.h @@ -0,0 +1,21 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#ifndef VALS16_H +#define VALS16_H + +void Ptngc_comp_conv_to_vals16(unsigned int *vals, const int nvals, + unsigned int *vals16, int *nvals16); + +void Ptngc_comp_conv_from_vals16(unsigned int *vals16, const int nvals16, + unsigned int *vals, int *nvals); + +#endif diff --git a/src/tng/compression/widemuldiv.h b/src/tng/compression/widemuldiv.h new file mode 100644 index 0000000000..dfa905be4e --- /dev/null +++ b/src/tng/compression/widemuldiv.h @@ -0,0 +1,24 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#ifndef WIDEMULDIV_H +#define WIDEMULDIV_H + +/* Add a unsigned int to a largeint. */ +void Ptngc_largeint_add(const unsigned int v1, unsigned int *largeint, const int n); + +/* Multiply v1 with largeint_in and return result in largeint_out */ +void Ptngc_largeint_mul(const unsigned int v1, unsigned int *largeint_in, unsigned int *largeint_out, const int n); + +/* Return the remainder from dividing largeint_in with v1. Result of the division is returned in largeint_out */ +unsigned int Ptngc_largeint_div(const unsigned int v1, unsigned int *largeint_in, unsigned int *largeint_out, const int n); + +#endif diff --git a/src/tng/dict.c b/src/tng/dict.c new file mode 100644 index 0000000000..b68d557eb0 --- /dev/null +++ b/src/tng/dict.c @@ -0,0 +1,45 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg and Magnus Lundborg + * Copyright (c) 2010, 2013-2014 The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#include +#include "compression/dict.h" + +void Ptngc_comp_canonical_dict(unsigned int *dict, int *ndict) +{ + int i; + for (i=0; i<0x20004; i++) + dict[i]=i; + + *ndict=0x20004; +} + +void Ptngc_comp_make_dict_hist(unsigned int *vals, const int nvals, + unsigned int *dict, int *ndict, + unsigned int *hist) +{ + int i; + int j=0; + + memset(hist, 0, sizeof(unsigned int)*0x20004); + + for (i=0; i +#include +#include +#include "compression/warnmalloc.h" +#include "compression/merge_sort.h" +#include "compression/huffman.h" + +#define MAX_HUFFMAN_LEN 31 + +enum htree_type { htree_leaf, htree_node }; + +struct htree_leaf +{ + enum htree_type nodeleaf; + unsigned int idict; /* Index into input dictionary */ + unsigned int prob; + unsigned int bit; /* One or zero */ +}; + +struct htree_node +{ + enum htree_type nodeleaf; + union htree_nodeleaf *n1; + union htree_nodeleaf *n2; + unsigned int bit; /* One or zero */ + unsigned int prob; +}; + +union htree_nodeleaf +{ + enum htree_type nodeleaf; + struct htree_node node; + struct htree_leaf leaf; +}; + +struct codelength +{ + unsigned int code; + int length; + unsigned int dict; + unsigned int prob; +}; + +static int comp_htree(const void *leafptr1, const void *leafptr2, const void *private) +{ + const union htree_nodeleaf *leaf1=(union htree_nodeleaf *)leafptr1; + const union htree_nodeleaf *leaf2=(union htree_nodeleaf *)leafptr2; + int rval=0; + (void)private; + + if (leaf1->leaf.probleaf.prob) + rval=1; + else if (leaf1->leaf.prob>leaf2->leaf.prob) + rval=-1; + return rval; +} + +static void assign_codes(union htree_nodeleaf *htree, + struct codelength *codelength, + unsigned int code, + int length, + const int top) +{ +#if 0 + printf("Assign codes called with code %d length %d\n",code,length); +#endif + if (htree->nodeleaf==htree_leaf) + { + codelength[htree->leaf.idict].length=length+1; + codelength[htree->leaf.idict].code=(code<<1)|htree->leaf.bit; +#if 0 + printf("I am a leaf: %d %d\n", + codelength[htree->leaf.idict].length, + codelength[htree->leaf.idict].code); +#endif + } + else + { + if (!top) + { + code<<=1; + code|=htree->node.bit; + length++; + } +#if 0 + printf("I am a node length: %d\n",length); + printf("I am a node code: %d\n",code); +#endif + assign_codes(htree->node.n1,codelength,code,length,0); + assign_codes(htree->node.n2,codelength,code,length,0); + } +} + +static void free_nodes(union htree_nodeleaf *htree, int top) +{ + if (htree->nodeleaf==htree_leaf) + { + if (!top) + free(htree); + } + else + { + free_nodes(htree->node.n1,0); + free_nodes(htree->node.n2,0); + if (!top) + free(htree); + } +} + +static void flush_8bits(unsigned int *combine, unsigned char **output, int *bitptr) +{ + while ((*bitptr)>=8) + { + unsigned int mask=~(0xFFU<<((*bitptr)-8)); + unsigned char out=(unsigned char)((*combine)>>((*bitptr)-8)); + **output=out; + (*output)++; + (*bitptr)-=8; + (*combine)&=mask; + } +} + +static void writebits(unsigned int value, int length, unsigned char **output, int *bitptr) +{ + unsigned int mask; + unsigned int combine=(unsigned int)**output; + if (length>=8) + mask=0xFFU<<(length-8); + else + mask=0xFFU>>(8-length); + while (length>8) + { + /* Make room for the bits. */ + combine<<=8; + (*bitptr)+=8; + combine|=(value&mask)>>(length-8); + flush_8bits(&combine,output,bitptr); + length-=8; + mask>>=8; + } + if (length) + { + /* Make room for the bits. */ + combine<<=length; + (*bitptr)+=length; + combine|=value; + flush_8bits(&combine,output,bitptr); + } + **output=(unsigned char)combine; +} + +static unsigned int readbits(int length, unsigned char **input, int *bitptr) +{ + unsigned int val=0U; + unsigned int extract_mask=0x80U>>*bitptr; + unsigned char thisval=**input; + while (length--) + { + val<<=1; + val|=((extract_mask & thisval)!=0); + *bitptr=(*bitptr)+1; + extract_mask>>=1; + if (!extract_mask) + { + extract_mask=0x80U; + *input=(*input)+1; + *bitptr=0; + thisval=**input; + } + } + return val; +} + +static int comp_codes(const void *codeptr1, const void *codeptr2, const void *private) +{ + const struct codelength *code1=(struct codelength *)codeptr1; + const struct codelength *code2=(struct codelength *)codeptr2; + int rval=0; /* It shouldn't be possible to get equal here, though. */ + (void)private; + if (code1->length>code2->length) + rval=1; + else if (code1->lengthlength) + rval=-1; + else if (code1->dict>code2->dict) + rval=1; + else + rval=-1; + return rval; +} + +static int comp_codes_value(const void *codeptr1, const void *codeptr2, const void *private) +{ + const struct codelength *code1=(struct codelength *)codeptr1; + const struct codelength *code2=(struct codelength *)codeptr2; + + int rval=0; /* It shouldn't be possible to get equal here, though. */ + (void)private; + if (code1->dict>code2->dict) + rval=1; + else + rval=-1; + return rval; +} + +/* The huffman_dict array should be 131077 (0x20005) long. The +huffman_dict_unpacked array should be 131077 long (note five longer than +0x20000) */ +void Ptngc_comp_conv_to_huffman(unsigned int *vals, const int nvals, + unsigned int *dict, const int ndict, + unsigned int *prob, + unsigned char *huffman, + int *huffman_len, + unsigned char *huffman_dict, + int *huffman_dictlen, + unsigned int *huffman_dict_unpacked, + int *huffman_dict_unpackedlen) +{ + int i; + int nleft; + union htree_nodeleaf *htree; + struct codelength *codelength; + int bitptr; + unsigned char *huffman_ptr; + int code; + int longcodes=1; + while (longcodes) + { + /* Create array of leafs (will be array of nodes/trees during + buildup of tree. */ + htree=warnmalloc(ndict*sizeof *htree); + codelength=warnmalloc(ndict*sizeof *codelength); + bitptr=0; + huffman_ptr=huffman; + for (i=0; i1) + { + union htree_nodeleaf *n1=warnmalloc(sizeof *n1); + union htree_nodeleaf *n2=warnmalloc(sizeof *n2); + int new_place; + int p1,p2, new_prob; + *n1=htree[nleft-1]; + *n2=htree[nleft-2]; + if (n1->nodeleaf==htree_leaf) + { + p1=n1->leaf.prob; + n1->leaf.bit=0; + } + else + { + p1=n1->node.prob; + n1->node.bit=0; + } + if (n2->nodeleaf==htree_leaf) + { + p2=n2->leaf.prob; + n2->leaf.bit=1; + } + else + { + p2=n2->node.prob; + n2->node.bit=1; + } + nleft--; + /* Create a new node */ + htree[nleft-1].nodeleaf=htree_node; + htree[nleft-1].node.n1=n1; + htree[nleft-1].node.n2=n2; + new_prob=p1+p2; + htree[nleft-1].node.prob=new_prob; + /* Use insertion sort to place this in the correct place in the + array. */ + /* Where should it be inserted? */ + new_place=nleft; + while (new_place>0) + { + int pc; + if (htree[new_place-1].nodeleaf==htree_node) + pc=htree[new_place-1].node.prob; + else + pc=htree[new_place-1].leaf.prob; + if (new_probMAX_HUFFMAN_LEN) + longcodes=1; + + /* If the codes are too long alter the probabilities. */ + if (longcodes) + { + for (i=0; i>=1; + if (prob[i]==0) + prob[i]=1; + } + + /* Free codelength. We will compute a new one. */ + free(codelength); + } + } + +#if 0 + { + for (i=0; i=0; j--) + { + int bit=c&mask; + if (bit) + printf("1"); + else + printf("0"); + mask>>=1; + } + printf("\n"); + } + } + } +#endif + + /* Simply do compression by writing out the bits. */ + for (i=0; i>8)&0xFFU); + *huffman_ptr++=(unsigned char)((codelength[ndict-1].dict>>16)&0xFFU); + huffman_dict_unpacked[0]=(unsigned char)(codelength[ndict-1].dict&0xFFU); + huffman_dict_unpacked[1]=(unsigned char)((codelength[ndict-1].dict>>8)&0xFFU); + huffman_dict_unpacked[2]=(unsigned char)((codelength[ndict-1].dict>>16)&0xFFU); + for (i=0; i<=(int)codelength[ndict-1].dict; i++) + { + /* Do I have this value? */ + int ihave=0; + int j; + for (j=0; j=0; j--) + { + int bit=c&mask; + if (bit) + printf("1"); + else + printf("0"); + mask>>=1; + } + printf("\n"); + } + } + } +#endif + /* Decompress data. */ + huffman_ptr=huffman; + bitptr=0; + for (i=0; i +#include +#include "compression/warnmalloc.h" +#include "compression/tng_compress.h" +#include "compression/bwlzh.h" +#include "compression/huffman.h" +#include "compression/dict.h" +#include "compression/rle.h" +#include "compression/vals16.h" + +int Ptngc_comp_huff_buflen(const int nvals) +{ + return 132000+nvals*8; +} + +/* the value pointed to by chosen_algo should be sent as -1 for autodetect. */ +void Ptngc_comp_huff_compress_verbose(unsigned int *vals, int nvals, + unsigned char *huffman, int *huffman_len, + int *huffdatalen, + int *huffman_lengths,int *chosen_algo, + const int isvals16) +{ + unsigned int *dict=warnmalloc(0x20005*sizeof *dict); + unsigned int *hist=warnmalloc(0x20005*sizeof *hist); + unsigned int *vals16=NULL; + unsigned char *huffdict=warnmalloc(0x20005*sizeof *huffdict); + unsigned int *huffdictunpack=warnmalloc(0x20005*sizeof *huffdictunpack); + unsigned char *huffman1=warnmalloc(2*0x20005*sizeof *huffman1); + unsigned char *huffdict1=warnmalloc(0x20005*sizeof *huffdict1); + unsigned int *huffdictunpack1=warnmalloc(0x20005*sizeof *huffdictunpack1); + unsigned int *huffdictrle=warnmalloc((3*0x20005+3)*sizeof *huffdictrle); + unsigned char *huffman2=warnmalloc(6*0x20005*sizeof *huffman2); + unsigned char *huffdict2=warnmalloc(0x20005*sizeof *huffdict2); + unsigned int *huffdictunpack2=warnmalloc(0x20005*sizeof *huffdictunpack2); + int i; + int ndict,ndict1,ndict2; + int nhuff,nhuffdict,nhuffdictunpack; + int nhuff1,nhuffdict1,nhuffdictunpack1; + int nhuffrle,nhuff2,nhuffdict2,nhuffdictunpack2; + int nvals16; + + /* Do I need to convert to vals16? */ + if (!isvals16) + { + vals16=warnmalloc(nvals*3*sizeof *vals16); + Ptngc_comp_conv_to_vals16(vals,nvals,vals16,&nvals16); + nvals=nvals16; + vals=vals16; + } + else + nvals16=nvals; + + /* Determine probabilities. */ + Ptngc_comp_make_dict_hist(vals,nvals,dict,&ndict,hist); + + /* First compress the data using huffman coding (place it ready for output at 14 (code for algorithm+length etc.). */ + Ptngc_comp_conv_to_huffman(vals,nvals,dict,ndict,hist, + huffman+14,&nhuff, + huffdict,&nhuffdict, + huffdictunpack,&nhuffdictunpack); + *huffdatalen=nhuff; + + /* Algorithm 0 stores the huffman dictionary directly (+ a code for + the algorithm) + lengths of the huffman buffer (4) and the huffman dictionary (3). */ + huffman_lengths[0]=nhuff+nhuffdict+1*2+3*4+3+3; + /* Next we try to compress the huffman dictionary using huffman + coding ... (algorithm 1) */ + + /* Determine probabilities. */ + Ptngc_comp_make_dict_hist(huffdictunpack,nhuffdictunpack,dict,&ndict1,hist); + /* Pack huffman dictionary */ + Ptngc_comp_conv_to_huffman(huffdictunpack,nhuffdictunpack, + dict,ndict1,hist, + huffman1,&nhuff1, + huffdict1,&nhuffdict1, + huffdictunpack1,&nhuffdictunpack1); + huffman_lengths[1]=nhuff+nhuff1+nhuffdict1+1*2+3*4+3+3+3+3+3; + + /* ... and rle + huffman coding ... (algorithm 2) Pack any repetetitive patterns. */ + Ptngc_comp_conv_to_rle(huffdictunpack,nhuffdictunpack, + huffdictrle,&nhuffrle,1); + + /* Determine probabilities. */ + Ptngc_comp_make_dict_hist(huffdictrle,nhuffrle,dict,&ndict2,hist); + /* Pack huffman dictionary */ + Ptngc_comp_conv_to_huffman(huffdictrle,nhuffrle, + dict,ndict2,hist, + huffman2,&nhuff2, + huffdict2,&nhuffdict2, + huffdictunpack2,&nhuffdictunpack2); + huffman_lengths[2]=nhuff+nhuff2+nhuffdict2+1*2+3*4+3+3+3+3+3+3; + + /* Choose the best algorithm and output the data. */ + if ((*chosen_algo==0) || ((*chosen_algo==-1) && + (((huffman_lengths[0]>8)&0xFFU; + huffman[4]=(((unsigned int)nvals16)>>16)&0xFFU; + huffman[5]=(((unsigned int)nvals16)>>24)&0xFFU; + huffman[6]=((unsigned int)nvals)&0xFFU; + huffman[7]=(((unsigned int)nvals)>>8)&0xFFU; + huffman[8]=(((unsigned int)nvals)>>16)&0xFFU; + huffman[9]=(((unsigned int)nvals)>>24)&0xFFU; + huffman[10]=((unsigned int)nhuff)&0xFFU; + huffman[11]=(((unsigned int)nhuff)>>8)&0xFFU; + huffman[12]=(((unsigned int)nhuff)>>16)&0xFFU; + huffman[13]=(((unsigned int)nhuff)>>24)&0xFFU; + huffman[14+nhuff]=((unsigned int)nhuffdict)&0xFFU; + huffman[15+nhuff]=(((unsigned int)nhuffdict)>>8)&0xFFU; + huffman[16+nhuff]=(((unsigned int)nhuffdict)>>16)&0xFFU; + huffman[17+nhuff]=((unsigned int)ndict)&0xFFU; + huffman[18+nhuff]=(((unsigned int)ndict)>>8)&0xFFU; + huffman[19+nhuff]=(((unsigned int)ndict)>>16)&0xFFU; + for (i=0; i>8)&0xFFU; + huffman[4]=(((unsigned int)nvals16)>>16)&0xFFU; + huffman[5]=(((unsigned int)nvals16)>>24)&0xFFU; + huffman[6]=((unsigned int)nvals)&0xFFU; + huffman[7]=(((unsigned int)nvals)>>8)&0xFFU; + huffman[8]=(((unsigned int)nvals)>>16)&0xFFU; + huffman[9]=(((unsigned int)nvals)>>24)&0xFFU; + huffman[10]=((unsigned int)nhuff)&0xFFU; + huffman[11]=(((unsigned int)nhuff)>>8)&0xFFU; + huffman[12]=(((unsigned int)nhuff)>>16)&0xFFU; + huffman[13]=(((unsigned int)nhuff)>>24)&0xFFU; + huffman[14+nhuff]=((unsigned int)nhuffdictunpack)&0xFFU; + huffman[15+nhuff]=(((unsigned int)nhuffdictunpack)>>8)&0xFFU; + huffman[16+nhuff]=(((unsigned int)nhuffdictunpack)>>16)&0xFFU; + huffman[17+nhuff]=((unsigned int)ndict)&0xFFU; + huffman[18+nhuff]=(((unsigned int)ndict)>>8)&0xFFU; + huffman[19+nhuff]=(((unsigned int)ndict)>>16)&0xFFU; + huffman[20+nhuff]=((unsigned int)nhuff1)&0xFFU; + huffman[21+nhuff]=(((unsigned int)nhuff1)>>8)&0xFFU; + huffman[22+nhuff]=(((unsigned int)nhuff1)>>16)&0xFFU; + huffman[23+nhuff]=((unsigned int)nhuffdict1)&0xFFU; + huffman[24+nhuff]=(((unsigned int)nhuffdict1)>>8)&0xFFU; + huffman[25+nhuff]=(((unsigned int)nhuffdict1)>>16)&0xFFU; + huffman[26+nhuff]=((unsigned int)ndict1)&0xFFU; + huffman[27+nhuff]=(((unsigned int)ndict1)>>8)&0xFFU; + huffman[28+nhuff]=(((unsigned int)ndict1)>>16)&0xFFU; + for (i=0; i>8)&0xFFU; + huffman[4]=(((unsigned int)nvals16)>>16)&0xFFU; + huffman[5]=(((unsigned int)nvals16)>>24)&0xFFU; + huffman[6]=((unsigned int)nvals)&0xFFU; + huffman[7]=(((unsigned int)nvals)>>8)&0xFFU; + huffman[8]=(((unsigned int)nvals)>>16)&0xFFU; + huffman[9]=(((unsigned int)nvals)>>24)&0xFFU; + huffman[10]=((unsigned int)nhuff)&0xFFU; + huffman[11]=(((unsigned int)nhuff)>>8)&0xFFU; + huffman[12]=(((unsigned int)nhuff)>>16)&0xFFU; + huffman[13]=(((unsigned int)nhuff)>>24)&0xFFU; + huffman[14+nhuff]=((unsigned int)nhuffdictunpack)&0xFFU; + huffman[15+nhuff]=(((unsigned int)nhuffdictunpack)>>8)&0xFFU; + huffman[16+nhuff]=(((unsigned int)nhuffdictunpack)>>16)&0xFFU; + huffman[17+nhuff]=((unsigned int)ndict)&0xFFU; + huffman[18+nhuff]=(((unsigned int)ndict)>>8)&0xFFU; + huffman[19+nhuff]=(((unsigned int)ndict)>>16)&0xFFU; + huffman[20+nhuff]=((unsigned int)nhuffrle)&0xFFU; + huffman[21+nhuff]=(((unsigned int)nhuffrle)>>8)&0xFFU; + huffman[22+nhuff]=(((unsigned int)nhuffrle)>>16)&0xFFU; + huffman[23+nhuff]=((unsigned int)nhuff2)&0xFFU; + huffman[24+nhuff]=(((unsigned int)nhuff2)>>8)&0xFFU; + huffman[25+nhuff]=(((unsigned int)nhuff2)>>16)&0xFFU; + huffman[26+nhuff]=((unsigned int)nhuffdict2)&0xFFU; + huffman[27+nhuff]=(((unsigned int)nhuffdict2)>>8)&0xFFU; + huffman[28+nhuff]=(((unsigned int)nhuffdict2)>>16)&0xFFU; + huffman[29+nhuff]=((unsigned int)ndict2)&0xFFU; + huffman[30+nhuff]=(((unsigned int)ndict2)>>8)&0xFFU; + huffman[31+nhuff]=(((unsigned int)ndict2)>>16)&0xFFU; + for (i=0; i=N_HUFFMAN_ALGO) + return NULL; + return huff_algo_names[algo]; +} diff --git a/src/tng/lz77.c b/src/tng/lz77.c new file mode 100644 index 0000000000..5608735e71 --- /dev/null +++ b/src/tng/lz77.c @@ -0,0 +1,348 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#include +#include +#include +#include "compression/warnmalloc.h" +#include "compression/bwt.h" +#include "compression/lz77.h" + +/* This is a simple Lempel-Ziv-77 compressor. It has not been set up + to remove every possible repeating pattern, but it might be better + than simple RLE. + + Lempel-Ziv 77 with separate outputs for length, data, and offsets. + */ + +#if 0 +/* Sort the strings (similar to BWT) to find similar patterns in the + input data. The output is an array with two values for each + input value. The sorted index value is the first in each doublet. + The second value is the "inverse" of the first value and can be + used to find the locations of similar strings. */ +static void sort_strings(unsigned int *vals, int nvals, + unsigned int *output) +{ + int i; + int *indices=warnmalloc(2*nvals*sizeof *indices); + unsigned int *nrepeat=warnmalloc(nvals*sizeof *nrepeat); + int *warr=indices+nvals; + + if (nvals>0xFFFFFF) + { + fprintf(stderr,"BWT cannot pack more than %d values.\n",0xFFFFFF); + exit(1); + } + + /* Also note that repeat pattern k (kmax) cannot be larger than 255. */ + for (i=0; i=1; k--) + { + try_next_k: + if (k>=1) + { + for (j=k; jmaxrepeat) + new_j=j; + if ((new_j>good_j) || ((new_j==good_j) && (knvals) + repeat=nvals; + nrepeat[i+m]=((unsigned int) (good_k)) | (((unsigned int) (repeat))<<8); + } + /* If no repetition was found for this value signal that here. */ + if (!nrepeat[i]) + nrepeat[i+m]=257U; /* This is 1<<8 | 1 */ + } + } + + /* Sort cyclic shift matrix. */ + Ptngc_bwt_merge_sort_inner(indices,nvals,vals,0,nvals,nrepeat,warr); + + /* Form output. */ + for (i=0; iNUM_PREVIOUS) + previous[(NUM_PREVIOUS+3)*v]=NUM_PREVIOUS; + previous[(NUM_PREVIOUS+3)*v+3+previous[(NUM_PREVIOUS+3)*v+1]]=i; + previous[(NUM_PREVIOUS+3)*v+1]++; + if (previous[(NUM_PREVIOUS+3)*v+1]>=NUM_PREVIOUS) + previous[(NUM_PREVIOUS+3)*v+1]=0; + } + previous[(NUM_PREVIOUS+3)*v+2]=i; +} + +void Ptngc_comp_to_lz77(unsigned int *vals, const int nvals, + unsigned int *data, int *ndata, + unsigned int *len, int *nlens, + unsigned int *offsets, int *noffsets) +{ + int noff=0; + int ndat=0; + int nlen=0; + int i,j; + int *previous=warnmalloc(0x20000*(NUM_PREVIOUS+3)*sizeof *previous); +#if 0 + unsigned int *info=warnmalloc(2*nvals*sizeof *info); + sort_strings(vals,nvals,info); +#endif + for (i=0; i<0x20000; i++) + { + previous[(NUM_PREVIOUS+3)*i]=0; /* Number of items in a circular buffer */ + previous[(NUM_PREVIOUS+3)*i+1]=0; /* Pointer to beginning of circular buffer. */ + previous[(NUM_PREVIOUS+3)*i+2]=-2; /* Last offset that had this value. -2 is really never... */ + } + for (i=0; i=firstoffset) + { + for (k=0; i+klargest_len) && ((k>=(i-j)+16) || ((k>4) && (i-j==1)))) + { + largest_len=k; + largest_offset=j; + } + } + j++; + } + } +#if 0 + /* Search in sorted string buffer too. */ + kmin=info[i*2+1]-MAX_STRING_SEARCH; + kmax=info[i*2+1]+MAX_STRING_SEARCH; + if (kmin<0) + kmin=0; + if (kmax>=nvals) + kmax=nvals; + for (k=kmin; k=i)) + { + for (m=0; i+mlargest_len) && (m>4) && (m+2>=(i-s))) + { + largest_len=m; + largest_offset=s; +#if 0 + fprintf(stderr,"Offset: %d %d\n",m,i-s); +#endif + } + } + } +#endif + /* Check how to write this info. */ + if (largest_len>MAX_LEN) + largest_len=MAX_LEN; + if (largest_len) + { + if (i-largest_offset==1) + { + data[ndat++]=0; + } + else + { + data[ndat++]=1; + offsets[noff++]=i-largest_offset; + } + len[nlen++]=largest_len; +#if 0 + fprintf(stderr,"l:o: %d:%d data=%d i=%d\n",largest_len,i-largest_offset,ndat,i); + fflush(stderr); +#endif + +#if 0 + fprintf(stderr,"Found largest len %d at %d.\n",largest_len,i-largest_offset); +#endif + /* Add these values to the circular buffer. */ + for (k=0; k=nvals) + { + fprintf(stderr,"too many vals.\n"); + exit(EXIT_FAILURE); + } + i++; + } + } + else + vals[i++]=v-2; + } +} diff --git a/src/tng/merge_sort.c b/src/tng/merge_sort.c new file mode 100644 index 0000000000..38d9206dd2 --- /dev/null +++ b/src/tng/merge_sort.c @@ -0,0 +1,128 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg + * Copyright (c) 2010, 2013, The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + + +#include +#include +#include +#include "compression/warnmalloc.h" +#include "compression/merge_sort.h" + +static void ms_inner(void *base, const size_t size, + const size_t start, const size_t end, + int (*compar)(const void *v1,const void *v2,const void *private), + const void *private, + char *workarray) +{ + size_t middle; + if ((end-start)>1) + { + char *cbase=(char *)base; + middle=start+(end-start)/2; +#if 0 + printf("For start %d end %d obtained new middle: %d\n",start,end,middle); +#endif + ms_inner(base,size, + start,middle, + compar,private,workarray); + ms_inner(base,size, + middle,end, + compar,private,workarray); +#if 0 + printf("For start %d end %d Before merge: Comparing element %d with %d\n",start,end,middle-1,middle); +#endif + if (compar(cbase+(middle-1)*size,cbase+middle*size,private)>0) + { + /* Merge to work array. */ + size_t i, n=end-start; + size_t ileft=start; + size_t iright=middle; + for (i=0; i0) + { + memcpy(workarray+i*size,cbase+iright*size,size); + iright++; + } + else + { + memcpy(workarray+i*size,cbase+ileft*size,size); + ileft++; + } + } + } + /* Copy result back. */ + memcpy(cbase+start*size,workarray,(end-start)*size); + } + } +} + + +void Ptngc_merge_sort(void *base, const size_t nmemb, const size_t size, + int (*compar)(const void *v1,const void *v2,const void *private), + void *private) +{ + char *warr=warnmalloc(nmemb*size); + ms_inner(base,size,0,nmemb,compar,private,warr); + free(warr); +} + + +#ifdef TEST + +static int compint(const void *v1, const void *v2,const void *private) +{ + const int *i1=(const int *)v1; + const int *i2=(const int *)v2; + if (*i1<*i2) + return -1; + else if (*i1>*i2) + return 1; + else + return 0; +} + +static int qcompint(const void *v1, const void *v2) +{ + return compint(v1,v2,NULL); +} + +#define N 1000000 +int main() +{ + int *arr=warnmalloc(N*sizeof *arr); + int i; + for (i=0; i +#include +#include "compression/warnmalloc.h" +#include "compression/mtf.h" + +/* "Partial" MTF. Byte based. */ +/* Move to front coding. + Acceptable inputs are max 8 bits (0-0xFF) */ +static void comp_conv_to_mtf_byte(unsigned char *vals, const int nvals, + unsigned char *valsmtf) +{ + int i; + /* Indices into a linked list */ + int list[256]; + int dict[256]; + /* Head of the linked list */ + int head; + for (i=0; i<256; i++) + dict[i]=i; + for (i=0; i<255; i++) + list[i]=i+1; + list[255]=-1; /* end. */ + head=0; + for (i=0; i>(8*j))&0xFF); + comp_conv_to_mtf_byte(tmp,nvals,tmp+nvals); + for (i=0; i>(8*j))&0xFF); + comp_conv_to_mtf_byte(tmp,nvals,valsmtf+j*nvals); + } + free(tmp); +} + +/* Move to front decoding */ +static void comp_conv_from_mtf_byte(unsigned char *valsmtf, const int nvals, + unsigned char *vals) +{ + int i; + /* Indices into a linked list */ + int list[256]; + int dict[256]; + /* Head of the linked list */ + int head; + for (i=0; i<256; i++) + dict[i]=i; + for (i=0; i<255; i++) + list[i]=i+1; + list[255]=-1; /* end. */ + head=0; + for (i=0; i>(8*j))&0xFF); + comp_conv_from_mtf_byte(tmp,nvals,tmp+nvals); + for (i=0; imin_rle) + { + /* Insert run-length */ + unsigned int run=((unsigned int)nsim); + while (run>1) + { + if (run&0x1U) + rle[(*j)++]=1; + else + rle[(*j)++]=0; + run>>=1; + } + nsim=1; + } + while (nsim--) + rle[(*j)++]=v+2; +} + +/* Run length encoding. + Acceptable inputs are about 16 bits (0-0xFFFF) + If input is 0-N output will be be values of 0-(N+2) */ +void Ptngc_comp_conv_to_rle(unsigned int *vals, const int nvals, + unsigned int *rle, int *nrle, + const int min_rle) +{ + int i; + int j=0; + int nsim=0; + int v=-1; + for (i=0; i>15; + vals16[j++]=lo; + if (hi<=0x7FFFU) + vals16[j++]=hi; + else + { + unsigned int lohi=(hi&0x7FFFU)|0x8000U; + unsigned int hihi=hi>>15; + vals16[j++]=lohi; + vals16[j++]=hihi; + } + } + } +#if 0 + /* Test that things that detect that this is bad really works. */ + vals16[0]=0; +#endif + *nvals16=j; +} + +void Ptngc_comp_conv_from_vals16(unsigned int *vals16, const int nvals16, + unsigned int *vals, int *nvals) +{ + int i=0; + int j=0; + while (i +#include +#include + +#include "compression/tng_compress.h" + +/* 64 bit integers are not required in this part of the program. But + they improve the running speed if present. If 64 bit integers are + available define the symbol HAVE64BIT. It should get automatically + defined by the defines in my64bit.h */ +#include "compression/my64bit.h" + +#include "compression/widemuldiv.h" + +#ifndef TRAJNG_X86_GCC_INLINE_MULDIV +#if defined(__GNUC__) && defined(__i386__) +#define TRAJNG_X86_GCC_INLINE_MULDIV +#endif /* gcc & i386 */ +#if defined(__GNUC__) && defined(__x86_64__) +#define TRAJNG_X86_GCC_INLINE_MULDIV +#endif /* gcc & x86_64 */ +#endif /* TRAJNG X86 GCC INLINE MULDIV */ + +#ifdef USE_WINDOWS +#define TNG_INLINE __inline +#else +#define TNG_INLINE inline +#endif + +/* Multiply two 32 bit unsigned integers returning a 64 bit unsigned value (in two integers) */ +static TNG_INLINE void Ptngc_widemul(unsigned int i1, unsigned int i2, unsigned int *ohi, unsigned int *olo) +{ +#if defined(TRAJNG_X86_GCC_INLINE_MULDIV) + __asm__ __volatile__ ("mull %%edx\n\t" + : "=a" (i1), "=d" (i2) + : "a" (i1),"d" (i2) + : "cc"); + *ohi=i2; + *olo=i1; +#else /* TRAJNG X86 GCC INLINE MULDIV */ + +#ifdef HAVE64BIT + my_uint64_t res= ((my_uint64_t)i1) * ((my_uint64_t)i2); + *olo=res & 0xFFFFFFFFU; + *ohi=(res>>32) & 0xFFFFFFFFU; +#else /* HAVE64BIT */ + + unsigned int bits=16; + unsigned int L_m=(1<>bits; + b_L=i2 & L_m; + b_U=i2>>bits; + + /* Do a*a=>2a multiply where a is half number of bits in an int */ + x=a_L*b_L; + x_LL=x & L_m; + x_LU=x>>bits; + + x=a_U*b_L; + x_LU+=x & L_m; + x_UL=x>>bits; + + x=a_L*b_U; + x_LU+=x & L_m; + x_UL+=x>>bits; + + x=a_U*b_U; + x_UL+=x & L_m; + x_UU=x>>bits; + + /* Combine results */ + x_UL+=x_LU>>bits; + x_LU&=L_m; + x_UU+=x_UL>>bits; + x_UL&=L_m; + + x_U=(x_UU<>(bits2-hibit); + s_L=(i<lo) + { + unsigned int t; + hi--; /* Borrow */ + t=allbits-s_L; + lo+=t+1; + } + else + lo-=s_L; + + /* Set bit. */ + res|=rmask; + } + rmask>>=1; + s_L>>=1; + if (s_U & 1U) + s_L|=hibit_mask; + s_U>>=1; + } + *remainder=lo; + *result=res; +#endif /* HAVE64BIT */ +#endif /* TRAJNG X86 GCC INLINE MULDIV */ +} + +/* Add a unsigned int to a largeint. j determines which value in the + largeint to add v1 to. */ +static TNG_INLINE void largeint_add_gen(const unsigned int v1, unsigned int *largeint, const int n, int j) +{ + /* Add with carry. unsigned ints in C wrap modulo 2**bits when "overflowed". */ + unsigned int v2=(v1+largeint[j])&0xFFFFFFFFU; /* Add and cap at 32 bits */ + unsigned int carry=0; + if ((((unsigned int)-1)&0xFFFFFFFFU) -v164 mul */ + largeint_add_gen(lo,largeint_out,n,i); + largeint_add_gen(hi,largeint_out,n,i+1); + } + } + if (largeint_in[i]!=0U) + { + Ptngc_widemul(v1,largeint_in[i],&hi,&lo); /* 32x32->64 mul */ + largeint_add_gen(lo,largeint_out,n,i); + } +} + +/* Return the remainder from dividing largeint_in with v1. Result of the division is returned in largeint_out */ +unsigned int Ptngc_largeint_div(const unsigned int v1, unsigned int *largeint_in, unsigned int *largeint_out, const int n) +{ + unsigned int result,remainder=0; + int i; + unsigned int hi; + /* Boot */ + hi=0U; + i=n; + while (i) + { + i--; + Ptngc_widediv(hi,largeint_in[i],v1,&result,&remainder); + largeint_out[i]=result; + hi=remainder; + } + return remainder; +} diff --git a/src/tng/xtc2.c b/src/tng/xtc2.c new file mode 100644 index 0000000000..7fca2172b2 --- /dev/null +++ b/src/tng/xtc2.c @@ -0,0 +1,1523 @@ +/* This code is part of the tng compression routines. + * + * Written by Daniel Spangberg and Magnus Lundborg + * Copyright (c) 2010, 2013-2014 The GROMACS development team. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Revised BSD License. + */ + +/* This code is heavily influenced by + http://hpcv100.rc.rug.nl/xdrf.html + Based on coordinate compression (c) by Frans van Hoesel. + and GROMACS xtc files (http://www.gromacs.org) + (c) Copyright (c) Erik Lindahl, David van der Spoel +*/ + +#include +#include +#include +#include +#include "compression/coder.h" +#include "compression/widemuldiv.h" +#include "compression/warnmalloc.h" + +/* Generated by gen_magic.py */ +#define MAX_MAGIC 92 + +#ifdef USE_WINDOWS +#define TNG_INLINE __inline +#else +#define TNG_INLINE inline +#endif + +static unsigned int magic[MAX_MAGIC]={ +2U, 3U, 4U, 5U, +6U, 8U, 10U, 12U, +16U, 20U, 25U, 32U, +40U, 50U, 64U, 80U, +101U, 128U, 161U, 203U, +256U, 322U, 406U, 512U, +645U, 812U, 1024U, 1290U, +1625U, 2048U, 2580U, 3250U, +4096U, 5160U, 6501U, 8192U, +10321U, 13003U, 16384U, 20642U, +26007U, 32768U, 41285U, 52015U, +65536U, 82570U, 104031U, 131072U, +165140U, 208063U, 262144U, 330280U, +416127U, 524288U, 660561U, 832255U, +1048576U, 1321122U, 1664510U, 2097152U, +2642245U, 3329021U, 4194304U, 5284491U, +6658042U, 8388608U, 10568983U, 13316085U, +16777216U, 21137967U, 26632170U, 33554432U, +42275935U, 53264340U, 67108864U, 84551870U, +106528681U, 134217728U, 169103740U, 213057362U, +268435456U, 338207481U, 426114725U, 536870912U, +676414963U, 852229450U, 1073741824U, 1352829926U, +1704458900U, 2147483648U, 2705659852U, 3408917801U, +}; + +static unsigned int magic_bits[MAX_MAGIC][8]={ +{ 3, 6, 9, 12, 15, 18, 21, 24, }, +{ 5, 10, 15, 20, 24, 29, 34, 39, }, +{ 6, 12, 18, 24, 30, 36, 42, 48, }, +{ 7, 14, 21, 28, 35, 42, 49, 56, }, +{ 8, 16, 24, 32, 39, 47, 55, 63, }, +{ 9, 18, 27, 36, 45, 54, 63, 72, }, +{ 10, 20, 30, 40, 50, 60, 70, 80, }, +{ 11, 22, 33, 44, 54, 65, 76, 87, }, +{ 12, 24, 36, 48, 60, 72, 84, 97, }, +{ 13, 26, 39, 52, 65, 78, 91, 104, }, +{ 14, 28, 42, 56, 70, 84, 98, 112, }, +{ 15, 30, 45, 60, 75, 90, 105, 120, }, +{ 16, 32, 48, 64, 80, 96, 112, 128, }, +{ 17, 34, 51, 68, 85, 102, 119, 136, }, +{ 18, 36, 54, 72, 90, 108, 127, 144, }, +{ 19, 38, 57, 76, 95, 114, 133, 152, }, +{ 20, 40, 60, 80, 100, 120, 140, 160, }, +{ 21, 42, 63, 84, 105, 127, 147, 168, }, +{ 22, 44, 66, 88, 110, 132, 154, 176, }, +{ 23, 46, 69, 92, 115, 138, 161, 184, }, +{ 24, 48, 72, 97, 120, 144, 168, 192, }, +{ 25, 50, 75, 100, 125, 150, 175, 200, }, +{ 26, 52, 78, 104, 130, 156, 182, 208, }, +{ 27, 54, 81, 108, 135, 162, 190, 216, }, +{ 28, 56, 84, 112, 140, 168, 196, 224, }, +{ 29, 58, 87, 116, 145, 174, 203, 232, }, +{ 30, 60, 90, 120, 150, 180, 210, 240, }, +{ 31, 62, 93, 124, 155, 186, 217, 248, }, +{ 32, 64, 96, 128, 160, 192, 224, 256, }, +{ 33, 66, 99, 132, 165, 198, 231, 264, }, +{ 34, 68, 102, 136, 170, 204, 238, 272, }, +{ 35, 70, 105, 140, 175, 210, 245, 280, }, +{ 36, 72, 108, 144, 180, 216, 252, 288, }, +{ 37, 74, 111, 148, 185, 222, 259, 296, }, +{ 38, 76, 114, 152, 190, 228, 266, 304, }, +{ 39, 78, 117, 157, 195, 234, 273, 312, }, +{ 40, 80, 120, 160, 200, 240, 280, 320, }, +{ 41, 82, 123, 164, 205, 246, 287, 328, }, +{ 42, 84, 127, 168, 210, 252, 294, 336, }, +{ 43, 86, 129, 172, 215, 258, 301, 344, }, +{ 44, 88, 132, 176, 220, 264, 308, 352, }, +{ 45, 90, 135, 180, 225, 270, 315, 360, }, +{ 46, 92, 138, 184, 230, 276, 322, 368, }, +{ 47, 94, 141, 188, 235, 282, 329, 376, }, +{ 48, 97, 144, 192, 240, 288, 336, 384, }, +{ 49, 98, 147, 196, 245, 294, 343, 392, }, +{ 50, 100, 150, 200, 250, 300, 350, 400, }, +{ 52, 102, 153, 204, 255, 306, 357, 408, }, +{ 52, 104, 156, 208, 260, 312, 364, 416, }, +{ 53, 106, 159, 212, 265, 318, 371, 424, }, +{ 54, 108, 162, 216, 270, 324, 378, 432, }, +{ 55, 110, 165, 220, 275, 330, 385, 440, }, +{ 56, 112, 168, 224, 280, 336, 392, 448, }, +{ 57, 114, 172, 228, 285, 342, 399, 456, }, +{ 58, 116, 174, 232, 290, 348, 406, 464, }, +{ 59, 118, 177, 236, 295, 354, 413, 472, }, +{ 60, 120, 180, 240, 300, 360, 420, 480, }, +{ 61, 122, 183, 244, 305, 366, 427, 488, }, +{ 62, 124, 186, 248, 310, 372, 434, 496, }, +{ 63, 127, 190, 252, 315, 378, 442, 505, }, +{ 64, 128, 192, 256, 320, 384, 448, 512, }, +{ 65, 130, 195, 260, 325, 390, 455, 520, }, +{ 66, 132, 198, 264, 330, 396, 462, 528, }, +{ 67, 134, 201, 268, 335, 402, 469, 536, }, +{ 68, 136, 204, 272, 340, 408, 476, 544, }, +{ 69, 138, 207, 276, 345, 414, 483, 552, }, +{ 70, 140, 210, 280, 350, 420, 490, 560, }, +{ 71, 142, 213, 284, 355, 426, 497, 568, }, +{ 72, 144, 216, 288, 360, 432, 505, 576, }, +{ 73, 146, 219, 292, 365, 438, 511, 584, }, +{ 74, 148, 222, 296, 370, 444, 518, 592, }, +{ 75, 150, 225, 300, 375, 451, 525, 600, }, +{ 76, 152, 228, 304, 380, 456, 532, 608, }, +{ 77, 154, 231, 308, 385, 462, 539, 616, }, +{ 78, 157, 234, 312, 390, 469, 546, 625, }, +{ 79, 158, 237, 316, 395, 474, 553, 632, }, +{ 80, 160, 240, 320, 400, 480, 560, 640, }, +{ 81, 162, 243, 324, 406, 486, 568, 648, }, +{ 82, 164, 246, 328, 410, 492, 574, 656, }, +{ 83, 166, 249, 332, 415, 498, 581, 664, }, +{ 84, 168, 252, 336, 420, 505, 588, 672, }, +{ 85, 170, 255, 340, 425, 510, 595, 680, }, +{ 86, 172, 258, 344, 430, 516, 602, 688, }, +{ 87, 174, 261, 348, 435, 522, 609, 696, }, +{ 88, 176, 264, 352, 440, 528, 616, 704, }, +{ 89, 178, 267, 356, 445, 534, 623, 712, }, +{ 90, 180, 270, 360, 451, 540, 631, 720, }, +{ 91, 182, 273, 364, 455, 546, 637, 728, }, +{ 92, 184, 276, 368, 460, 552, 644, 736, }, +{ 94, 187, 279, 373, 466, 558, 651, 745, }, +{ 94, 188, 282, 376, 470, 564, 658, 752, }, +{ 95, 190, 285, 380, 475, 570, 665, 760, }, +}; + + +static const double iflipgaincheck=0.89089871814033927; /* 1./(2**(1./6)) */ + + +/* Difference in indices used for determining whether to store as large or small */ +#define QUITE_LARGE 3 +#define IS_LARGE 6 + +#if 0 +#define SHOWIT +#endif + +#ifdef USE_WINDOWS +#define TNG_INLINE __inline +#else +#define TNG_INLINE inline +#endif + +int Ptngc_magic(const unsigned int i) +{ + return magic[i]; +} + +int Ptngc_find_magic_index(const unsigned int maxval) +{ + int i; + + if(maxval > magic[MAX_MAGIC/4]) + { + if(maxval > magic[MAX_MAGIC/2]) + { + i = MAX_MAGIC/2 + 1; + } + else + { + i = MAX_MAGIC/4 + 1; + } + } + else + { + i = 0; + } + + while (magic[i]<=maxval) + i++; + return i; +} + +static TNG_INLINE unsigned int positive_int(const int item) +{ + int s=0; + if (item>0) + s=1+(item-1)*2; + else if (item<0) + s=2+(-item-1)*2; + return s; +} + +static TNG_INLINE int unpositive_int(const int val) +{ + int s=(val+1)/2; + if ((val%2)==0) + s=-s; + return s; +} + + +/* Sequence instructions */ +#define INSTR_DEFAULT 0 +#define INSTR_BASE_RUNLENGTH 1 +#define INSTR_ONLY_LARGE 2 +#define INSTR_ONLY_SMALL 3 +#define INSTR_LARGE_BASE_CHANGE 4 +#define INSTR_FLIP 5 +#define INSTR_LARGE_RLE 6 + +#define MAXINSTR 7 + +#ifdef SHOWIT +static char *instrnames[MAXINSTR]={ + "large+small", + "base+run", + "large", + "small", + "large base change", + "flip", + "large rle", +}; +#endif + +/* Bit patterns in the compressed code stream: */ + +static const int seq_instr[MAXINSTR][2]= + { + { 1,1 }, /* 1 : one large atom + runlength encoded small integers. Use same settings as before. */ + { 0,2 }, /* 00 : set base and runlength in next four bits (x). base (increase/keep/decrease)=x%3-1. runlength=1+x/3. + The special value 1111 in the four bits means runlength=6 and base change=0 */ + { 4,4 }, /* 0100 : next only a large atom comes. */ + { 5,4 }, /* 0101 : next only runlength encoded small integers. Use same settings as before. */ + { 6,4 }, /* 0110 : Large change in base. Change is encoded in the + following 2 bits. change direction (sign) is the first + bit. The next bit +1 is the actual change. This + allows the change of up to +/- 2 indices. */ + { 14,5 }, /* 01110 : flip whether integers should be modified to compress water better */ + { 15,5 }, /* 01111 : Large rle. The next 4 bits encode how many + large atoms are in the following sequence: 3-18. (2 is + more efficiently coded with two large instructions. */ + }; + +static void write_instruction(struct coder *coder, const int instr, unsigned char **output_ptr) +{ + Ptngc_writebits(coder,seq_instr[instr][0],seq_instr[instr][1],output_ptr); +#ifdef SHOWIT + fprintf(stderr,"INSTR: %s (%d bits)\n",instrnames[instr],seq_instr[instr][1]); +#endif +} + +static unsigned int readbits(unsigned char **ptr, int *bitptr, int nbits) +{ + unsigned int val=0U; + unsigned int extract_mask=0x80U>>*bitptr; + unsigned char thisval=**ptr; +#ifdef SHOWIT + fprintf(stderr,"Read nbits=%d val=",nbits); +#endif + while (nbits--) + { + val<<=1; + val|=((extract_mask & thisval)!=0); + *bitptr=(*bitptr)+1; + extract_mask>>=1; + if (!extract_mask) + { + extract_mask=0x80U; + *ptr=(*ptr)+1; + *bitptr=0; + if (nbits) + thisval=**ptr; + } + } +#ifdef SHOWIT + fprintf(stderr,"%x\n",val); +#endif + return val; +} + +static void readmanybits(unsigned char **ptr, int *bitptr, int nbits, unsigned char *buffer) +{ + while (nbits>=8) + { + *buffer++=readbits(ptr,bitptr,8); + nbits-=8; +#ifdef SHOWIT + fprintf(stderr,"Read value %02x\n",buffer[-1]); +#endif + } + if (nbits) + { + *buffer++=readbits(ptr,bitptr,nbits); +#ifdef SHOWIT + fprintf(stderr,"Read value %02x\n",buffer[-1]); +#endif + } +} + +static int read_instruction(unsigned char **ptr, int *bitptr) +{ + int instr=-1; + unsigned int bits=readbits(ptr,bitptr,1); + if (bits) + instr=INSTR_DEFAULT; + else + { + bits=readbits(ptr,bitptr,1); + if (!bits) + instr=INSTR_BASE_RUNLENGTH; + else + { + bits=readbits(ptr,bitptr,2); + if (bits==0) + instr=INSTR_ONLY_LARGE; + else if (bits==1) + instr=INSTR_ONLY_SMALL; + else if (bits==2) + instr=INSTR_LARGE_BASE_CHANGE; + else if (bits==3) + { + bits=readbits(ptr,bitptr,1); + if (bits==0) + instr=INSTR_FLIP; + else + instr=INSTR_LARGE_RLE; + } + } + } + return instr; +} + +/* Modifies three integer values for better compression of water */ +static void swap_ints(int *in, int *out) +{ + out[0]=in[0]+in[1]; + out[1]=-in[1]; + out[2]=in[1]+in[2]; +} + +static void swap_is_better(int *input, int *minint, int *sum_normal, int *sum_swapped) +{ + int normal_max=0; + int swapped_max=0; + int i,j; + int normal[3]; + int swapped[3]; + for (i=0; i<3; i++) + { + normal[0]=input[i]-minint[i]; + normal[1]=input[3+i]-input[i]; /* minint[i]-minint[i] cancels out */ + normal[2]=input[6+i]-input[3+i]; /* minint[i]-minint[i] cancels out */ + swap_ints(normal,swapped); + for (j=1; j<3; j++) + { + if (positive_int(normal[j])>(unsigned int)normal_max) + normal_max=positive_int(normal[j]); + if (positive_int(swapped[j])>(unsigned int)swapped_max) + swapped_max=positive_int(swapped[j]); + } + } + if (normal_max==0) + normal_max=1; + if (swapped_max==0) + swapped_max=1; + *sum_normal=normal_max; + *sum_swapped=swapped_max; +} + +static void swapdecide(struct coder *coder, int *input, int *swapatoms, int *large_index, int *minint, unsigned char **output_ptr) +{ + int didswap=0; + int normal,swapped; + (void)large_index; + swap_is_better(input,minint,&normal,&swapped); + /* We have to determine if it is worth to change the behaviour. + If diff is positive it means that it is worth something to + swap. But it costs 4 bits to do the change. If we assume that + we gain 0.17 bit by the swap per value, and the runlength>2 + for four molecules in a row, we gain something. So check if we + gain at least 0.17 bits to even attempt the swap. + */ +#ifdef SHOWIT + fprintf(stderr,"Trying Flip: %g %g\n",(double)swapped/normal, (double)normal/swapped); +#endif + if (((swapped 0) + { + Ptngc_largeint_add(input[0],largeint,19); + } + + for (i=1; i>shift) & 0xFFU; + shift+=8; + } + } +} + +/* The opposite of base_compress. */ +static void trajcoder_base_decompress(unsigned char *input, const int n, int *index, int *output) +{ + unsigned int largeint[19]; + unsigned int largeint_tmp[19]; + int i,j; + /* Convert the sequence of bytes to a largeint. */ + for (i=0; i<18; i++) + { + int shift=0; + largeint[i]=0U; + for (j=0; j<4; j++) + { + largeint[i]|=((unsigned int)input[i*4+j])<=0; i--) + { + unsigned int remainder=Ptngc_largeint_div(magic[index[i%3]],largeint,largeint_tmp,19); +#if 0 +#ifdef SHOWIT + fprintf(stderr,"Remainder: %u\n",remainder); +#endif +#endif +#if 0 + for (j=0; j<19; j++) + largeint[j]=largeint_tmp[j]; +#endif + memcpy(largeint,largeint_tmp,19*sizeof *largeint); + output[i]=remainder; + } +} + +/* It is "large" if we have to increase the small index quite a + bit. Not so much to be rejected by the not very large check + later. */ +static int is_quite_large(int *input, const int small_index, const int max_large_index) +{ + int is=0; + int i; + if (small_index+QUITE_LARGE>=max_large_index) + is=1; + else + { + for (i=0; i<3; i++) + if (positive_int(input[i])>magic[small_index+QUITE_LARGE]) + { + is=1; + break; + } + } + return is; +} + +#ifdef SHOWIT +int nbits_sum; +int nvalues_sum; +#endif + +static void write_three_large(struct coder *coder, int *encode_ints, int *large_index, const int nbits, unsigned char *compress_buffer, unsigned char **output_ptr) +{ + trajcoder_base_compress(encode_ints,3,large_index,compress_buffer); + Ptngc_writemanybits(coder,compress_buffer,nbits,output_ptr); +#ifdef SHOWIT + fprintf(stderr,"nbits=%d (%g)\n",nbits,nbits/3.); + nbits_sum+=nbits; + nvalues_sum+=3; + fprintf(stderr,"Large: %d %d %d\n",encode_ints[0],encode_ints[1],encode_ints[2]); +#endif +} + +static void insert_batch(int *input_ptr, int ntriplets_left, const int *prevcoord,int *minint, int *encode_ints, const int startenc, int *nenc) +{ + int nencode=startenc*3; + int tmp_prevcoord[3]; + + tmp_prevcoord[0]=prevcoord[0]; + tmp_prevcoord[1]=prevcoord[1]; + tmp_prevcoord[2]=prevcoord[2]; + + if (startenc) + { + int i; + for (i=0; imaxint[j]) + maxint[j]=input[i*3+j]; + if (input[i*3+j]max_large_index) + max_large_index=large_index[1]; + if (large_index[2]>max_large_index) + max_large_index=large_index[2]; + +#ifdef SHOWIT + for (j=0; j<3; j++) + fprintf(stderr,"minint[%d]=%d. maxint[%d]=%d large_index[%d]=%d value=%d\n",j,minint[j],j,maxint[j], + j,large_index[j],magic[large_index[j]]); + fprintf(stderr,"large_nbits=%d\n",large_nbits); +#endif + + + /* Guess initial small index */ + small_index=max_large_index/2; + + /* Find the largest value that is not large. Not large is half index of + large. */ + max_small=magic[small_index]; + intmax=0; + for (i=0; i<*length; i++) + { + int item=input[i]; + int s=positive_int(item); + if (s>intmax) + if (spack_temporary_bits=32; + coder->pack_temporary=positive_int(minint[0]); + Ptngc_out8bits(coder,&output_ptr); + coder->pack_temporary_bits=32; + coder->pack_temporary=positive_int(minint[1]); + Ptngc_out8bits(coder,&output_ptr); + coder->pack_temporary_bits=32; + coder->pack_temporary=positive_int(minint[2]); + Ptngc_out8bits(coder,&output_ptr); + /* Store max indices */ + coder->pack_temporary_bits=8; + coder->pack_temporary=large_index[0]; + Ptngc_out8bits(coder,&output_ptr); + coder->pack_temporary_bits=8; + coder->pack_temporary=large_index[1]; + Ptngc_out8bits(coder,&output_ptr); + coder->pack_temporary_bits=8; + coder->pack_temporary=large_index[2]; + Ptngc_out8bits(coder,&output_ptr); + /* Store initial small index */ + coder->pack_temporary_bits=8; + coder->pack_temporary=small_index; + Ptngc_out8bits(coder,&output_ptr); + +#if 0 +#ifdef SHOWIT + for (i=0; ilargest_required_base) + largest_required_base=encode_ints[ienc]; + /* Also compute what the largest base is for the current runlength setting! */ + largest_runlength_base=0; + for (ienc=0; (ienclargest_runlength_base) + largest_runlength_base=encode_ints[ienc]; + + largest_required_index=Ptngc_find_magic_index(largest_required_base); + largest_runlength_index=Ptngc_find_magic_index(largest_runlength_base); + + if (largest_required_indexntriplets_left) + new_runlength=ntriplets_left; + + /* We must at least try to get some small integers going. */ + if (new_runlength==0) + { + new_runlength=1; + new_small_index=small_index; + } + + iter_runlength=new_runlength; + iter_small_index=new_small_index; + + /* Iterate to find optimal encoding and runlength */ +#ifdef SHOWIT + fprintf(stderr,"Entering iterative loop.\n"); + fflush(stderr); +#endif + + do { + new_runlength=iter_runlength; + new_small_index=iter_small_index; + +#ifdef SHOWIT + fprintf(stderr,"Test new_small_index=%d Base=%d\n",new_small_index,magic[new_small_index]); +#endif + /* What is the largest runlength + we can do with the currently + selected encoding? Also the max supported runlength is 6 triplets! */ + for (ienc=0; iencnew_small_index) + break; + } + if (ienc/3>new_runlength) + { + iter_runlength=ienc/3; +#ifdef SHOWIT + fprintf(stderr,"I found a new possible runlength: %d\n",iter_runlength); +#endif + } + + /* How large encoding do we have to use? */ + largest_runlength_base=0; + for (ienc=0; ienclargest_runlength_base) + largest_runlength_base=encode_ints[ienc]; + largest_runlength_index=Ptngc_find_magic_index(largest_runlength_base); + if (largest_runlength_index!=new_small_index) + { + iter_small_index=largest_runlength_index; +#ifdef SHOWIT + fprintf(stderr,"I found a new possible small index: %d Base=%d\n",iter_small_index,magic[iter_small_index]); +#endif + } + } while ((new_runlength!=iter_runlength) || + (new_small_index!=iter_small_index)); + +#ifdef SHOWIT + fprintf(stderr,"Exit iterative loop.\n"); + fflush(stderr); +#endif + + /* Verify that we got something good. We may have caught a + substantially larger atom. If so we should just bail + out and let the loop get on another lap. We may have a + minimum runlength though and then we have to fulfill + the request to write out these atoms! */ + rle_index_dep=0; + if (new_runlength<3) + rle_index_dep=IS_LARGE; + else if (new_runlength<6) + rle_index_dep=QUITE_LARGE; + if ((min_runlength) + || ((new_small_index=%g?\n",change,isum,(double)magic[small_index+change]*(double)magic[small_index+change]); +#endif + if (isum>(double)magic[small_index+change]*(double)magic[small_index+change]) + { +#ifdef SHOWIT + fprintf(stderr,"Rejected decrease %d of index due to length of vector: %g>=%g\n",change,isum,(double)magic[small_index+change]*(double)magic[small_index+change]); +#endif + rejected=1; + change++; + } + } while ((change<0) && (rejected)); + if (change==0) + break; + } + } + + /* If the only thing to do is to change the base by + only one -1 it is probably not worth it. */ + if (!((change==-1) && (runlength==new_runlength))) + { + /* If we have a very short runlength we do not + want to do large base changes. It costs 6 + extra bits to do -2. We gain 2/3 + bits per value to decrease the index by -2, + ie 2 bits, so to any changes down we must + have a runlength of 3 or more to do it for + one molecule! If we have several molecules we + will gain of course, so not be so strict. */ + if ((change==-2) && (new_runlength<3)) + { + if (runlength==new_runlength) + change=0; + else + change=-1; +#ifdef SHOWIT + fprintf(stderr,"Rejected change by -2 due to too short runlenght. Change set to %d\n",change); +#endif + } + + /* First adjust base using large base change instruction (if necessary) */ + while ((change>1) || (change<-1) || ((new_runlength==6) && (change))) + { + unsigned int code=0U; + int this_change=change; + if (this_change>2) + this_change=2; + if (this_change<-2) + this_change=-2; + change-=this_change; +#ifdef SHOWIT + fprintf(stderr,"Large base change: %d.\n",this_change); +#endif + small_index+=this_change; + if (this_change<0) + { + code|=2U; + this_change=-this_change; + } + code|=(unsigned int)(this_change-1); + write_instruction(coder,INSTR_LARGE_BASE_CHANGE,&output_ptr); + Ptngc_writebits(coder,code,2,&output_ptr); + } + /* If there is still base change or runlength changes to do, we do them now. */ + if ((new_runlength!=runlength) || (change)) + { + unsigned int ichange=(unsigned int)(change+1); + unsigned int code=0U; + unsigned int irun=(unsigned int)((new_runlength-1)*3); + if (new_runlength==6) + ichange=0; /* Means no change. The change has been taken care of explicitly by a large + base change instruction above. */ + code=ichange+irun; +#ifdef SHOWIT + fprintf(stderr,"Small base change: %d Runlength change: %d\n",change,new_runlength); +#endif + small_index+=change; + write_instruction(coder,INSTR_BASE_RUNLENGTH,&output_ptr); + Ptngc_writebits(coder,code,4,&output_ptr); + runlength=new_runlength; + } + } +#ifdef SHOWIT + else + fprintf(stderr,"Rejected base change due to only change==-1\n"); +#endif +#ifdef SHOWIT + fprintf(stderr,"Current small index: %d Base=%d\n",small_index,magic[small_index]); +#endif + } + /* If we have a large previous integer we can combine it with a sequence of small ints. */ + if (has_large) + { + /* If swapatoms is set to 1 but we did actually not + do any swapping, we must first write out the + large atom and then the small. If swapatoms is 1 + and we did swapping we can use the efficient + encoding. */ + if ((swapatoms) && (!didswap)) + { +#ifdef SHOWIT + fprintf(stderr,"Swapatoms was set to 1 but we did not do swapping!\n"); + fprintf(stderr,"Only one large integer.\n"); +#endif + /* Flush all large atoms. */ + flush_large(coder,&has_large,has_large_ints,has_large,large_index,large_nbits,compress_buffer,&output_ptr); +#ifdef SHOWIT + fprintf(stderr,"Sequence of only small integers.\n"); +#endif + write_instruction(coder,INSTR_ONLY_SMALL,&output_ptr); + } + else + { + +#ifdef SHOWIT + fprintf(stderr,"Sequence of one large and small integers (good compression).\n"); +#endif + /* Flush all large atoms but one! */ + if (has_large>1) + flush_large(coder,&has_large,has_large_ints,has_large-1,large_index,large_nbits,compress_buffer,&output_ptr); + write_instruction(coder,INSTR_DEFAULT,&output_ptr); + write_three_large(coder,has_large_ints,large_index,large_nbits,compress_buffer,&output_ptr); + has_large=0; + } + } + else + { +#ifdef SHOWIT + fprintf(stderr,"Sequence of only small integers.\n"); +#endif + write_instruction(coder,INSTR_ONLY_SMALL,&output_ptr); + } + /* Base compress small integers using the current parameters. */ + nbits=magic_bits[small_index][runlength-1]; + /* The same base is used for the small changes. */ + small_idx[0]=small_index; + small_idx[1]=small_index; + small_idx[2]=small_index; + trajcoder_base_compress(encode_ints,runlength*3,small_idx,compress_buffer); +#ifdef SHOWIT + fprintf(stderr,"nbits=%d (%g)\n",nbits,nbits/(runlength*3.)); + nbits_sum+=nbits; + nvalues_sum+=runlength*3; + fprintf(stderr,"Runlength encoded small integers. runlength=%d\n",runlength); +#endif + /* write out base compressed small integers */ + Ptngc_writemanybits(coder,compress_buffer,nbits,&output_ptr); +#ifdef SHOWIT + for (ienc=0; ienc=0) && (instr +#include +#include +#include +#include +#include "compression/warnmalloc.h" +#include "compression/widemuldiv.h" +#include "compression/bwlzh.h" + +static const double iflipgaincheck=0.89089871814033927; /* 1./(2**(1./6)) */ + +#define MAX_LARGE_RLE 1024 /* Maximum number of large atoms for large RLE. */ +#define MAX_SMALL_RLE 12 /* Maximum number of small atoms in one group. */ + +#define TRESHOLD_INTRA_INTER_DIRECT 1.5 /* How much larger can the direct + frame deltas for the small + triplets be and be accepted anyway + as better than the intra/inter frame + deltas. For better instructions/RLEs. */ + +#define TRESHOLD_INTER_INTRA 5.0 /* How much larger can the intra + frame deltas for the small + triplets be and be accepted anyway + as better than the inter frame + deltas. */ + +/* Difference in indices used for determining whether to store as + large or small. A fun detail in this compression algorithm is that + if everything works fine, large can often be smaller than small, or + at least not as large as is large in magic.c. This is a key idea of + xtc3. */ +#define QUITE_LARGE 3 +#define IS_LARGE 6 + +#if 0 +#define SHOWIT +#endif + +#if 0 +#define SHOWIT_LIGHT +#endif + +#ifdef USE_WINDOWS +#define TNG_INLINE __inline +#else +#define TNG_INLINE inline +#endif + +/* These routines are in xtc2.c */ +int Ptngc_magic(unsigned int i); +int Ptngc_find_magic_index(const unsigned int maxval); + +static TNG_INLINE unsigned int positive_int(const int item) +{ + int s=0; + if (item>0) + s=1+(item-1)*2; + else if (item<0) + s=2+(-item-1)*2; + return s; +} + +static TNG_INLINE int unpositive_int(const int val) +{ + int s=(val+1)/2; + if ((val%2)==0) + s=-s; + return s; +} + + +/* Sequence instructions */ +#define INSTR_DEFAULT 0U +#define INSTR_SMALL_RUNLENGTH 1U +#define INSTR_ONLY_LARGE 2U +#define INSTR_ONLY_SMALL 3U +#define INSTR_FLIP 4U +#define INSTR_LARGE_RLE 5U +#define INSTR_LARGE_DIRECT 6U +#define INSTR_LARGE_INTRA_DELTA 7U +#define INSTR_LARGE_INTER_DELTA 8U + +#define MAXINSTR 9 + +struct xtc3_context +{ + unsigned int *instructions; + int ninstr, ninstr_alloc; + unsigned int *rle; + int nrle, nrle_alloc; + unsigned int *large_direct; + int nlargedir, nlargedir_alloc; + unsigned int *large_intra_delta; + int nlargeintra, nlargeintra_alloc; + unsigned int *large_inter_delta; + int nlargeinter, nlargeinter_alloc; + unsigned int *smallintra; + int nsmallintra, nsmallintra_alloc; + int minint[3],maxint[3]; + int has_large; + int has_large_ints[MAX_LARGE_RLE*3]; /* Large cache. */ + int has_large_type[MAX_LARGE_RLE]; /* What kind of type this large + int is. */ + int current_large_type; +}; + +static void init_xtc3_context(struct xtc3_context *xtc3_context) +{ + xtc3_context->instructions=NULL; + xtc3_context->ninstr=0; + xtc3_context->ninstr_alloc=0; + xtc3_context->rle=NULL; + xtc3_context->nrle=0; + xtc3_context->nrle_alloc=0; + xtc3_context->large_direct=NULL; + xtc3_context->nlargedir=0; + xtc3_context->nlargedir_alloc=0; + xtc3_context->large_intra_delta=NULL; + xtc3_context->nlargeintra=0; + xtc3_context->nlargeintra_alloc=0; + xtc3_context->large_inter_delta=NULL; + xtc3_context->nlargeinter=0; + xtc3_context->nlargeinter_alloc=0; + xtc3_context->smallintra=NULL; + xtc3_context->nsmallintra=0; + xtc3_context->nsmallintra_alloc=0; + xtc3_context->has_large=0; + xtc3_context->current_large_type=0; +} + +static void free_xtc3_context(struct xtc3_context *xtc3_context) +{ + free(xtc3_context->instructions); + free(xtc3_context->rle); + free(xtc3_context->large_direct); + free(xtc3_context->large_intra_delta); + free(xtc3_context->large_inter_delta); + free(xtc3_context->smallintra); +} + +/* Modifies three integer values for better compression of water */ +static void swap_ints(const int *in, int *out) +{ + out[0]=in[0]+in[1]; + out[1]=-in[1]; + out[2]=in[1]+in[2]; +} + +static void swap_is_better(const int *input, const int *minint, int *sum_normal, int *sum_swapped) +{ + int normal_max=0; + int swapped_max=0; + int i,j; + int normal[3]; + int swapped[3]; + for (i=0; i<3; i++) + { + normal[0]=input[i]-minint[i]; + normal[1]=input[3+i]-input[i]; /* minint[i]-minint[i] cancels out */ + normal[2]=input[6+i]-input[3+i]; /* minint[i]-minint[i] cancels out */ + swap_ints(normal,swapped); + for (j=1; j<3; j++) + { + if (positive_int(normal[j])>(unsigned int)normal_max) + normal_max=positive_int(normal[j]); + if (positive_int(swapped[j])>(unsigned int)swapped_max) + swapped_max=positive_int(swapped[j]); + } + } + if (normal_max==0) + normal_max=1; + if (swapped_max==0) + swapped_max=1; + *sum_normal=normal_max; + *sum_swapped=swapped_max; +} + +static void allocate_enough_memory(unsigned int **ptr, int *nele, int *nele_alloc) +{ + (*nele)++; + if (*nele>*nele_alloc) + { + *nele_alloc=*nele + *nele/2; + *ptr=warnrealloc(*ptr,*nele_alloc*sizeof **ptr); + } +} + +static void insert_value_in_array(unsigned int **ptr, int *nele, int *nele_alloc, + const unsigned int value, + char *arrayname) +{ +#ifndef SHOWIT + (void)arrayname; +#endif + allocate_enough_memory(ptr,nele,nele_alloc); +#ifdef SHOWIT + fprintf(stderr,"Inserting value %u into array %s @ %d\n",value,arrayname,(*nele)-1); +#endif + (*ptr)[(*nele)-1]=value; +} + + + +static void swapdecide(struct xtc3_context *xtc3_context, int *input,int *swapatoms, int *large_index, int *minint) +{ + int didswap=0; + int normal,swapped; + (void)large_index; + swap_is_better(input,minint,&normal,&swapped); + /* We have to determine if it is worth to change the behaviour. + If diff is positive it means that it is worth something to + swap. But it costs 4 bits to do the change. If we assume that + we gain 0.17 bit by the swap per value, and the runlength>2 + for four molecules in a row, we gain something. So check if we + gain at least 0.17 bits to even attempt the swap. + */ +#ifdef SHOWIT + fprintf(stderr,"Trying Flip: %g %g\n",(double)swapped/normal, (double)normal/swapped); +#endif + if (((swappedinstructions, + &xtc3_context->ninstr, + &xtc3_context->ninstr_alloc, + INSTR_FLIP,"instr"); + } +} + +/* It is "large" if we have to increase the small index quite a + bit. Not so much to be rejected by the not very large check + later. */ +static int is_quite_large(const int *input, const int small_index, const int max_large_index) +{ + int is=0; + int i; + if (small_index+QUITE_LARGE>=max_large_index) + is=1; + else + { + for (i=0; i<3; i++) + if (positive_int(input[i])>(unsigned int)Ptngc_magic(small_index+QUITE_LARGE)) + { + is=1; + break; + } + } + return is; +} + +#ifdef SHOWIT +int nbits_sum; +int nvalues_sum; +#endif + +static void insert_batch(const int *input_ptr, const int ntriplets_left, const int *prevcoord, int *encode_ints, const int startenc, int *nenc) +{ + int nencode=startenc*3; + int tmp_prevcoord[3]; + + tmp_prevcoord[0]=prevcoord[0]; + tmp_prevcoord[1]=prevcoord[1]; + tmp_prevcoord[2]=prevcoord[2]; + + if (startenc) + { + int i; + for (i=0; ihas_large_type[i]!=xtc3_context->current_large_type) + { + unsigned int instr; + xtc3_context->current_large_type=xtc3_context->has_large_type[i]; + if (xtc3_context->current_large_type==0) + instr=INSTR_LARGE_DIRECT; + else if (xtc3_context->current_large_type==1) + instr=INSTR_LARGE_INTRA_DELTA; + else + instr=INSTR_LARGE_INTER_DELTA; + insert_value_in_array(&xtc3_context->instructions, + &xtc3_context->ninstr, + &xtc3_context->ninstr_alloc, + instr,"instr"); + } +} + +static void write_three_large(struct xtc3_context *xtc3_context, + const int i) +{ + int m; + if (xtc3_context->current_large_type==0) + { + for (m=0; m<3; m++) + insert_value_in_array(&xtc3_context->large_direct, + &xtc3_context->nlargedir, + &xtc3_context->nlargedir_alloc, + xtc3_context->has_large_ints[i*3+m],"large direct"); + } + else if (xtc3_context->current_large_type==1) + { + for (m=0; m<3; m++) + insert_value_in_array(&xtc3_context->large_intra_delta, + &xtc3_context->nlargeintra, + &xtc3_context->nlargeintra_alloc, + xtc3_context->has_large_ints[i*3+m],"large intra"); + } + else + { + for (m=0; m<3; m++) + insert_value_in_array(&xtc3_context->large_inter_delta, + &xtc3_context->nlargeinter, + &xtc3_context->nlargeinter_alloc, + xtc3_context->has_large_ints[i*3+m],"large inter"); + } +} + +static void flush_large(struct xtc3_context *xtc3_context, + const int n) /* How many to flush. */ +{ + int i; + i=0; + while (ihas_large_type[i+j]==xtc3_context->has_large_type[i]); + j++); + if (j<3) + { + for (k=0; kinstructions, + &xtc3_context->ninstr, + &xtc3_context->ninstr_alloc, + INSTR_ONLY_LARGE,"instr"); + write_three_large(xtc3_context,i+k); + } + } + else + { + insert_value_in_array(&xtc3_context->instructions, + &xtc3_context->ninstr, + &xtc3_context->ninstr_alloc, + INSTR_LARGE_RLE,"instr"); + insert_value_in_array(&xtc3_context->rle, + &xtc3_context->nrle, + &xtc3_context->nrle_alloc, + (unsigned int)j,"rle (large)"); + for (k=0; khas_large-n)!=0) + { + int j; + for (i=0; ihas_large-n; i++) + { + xtc3_context->has_large_type[i]=xtc3_context->has_large_type[i+n]; + for (j=0; j<3; j++) + xtc3_context->has_large_ints[i*3+j]=xtc3_context->has_large_ints[(i+n)*3+j]; + } + } + xtc3_context->has_large-=n; /* Number of remaining large atoms in buffer */ +} + +static double compute_intlen(unsigned int *ints) +{ + /* The largest value. */ + unsigned int m=ints[0]; + if (ints[1]>m) + m=ints[1]; + if (ints[2]>m) + m=ints[2]; + return (double)m; +} + +static void buffer_large(struct xtc3_context *xtc3_context, int *input, const int inpdata, + const int natoms, const int intradelta_ok) +{ + unsigned int direct[3], intradelta[3]={0,}, interdelta[3]={0,}; + double minlen; + int best_type; + int frame=inpdata/(natoms*3); + int atomframe=inpdata%(natoms*3); + /* If it is full we must write them all. */ + if (xtc3_context->has_large==MAX_LARGE_RLE) + flush_large(xtc3_context,xtc3_context->has_large); /* Flush all. */ + /* Find out which is the best choice for the large integer. Direct coding, or some + kind of delta coding? */ + /* First create direct coding. */ + direct[0]=(unsigned int)(input[inpdata]-xtc3_context->minint[0]); + direct[1]=(unsigned int)(input[inpdata+1]-xtc3_context->minint[1]); + direct[2]=(unsigned int)(input[inpdata+2]-xtc3_context->minint[2]); + minlen=compute_intlen(direct); + best_type=0; /* Direct. */ +#if 1 + /* Then try intra coding if we can. */ + if ((intradelta_ok) && (atomframe>=3)) + { + double thislen; + intradelta[0]=positive_int(input[inpdata]-input[inpdata-3]); + intradelta[1]=positive_int(input[inpdata+1]-input[inpdata-2]); + intradelta[2]=positive_int(input[inpdata+2]-input[inpdata-1]); + thislen=compute_intlen(intradelta); + if (thislen*TRESHOLD_INTRA_INTER_DIRECT0) + { + double thislen; + interdelta[0]=positive_int(input[inpdata]-input[inpdata-natoms*3]); + interdelta[1]=positive_int(input[inpdata+1]-input[inpdata-natoms*3+1]); + interdelta[2]=positive_int(input[inpdata+2]-input[inpdata-natoms*3+2]); + thislen=compute_intlen(interdelta); + if (thislen*TRESHOLD_INTRA_INTER_DIRECThas_large_type[xtc3_context->has_large]=best_type; + if (best_type==0) + { + xtc3_context->has_large_ints[xtc3_context->has_large*3]=direct[0]; + xtc3_context->has_large_ints[xtc3_context->has_large*3+1]=direct[1]; + xtc3_context->has_large_ints[xtc3_context->has_large*3+2]=direct[2]; + } + else if (best_type==1) + { + xtc3_context->has_large_ints[xtc3_context->has_large*3]=intradelta[0]; + xtc3_context->has_large_ints[xtc3_context->has_large*3+1]=intradelta[1]; + xtc3_context->has_large_ints[xtc3_context->has_large*3+2]=intradelta[2]; + } + else if (best_type==2) + { + xtc3_context->has_large_ints[xtc3_context->has_large*3]=interdelta[0]; + xtc3_context->has_large_ints[xtc3_context->has_large*3+1]=interdelta[1]; + xtc3_context->has_large_ints[xtc3_context->has_large*3+2]=interdelta[2]; + } + xtc3_context->has_large++; +} + +static void output_int(unsigned char *output,int *outdata, const unsigned int n) +{ + output[(*outdata)++]=((unsigned int)n)&0xFFU; + output[(*outdata)++]=(((unsigned int)n)>>8)&0xFFU; + output[(*outdata)++]=(((unsigned int)n)>>16)&0xFFU; + output[(*outdata)++]=(((unsigned int)n)>>24)&0xFFU; +} + +#if 0 +static void printarray(unsigned int *a, int n, char *name) +{ + int i; + for (i=0; i>(j*8))&0xFFU) + numbytes=i*4+j+1; + return numbytes; +} + +static void base_compress(unsigned int *data, const int len, unsigned char *output, int *outlen) +{ + unsigned int largeint[MAXBASEVALS+1]; + unsigned int largeint_tmp[MAXBASEVALS+1]; + int ixyz, i; + unsigned int j; + int nwrittenout=0; + unsigned int numbytes=0; + /* Store the MAXBASEVALS value in the output. */ + output[nwrittenout++]=(unsigned char)(MAXBASEVALS&0xFFU); + output[nwrittenout++]=(unsigned char)((MAXBASEVALS>>8)&0xFFU); + /* Store the BASEINTERVAL value in the output. */ + output[nwrittenout++]=(unsigned char)(BASEINTERVAL&0xFFU); + for (ixyz=0; ixyz<3; ixyz++) + { + unsigned int base=0U; + int nvals=0; + int basegiven=0; + + memset(largeint, 0U, sizeof(unsigned int) * (MAXBASEVALS+1)); + + for (i=ixyz; ibase) + base=data[k]; + basecheckvals++; + if (basecheckvals==MAXBASEVALS*BASEINTERVAL) + break; + } + /* The base is one larger than the largest values. */ + base++; + if (base<2) + base=2; + /* Store the base in the output. */ + output[nwrittenout++]=(unsigned char)(base&0xFFU); + output[nwrittenout++]=(unsigned char)((base>>8)&0xFFU); + output[nwrittenout++]=(unsigned char)((base>>16)&0xFFU); + output[nwrittenout++]=(unsigned char)((base>>24)&0xFFU); + basegiven=BASEINTERVAL; + /* How many bytes is needed to store MAXBASEVALS values using this base? */ + numbytes=base_bytes(base,MAXBASEVALS); + } + basegiven--; +#ifdef SHOWIT + fprintf(stderr,"Base for %d is %u. I need %d bytes for %d values.\n",ixyz,base,numbytes,MAXBASEVALS); +#endif + } + if (nvals!=0) + { + Ptngc_largeint_mul(base,largeint,largeint_tmp,MAXBASEVALS+1); + for (j=0; j>(ibyte*8))&(0xFFU)); +#ifdef SHOWIT + fprintf(stderr,"%02x",(unsigned int)output[nwrittenout-1]); +#endif + } +#ifdef SHOWIT + fprintf(stderr,"\n"); +#endif + nvals=0; + + memset(largeint, 0U, sizeof(unsigned int) * (MAXBASEVALS+1)); + } + } + if (nvals) + { + numbytes=base_bytes(base,nvals); +#ifdef SHOWIT + fprintf(stderr,"Base for %d is %u. I need %d bytes for %d values.\n",ixyz,base,numbytes,nvals); +#endif + for (j=0; j>(ibyte*8))&(0xFFU)); + } + } + } + *outlen=nwrittenout; +} + +static void base_decompress(unsigned char *input, const int len, unsigned int *output) +{ + unsigned int largeint[MAXMAXBASEVALS+1]; + unsigned int largeint_tmp[MAXMAXBASEVALS+1]; + int ixyz, i, j; + int maxbasevals=(int)((unsigned int)(input[0])|(((unsigned int)(input[1]))<<8)); + int baseinterval=(int)input[2]; + if (maxbasevals>(int)MAXMAXBASEVALS) + { + fprintf(stderr,"Read a larger maxbasevals value from the file than I can handle. Fix" + " by increasing MAXMAXBASEVALS to at least %d. Although, this is" + " probably a bug in TRAJNG, since MAXMAXBASEVALS should already be insanely large enough.\n",maxbasevals); + exit(EXIT_FAILURE); + } + input+=3; + for (ixyz=0; ixyz<3; ixyz++) + { + int numbytes=0; + int nvals_left=len/3; + int outvals=ixyz; + int basegiven=0; + unsigned int base=0U; +#ifdef SHOWIT + fprintf(stderr,"Base for %d is %u. I need %d bytes for %d values.\n",ixyz,base,numbytes,maxbasevals); +#endif + while (nvals_left) + { + int n; + if (basegiven==0) + { + base=(unsigned int)(input[0])| + (((unsigned int)(input[1]))<<8)| + (((unsigned int)(input[2]))<<16)| + (((unsigned int)(input[3]))<<24); + input+=4; + basegiven=baseinterval; + /* How many bytes is needed to store maxbasevals values using this base? */ + numbytes=base_bytes(base,maxbasevals); + } + basegiven--; + if (nvals_leftnvals_left) + n=nvals_left; + for (i=n-1; i>=0; i--) + { + output[outvals+i*3]=Ptngc_largeint_div(base,largeint,largeint_tmp,maxbasevals+1); + for (j=0; j14 bits) we return 0, otherwise 1 */ +static int heuristic_bwlzh(unsigned int *ints, const int nints) +{ + int i,num; + num=0; + for (i=0; i=16384) + num++; + if (num>nints/10) + return 0; + else + return 1; +} + +/* Speed selects how careful to try to find the most efficient compression. The BWLZH algo is expensive! + Speed <=2 always avoids BWLZH everywhere it is possible. + Speed 3 and 4 and 5 use heuristics (check proportion of large value). This should mostly be safe. + Speed 5 enables the LZ77 component of BWLZH. + Speed 6 always tests if BWLZH is better and if it is uses it. This can be very slow. + */ +unsigned char *Ptngc_pack_array_xtc3(int *input, int *length, const int natoms, int speed) +{ + unsigned char *output=NULL; + int i,ienc,j; + int outdata=0; + /* Pack triplets. */ + int ntriplets=*length/3; + int intmax; + int max_small; + int small_index; + int max_large_index; + int large_index[3]; + int prevcoord[3]; + int runlength=0; /* Initial runlength. "Stupidly" set to zero for + simplicity and explicity */ + int swapatoms=0; /* Initial guess is that we should not swap the + first two atoms in each large+small + transition */ + int didswap; /* Whether swapping was actually done. */ + int inpdata=0; + int encode_ints[3+MAX_SMALL_RLE*3]; /* Up to 3 large + 24 small ints can be encoded at once */ + int nencode; + int ntriplets_left=ntriplets; + int refused=0; + unsigned char *bwlzh_buf=NULL; + int bwlzh_buf_len; + unsigned char *base_buf=NULL; + int base_buf_len; + + struct xtc3_context xtc3_context; + init_xtc3_context(&xtc3_context); + + memcpy(xtc3_context.maxint, input, 3*sizeof *xtc3_context.maxint); + memcpy(xtc3_context.minint, input, 3*sizeof *xtc3_context.maxint); + + /* Values of speed should be sane. */ + if (speed<1) + speed=1; + if (speed>6) + speed=6; + +#ifdef SHOWIT + nbits_sum=0; + nvalues_sum=0; +#endif + /* Allocate enough memory for output */ + if (*length < 48) + output=warnmalloc(8*48*sizeof *output); + else + output=warnmalloc(8* *length*sizeof *output); + + + for (i=1; ixtc3_context.maxint[j]) + xtc3_context.maxint[j]=input[i*3+j]; + if (input[i*3+j]max_large_index) + max_large_index=large_index[1]; + if (large_index[2]>max_large_index) + max_large_index=large_index[2]; + +#ifdef SHOWIT + for (j=0; j<3; j++) + fprintf(stderr,"minint[%d]=%d. maxint[%d]=%d large_index[%d]=%d value=%d\n",j,xtc3_context.minint[j],j,xtc3_context.maxint[j], + j,large_index[j],Ptngc_magic(large_index[j])); +#endif + + /* Guess initial small index */ + small_index=max_large_index/2; + + /* Find the largest value that is not large. Not large is half index of + large. */ + max_small=Ptngc_magic(small_index); + intmax=0; + for (i=0; i<*length; i++) + { + int item=input[i]; + int s=positive_int(item); + if (s>intmax) + if (s0) + { + unsigned int delta[3], delta2[3]; + delta[0]=positive_int(input[inpdata+3]-input[inpdata-natoms*3+3]); + delta[1]=positive_int(input[inpdata+4]-input[inpdata-natoms*3+4]); + delta[2]=positive_int(input[inpdata+5]-input[inpdata-natoms*3+5]); + delta2[0]=positive_int(encode_ints[3]); + delta2[1]=positive_int(encode_ints[4]); + delta2[2]=positive_int(encode_ints[5]); +#ifdef SHOWIT + fprintf(stderr,"A1: inter delta: %u %u %u. intra delta=%u %u %u\n", + delta[0],delta[1],delta[2], + delta2[0],delta2[1],delta2[2]); +#endif + if (compute_intlen(delta)*TRESHOLD_INTER_INTRAlargest_required_base) + largest_required_base=encode_ints[ienc]; + /* Also compute what the largest base is for the current runlength setting! */ + largest_runlength_base=0; + for (ienc=0; (ienclargest_runlength_base) + largest_runlength_base=encode_ints[ienc]; + + largest_required_index=Ptngc_find_magic_index(largest_required_base); + largest_runlength_index=Ptngc_find_magic_index(largest_runlength_base); + + if (largest_required_indexntriplets_left) + new_runlength=ntriplets_left; + + /* We must at least try to get some small integers going. */ + if (new_runlength==0) + { + new_runlength=1; + new_small_index=small_index; + } + + iter_runlength=new_runlength; + iter_small_index=new_small_index; + + /* Iterate to find optimal encoding and runlength */ +#ifdef SHOWIT + fprintf(stderr,"Entering iterative loop.\n"); + fflush(stderr); +#endif + + do { + new_runlength=iter_runlength; + new_small_index=iter_small_index; + +#ifdef SHOWIT + fprintf(stderr,"Test new_small_index=%d Base=%d\n",new_small_index,Ptngc_magic(new_small_index)); +#endif + /* What is the largest runlength + we can do with the currently + selected encoding? Also the max supported runlength is MAX_SMALL_RLE triplets! */ + for (ienc=0; iencnew_small_index) + break; + } + if (ienc/3>new_runlength) + { + iter_runlength=ienc/3; +#ifdef SHOWIT + fprintf(stderr,"I found a new possible runlength: %d\n",iter_runlength); +#endif + } + + /* How large encoding do we have to use? */ + largest_runlength_base=0; + for (ienc=0; ienclargest_runlength_base) + largest_runlength_base=encode_ints[ienc]; + largest_runlength_index=Ptngc_find_magic_index(largest_runlength_base); + if (largest_runlength_index!=new_small_index) + { + iter_small_index=largest_runlength_index; +#ifdef SHOWIT + fprintf(stderr,"I found a new possible small index: %d Base=%d\n",iter_small_index,Ptngc_magic(iter_small_index)); +#endif + } + } while ((new_runlength!=iter_runlength) || + (new_small_index!=iter_small_index)); + +#ifdef SHOWIT + fprintf(stderr,"Exit iterative loop.\n"); + fflush(stderr); +#endif + + /* Verify that we got something good. We may have caught a + substantially larger atom. If so we should just bail + out and let the loop get on another lap. We may have a + minimum runlength though and then we have to fulfill + the request to write out these atoms! */ + rle_index_dep=0; + if (new_runlength<3) + rle_index_dep=IS_LARGE; + else if (new_runlength<6) + rle_index_dep=QUITE_LARGE; + if ((min_runlength) + || ((new_small_index0)) + { + for (i=0; i=2*new_runlength/3)) + { + /* Put all the values in large arrays, instead of the small array */ + if (new_runlength) + { + for (i=0; i=%g?\n",change,isum,(double)Ptngc_magic(small_index+change)*(double)Ptngc_magic(small_index+change)); +#endif + if (isum>(double)Ptngc_magic(small_index+change)*(double)Ptngc_magic(small_index+change)) + { +#ifdef SHOWIT + fprintf(stderr,"Rejected decrease %d of index due to length of vector: %g>=%g\n",change,isum,(double)Ptngc_magic(small_index+change)*(double)Ptngc_magic(small_index+change)); +#endif + rejected=1; + change++; + } + } while ((change<0) && (rejected)); + if (change==0) + break; + } + } + + /* Always accept the new small indices here. */ + small_index=new_small_index; + /* If we have a new runlength emit it */ + if (runlength!=new_runlength) + { + runlength=new_runlength; + insert_value_in_array(&xtc3_context.instructions, + &xtc3_context.ninstr, + &xtc3_context.ninstr_alloc, + INSTR_SMALL_RUNLENGTH,"instr"); + insert_value_in_array(&xtc3_context.rle, + &xtc3_context.nrle, + &xtc3_context.nrle_alloc, + (unsigned int)runlength,"rle (small)"); + } +#ifdef SHOWIT + fprintf(stderr,"Current small index: %d Base=%d\n",small_index,Ptngc_magic(small_index)); +#endif + } + /* If we have a large previous integer we can combine it with a sequence of small ints. */ + if (xtc3_context.has_large) + { + /* If swapatoms is set to 1 but we did actually not + do any swapping, we must first write out the + large atom and then the small. If swapatoms is 1 + and we did swapping we can use the efficient + encoding. */ + if ((swapatoms) && (!didswap)) + { +#ifdef SHOWIT + fprintf(stderr,"Swapatoms was set to 1 but we did not do swapping!\n"); + fprintf(stderr,"Only one large integer.\n"); +#endif + /* Flush all large atoms. */ + flush_large(&xtc3_context,xtc3_context.has_large); +#ifdef SHOWIT + fprintf(stderr,"Sequence of only small integers.\n"); +#endif + insert_value_in_array(&xtc3_context.instructions, + &xtc3_context.ninstr, + &xtc3_context.ninstr_alloc, + INSTR_ONLY_SMALL,"instr"); + } + else + { + +#ifdef SHOWIT + fprintf(stderr,"Sequence of one large and small integers (good compression).\n"); +#endif + /* Flush all large atoms but one! */ + if (xtc3_context.has_large>1) + flush_large(&xtc3_context,xtc3_context.has_large-1); + + /* Here we must check if we should emit a large + type change instruction. */ + large_instruction_change(&xtc3_context,0); + + insert_value_in_array(&xtc3_context.instructions, + &xtc3_context.ninstr, + &xtc3_context.ninstr_alloc, + INSTR_DEFAULT,"instr"); + + write_three_large(&xtc3_context,0); + xtc3_context.has_large=0; + } + } + else + { +#ifdef SHOWIT + fprintf(stderr,"Sequence of only small integers.\n"); +#endif + insert_value_in_array(&xtc3_context.instructions, + &xtc3_context.ninstr, + &xtc3_context.ninstr_alloc, + INSTR_ONLY_SMALL,"instr"); + } + /* Insert the small integers into the small integer array. */ + for (ienc=0; ienc=5) + bwlzh_compress(xtc3_context.instructions,xtc3_context.ninstr,bwlzh_buf,&bwlzh_buf_len); + else + bwlzh_compress_no_lz77(xtc3_context.instructions,xtc3_context.ninstr,bwlzh_buf,&bwlzh_buf_len); + output_int(output,&outdata,(unsigned int)bwlzh_buf_len); + memcpy(output+outdata,bwlzh_buf,bwlzh_buf_len); + outdata+=bwlzh_buf_len; + free(bwlzh_buf); + } + +#if defined(SHOWIT) || defined(SHOWIT_LIGHT) + fprintf(stderr,"rle: %d\n",xtc3_context.nrle); +#endif + + output_int(output,&outdata,(unsigned int)xtc3_context.nrle); + if (xtc3_context.nrle) + { + bwlzh_buf=warnmalloc(bwlzh_get_buflen(xtc3_context.nrle)); + if (speed>=5) + bwlzh_compress(xtc3_context.rle,xtc3_context.nrle,bwlzh_buf,&bwlzh_buf_len); + else + bwlzh_compress_no_lz77(xtc3_context.rle,xtc3_context.nrle,bwlzh_buf,&bwlzh_buf_len); + output_int(output,&outdata,(unsigned int)bwlzh_buf_len); + memcpy(output+outdata,bwlzh_buf,bwlzh_buf_len); + outdata+=bwlzh_buf_len; + free(bwlzh_buf); + } + +#if defined(SHOWIT) || defined(SHOWIT_LIGHT) + fprintf(stderr,"large direct: %d\n",xtc3_context.nlargedir); +#endif + + output_int(output,&outdata,(unsigned int)xtc3_context.nlargedir); + if (xtc3_context.nlargedir) + { + if ((speed<=2) || ((speed<=5) && (!heuristic_bwlzh(xtc3_context.large_direct,xtc3_context.nlargedir)))) + { + bwlzh_buf=NULL; + bwlzh_buf_len=INT_MAX; + } + else + { + bwlzh_buf=warnmalloc(bwlzh_get_buflen(xtc3_context.nlargedir)); + if (speed>=5) + bwlzh_compress(xtc3_context.large_direct,xtc3_context.nlargedir,bwlzh_buf,&bwlzh_buf_len); + else + bwlzh_compress_no_lz77(xtc3_context.large_direct,xtc3_context.nlargedir,bwlzh_buf,&bwlzh_buf_len); + } + /* If this can be written smaller using base compression we should do that. */ + base_buf=warnmalloc((xtc3_context.nlargedir+3)*sizeof(int)); + base_compress(xtc3_context.large_direct,xtc3_context.nlargedir,base_buf,&base_buf_len); +#if defined(SHOWIT) || defined(SHOWIT_LIGHT) + fprintf(stderr,"Large direct: Base len=%d. BWLZH len=%d\n",base_buf_len,bwlzh_buf_len); +#endif + if (base_buf_len=5) + bwlzh_compress(xtc3_context.large_intra_delta,xtc3_context.nlargeintra,bwlzh_buf,&bwlzh_buf_len); + else + bwlzh_compress_no_lz77(xtc3_context.large_intra_delta,xtc3_context.nlargeintra,bwlzh_buf,&bwlzh_buf_len); + } + /* If this can be written smaller using base compression we should do that. */ + base_buf=warnmalloc((xtc3_context.nlargeintra+3)*sizeof(int)); + base_compress(xtc3_context.large_intra_delta,xtc3_context.nlargeintra,base_buf,&base_buf_len); +#if defined(SHOWIT) || defined(SHOWIT_LIGHT) + fprintf(stderr,"Large intra: Base len=%d. BWLZH len=%d\n",base_buf_len,bwlzh_buf_len); +#endif + if (base_buf_len=5) + bwlzh_compress(xtc3_context.large_inter_delta,xtc3_context.nlargeinter,bwlzh_buf,&bwlzh_buf_len); + else + bwlzh_compress_no_lz77(xtc3_context.large_inter_delta,xtc3_context.nlargeinter,bwlzh_buf,&bwlzh_buf_len); + } + /* If this can be written smaller using base compression we should do that. */ + base_buf=warnmalloc((xtc3_context.nlargeinter+3)*sizeof(int)); + base_compress(xtc3_context.large_inter_delta,xtc3_context.nlargeinter,base_buf,&base_buf_len); +#if defined(SHOWIT) || defined(SHOWIT_LIGHT) + fprintf(stderr,"Large inter: Base len=%d. BWLZH len=%d\n",base_buf_len,bwlzh_buf_len); +#endif + if (base_buf_len=5) + bwlzh_compress(xtc3_context.smallintra,xtc3_context.nsmallintra,bwlzh_buf,&bwlzh_buf_len); + else + bwlzh_compress_no_lz77(xtc3_context.smallintra,xtc3_context.nsmallintra,bwlzh_buf,&bwlzh_buf_len); + } + /* If this can be written smaller using base compression we should do that. */ + base_buf=warnmalloc((xtc3_context.nsmallintra+3)*sizeof(int)); + base_compress(xtc3_context.smallintra,xtc3_context.nsmallintra,base_buf,&base_buf_len); +#if defined(SHOWIT) || defined(SHOWIT_LIGHT) + fprintf(stderr,"Small intra: Base len=%d. BWLZH len=%d\n",base_buf_len,bwlzh_buf_len); +#endif + if (base_buf_lenlarge_direct) + { + large_ints[0]=(int)xtc3_context->large_direct[(*ilargedir)]+minint[0]; + large_ints[1]=(int)xtc3_context->large_direct[(*ilargedir)+1]+minint[1]; + large_ints[2]=(int)xtc3_context->large_direct[(*ilargedir)+2]+minint[2]; + (*ilargedir)+=3; + } + else if (current_large_type==1 && xtc3_context->large_intra_delta) + { + large_ints[0]=unpositive_int(xtc3_context->large_intra_delta[(*ilargeintra)])+prevcoord[0]; + large_ints[1]=unpositive_int(xtc3_context->large_intra_delta[(*ilargeintra)+1])+prevcoord[1]; + large_ints[2]=unpositive_int(xtc3_context->large_intra_delta[(*ilargeintra)+2])+prevcoord[2]; + (*ilargeintra)+=3; + } + else if (xtc3_context->large_inter_delta) + { + large_ints[0]=unpositive_int(xtc3_context->large_inter_delta[(*ilargeinter)]) + +output[outdata-natoms*3+didswap*3]; + large_ints[1]=unpositive_int(xtc3_context->large_inter_delta[(*ilargeinter)+1]) + +output[outdata-natoms*3+1+didswap*3]; + large_ints[2]=unpositive_int(xtc3_context->large_inter_delta[(*ilargeinter)+2]) + +output[outdata-natoms*3+2+didswap*3]; + (*ilargeinter)+=3; + } + memcpy(prevcoord, large_ints, 3*sizeof *prevcoord); + output[outdata]=large_ints[0]; + output[outdata+1]=large_ints[1]; + output[outdata+2]=large_ints[2]; +#ifdef SHOWIT + fprintf(stderr,"Unpack one large: %d %d %d\n",prevcoord[0],prevcoord[1],prevcoord[2]); +#endif +} + + +int Ptngc_unpack_array_xtc3(unsigned char *packed,int *output, const int length, const int natoms) +{ + int i; + int minint[3]; + unsigned char *ptr=packed; + int prevcoord[3]; + int outdata=0; + int ntriplets_left=length/3; + int swapatoms=0; + int runlength=0; + int current_large_type=0; + int iinstr=0; + int irle=0; + int ilargedir=0; + int ilargeintra=0; + int ilargeinter=0; + int ismallintra=0; + + struct xtc3_context xtc3_context; + init_xtc3_context(&xtc3_context); + + for (i=0; i<3; i++) + { + minint[i]=unpositive_int((int)(((unsigned int)ptr[0]) | + (((unsigned int)ptr[1])<<8) | + (((unsigned int)ptr[2])<<16) | + (((unsigned int)ptr[3])<<24))); + ptr+=4; + } + + xtc3_context.ninstr=(int)(((unsigned int)ptr[0]) | + (((unsigned int)ptr[1])<<8) | + (((unsigned int)ptr[2])<<16) | + (((unsigned int)ptr[3])<<24)); + ptr+=4; + if (xtc3_context.ninstr) + decompress_bwlzh_block(&ptr,xtc3_context.ninstr,&xtc3_context.instructions); + + xtc3_context.nrle=(int)(((unsigned int)ptr[0]) | + (((unsigned int)ptr[1])<<8) | + (((unsigned int)ptr[2])<<16) | + (((unsigned int)ptr[3])<<24)); + ptr+=4; + if (xtc3_context.nrle) + decompress_bwlzh_block(&ptr,xtc3_context.nrle,&xtc3_context.rle); + + xtc3_context.nlargedir=(int)(((unsigned int)ptr[0]) | + (((unsigned int)ptr[1])<<8) | + (((unsigned int)ptr[2])<<16) | + (((unsigned int)ptr[3])<<24)); + ptr+=4; + if (xtc3_context.nlargedir) + { + if (*ptr++==1) + decompress_bwlzh_block(&ptr,xtc3_context.nlargedir,&xtc3_context.large_direct); + else + decompress_base_block(&ptr,xtc3_context.nlargedir,&xtc3_context.large_direct); + } + + xtc3_context.nlargeintra=(int)(((unsigned int)ptr[0]) | + (((unsigned int)ptr[1])<<8) | + (((unsigned int)ptr[2])<<16) | + (((unsigned int)ptr[3])<<24)); + ptr+=4; + if (xtc3_context.nlargeintra) + { + if (*ptr++==1) + decompress_bwlzh_block(&ptr,xtc3_context.nlargeintra,&xtc3_context.large_intra_delta); + else + decompress_base_block(&ptr,xtc3_context.nlargeintra,&xtc3_context.large_intra_delta); + } + + xtc3_context.nlargeinter=(int)(((unsigned int)ptr[0]) | + (((unsigned int)ptr[1])<<8) | + (((unsigned int)ptr[2])<<16) | + (((unsigned int)ptr[3])<<24)); + ptr+=4; + if (xtc3_context.nlargeinter) + { + if (*ptr++==1) + decompress_bwlzh_block(&ptr,xtc3_context.nlargeinter,&xtc3_context.large_inter_delta); + else + decompress_base_block(&ptr,xtc3_context.nlargeinter,&xtc3_context.large_inter_delta); + } + + xtc3_context.nsmallintra=(int)(((unsigned int)ptr[0]) | + (((unsigned int)ptr[1])<<8) | + (((unsigned int)ptr[2])<<16) | + (((unsigned int)ptr[3])<<24)); + ptr+=4; + if (xtc3_context.nsmallintra) + { + if (*ptr++==1) + decompress_bwlzh_block(&ptr,xtc3_context.nsmallintra,&xtc3_context.smallintra); + else + decompress_base_block(&ptr,xtc3_context.nsmallintra,&xtc3_context.smallintra); + } + + /* Initial prevcoord is the minimum integers. */ + memcpy(prevcoord, minint, 3*sizeof *prevcoord); + + while (ntriplets_left>0 && iinstr Date: Mon, 7 Oct 2019 14:33:37 -0400 Subject: [PATCH 10/77] Make the test depend on existence of the example file. --- src/tng/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tng/Makefile b/src/tng/Makefile index 6b5e3bb3b6..4b050d6a6d 100644 --- a/src/tng/Makefile +++ b/src/tng/Makefile @@ -22,7 +22,7 @@ $(TARGET): $(OBJECTS) -$(DEL_FILE) $(TARGET) $(AR) $(TARGET) $(OBJECTS) -test: $(TARGET) tng_io_testing.o +test: $(TARGET) tng_io_testing.o tng_example.tng $(CC) -o a.out tng_io_testing.c $(TARGET) -lm $(ZLIB_FLAG) ./a.out From fb4b6c1fa0a469941a09367d43a67a8865b5873e Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 14:35:50 -0400 Subject: [PATCH 11/77] Have clean rule remove test output as well. --- src/tng/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tng/Makefile b/src/tng/Makefile index 4b050d6a6d..9310dfb911 100644 --- a/src/tng/Makefile +++ b/src/tng/Makefile @@ -27,7 +27,7 @@ test: $(TARGET) tng_io_testing.o tng_example.tng ./a.out clean: - $(DEL_FILE) *.o $(TARGET) tng_io_testing.o a.out + $(DEL_FILE) *.o $(TARGET) tng_io_testing.o a.out tng_example_out.tng tng_test.tng uninstall: clean From cffff5eaeb8d67a32631ed11af3f0aff4e3ca571 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 14:49:22 -0400 Subject: [PATCH 12/77] DRR - Cpptraj: Start adding traj class for TNG --- src/Traj_TNG.cpp | 133 +++++++++++++++++++++++++++++++++++++++++ src/Traj_TNG.h | 41 +++++++++++++ src/TrajectoryFile.cpp | 6 ++ src/cpptrajdepend | 3 +- src/cpptrajfiles | 1 + 5 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 src/Traj_TNG.cpp create mode 100644 src/Traj_TNG.h diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp new file mode 100644 index 0000000000..a9036e699c --- /dev/null +++ b/src/Traj_TNG.cpp @@ -0,0 +1,133 @@ +#include "Traj_TNG.h" +#include "CpptrajStdio.h" + +/// CONSTRUCTOR +Traj_TNG::Traj_TNG() {} + +/** Identify trajectory format. File should be setup for READ */ +bool Traj_TNG::ID_TrajFormat(CpptrajFile& fileIn) { + + return false; +} + +/** Print trajectory info to stdout. */ +void Traj_TNG::Info() { + mprintf("is a "); +} + +/** Close file. */ +void Traj_TNG::closeTraj() { + +} + +// ----------------------------------------------------------------------------- +/** Open trajectory for reading. */ +int Traj_TNG::openTrajin() { + + return 0; +} + +/** Read help */ +void Traj_TNG::ReadHelp() { + +} + +/** Process read arguments. */ +int Traj_TNG::processReadArgs(ArgList& argIn) { + + return 0; +} + +/** Set up trajectory for reading. + * \return Number of frames in trajectory. + */ +int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) +{ + + return TRAJIN_ERR; +} + +/** Read specified trajectory frame. */ +int Traj_TNG::readFrame(int set, Frame& frameIn) { + + return 0; +} + +/** Read velocities from specified frame. */ +int Traj_TNG::readVelocity(int set, Frame& frameIn) { + + return 0; +} + +/** Read forces from specified frame. */ +int Traj_TNG::readForce(int set, Frame& frameIn) { + + return 0; +} + +// ----------------------------------------------------------------------------- +/** Write help. */ +void Traj_TNG::WriteHelp() { + +} + +/** Process write arguments. */ +int Traj_TNG::processWriteArgs(ArgList& argIn) { + + return 0; +} + +/** Set up trajectory for write. */ +int Traj_TNG::setupTrajout(FileName const& fname, Topology* trajParm, + CoordinateInfo const& cInfoIn, + int NframesToWrite, bool append) +{ + + return 1; +} + +/** Write specified trajectory frame. */ +int Traj_TNG::writeFrame(int set, Frame const& frameOut) { + + return 0; +} + +// ============================================================================= +#ifdef MPI +/** Open trajectory for reading in parallel. */ +int Traj_TNG::parallelOpenTrajin(Parallel::Comm const& commIn) { + return 1; +} + +/** Open trajectory for writing in parallel. */ +int Traj_TNG::parallelOpenTrajout(Parallel::Comm const& commIn) { + return 1; +} + +/** Set up trajectory for write in parallel. */ +int Traj_TNG::parallelSetupTrajout(FileName const& fname, Topology* trajParm, + CoordinateInfo const& cInfoIn, + int NframesToWrite, bool append, + Parallel::Comm const& commIn) +{ + + return 1; +} + +/** Read frame in parallel. */ +int Traj_TNG::parallelReadFrame(int set, Frame& frameIn) { + + return 1; +} + +/** Write frame in parallel. */ +int Traj_TNG::parallelWriteFrame(int set, Frame const& frameOut) { + + return 1; +} + +/** Close trajectory in parallel. */ +void Traj_TNG::parallelCloseTraj() { + +} +#endif diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h new file mode 100644 index 0000000000..f5d5476687 --- /dev/null +++ b/src/Traj_TNG.h @@ -0,0 +1,41 @@ +#ifndef INC_TRAJ_TNG_H +#define INC_TRAJ_TNG_H +#include "TrajectoryIO.h" +#ifndef NO_TNGFILE +# include +#endif +/// Read Gromacs TNG trajectories +class Traj_TNG : public TrajectoryIO { + public: + Traj_TNG(); + static BaseIOtype* Alloc() { return (BaseIOtype*)new Traj_TNG(); } + static void WriteHelp(); + static void ReadHelp(); + private: + // ----- Inherited functions ----------------- + bool ID_TrajFormat(CpptrajFile&); + int setupTrajin(FileName const&, Topology*); + int setupTrajout(FileName const&, Topology*, CoordinateInfo const&,int, bool); + int openTrajin(); + void closeTraj(); + int readFrame(int,Frame&); + int writeFrame(int,Frame const&); + void Info(); + int readVelocity(int, Frame&); + int readForce(int, Frame&); + int processWriteArgs(ArgList&); + int processReadArgs(ArgList&); + // ------------------------------------------- +# ifdef MPI + // ----- Parallel functions ------------------ + int parallelOpenTrajin(Parallel::Comm const&); + int parallelOpenTrajout(Parallel::Comm const&); + int parallelSetupTrajout(FileName const&, Topology*, CoordinateInfo const&, + int, bool, Parallel::Comm const&); + int parallelReadFrame(int, Frame&); + int parallelWriteFrame(int, Frame const&); + void parallelCloseTraj(); + // ------------------------------------------- +# endif +}; +#endif diff --git a/src/TrajectoryFile.cpp b/src/TrajectoryFile.cpp index c47cee71cc..58d509a023 100644 --- a/src/TrajectoryFile.cpp +++ b/src/TrajectoryFile.cpp @@ -23,6 +23,7 @@ #include "Traj_GmxXtc.h" #include "Traj_CharmmRestart.h" #include "Traj_XYZ.h" +#include "Traj_TNG.h" // ----- STATIC VARS / ROUTINES ------------------------------------------------ // NOTE: Must be in same order as TrajFormatType @@ -49,6 +50,11 @@ const FileTypes::AllocToken TrajectoryFile::TF_AllocArray[] = { { "Gromacs XTC", 0, 0, 0 }, # else { "Gromacs XTC", 0, Traj_GmxXtc::WriteHelp, Traj_GmxXtc::Alloc }, +# endif +# ifdef NO_TRRFILE + { "Gromacs TNG", 0, 0, 0 }, +# else + { "Gromacs TNG", 0, 0, Traj_TNG::Alloc }, # endif { "BINPOS", 0, 0, Traj_Binpos::Alloc }, { "Amber Restart", Traj_AmberRestart::ReadHelp, Traj_AmberRestart::WriteHelp, Traj_AmberRestart::Alloc }, diff --git a/src/cpptrajdepend b/src/cpptrajdepend index 83f099c656..6b64b8f66b 100644 --- a/src/cpptrajdepend +++ b/src/cpptrajdepend @@ -362,9 +362,10 @@ Traj_NcEnsemble.o : Traj_NcEnsemble.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h Traj_PDBfile.o : Traj_PDBfile.cpp ArgList.h AssociatedData.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataSet.h DataSetList.h DataSet_1D.h DataSet_Coords.h DataSet_Coords_REF.h Dimension.h DistRoutines.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h PDBfile.h Parallel.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h SymbolExporting.h TextFormat.h Timer.h Topology.h Traj_PDBfile.h TrajectoryIO.h Vec3.h Traj_SDF.o : Traj_SDF.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SDFfile.h SymbolExporting.h Topology.h Traj_SDF.h TrajectoryIO.h Vec3.h Traj_SQM.o : Traj_SQM.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h StringRoutines.h SymbolExporting.h Topology.h Traj_SQM.h TrajectoryIO.h Vec3.h +Traj_TNG.o : Traj_TNG.cpp BaseIOtype.h Box.h CoordinateInfo.h CpptrajStdio.h FramePtrArray.h Matrix_3x3.h Parallel.h ReplicaDimArray.h Traj_TNG.h TrajectoryIO.h Vec3.h Traj_Tinker.o : Traj_Tinker.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedLine.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h TinkerFile.h Topology.h Traj_Tinker.h TrajectoryIO.h Vec3.h Traj_XYZ.o : Traj_XYZ.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedLine.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h StringRoutines.h SymbolExporting.h TextFormat.h Topology.h Traj_XYZ.h TrajectoryIO.h Vec3.h -TrajectoryFile.o : TrajectoryFile.cpp ArgList.h Atom.h AtomMask.h BaseIOtype.h Box.h BufferedFrame.h BufferedLine.h CIFfile.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h FileTypes.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Mol2File.h Molecule.h NameType.h NetcdfFile.h PDBfile.h Parallel.h ReplicaDimArray.h Residue.h SDFfile.h SymbolExporting.h TextFormat.h TinkerFile.h Traj_AmberCoord.h Traj_AmberNetcdf.h Traj_AmberRestart.h Traj_AmberRestartNC.h Traj_Binpos.h Traj_CIF.h Traj_CharmmCor.h Traj_CharmmDcd.h Traj_CharmmRestart.h Traj_Conflib.h Traj_GmxTrX.h Traj_GmxXtc.h Traj_Gro.h Traj_Mol2File.h Traj_NcEnsemble.h Traj_PDBfile.h Traj_SDF.h Traj_SQM.h Traj_Tinker.h Traj_XYZ.h TrajectoryFile.h TrajectoryIO.h Vec3.h +TrajectoryFile.o : TrajectoryFile.cpp ArgList.h Atom.h AtomMask.h BaseIOtype.h Box.h BufferedFrame.h BufferedLine.h CIFfile.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h FileTypes.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Mol2File.h Molecule.h NameType.h NetcdfFile.h PDBfile.h Parallel.h ReplicaDimArray.h Residue.h SDFfile.h SymbolExporting.h TextFormat.h TinkerFile.h Traj_AmberCoord.h Traj_AmberNetcdf.h Traj_AmberRestart.h Traj_AmberRestartNC.h Traj_Binpos.h Traj_CIF.h Traj_CharmmCor.h Traj_CharmmDcd.h Traj_CharmmRestart.h Traj_Conflib.h Traj_GmxTrX.h Traj_GmxXtc.h Traj_Gro.h Traj_Mol2File.h Traj_NcEnsemble.h Traj_PDBfile.h Traj_SDF.h Traj_SQM.h Traj_TNG.h Traj_Tinker.h Traj_XYZ.h TrajectoryFile.h TrajectoryIO.h Vec3.h TrajectoryIO.o : TrajectoryIO.cpp BaseIOtype.h Box.h CoordinateInfo.h FramePtrArray.h Matrix_3x3.h Parallel.h ReplicaDimArray.h TrajectoryIO.h Vec3.h TrajinList.o : TrajinList.cpp ArgList.h AssociatedData.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataSet.h DataSet_RemLog.h Dimension.h EnsembleIn.h EnsembleIn_Multi.h EnsembleIn_Single.h FileIO.h FileName.h FileTypes.h Frame.h FramePtrArray.h InputTrajCommon.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h ReplicaInfo.h Residue.h StringRoutines.h SymbolExporting.h TextFormat.h Timer.h Topology.h TrajFrameCounter.h TrajIOarray.h TrajectoryFile.h TrajectoryIO.h Trajin.h TrajinList.h Trajin_Multi.h Trajin_Single.h Vec3.h Trajin_Multi.o : Trajin_Multi.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajStdio.h FileName.h Frame.h FramePtrArray.h InputTrajCommon.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h ReplicaInfo.h Residue.h StringRoutines.h SymbolExporting.h Topology.h TrajFrameCounter.h TrajIOarray.h TrajectoryIO.h Trajin.h Trajin_Multi.h Vec3.h diff --git a/src/cpptrajfiles b/src/cpptrajfiles index a29bf7dfe6..727900e5a4 100644 --- a/src/cpptrajfiles +++ b/src/cpptrajfiles @@ -359,6 +359,7 @@ COMMON_SOURCES= \ Traj_SDF.cpp \ Traj_SQM.cpp \ Traj_Tinker.cpp \ + Traj_TNG.cpp \ Traj_XYZ.cpp \ TrajectoryFile.cpp \ TrajectoryIO.cpp \ From 88c5bb39e543230e8625a99df93f6a3e0e76cbe2 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 14:52:17 -0400 Subject: [PATCH 13/77] Change libtngfile to libtng --- src/tng/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tng/Makefile b/src/tng/Makefile index 9310dfb911..cfa7232d8a 100644 --- a/src/tng/Makefile +++ b/src/tng/Makefile @@ -6,7 +6,7 @@ CFLAGS += -I . # Variables DEL_FILE = /bin/rm -f AR = ar cqs -TARGET = libtngfile.a +TARGET = libtng.a # Source files SOURCES=md5.c tng_io.c tng_compress.c coder.c warnmalloc.c fixpoint.c xtc3.c bwlzh.c xtc2.c widemuldiv.c huffmem.c vals16.c bwt.c mtf.c rle.c lz77.c dict.c huffman.c merge_sort.c From 847d101df5e4241c7a2a011d7c76e421edc0d70d Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 15:00:43 -0400 Subject: [PATCH 14/77] DRR - Cpptraj: Add TNG stuff to configure --- configure | 18 +++++++++++++++++- src/Traj_TNG.cpp | 2 ++ src/Traj_TNG.h | 4 ++-- src/TrajectoryFile.cpp | 2 +- 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/configure b/configure index 46dd549250..272d206da6 100755 --- a/configure +++ b/configure @@ -142,7 +142,7 @@ CPPTRAJLIB='' # ----- External Libraries ----------------------- # Total number of external libraries -NLIB=13 +NLIB=14 # Library indices # Original: FFT ARPACK LAPACK BLAS NETCDF PARANC BZIP ZIP READLINE XDRFILE LNETCDF=0 @@ -158,6 +158,7 @@ LXDRFILE=9 LSANDER=10 LTIMER=11 LCUDA=12 +LTNGFILE=13 # LIB_STAT = Library status: # off : Do not use library. @@ -281,6 +282,15 @@ LIB_D_ON[$LCUDA]='-DCUDA' LIB_DOFF[$LCUDA]='' LIB_TYPE[$LCUDA]='cpp' +LIB_STAT[$LTNGFILE]='bundled' +LIB_CKEY[$LTNGFILE]='tng' +LIB_HOME[$LTNGFILE]='tng' +LIB_FLAG[$LTNGFILE]='-ltng' +LIB_STTC[$LTNGFILE]='libtng.a' +LIB_D_ON[$LTNGFILE]='' +LIB_DOFF[$LTNGFILE]='-DNO_TNGFILE' +LIB_TYPE[$LTNGFILE]='ld' + for ((i=0; i < $NLIB; i++)) ; do LIB_LINK[$i]='dynamic' done @@ -2044,6 +2054,10 @@ if [ "${LIB_STAT[$LXDRFILE]}" = 'bundled' ] ; then else XDRFILE_TARGET='noxdrfile' fi +# TNG +if [ "${LIB_STAT[$LTNGFILE]}" = 'bundled' ] ; then + TNGFILE_TARGET=${LIB_FLAG[$LTNGFILE]} +fi # Arpack if [ "${LIB_STAT[$LARPACK]}" = 'bundled' ] ; then ARPACK_TARGET=${LIB_FLAG[$LARPACK]} @@ -2091,6 +2105,8 @@ READLINE_LIB=${LIB_FLAG[$LREADLINE]} XDRFILE_TARGET=$XDRFILE_TARGET +TNGFILE_TARGET=$TNGFILE_TARGET + ARPACK_TARGET=$ARPACK_TARGET FFT_TARGET=$FFT_TARGET diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index a9036e699c..fdd9c360b5 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -1,3 +1,4 @@ +#ifndef NO_TNGFILE #include "Traj_TNG.h" #include "CpptrajStdio.h" @@ -131,3 +132,4 @@ void Traj_TNG::parallelCloseTraj() { } #endif +#endif /* NO_TNGFILE */ diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index f5d5476687..9e6f51d41c 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -1,9 +1,8 @@ #ifndef INC_TRAJ_TNG_H #define INC_TRAJ_TNG_H -#include "TrajectoryIO.h" #ifndef NO_TNGFILE +#include "TrajectoryIO.h" # include -#endif /// Read Gromacs TNG trajectories class Traj_TNG : public TrajectoryIO { public: @@ -38,4 +37,5 @@ class Traj_TNG : public TrajectoryIO { // ------------------------------------------- # endif }; +#endif /* NO_TNGFILE */ #endif diff --git a/src/TrajectoryFile.cpp b/src/TrajectoryFile.cpp index 58d509a023..fd860f7cf3 100644 --- a/src/TrajectoryFile.cpp +++ b/src/TrajectoryFile.cpp @@ -51,7 +51,7 @@ const FileTypes::AllocToken TrajectoryFile::TF_AllocArray[] = { # else { "Gromacs XTC", 0, Traj_GmxXtc::WriteHelp, Traj_GmxXtc::Alloc }, # endif -# ifdef NO_TRRFILE +# ifdef NO_TNGFILE { "Gromacs TNG", 0, 0, 0 }, # else { "Gromacs TNG", 0, 0, Traj_TNG::Alloc }, From 5c7df27282a7d607a3c32abe73eba1bf86157a98 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 15:08:59 -0400 Subject: [PATCH 15/77] Change tng to tng_io, seems to be what the actually library wants to be called. --- configure | 4 ++-- src/tng/Makefile | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 272d206da6..39fcdf93db 100755 --- a/configure +++ b/configure @@ -285,8 +285,8 @@ LIB_TYPE[$LCUDA]='cpp' LIB_STAT[$LTNGFILE]='bundled' LIB_CKEY[$LTNGFILE]='tng' LIB_HOME[$LTNGFILE]='tng' -LIB_FLAG[$LTNGFILE]='-ltng' -LIB_STTC[$LTNGFILE]='libtng.a' +LIB_FLAG[$LTNGFILE]='-ltng_io' +LIB_STTC[$LTNGFILE]='libtng_io.a' LIB_D_ON[$LTNGFILE]='' LIB_DOFF[$LTNGFILE]='-DNO_TNGFILE' LIB_TYPE[$LTNGFILE]='ld' diff --git a/src/tng/Makefile b/src/tng/Makefile index cfa7232d8a..d24a73f647 100644 --- a/src/tng/Makefile +++ b/src/tng/Makefile @@ -6,7 +6,7 @@ CFLAGS += -I . # Variables DEL_FILE = /bin/rm -f AR = ar cqs -TARGET = libtng.a +TARGET = libtng_io.a # Source files SOURCES=md5.c tng_io.c tng_compress.c coder.c warnmalloc.c fixpoint.c xtc3.c bwlzh.c xtc2.c widemuldiv.c huffmem.c vals16.c bwt.c mtf.c rle.c lz77.c dict.c huffman.c merge_sort.c From 9b35e59e5910c109cc3183b5f0ec7574d01e9131 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 15:14:09 -0400 Subject: [PATCH 16/77] Add missing stuff to Traj template --- devtools/Template.sh | 4 ++-- src/Traj_TNG.cpp | 2 +- src/Traj_TNG.h | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/devtools/Template.sh b/devtools/Template.sh index c7517dbe48..bbf82916b7 100755 --- a/devtools/Template.sh +++ b/devtools/Template.sh @@ -181,7 +181,7 @@ elif [ "$TYPE" = 'Traj' ] ; then void Info(); int readVelocity(int, Frame&); int readForce(int, Frame&); - int processWriteArgs(ArgList&); + int processWriteArgs(ArgList&, DataSetList const&); int processReadArgs(ArgList&); // ------------------------------------------- # ifdef MPI @@ -273,7 +273,7 @@ void $CLASS::WriteHelp() { } /** Process write arguments. */ -int $CLASS::processWriteArgs(ArgList& argIn) { +int $CLASS::processWriteArgs(ArgList& argIn, DataSetList const& DSLin) { return 0; } diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index fdd9c360b5..eccabcead3 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -73,7 +73,7 @@ void Traj_TNG::WriteHelp() { } /** Process write arguments. */ -int Traj_TNG::processWriteArgs(ArgList& argIn) { +int Traj_TNG::processWriteArgs(ArgList& argIn, DataSetList const& DSLin) { return 0; } diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index 9e6f51d41c..90d2d38625 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -22,7 +22,7 @@ class Traj_TNG : public TrajectoryIO { void Info(); int readVelocity(int, Frame&); int readForce(int, Frame&); - int processWriteArgs(ArgList&); + int processWriteArgs(ArgList&, DataSetList const&); int processReadArgs(ArgList&); // ------------------------------------------- # ifdef MPI @@ -36,6 +36,8 @@ class Traj_TNG : public TrajectoryIO { void parallelCloseTraj(); // ------------------------------------------- # endif + + tng_trajectory_t traj_; }; #endif /* NO_TNGFILE */ #endif From fa365049d76ebb84a76f53774711d84159e47f64 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 15:22:24 -0400 Subject: [PATCH 17/77] Add file open and number of atoms check --- src/Traj_TNG.cpp | 16 ++++++++++++++++ src/Traj_TNG.h | 1 + 2 files changed, 17 insertions(+) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index eccabcead3..af5039a6b7 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -1,6 +1,8 @@ #ifndef NO_TNGFILE #include "Traj_TNG.h" #include "CpptrajStdio.h" +#include "FileName.h" +#include "Topology.h" /// CONSTRUCTOR Traj_TNG::Traj_TNG() {} @@ -44,6 +46,20 @@ int Traj_TNG::processReadArgs(ArgList& argIn) { */ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) { + tng_function_status stat = tng_util_trajectory_open(fname.full(), 'r', &traj_); + if (stat != TNG_SUCCESS) { + mprinterr("Error: Could not open TNG file '%s'\n", fname.full()); + return TRAJIN_ERR; + } + + // Get number of atoms + tng_num_particles_get(traj_, &tngatoms_); + if (tngatoms_ != (long int)trajParm->Natom()) { + mprinterr("Error: Number of atoms in TNG file (%li) does not match number\n" + "Error: of atoms in associated topology (%i)\n", + tngatoms_, trajParm->Natom()); + return TRAJIN_ERR; + } return TRAJIN_ERR; } diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index 90d2d38625..dcf786f9c5 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -38,6 +38,7 @@ class Traj_TNG : public TrajectoryIO { # endif tng_trajectory_t traj_; + long int tngatoms_; }; #endif /* NO_TNGFILE */ #endif From 8b630e8f89ad065ce4e163191e1d5beba9fc8750 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 15:30:48 -0400 Subject: [PATCH 18/77] Add get number of frames from TNG --- src/Traj_TNG.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index af5039a6b7..79c7d3dd07 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -61,7 +61,12 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) return TRAJIN_ERR; } - return TRAJIN_ERR; + // Get number of frames + long int nframes; + tng_num_frames_get(traj_, &nframes); + mprintf("\tTNG file has %li frames.\n", nframes); + + return (int)nframes; } /** Read specified trajectory frame. */ From cf6fe7809dff2fe646df77adf3be8ce70f9f6375 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Mon, 7 Oct 2019 15:36:53 -0400 Subject: [PATCH 19/77] Add TNG link stuff --- configure | 2 ++ src/Makefile | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 39fcdf93db..2aca13adc7 100755 --- a/configure +++ b/configure @@ -2057,6 +2057,8 @@ fi # TNG if [ "${LIB_STAT[$LTNGFILE]}" = 'bundled' ] ; then TNGFILE_TARGET=${LIB_FLAG[$LTNGFILE]} +else + TNGFILE_TARGET='notngfile' fi # Arpack if [ "${LIB_STAT[$LARPACK]}" = 'bundled' ] ; then diff --git a/src/Makefile b/src/Makefile index d05679eac0..d0338a86ed 100644 --- a/src/Makefile +++ b/src/Makefile @@ -17,7 +17,7 @@ install: $(INSTALL_TARGETS) install_cpptraj: cpptraj$(SFX)$(EXE) mv cpptraj$(SFX)$(EXE) $(CPPTRAJBIN) -cpptraj$(SFX)$(EXE): $(OBJECTS) $(FFT_TARGET) $(READLINE_TARGET) $(CUDA_TARGET) $(XDRFILE_TARGET) $(ARPACK_TARGET) +cpptraj$(SFX)$(EXE): $(OBJECTS) $(FFT_TARGET) $(READLINE_TARGET) $(CUDA_TARGET) $(XDRFILE_TARGET) $(ARPACK_TARGET) $(TNGFILE_TARGET) $(CXX) -o cpptraj$(SFX)$(EXE) $(OBJECTS) $(CUDA_TARGET) $(FFT_TARGET) $(READLINE_LIB) $(CPPTRAJ_LIB) $(LDFLAGS) # libcpptraj --------------------------- @@ -27,7 +27,7 @@ cpptraj$(SFX)$(EXE): $(OBJECTS) $(FFT_TARGET) $(READLINE_TARGET) $(CUDA_TARGET) libcpptraj: $(LIBCPPTRAJ_TARGET) -$(CPPTRAJLIB)/libcpptraj$(SHARED_SUFFIX): $(LIBCPPTRAJ_OBJECTS) $(FFT_TARGET) $(CUDA_TARGET) $(XDRFILE_TARGET) $(ARPACK_TARGET) +$(CPPTRAJLIB)/libcpptraj$(SHARED_SUFFIX): $(LIBCPPTRAJ_OBJECTS) $(FFT_TARGET) $(CUDA_TARGET) $(XDRFILE_TARGET) $(ARPACK_TARGET) $(TNGFILE_TARGET) $(CXX) -shared -o $(CPPTRAJLIB)/libcpptraj$(SHARED_SUFFIX) $(LIBCPPTRAJ_OBJECTS) $(FFT_TARGET) $(CUDA_TARGET) $(CPPTRAJ_LIB) $(LDFLAGS) # Static libraries --------------------- @@ -82,6 +82,11 @@ noxdrfile: @echo "Skipping bundled XDRFILE build" @echo "" +notngfile: + @echo "" + @echo "Skipping bundled TNG build" + @echo "" + noarpack: @echo "" @echo "Skipping bundled ARPACK build" From 9e5df0495d2a756b5cc896bb5cf29cb5c8f658bc Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 08:46:36 -0400 Subject: [PATCH 20/77] Get TNG distance scaling factor --- src/Traj_TNG.cpp | 13 +++++++++++++ src/Traj_TNG.h | 5 +++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 79c7d3dd07..c3363f4753 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -1,4 +1,5 @@ #ifndef NO_TNGFILE +#include #include "Traj_TNG.h" #include "CpptrajStdio.h" #include "FileName.h" @@ -66,6 +67,18 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) tng_num_frames_get(traj_, &nframes); mprintf("\tTNG file has %li frames.\n", nframes); + // Get the exponential distance scaling factor + long int tngexp; + if (tng_distance_unit_exponential_get(traj_, &tngexp) != TNG_SUCCESS) { + mprinterr("Error: Could not get distance scaling exponential from TNG.\n"); + return TRAJIN_ERR; + } + switch (tngexp) { + case 9 : tngfac_ = 1.0; break; + case 10 : tngfac_ = 10.0; break; + default : tngfac_ = pow(10.0, tngexp + 9); break; + } + return (int)nframes; } diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index dcf786f9c5..e38e532979 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -37,8 +37,9 @@ class Traj_TNG : public TrajectoryIO { // ------------------------------------------- # endif - tng_trajectory_t traj_; - long int tngatoms_; + tng_trajectory_t traj_; ///< The TNG trajectory file object + long int tngatoms_; ///< Number of atoms in the TNG trajectory file. + double tngfac_; ///< Coordinates scaling factor }; #endif /* NO_TNGFILE */ #endif From ba105f8b57d3d14fb4d476c4ee8e7bc545cac70f Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 08:59:35 -0400 Subject: [PATCH 21/77] Ensure conversion to Angstroms --- src/Traj_TNG.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index c3363f4753..8965b169bf 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -73,11 +73,23 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) mprinterr("Error: Could not get distance scaling exponential from TNG.\n"); return TRAJIN_ERR; } + mprintf("\tTNG exponential: %li\n", tngexp); switch (tngexp) { - case 9 : tngfac_ = 1.0; break; - case 10 : tngfac_ = 10.0; break; - default : tngfac_ = pow(10.0, tngexp + 9); break; + case 9 : + // Input is in nm. Convert to Angstroms. + //tngfac_ = 1.0; + tngfac_ = 0.1; + break; + case 10 : + // Input is in Angstroms. + //tngfac_ = 10.0; + tngfac_ = 1.0; + break; + default : + // Convert to Angstroms. + tngfac_ = pow(10.0, tngexp + 10); break; } + mprintf("\tTNG distance scaling factor: %g\n", tngfac_); return (int)nframes; } From a593d9dadae2251693fad407511f7f0719812242 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 09:20:33 -0400 Subject: [PATCH 22/77] Use the same types defined in the TNG headers --- src/Traj_TNG.cpp | 6 +++--- src/Traj_TNG.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 8965b169bf..6e78f3e2d5 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -55,7 +55,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) // Get number of atoms tng_num_particles_get(traj_, &tngatoms_); - if (tngatoms_ != (long int)trajParm->Natom()) { + if (tngatoms_ != (int64_t)trajParm->Natom()) { mprinterr("Error: Number of atoms in TNG file (%li) does not match number\n" "Error: of atoms in associated topology (%i)\n", tngatoms_, trajParm->Natom()); @@ -63,12 +63,12 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) } // Get number of frames - long int nframes; + int64_t nframes; tng_num_frames_get(traj_, &nframes); mprintf("\tTNG file has %li frames.\n", nframes); // Get the exponential distance scaling factor - long int tngexp; + int64_t tngexp; if (tng_distance_unit_exponential_get(traj_, &tngexp) != TNG_SUCCESS) { mprinterr("Error: Could not get distance scaling exponential from TNG.\n"); return TRAJIN_ERR; diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index e38e532979..cdf77e7299 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -38,7 +38,7 @@ class Traj_TNG : public TrajectoryIO { # endif tng_trajectory_t traj_; ///< The TNG trajectory file object - long int tngatoms_; ///< Number of atoms in the TNG trajectory file. + int64_t tngatoms_; ///< Number of atoms in the TNG trajectory file. double tngfac_; ///< Coordinates scaling factor }; #endif /* NO_TNGFILE */ From 5344fca02dd40b8b637ff932ef452451b438058e Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 10:42:27 -0400 Subject: [PATCH 23/77] Add code to try to get TNG box status --- src/Traj_TNG.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 6e78f3e2d5..74433264f9 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -91,6 +91,17 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) } mprintf("\tTNG distance scaling factor: %g\n", tngfac_); + // Get box status + float *boxptr = 0; + int64_t stride; + if (tng_util_box_shape_read(traj_, &boxptr, &stride) == TNG_SUCCESS) { + mprintf("\tBox shape:"); + for (unsigned int i = 0; i < 9; i++) // NOTE: Should get vector length? + mprintf(" %f", boxptr[i]); + mprintf("\n"); + delete boxptr; + } + return (int)nframes; } From 77539c024a45fcee031852fb8b2ee697f2b9999c Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 11:22:14 -0400 Subject: [PATCH 24/77] Add TNG trajectory close and destructor --- src/Traj_TNG.cpp | 9 +++++++-- src/Traj_TNG.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 74433264f9..05ee211c56 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -8,6 +8,11 @@ /// CONSTRUCTOR Traj_TNG::Traj_TNG() {} +/// DESTRUCTOR +Traj_TNG::~Traj_TNG() { + closeTraj(); +} + /** Identify trajectory format. File should be setup for READ */ bool Traj_TNG::ID_TrajFormat(CpptrajFile& fileIn) { @@ -16,12 +21,12 @@ bool Traj_TNG::ID_TrajFormat(CpptrajFile& fileIn) { /** Print trajectory info to stdout. */ void Traj_TNG::Info() { - mprintf("is a "); + mprintf("is a GROMACS TNG file"); } /** Close file. */ void Traj_TNG::closeTraj() { - + tng_util_trajectory_close(&traj_); } // ----------------------------------------------------------------------------- diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index cdf77e7299..ab54e7fdb3 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -7,6 +7,7 @@ class Traj_TNG : public TrajectoryIO { public: Traj_TNG(); + ~Traj_TNG(); static BaseIOtype* Alloc() { return (BaseIOtype*)new Traj_TNG(); } static void WriteHelp(); static void ReadHelp(); From 3e62e7a441abba3af0146ebd32adf50db10b3eb8 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 12:51:12 -0400 Subject: [PATCH 25/77] Since the TNG API doesn't seem to have a simple way of telling if a given file is TNG or not, look for the 'GENERAL INFO' block in the first 52 bytes. Keep track of file open status since calling the TNG close routine on a TNG file that is not open results in a segfault. --- src/Traj_TNG.cpp | 33 +++++++++++++++++++++++++++++---- src/Traj_TNG.h | 1 + src/cpptrajdepend | 2 +- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 05ee211c56..017cf02f52 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -1,20 +1,41 @@ #ifndef NO_TNGFILE -#include +#include //pow +#include //strncmp #include "Traj_TNG.h" #include "CpptrajStdio.h" #include "FileName.h" #include "Topology.h" +#include "CpptrajFile.h" /// CONSTRUCTOR -Traj_TNG::Traj_TNG() {} +Traj_TNG::Traj_TNG() : + tngatoms_(0), + tngfac_(0), + isOpen_(false) +{} /// DESTRUCTOR Traj_TNG::~Traj_TNG() { closeTraj(); } -/** Identify trajectory format. File should be setup for READ */ +/** Identify trajectory format. File should be setup for READ. + * Note that as of version 1.8.2 the TNG library routines provide + * no straightforward way to confirm that a file is indeed a TNG + * file; providing a non-TNG file to the routines results in lots + * of memory errors. Therefore, relying on the fact that the + * 'GENERAL INFO' block should be present in all TNG files, and that + * that string seems to always be in bytes 40-51. + */ bool Traj_TNG::ID_TrajFormat(CpptrajFile& fileIn) { + char tngheader[52]; + if (fileIn.OpenFile()) return false; + if (fileIn.Read(&tngheader, 52) != 52) return false; + fileIn.CloseFile(); + if (strncmp(tngheader+40, "GENERAL INFO", 12)==0) { + mprintf("DEBUG: TNG file.\n"); + return true; + } return false; } @@ -26,7 +47,10 @@ void Traj_TNG::Info() { /** Close file. */ void Traj_TNG::closeTraj() { - tng_util_trajectory_close(&traj_); + if (isOpen_) { + tng_util_trajectory_close(&traj_); + } + isOpen_ = false; } // ----------------------------------------------------------------------------- @@ -57,6 +81,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) mprinterr("Error: Could not open TNG file '%s'\n", fname.full()); return TRAJIN_ERR; } + isOpen_ = true; // Get number of atoms tng_num_particles_get(traj_, &tngatoms_); diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index ab54e7fdb3..37eb6acf4d 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -41,6 +41,7 @@ class Traj_TNG : public TrajectoryIO { tng_trajectory_t traj_; ///< The TNG trajectory file object int64_t tngatoms_; ///< Number of atoms in the TNG trajectory file. double tngfac_; ///< Coordinates scaling factor + bool isOpen_; ///< Calling the TNG library close routine if file is not open is an error, so keep track ourselves. }; #endif /* NO_TNGFILE */ #endif diff --git a/src/cpptrajdepend b/src/cpptrajdepend index 6b64b8f66b..4b111c0f0b 100644 --- a/src/cpptrajdepend +++ b/src/cpptrajdepend @@ -362,7 +362,7 @@ Traj_NcEnsemble.o : Traj_NcEnsemble.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h Traj_PDBfile.o : Traj_PDBfile.cpp ArgList.h AssociatedData.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataSet.h DataSetList.h DataSet_1D.h DataSet_Coords.h DataSet_Coords_REF.h Dimension.h DistRoutines.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h PDBfile.h Parallel.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h SymbolExporting.h TextFormat.h Timer.h Topology.h Traj_PDBfile.h TrajectoryIO.h Vec3.h Traj_SDF.o : Traj_SDF.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SDFfile.h SymbolExporting.h Topology.h Traj_SDF.h TrajectoryIO.h Vec3.h Traj_SQM.o : Traj_SQM.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h StringRoutines.h SymbolExporting.h Topology.h Traj_SQM.h TrajectoryIO.h Vec3.h -Traj_TNG.o : Traj_TNG.cpp BaseIOtype.h Box.h CoordinateInfo.h CpptrajStdio.h FramePtrArray.h Matrix_3x3.h Parallel.h ReplicaDimArray.h Traj_TNG.h TrajectoryIO.h Vec3.h +Traj_TNG.o : Traj_TNG.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_TNG.h TrajectoryIO.h Vec3.h Traj_Tinker.o : Traj_Tinker.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedLine.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h TinkerFile.h Topology.h Traj_Tinker.h TrajectoryIO.h Vec3.h Traj_XYZ.o : Traj_XYZ.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedLine.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h StringRoutines.h SymbolExporting.h TextFormat.h Topology.h Traj_XYZ.h TrajectoryIO.h Vec3.h TrajectoryFile.o : TrajectoryFile.cpp ArgList.h Atom.h AtomMask.h BaseIOtype.h Box.h BufferedFrame.h BufferedLine.h CIFfile.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h FileTypes.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Mol2File.h Molecule.h NameType.h NetcdfFile.h PDBfile.h Parallel.h ReplicaDimArray.h Residue.h SDFfile.h SymbolExporting.h TextFormat.h TinkerFile.h Traj_AmberCoord.h Traj_AmberNetcdf.h Traj_AmberRestart.h Traj_AmberRestartNC.h Traj_Binpos.h Traj_CIF.h Traj_CharmmCor.h Traj_CharmmDcd.h Traj_CharmmRestart.h Traj_Conflib.h Traj_GmxTrX.h Traj_GmxXtc.h Traj_Gro.h Traj_Mol2File.h Traj_NcEnsemble.h Traj_PDBfile.h Traj_SDF.h Traj_SQM.h Traj_TNG.h Traj_Tinker.h Traj_XYZ.h TrajectoryFile.h TrajectoryIO.h Vec3.h From df9aa70aef8c6c87eef002e82ecd29dabfce17be Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 13:54:54 -0400 Subject: [PATCH 26/77] Fix up TNG build and clean in Makefile --- src/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Makefile b/src/Makefile index d0338a86ed..61662fc546 100644 --- a/src/Makefile +++ b/src/Makefile @@ -72,6 +72,9 @@ xdrfile/libxdrfile.a: ../external.config.h arpack/libarpack.a: ../external.config.h cd arpack && $(MAKE) install +tng/libtng_io.a: ../external.config.h + cd tng && $(MAKE) all + noreadline: @echo "" @echo "Skipping bundled READLINE build" @@ -112,6 +115,7 @@ clean: cd xdrfile && $(MAKE) clean cd arpack && $(MAKE) clean cd cuda_kernels && $(MAKE) clean + cd tng && $(MAKE) clean uninstall: $(DEL_FILE) $(CPPTRAJBIN)/cpptraj$(SFX)$(EXE) From 868a1f43e81b4418afdb9d7969f8372c0b51d4e0 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 13:55:30 -0400 Subject: [PATCH 27/77] Fix up TNG box detection. --- src/Traj_TNG.cpp | 27 ++++++++++++++++++++++----- src/Traj_TNG.h | 2 ++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 017cf02f52..330ea302d4 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -71,6 +71,12 @@ int Traj_TNG::processReadArgs(ArgList& argIn) { return 0; } +/* Utility function for properly scaling coordinates according to the factor. */ +void Traj_TNG::convertArray(double* out, float* in, unsigned int nvals) const { + for (unsigned int i = 0; i != nvals; i++) + out[i] = ((double)in[i]) * tngfac_; +} + /** Set up trajectory for reading. * \return Number of frames in trajectory. */ @@ -122,16 +128,27 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) mprintf("\tTNG distance scaling factor: %g\n", tngfac_); // Get box status - float *boxptr = 0; - int64_t stride; - if (tng_util_box_shape_read(traj_, &boxptr, &stride) == TNG_SUCCESS) { + Matrix_3x3 boxShape(0.0); + float* boxptr = 0; + int64_t stride = 0; + stat = tng_util_box_shape_read_range(traj_, 0, 0, &boxptr, &stride); + mprintf("DEBUG: Box Stride: %li\n", stride); + if (stat == TNG_FAILURE) + mprintf("DEBUG: Box minor error.\n"); + else if (stat == TNG_CRITICAL) + mprintf("DEBUG: Box major error.\n"); + else if (stat == TNG_SUCCESS) { + convertArray(boxShape.Dptr(), boxptr, 9); mprintf("\tBox shape:"); for (unsigned int i = 0; i < 9; i++) // NOTE: Should get vector length? - mprintf(" %f", boxptr[i]); + { + mprintf(" %f", boxShape[i]); + } mprintf("\n"); - delete boxptr; } + SetCoordInfo( CoordinateInfo( Box(boxShape), false, false, false ) ); + return (int)nframes; } diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index 37eb6acf4d..a87872ecc4 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -38,6 +38,8 @@ class Traj_TNG : public TrajectoryIO { // ------------------------------------------- # endif + void convertArray(double*, float*, unsigned int) const; + tng_trajectory_t traj_; ///< The TNG trajectory file object int64_t tngatoms_; ///< Number of atoms in the TNG trajectory file. double tngfac_; ///< Coordinates scaling factor From 46bcc3c4449079cb7226cf8ee1d13471fb45a989 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 14:00:20 -0400 Subject: [PATCH 28/77] Properly free memory allocated for box detection. --- src/Traj_TNG.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 330ea302d4..bd63bdc51a 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -1,6 +1,7 @@ #ifndef NO_TNGFILE -#include //pow -#include //strncmp +#include // pow +#include // strncmp +#include // free #include "Traj_TNG.h" #include "CpptrajStdio.h" #include "FileName.h" @@ -133,11 +134,10 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) int64_t stride = 0; stat = tng_util_box_shape_read_range(traj_, 0, 0, &boxptr, &stride); mprintf("DEBUG: Box Stride: %li\n", stride); - if (stat == TNG_FAILURE) - mprintf("DEBUG: Box minor error.\n"); - else if (stat == TNG_CRITICAL) - mprintf("DEBUG: Box major error.\n"); - else if (stat == TNG_SUCCESS) { + if (stat == TNG_CRITICAL) { + mprinterr("Error: Major error encountered reading TNG box.\n"); + return TRAJIN_ERR; + } else if (stat == TNG_SUCCESS) { convertArray(boxShape.Dptr(), boxptr, 9); mprintf("\tBox shape:"); for (unsigned int i = 0; i < 9; i++) // NOTE: Should get vector length? @@ -146,6 +146,8 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) } mprintf("\n"); } + // NOTE: Use free here since thats what underlying TNG library does + if (boxptr != 0) free( boxptr ); SetCoordInfo( CoordinateInfo( Box(boxShape), false, false, false ) ); From bff43016c5cef96889d9070e6f0215ce3f15aa0f Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 14:04:27 -0400 Subject: [PATCH 29/77] Add TNG velocity detection. --- src/Traj_TNG.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index bd63bdc51a..9cfe6b8111 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -128,14 +128,27 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) } mprintf("\tTNG distance scaling factor: %g\n", tngfac_); + // Check if there are velocities + float* ftmp = 0; + int64_t stride = 0; + bool hasVel = false; + stat = tng_util_vel_read_range(traj_, 0, 0, &ftmp, &stride); + mprintf("DEBUG: Velocity stride: %li\n", stride); + if (stat == TNG_CRITICAL) { + mprinterr("Error: Major error encountered checking TNG velocities.\n"); + return TRAJIN_ERR; + } else if (stat == TNG_SUCCESS) { + hasVel = true; + } + if (ftmp != 0) free( ftmp ); + // Get box status Matrix_3x3 boxShape(0.0); float* boxptr = 0; - int64_t stride = 0; stat = tng_util_box_shape_read_range(traj_, 0, 0, &boxptr, &stride); mprintf("DEBUG: Box Stride: %li\n", stride); if (stat == TNG_CRITICAL) { - mprinterr("Error: Major error encountered reading TNG box.\n"); + mprinterr("Error: Major error encountered checking TNG box.\n"); return TRAJIN_ERR; } else if (stat == TNG_SUCCESS) { convertArray(boxShape.Dptr(), boxptr, 9); @@ -149,7 +162,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) // NOTE: Use free here since thats what underlying TNG library does if (boxptr != 0) free( boxptr ); - SetCoordInfo( CoordinateInfo( Box(boxShape), false, false, false ) ); + SetCoordInfo( CoordinateInfo( Box(boxShape), hasVel, false, false ) ); return (int)nframes; } From 7caa2b62422d759e1f8447eb45f3757374c3546e Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 14:10:42 -0400 Subject: [PATCH 30/77] Clean up TNG exponential factor calc --- src/Traj_TNG.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 9cfe6b8111..89f832cf46 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -112,14 +112,14 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) } mprintf("\tTNG exponential: %li\n", tngexp); switch (tngexp) { - case 9 : + case -9 : + mprintf("\tTNG has units of nm\n"); // Input is in nm. Convert to Angstroms. - //tngfac_ = 1.0; - tngfac_ = 0.1; + tngfac_ = 10.0; break; - case 10 : + case -10 : + mprintf("\tTNG has units of Angstrom\n"); // Input is in Angstroms. - //tngfac_ = 10.0; tngfac_ = 1.0; break; default : @@ -153,7 +153,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) } else if (stat == TNG_SUCCESS) { convertArray(boxShape.Dptr(), boxptr, 9); mprintf("\tBox shape:"); - for (unsigned int i = 0; i < 9; i++) // NOTE: Should get vector length? + for (unsigned int i = 0; i < 9; i++) { mprintf(" %f", boxShape[i]); } From 1d557a85b7d471c226de163ac9bcb42ebdb209be Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 14:15:43 -0400 Subject: [PATCH 31/77] Allocate a temp coords array for TNG --- src/Traj_TNG.cpp | 9 ++++++--- src/Traj_TNG.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 89f832cf46..e6e9e7c5ac 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -10,6 +10,7 @@ /// CONSTRUCTOR Traj_TNG::Traj_TNG() : + ftmp_(0), tngatoms_(0), tngfac_(0), isOpen_(false) @@ -18,6 +19,7 @@ Traj_TNG::Traj_TNG() : /// DESTRUCTOR Traj_TNG::~Traj_TNG() { closeTraj(); + if (ftmp_ != 0) delete[] ftmp_; } /** Identify trajectory format. File should be setup for READ. @@ -128,11 +130,13 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) } mprintf("\tTNG distance scaling factor: %g\n", tngfac_); + // Allocate coords temp memory + if (ftmp_ != 0) delete[] ftmp_; + ftmp_ = new float[ 3*tngatoms_ ]; // Check if there are velocities - float* ftmp = 0; int64_t stride = 0; bool hasVel = false; - stat = tng_util_vel_read_range(traj_, 0, 0, &ftmp, &stride); + stat = tng_util_vel_read_range(traj_, 0, 0, &ftmp_, &stride); mprintf("DEBUG: Velocity stride: %li\n", stride); if (stat == TNG_CRITICAL) { mprinterr("Error: Major error encountered checking TNG velocities.\n"); @@ -140,7 +144,6 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) } else if (stat == TNG_SUCCESS) { hasVel = true; } - if (ftmp != 0) free( ftmp ); // Get box status Matrix_3x3 boxShape(0.0); diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index a87872ecc4..56058a54b9 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -41,6 +41,7 @@ class Traj_TNG : public TrajectoryIO { void convertArray(double*, float*, unsigned int) const; tng_trajectory_t traj_; ///< The TNG trajectory file object + float* ftmp_; ///< Temporary array for reading in coordinates int64_t tngatoms_; ///< Number of atoms in the TNG trajectory file. double tngfac_; ///< Coordinates scaling factor bool isOpen_; ///< Calling the TNG library close routine if file is not open is an error, so keep track ourselves. From cbd34f7a89307e598762721701a074af15bd8843 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 14:28:09 -0400 Subject: [PATCH 32/77] Start trying to add TNG read. Currently only works for a single frame. --- src/Traj_TNG.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index e6e9e7c5ac..e739bf544f 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -172,7 +172,26 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) /** Read specified trajectory frame. */ int Traj_TNG::readFrame(int set, Frame& frameIn) { + int64_t stride; + // Read coordinates + if ( tng_util_pos_read_range(traj_, set, set, &ftmp_, &stride) != TNG_SUCCESS ) { + mprinterr("Error: Could not read set %i for TNG file.\n", set+1); + return 1; + } + convertArray(frameIn.xAddress(), ftmp_, 3*tngatoms_); + if (CoordInfo().HasBox()) { + float* boxptr = 0; + if (tng_util_box_shape_read_range(traj_, set, set, &boxptr, &stride) != TNG_SUCCESS) { + mprinterr("Error: Could not read set %i box for TNG file.\n", set+1); + return 1; + } + Matrix_3x3 boxShape(0.0); + convertArray(boxShape.Dptr(), boxptr, 9); + frameIn.SetBox( Box(boxShape) ); + free( boxptr ); + } + return 0; } From 7143a4dcd92027f810e3aa3b7373aad267d04bce Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 15:22:22 -0400 Subject: [PATCH 33/77] Fix up TNG openTrajin function --- src/Traj_TNG.cpp | 20 +++++++++++++------- src/Traj_TNG.h | 4 +++- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index e739bf544f..d5a59f9b77 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -59,6 +59,14 @@ void Traj_TNG::closeTraj() { // ----------------------------------------------------------------------------- /** Open trajectory for reading. */ int Traj_TNG::openTrajin() { + if (isOpen_) + closeTraj(); + tng_function_status stat = tng_util_trajectory_open(filename_.full(), 'r', &traj_); + if (stat != TNG_SUCCESS) { + mprinterr("Error: Could not open TNG file '%s'\n", filename_.full()); + return TRAJIN_ERR; + } + isOpen_ = true; return 0; } @@ -85,12 +93,8 @@ void Traj_TNG::convertArray(double* out, float* in, unsigned int nvals) const { */ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) { - tng_function_status stat = tng_util_trajectory_open(fname.full(), 'r', &traj_); - if (stat != TNG_SUCCESS) { - mprinterr("Error: Could not open TNG file '%s'\n", fname.full()); - return TRAJIN_ERR; - } - isOpen_ = true; + filename_ = fname; + openTrajin(); // Get number of atoms tng_num_particles_get(traj_, &tngatoms_); @@ -136,7 +140,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) // Check if there are velocities int64_t stride = 0; bool hasVel = false; - stat = tng_util_vel_read_range(traj_, 0, 0, &ftmp_, &stride); + tng_function_status stat = tng_util_vel_read_range(traj_, 0, 0, &ftmp_, &stride); mprintf("DEBUG: Velocity stride: %li\n", stride); if (stat == TNG_CRITICAL) { mprinterr("Error: Major error encountered checking TNG velocities.\n"); @@ -165,6 +169,8 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) // NOTE: Use free here since thats what underlying TNG library does if (boxptr != 0) free( boxptr ); + closeTraj(); + SetCoordInfo( CoordinateInfo( Box(boxShape), hasVel, false, false ) ); return (int)nframes; diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index 56058a54b9..cc7748ecec 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -1,8 +1,9 @@ #ifndef INC_TRAJ_TNG_H #define INC_TRAJ_TNG_H #ifndef NO_TNGFILE +#include #include "TrajectoryIO.h" -# include +#include "FileName.h" /// Read Gromacs TNG trajectories class Traj_TNG : public TrajectoryIO { public: @@ -45,6 +46,7 @@ class Traj_TNG : public TrajectoryIO { int64_t tngatoms_; ///< Number of atoms in the TNG trajectory file. double tngfac_; ///< Coordinates scaling factor bool isOpen_; ///< Calling the TNG library close routine if file is not open is an error, so keep track ourselves. + FileName filename_; ///< File name, for openTrajin }; #endif /* NO_TNGFILE */ #endif From 5bc2eec6c5ea46605c86e1032f9a0e78b5f52ef5 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Tue, 8 Oct 2019 15:42:39 -0400 Subject: [PATCH 34/77] Try a different way of reading. Does not seem to work. --- src/Traj_TNG.cpp | 32 +++++++++++++++++++++++++++++++- src/Traj_TNG.h | 4 ++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index d5a59f9b77..a2c6382639 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -12,6 +12,7 @@ Traj_TNG::Traj_TNG() : ftmp_(0), tngatoms_(0), + current_frame_(0), tngfac_(0), isOpen_(false) {} @@ -67,6 +68,7 @@ int Traj_TNG::openTrajin() { return TRAJIN_ERR; } isOpen_ = true; + current_frame_ = 0; return 0; } @@ -173,11 +175,39 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) SetCoordInfo( CoordinateInfo( Box(boxShape), hasVel, false, false ) ); + blockIds_.clear(); + if (CoordInfo().HasBox()) + blockIds_.push_back( TNG_TRAJ_BOX_SHAPE ); + blockIds_.push_back( TNG_TRAJ_POSITIONS ); + if (CoordInfo().HasVel()) + blockIds_.push_back( TNG_TRAJ_VELOCITIES ); + return (int)nframes; } /** Read specified trajectory frame. */ int Traj_TNG::readFrame(int set, Frame& frameIn) { + // Determine next frame with data + int64_t next_frame, n_data_blocks_in_next_frame, *block_ids_in_next_frame = 0; + tng_function_status stat = tng_util_trajectory_next_frame_present_data_blocks_find( + traj_, + current_frame_, + blockIds_.size(), + &blockIds_[0], + &next_frame, + &n_data_blocks_in_next_frame, + &block_ids_in_next_frame); + if (stat == TNG_CRITICAL) { + mprinterr("Error: could not get data blocks in next frame (set %i)\n", set+1); + return 1; + } + if (stat == TNG_FAILURE) { + mprintf("DEBUG: No more blocks.\n"); + return 1; + } + mprintf("DEBUG: Set %i next_frame %li nblocksnext %i\n", set, next_frame, n_data_blocks_in_next_frame); + +/* int64_t stride; // Read coordinates if ( tng_util_pos_read_range(traj_, set, set, &ftmp_, &stride) != TNG_SUCCESS ) { @@ -197,7 +227,7 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { frameIn.SetBox( Box(boxShape) ); free( boxptr ); } - + */ return 0; } diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index cc7748ecec..d35f91f99e 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -41,12 +41,16 @@ class Traj_TNG : public TrajectoryIO { void convertArray(double*, float*, unsigned int) const; + typedef std::vector Iarray; + tng_trajectory_t traj_; ///< The TNG trajectory file object float* ftmp_; ///< Temporary array for reading in coordinates int64_t tngatoms_; ///< Number of atoms in the TNG trajectory file. + int64_t current_frame_; ///< The current frame. double tngfac_; ///< Coordinates scaling factor bool isOpen_; ///< Calling the TNG library close routine if file is not open is an error, so keep track ourselves. FileName filename_; ///< File name, for openTrajin + Iarray blockIds_; ///< Currently active block IDs }; #endif /* NO_TNGFILE */ #endif From 8c33f48ba41e9695318d81472375a6008b066afc Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 09:54:09 -0400 Subject: [PATCH 35/77] Try reading header every time file is opened. No matter what I do or how I call the functions, I cannot seem to get more than 1 frame of a TNG file... --- src/Traj_TNG.cpp | 102 +++++++++++++++++++++++++++++++---------------- src/Traj_TNG.h | 1 + 2 files changed, 69 insertions(+), 34 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index a2c6382639..d7f08f5215 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -12,6 +12,7 @@ Traj_TNG::Traj_TNG() : ftmp_(0), tngatoms_(0), + tngframes_(-1), current_frame_(0), tngfac_(0), isOpen_(false) @@ -51,6 +52,7 @@ void Traj_TNG::Info() { /** Close file. */ void Traj_TNG::closeTraj() { + mprintf("DEBUG: Calling closeTrajin() isOpen_=%1i\n", (int)isOpen_); if (isOpen_) { tng_util_trajectory_close(&traj_); } @@ -60,6 +62,7 @@ void Traj_TNG::closeTraj() { // ----------------------------------------------------------------------------- /** Open trajectory for reading. */ int Traj_TNG::openTrajin() { + mprintf("DEBUG: Calling openTrajin() isOpen_=%1i\n", (int)isOpen_); if (isOpen_) closeTraj(); tng_function_status stat = tng_util_trajectory_open(filename_.full(), 'r', &traj_); @@ -70,6 +73,42 @@ int Traj_TNG::openTrajin() { isOpen_ = true; current_frame_ = 0; + // Get number of atoms + if (tng_num_particles_get(traj_, &tngatoms_) != TNG_SUCCESS) { + mprinterr("Error: Could not get number of particles from TNG file.\n"); + return 1; + } + + // Get number of frames + tngframes_ = -1; + if (tng_num_frames_get(traj_, &tngframes_) != TNG_SUCCESS) { + mprinterr("Error: Could not get number of frames from TNG file.\n"); + return 1; + } + + // Get the exponential distance scaling factor + int64_t tngexp; + if (tng_distance_unit_exponential_get(traj_, &tngexp) != TNG_SUCCESS) { + mprinterr("Error: Could not get distance scaling exponential from TNG.\n"); + return 1; + } + mprintf("\tTNG exponential: %li\n", tngexp); + switch (tngexp) { + case -9 : + mprintf("\tTNG has units of nm\n"); + // Input is in nm. Convert to Angstroms. + tngfac_ = 10.0; + break; + case -10 : + mprintf("\tTNG has units of Angstrom\n"); + // Input is in Angstroms. + tngfac_ = 1.0; + break; + default : + // Convert to Angstroms. + tngfac_ = pow(10.0, tngexp + 10); break; + } + return 0; } @@ -96,10 +135,10 @@ void Traj_TNG::convertArray(double* out, float* in, unsigned int nvals) const { int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) { filename_ = fname; - openTrajin(); + // Open the trajectory + if (openTrajin()) return TRAJIN_ERR; - // Get number of atoms - tng_num_particles_get(traj_, &tngatoms_); + // Check number of atoms if (tngatoms_ != (int64_t)trajParm->Natom()) { mprinterr("Error: Number of atoms in TNG file (%li) does not match number\n" "Error: of atoms in associated topology (%i)\n", @@ -107,38 +146,17 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) return TRAJIN_ERR; } - // Get number of frames - int64_t nframes; - tng_num_frames_get(traj_, &nframes); - mprintf("\tTNG file has %li frames.\n", nframes); + // Print number of frames + mprintf("\tTNG file has %li frames.\n", tngframes_); + int nframes = (int)tngframes_; // Could overflow here - // Get the exponential distance scaling factor - int64_t tngexp; - if (tng_distance_unit_exponential_get(traj_, &tngexp) != TNG_SUCCESS) { - mprinterr("Error: Could not get distance scaling exponential from TNG.\n"); - return TRAJIN_ERR; - } - mprintf("\tTNG exponential: %li\n", tngexp); - switch (tngexp) { - case -9 : - mprintf("\tTNG has units of nm\n"); - // Input is in nm. Convert to Angstroms. - tngfac_ = 10.0; - break; - case -10 : - mprintf("\tTNG has units of Angstrom\n"); - // Input is in Angstroms. - tngfac_ = 1.0; - break; - default : - // Convert to Angstroms. - tngfac_ = pow(10.0, tngexp + 10); break; - } + // Print the scaling factor mprintf("\tTNG distance scaling factor: %g\n", tngfac_); // Allocate coords temp memory if (ftmp_ != 0) delete[] ftmp_; ftmp_ = new float[ 3*tngatoms_ ]; + // Check if there are velocities int64_t stride = 0; bool hasVel = false; @@ -187,6 +205,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) /** Read specified trajectory frame. */ int Traj_TNG::readFrame(int set, Frame& frameIn) { +/* // Determine next frame with data int64_t next_frame, n_data_blocks_in_next_frame, *block_ids_in_next_frame = 0; tng_function_status stat = tng_util_trajectory_next_frame_present_data_blocks_find( @@ -206,28 +225,43 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { return 1; } mprintf("DEBUG: Set %i next_frame %li nblocksnext %i\n", set, next_frame, n_data_blocks_in_next_frame); +*/ -/* int64_t stride; // Read coordinates - if ( tng_util_pos_read_range(traj_, set, set, &ftmp_, &stride) != TNG_SUCCESS ) { + tng_function_status stat = tng_util_pos_read_range(traj_, set, set, &ftmp_, &stride); + + if ( stat != TNG_SUCCESS ) { mprinterr("Error: Could not read set %i for TNG file.\n", set+1); return 1; } + mprintf("DEBUG: positions set %i stride %li\n", set, stride); convertArray(frameIn.xAddress(), ftmp_, 3*tngatoms_); + const double* tmpXYZ = frameIn.XYZ(0); + mprintf("DEBUG: positions set %i %g %g %g\n", set, tmpXYZ[0], tmpXYZ[1], tmpXYZ[2]); - if (CoordInfo().HasBox()) { + // Read time + double tngtime; + if (tng_util_time_of_frame_get(traj_, set, &tngtime) == TNG_SUCCESS) { + mprintf("DEBUG: TNG time: %g\n", tngtime); + } + +/* if (CoordInfo().HasBox()) { float* boxptr = 0; if (tng_util_box_shape_read_range(traj_, set, set, &boxptr, &stride) != TNG_SUCCESS) { mprinterr("Error: Could not read set %i box for TNG file.\n", set+1); return 1; } + mprintf("DEBUG: box set %i stride %li\n", set, stride); Matrix_3x3 boxShape(0.0); convertArray(boxShape.Dptr(), boxptr, 9); frameIn.SetBox( Box(boxShape) ); + mprintf("DEBUG: box set %i %g %g %g\n", set, + frameIn.BoxCrd().BoxX(), + frameIn.BoxCrd().BoxY(), + frameIn.BoxCrd().BoxZ()); free( boxptr ); - } - */ + }*/ return 0; } diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index d35f91f99e..e576c3b143 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -46,6 +46,7 @@ class Traj_TNG : public TrajectoryIO { tng_trajectory_t traj_; ///< The TNG trajectory file object float* ftmp_; ///< Temporary array for reading in coordinates int64_t tngatoms_; ///< Number of atoms in the TNG trajectory file. + int64_t tngframes_; ///< Number of frames in the TNG trajectory file. int64_t current_frame_; ///< The current frame. double tngfac_; ///< Coordinates scaling factor bool isOpen_; ///< Calling the TNG library close routine if file is not open is an error, so keep track ourselves. From a07228ea959d8351537c2058c4b2d9c0320fc07f Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 11:08:16 -0400 Subject: [PATCH 36/77] DRR - Now we're starting to get somewhere. Needed to call the next_frame_present routine with current frame set *before* the set we want. --- src/Traj_TNG.cpp | 96 +++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 45 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index d7f08f5215..bf580075a1 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -70,44 +70,9 @@ int Traj_TNG::openTrajin() { mprinterr("Error: Could not open TNG file '%s'\n", filename_.full()); return TRAJIN_ERR; } + mprintf("DEBUG: Successfully opened TNG file.\n"); isOpen_ = true; - current_frame_ = 0; - - // Get number of atoms - if (tng_num_particles_get(traj_, &tngatoms_) != TNG_SUCCESS) { - mprinterr("Error: Could not get number of particles from TNG file.\n"); - return 1; - } - - // Get number of frames - tngframes_ = -1; - if (tng_num_frames_get(traj_, &tngframes_) != TNG_SUCCESS) { - mprinterr("Error: Could not get number of frames from TNG file.\n"); - return 1; - } - - // Get the exponential distance scaling factor - int64_t tngexp; - if (tng_distance_unit_exponential_get(traj_, &tngexp) != TNG_SUCCESS) { - mprinterr("Error: Could not get distance scaling exponential from TNG.\n"); - return 1; - } - mprintf("\tTNG exponential: %li\n", tngexp); - switch (tngexp) { - case -9 : - mprintf("\tTNG has units of nm\n"); - // Input is in nm. Convert to Angstroms. - tngfac_ = 10.0; - break; - case -10 : - mprintf("\tTNG has units of Angstrom\n"); - // Input is in Angstroms. - tngfac_ = 1.0; - break; - default : - // Convert to Angstroms. - tngfac_ = pow(10.0, tngexp + 10); break; - } + current_frame_ = -1; return 0; } @@ -138,6 +103,11 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) // Open the trajectory if (openTrajin()) return TRAJIN_ERR; + // Get number of atoms + if (tng_num_particles_get(traj_, &tngatoms_) != TNG_SUCCESS) { + mprinterr("Error: Could not get number of particles from TNG file.\n"); + return 1; + } // Check number of atoms if (tngatoms_ != (int64_t)trajParm->Natom()) { mprinterr("Error: Number of atoms in TNG file (%li) does not match number\n" @@ -146,10 +116,38 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) return TRAJIN_ERR; } + // Get number of frames + tngframes_ = -1; + if (tng_num_frames_get(traj_, &tngframes_) != TNG_SUCCESS) { + mprinterr("Error: Could not get number of frames from TNG file.\n"); + return 1; + } // Print number of frames mprintf("\tTNG file has %li frames.\n", tngframes_); int nframes = (int)tngframes_; // Could overflow here + // Get the exponential distance scaling factor + int64_t tngexp; + if (tng_distance_unit_exponential_get(traj_, &tngexp) != TNG_SUCCESS) { + mprinterr("Error: Could not get distance scaling exponential from TNG.\n"); + return 1; + } + mprintf("\tTNG exponential: %li\n", tngexp); + switch (tngexp) { + case -9 : + mprintf("\tTNG has units of nm\n"); + // Input is in nm. Convert to Angstroms. + tngfac_ = 10.0; + break; + case -10 : + mprintf("\tTNG has units of Angstrom\n"); + // Input is in Angstroms. + tngfac_ = 1.0; + break; + default : + // Convert to Angstroms. + tngfac_ = pow(10.0, tngexp + 10); break; + } // Print the scaling factor mprintf("\tTNG distance scaling factor: %g\n", tngfac_); @@ -189,23 +187,30 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) // NOTE: Use free here since thats what underlying TNG library does if (boxptr != 0) free( boxptr ); - closeTraj(); - + // Set up coordinate info SetCoordInfo( CoordinateInfo( Box(boxShape), hasVel, false, false ) ); + // Set up blocks blockIds_.clear(); - if (CoordInfo().HasBox()) +/* if (CoordInfo().HasBox()) blockIds_.push_back( TNG_TRAJ_BOX_SHAPE ); blockIds_.push_back( TNG_TRAJ_POSITIONS ); if (CoordInfo().HasVel()) - blockIds_.push_back( TNG_TRAJ_VELOCITIES ); + blockIds_.push_back( TNG_TRAJ_VELOCITIES );*/ + blockIds_.push_back( TNG_TRAJ_BOX_SHAPE ); + blockIds_.push_back( TNG_TRAJ_POSITIONS ); + blockIds_.push_back( TNG_TRAJ_VELOCITIES ); + blockIds_.push_back( TNG_TRAJ_FORCES ); + blockIds_.push_back( TNG_GMX_LAMBDA ); + closeTraj(); return (int)nframes; } /** Read specified trajectory frame. */ int Traj_TNG::readFrame(int set, Frame& frameIn) { -/* + int64_t numberOfAtoms = -1; + tng_num_particles_get(traj_, &numberOfAtoms); // Determine next frame with data int64_t next_frame, n_data_blocks_in_next_frame, *block_ids_in_next_frame = 0; tng_function_status stat = tng_util_trajectory_next_frame_present_data_blocks_find( @@ -225,8 +230,9 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { return 1; } mprintf("DEBUG: Set %i next_frame %li nblocksnext %i\n", set, next_frame, n_data_blocks_in_next_frame); -*/ - + + current_frame_ = next_frame; +/* int64_t stride; // Read coordinates tng_function_status stat = tng_util_pos_read_range(traj_, set, set, &ftmp_, &stride); @@ -245,7 +251,7 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { if (tng_util_time_of_frame_get(traj_, set, &tngtime) == TNG_SUCCESS) { mprintf("DEBUG: TNG time: %g\n", tngtime); } - +*/ /* if (CoordInfo().HasBox()) { float* boxptr = 0; if (tng_util_box_shape_read_range(traj_, set, set, &boxptr, &stride) != TNG_SUCCESS) { From dcf3bb58f290dc3c60f7933702c4152a3dc2f6c9 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 11:18:09 -0400 Subject: [PATCH 37/77] DRR - In TNG files, frames is relative to the MD simulation, sets is what cpptraj usually thinks of as frames (i.e. frames refers to the number of trajectory frames in the traj file itself) --- src/Traj_TNG.cpp | 13 +++++++++++-- src/Traj_TNG.h | 5 +++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index bf580075a1..b034bcbf58 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -13,7 +13,8 @@ Traj_TNG::Traj_TNG() : ftmp_(0), tngatoms_(0), tngframes_(-1), - current_frame_(0), + tngsets_(-1), + current_frame_(-1), tngfac_(0), isOpen_(false) {} @@ -124,7 +125,15 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) } // Print number of frames mprintf("\tTNG file has %li frames.\n", tngframes_); - int nframes = (int)tngframes_; // Could overflow here + + // Get number of frame sets + tngsets_ = -1; + if (tng_num_frame_sets_get(traj_, &tngsets_) != TNG_SUCCESS) { + mprinterr("Error: could not get number of frame sets from TNG file.\n"); + return 1; + } + mprintf("\tTNG file has %li frame sets.\n", tngsets_); + int nframes = (int)tngsets_; // Could overflow here // Get the exponential distance scaling factor int64_t tngexp; diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index e576c3b143..ce2821919f 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -46,8 +46,9 @@ class Traj_TNG : public TrajectoryIO { tng_trajectory_t traj_; ///< The TNG trajectory file object float* ftmp_; ///< Temporary array for reading in coordinates int64_t tngatoms_; ///< Number of atoms in the TNG trajectory file. - int64_t tngframes_; ///< Number of frames in the TNG trajectory file. - int64_t current_frame_; ///< The current frame. + int64_t tngframes_; ///< Number of *MD sim( frames in the TNG trajectory file. + int64_t tngsets_; ///< Number of actual frames in the TNG traectory file. + int64_t current_frame_; ///< The current frame (relative to MD sim, not the trajectory!) double tngfac_; ///< Coordinates scaling factor bool isOpen_; ///< Calling the TNG library close routine if file is not open is an error, so keep track ourselves. FileName filename_; ///< File name, for openTrajin From 20691324344b1b8a73e544a7608735326f32dc5c Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 11:33:17 -0400 Subject: [PATCH 38/77] DRR - Start handling blocks --- src/Traj_TNG.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index b034bcbf58..d934a4e298 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -240,6 +240,45 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { } mprintf("DEBUG: Set %i next_frame %li nblocksnext %i\n", set, next_frame, n_data_blocks_in_next_frame); + if (n_data_blocks_in_next_frame < 1) { + mprinterr("Error: No data blocks in next frame (set %i, TNG frame %li)\n", set+1, next_frame); + return 1; + } + + // Process data blocks + void* values = 0; + double frameTime; + char datatype; + for (int64_t idx = 0; idx < n_data_blocks_in_next_frame; idx++) + { + int64_t blockId = block_ids_in_next_frame[idx]; + int blockDependency; + tng_data_block_dependency_get(traj_, blockId, &blockDependency); + if (blockDependency & TNG_PARTICLE_DEPENDENT) { + stat = tng_util_particle_data_next_frame_read( traj_, + blockId, + &values, + &datatype, + &next_frame, + &frameTime ); + } else { + stat = tng_util_non_particle_data_next_frame_read( traj_, + blockId, + &values, + &datatype, + &next_frame, + &frameTime ); + } + if (stat == TNG_CRITICAL) { + mprinterr("Error: Could not read TNG block %li\n", blockId); + } else if (stat == TNG_FAILURE) { + mprintf("Warning: Skipping TNG block %li\n", blockId); + continue; + } + } // END loop over blocks in next frame + if (values != 0) free(values); + + // Update current frame current_frame_ = next_frame; /* int64_t stride; From 863f0dd13bf3e17a717425914812e512c5b23e93 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 12:17:05 -0400 Subject: [PATCH 39/77] DRR - Add box read --- src/Traj_TNG.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index d934a4e298..ecc0af9629 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -216,6 +216,16 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) return (int)nframes; } +static inline const char* DtypeStr(char typeIn) { + switch (typeIn) { + case TNG_INT_DATA : return "integer"; + case TNG_FLOAT_DATA : return "float"; + case TNG_DOUBLE_DATA : return "double"; + default : return "unknown"; + } + return 0; +} + /** Read specified trajectory frame. */ int Traj_TNG::readFrame(int set, Frame& frameIn) { int64_t numberOfAtoms = -1; @@ -238,7 +248,7 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { mprintf("DEBUG: No more blocks.\n"); return 1; } - mprintf("DEBUG: Set %i next_frame %li nblocksnext %i\n", set, next_frame, n_data_blocks_in_next_frame); + mprintf("DEBUG: Set %i next_frame %li nblocksnext %i\n", set+1, next_frame, n_data_blocks_in_next_frame); if (n_data_blocks_in_next_frame < 1) { mprinterr("Error: No data blocks in next frame (set %i, TNG frame %li)\n", set+1, next_frame); @@ -275,6 +285,23 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { mprintf("Warning: Skipping TNG block %li\n", blockId); continue; } + mprintf("DEBUG: set %i frameTime %g block %li data %s\n", set+1, frameTime, blockId, DtypeStr(datatype)); + // TODO: ok to only expect float data? + if (datatype != TNG_FLOAT_DATA) { + mprinterr("Error: TNG block %li data type is %s, expected float!\n", blockId, DtypeStr(datatype)); + if (values != 0) free(values); + return 1; + } + if ( blockId == TNG_TRAJ_BOX_SHAPE ) { // TODO switch? + Matrix_3x3 boxShape(0.0); + convertArray(boxShape.Dptr(), (float*)values, 9); + frameIn.SetBox( Box(boxShape) ); + mprintf("DEBUG: box set %i %g %g %g\n", set, + frameIn.BoxCrd().BoxX(), + frameIn.BoxCrd().BoxY(), + frameIn.BoxCrd().BoxZ()); + } + } // END loop over blocks in next frame if (values != 0) free(values); From 95a637632c72eef7656681d53698022c334579cf Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 12:23:18 -0400 Subject: [PATCH 40/77] DRR - Read positions --- src/Traj_TNG.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index ecc0af9629..2d40ce6dc9 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -300,6 +300,10 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { frameIn.BoxCrd().BoxX(), frameIn.BoxCrd().BoxY(), frameIn.BoxCrd().BoxZ()); + } else if ( blockId == TNG_TRAJ_POSITIONS ) { + convertArray( frameIn.xAddress(), (float*)values, tngatoms_*3 ); + const double* tmpXYZ = frameIn.XYZ(0); + mprintf("DEBUG: positions set %i %g %g %g\n", set, tmpXYZ[0], tmpXYZ[1], tmpXYZ[2]); } } // END loop over blocks in next frame @@ -318,8 +322,6 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { } mprintf("DEBUG: positions set %i stride %li\n", set, stride); convertArray(frameIn.xAddress(), ftmp_, 3*tngatoms_); - const double* tmpXYZ = frameIn.XYZ(0); - mprintf("DEBUG: positions set %i %g %g %g\n", set, tmpXYZ[0], tmpXYZ[1], tmpXYZ[2]); // Read time double tngtime; From 689ccc6100a377d0bff55a20af11e5ad26367784 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 13:04:41 -0400 Subject: [PATCH 41/77] Fix a mem leak --- src/Traj_TNG.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 2d40ce6dc9..216a2ec5d1 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -231,7 +231,9 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { int64_t numberOfAtoms = -1; tng_num_particles_get(traj_, &numberOfAtoms); // Determine next frame with data - int64_t next_frame, n_data_blocks_in_next_frame, *block_ids_in_next_frame = 0; + int64_t next_frame; // Will get set to the next frame (MD) with data + int64_t n_data_blocks_in_next_frame; // Will get set to # blocks in next frame + int64_t *block_ids_in_next_frame = 0; // Will hold blocks in next frame tng_function_status stat = tng_util_trajectory_next_frame_present_data_blocks_find( traj_, current_frame_, @@ -308,6 +310,7 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { } // END loop over blocks in next frame if (values != 0) free(values); + if (block_ids_in_next_frame != 0) free(block_ids_in_next_frame); // Update current frame current_frame_ = next_frame; From 86da44e7689d1de584fd82c43d37bab8e1102c1a Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 13:25:58 -0400 Subject: [PATCH 42/77] DRR - Add missing enum entry for TNG --- src/TrajectoryFile.cpp | 8 +++++--- src/TrajectoryFile.h | 9 ++++++--- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/TrajectoryFile.cpp b/src/TrajectoryFile.cpp index fd860f7cf3..a75814e6a5 100644 --- a/src/TrajectoryFile.cpp +++ b/src/TrajectoryFile.cpp @@ -27,13 +27,15 @@ // ----- STATIC VARS / ROUTINES ------------------------------------------------ // NOTE: Must be in same order as TrajFormatType -/** Static array containing traj allocators, optionally read/write help functions. */ +/** Static array containing traj allocators, optionally read/write help functions. + * MUST BE IN SYNC WITH TrajFormatType. + */ const FileTypes::AllocToken TrajectoryFile::TF_AllocArray[] = { # ifdef BINTRAJ - { "Amber NetCDF", Traj_AmberNetcdf::ReadHelp, Traj_AmberNetcdf::WriteHelp, Traj_AmberNetcdf::Alloc }, + { "Amber NetCDF", Traj_AmberNetcdf::ReadHelp, Traj_AmberNetcdf::WriteHelp, Traj_AmberNetcdf::Alloc }, // 0 = AMBERNETCDF { "Amber NC Restart", Traj_AmberRestartNC::ReadHelp, Traj_AmberRestartNC::WriteHelp, Traj_AmberRestartNC::Alloc }, # else - { "Amber NetCDF", 0, 0, 0 }, + { "Amber NetCDF", 0, 0, 0 }, // 0 = AMBERNETCDF { "Amber NC Restart", 0, 0, 0 }, # endif # if defined (ENABLE_SINGLE_ENSEMBLE) && defined (BINTRAJ) diff --git a/src/TrajectoryFile.h b/src/TrajectoryFile.h index dee41b56ba..785e1aeff7 100644 --- a/src/TrajectoryFile.h +++ b/src/TrajectoryFile.h @@ -22,10 +22,13 @@ class TrajectoryFile { static const FileTypes::KeyToken TF_WriteKeyArray[]; public: /// Known trajectory formats. + /** MUST BE IN SYNC WITH TF_AllocArray[] */ enum TrajFormatType { - AMBERNETCDF = 0, AMBERRESTARTNC, AMBERNCENSEMBLE, PDBFILE, MOL2FILE, CIF, CHARMMDCD, - GMXTRX, GMXXTC, BINPOS, AMBERRESTART, GRO, TINKER, CHARMMCOR, CHARMMREST,AMBERTRAJ, - SQM, SDF, XYZ, CONFLIB, + AMBERNETCDF = 0, AMBERRESTARTNC, AMBERNCENSEMBLE, PDBFILE, MOL2FILE, + CIF, CHARMMDCD, GMXTRX, GMXXTC, GMXTNG, + BINPOS, AMBERRESTART, GRO, TINKER, CHARMMCOR, + CHARMMREST, AMBERTRAJ, SQM, SDF, XYZ, + CONFLIB, UNKNOWN_TRAJ }; From 4fee60dac17e0971e0946d873dc363d11206f20e Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 13:37:58 -0400 Subject: [PATCH 43/77] DRR - Add velocities and forces read --- src/Traj_TNG.cpp | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 216a2ec5d1..75277d1539 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -226,6 +226,24 @@ static inline const char* DtypeStr(char typeIn) { return 0; } +static inline const char* BtypeStr(int64_t typeIn) { + switch (typeIn) { + case TNG_TRAJ_BOX_SHAPE : return "box"; + case TNG_TRAJ_POSITIONS : return "positions"; + case TNG_TRAJ_VELOCITIES : return "velocities"; + case TNG_TRAJ_FORCES : return "forces"; + case TNG_TRAJ_PARTIAL_CHARGES : return "partial charges"; + case TNG_TRAJ_FORMAL_CHARGES : return "formal charges"; + case TNG_TRAJ_B_FACTORS : return "B factors"; + case TNG_TRAJ_ANISOTROPIC_B_FACTORS : return "anisotropic B factors"; + case TNG_TRAJ_OCCUPANCY : return "occupancy"; + case TNG_TRAJ_GENERAL_COMMENTS : return "general comments"; + case TNG_TRAJ_MASSES : return "masses"; + default : return "unknown"; + } + return 0; +} + /** Read specified trajectory frame. */ int Traj_TNG::readFrame(int set, Frame& frameIn) { int64_t numberOfAtoms = -1; @@ -282,18 +300,19 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { &frameTime ); } if (stat == TNG_CRITICAL) { - mprinterr("Error: Could not read TNG block %li\n", blockId); + mprinterr("Error: Could not read TNG block '%s'\n", BtypeStr(blockId)); } else if (stat == TNG_FAILURE) { - mprintf("Warning: Skipping TNG block %li\n", blockId); + mprintf("Warning: Skipping TNG block '%s'\n", BtypeStr(blockId)); continue; } - mprintf("DEBUG: set %i frameTime %g block %li data %s\n", set+1, frameTime, blockId, DtypeStr(datatype)); + mprintf("DEBUG: set %i frameTime %g block %s data %s\n", set+1, frameTime, BtypeStr(blockId), DtypeStr(datatype)); // TODO: ok to only expect float data? if (datatype != TNG_FLOAT_DATA) { - mprinterr("Error: TNG block %li data type is %s, expected float!\n", blockId, DtypeStr(datatype)); + mprinterr("Error: TNG block '%s' data type is %s, expected float!\n", BtypeStr(blockId), DtypeStr(datatype)); if (values != 0) free(values); return 1; } + // ----- Box ----------------------- if ( blockId == TNG_TRAJ_BOX_SHAPE ) { // TODO switch? Matrix_3x3 boxShape(0.0); convertArray(boxShape.Dptr(), (float*)values, 9); @@ -302,12 +321,16 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { frameIn.BoxCrd().BoxX(), frameIn.BoxCrd().BoxY(), frameIn.BoxCrd().BoxZ()); + // ----- Coords -------------------- } else if ( blockId == TNG_TRAJ_POSITIONS ) { convertArray( frameIn.xAddress(), (float*)values, tngatoms_*3 ); const double* tmpXYZ = frameIn.XYZ(0); mprintf("DEBUG: positions set %i %g %g %g\n", set, tmpXYZ[0], tmpXYZ[1], tmpXYZ[2]); + } else if ( blockId == TNG_TRAJ_VELOCITIES ) { + convertArray( frameIn.vAddress(), (float*)values, tngatoms_*3 ); + } else if ( blockId == TNG_TRAJ_FORCES ) { + convertArray( frameIn.fAddress(), (float*)values, tngatoms_*3 ); } - } // END loop over blocks in next frame if (values != 0) free(values); if (block_ids_in_next_frame != 0) free(block_ids_in_next_frame); From 20e32bbe4a29928dd58b495eb97491d42c262a3f Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 13:49:57 -0400 Subject: [PATCH 44/77] DRR - Add time read --- src/Constants.h | 2 ++ src/Traj_TNG.cpp | 15 ++++++++++++--- src/cpptrajdepend | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Constants.h b/src/Constants.h index 50baa40931..583406360f 100644 --- a/src/Constants.h +++ b/src/Constants.h @@ -65,5 +65,7 @@ namespace Constants { * itself is derived from sqrt(1 / ((AMU_TO_KG * NA) / (1000 * CAL_TO_J))). */ const double AMBERTIME_TO_PS = 20.455; + // Pico prefix + const double PICO = 1e-12; } #endif diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 75277d1539..36a42bc826 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -7,6 +7,7 @@ #include "FileName.h" #include "Topology.h" #include "CpptrajFile.h" +#include "Constants.h" /// CONSTRUCTOR Traj_TNG::Traj_TNG() : @@ -135,6 +136,12 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) mprintf("\tTNG file has %li frame sets.\n", tngsets_); int nframes = (int)tngsets_; // Could overflow here + // Get the time per frame + double tpf = 0.0; + if (tng_time_per_frame_get( traj_, &tpf) != TNG_SUCCESS) + tpf = 0.0; + mprintf("\tTNG file time per frame: %g\n", tpf); + // Get the exponential distance scaling factor int64_t tngexp; if (tng_distance_unit_exponential_get(traj_, &tngexp) != TNG_SUCCESS) { @@ -196,8 +203,8 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) // NOTE: Use free here since thats what underlying TNG library does if (boxptr != 0) free( boxptr ); - // Set up coordinate info - SetCoordInfo( CoordinateInfo( Box(boxShape), hasVel, false, false ) ); + // Set up coordinate info. Box, coord, vel, force, time + SetCoordInfo( CoordinateInfo( Box(boxShape), true, hasVel, false, (tpf > 0.0) ) ); // Set up blocks blockIds_.clear(); @@ -334,8 +341,10 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { } // END loop over blocks in next frame if (values != 0) free(values); if (block_ids_in_next_frame != 0) free(block_ids_in_next_frame); + // TODO is it OK that frameTime is potentially set multiple times? + frameIn.SetTime( frameTime / Constants::PICO ); - // Update current frame + // Update current frame number current_frame_ = next_frame; /* int64_t stride; diff --git a/src/cpptrajdepend b/src/cpptrajdepend index 4b111c0f0b..225769faa9 100644 --- a/src/cpptrajdepend +++ b/src/cpptrajdepend @@ -362,7 +362,7 @@ Traj_NcEnsemble.o : Traj_NcEnsemble.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h Traj_PDBfile.o : Traj_PDBfile.cpp ArgList.h AssociatedData.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataSet.h DataSetList.h DataSet_1D.h DataSet_Coords.h DataSet_Coords_REF.h Dimension.h DistRoutines.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h PDBfile.h Parallel.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h SymbolExporting.h TextFormat.h Timer.h Topology.h Traj_PDBfile.h TrajectoryIO.h Vec3.h Traj_SDF.o : Traj_SDF.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SDFfile.h SymbolExporting.h Topology.h Traj_SDF.h TrajectoryIO.h Vec3.h Traj_SQM.o : Traj_SQM.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h StringRoutines.h SymbolExporting.h Topology.h Traj_SQM.h TrajectoryIO.h Vec3.h -Traj_TNG.o : Traj_TNG.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_TNG.h TrajectoryIO.h Vec3.h +Traj_TNG.o : Traj_TNG.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_TNG.h TrajectoryIO.h Vec3.h Traj_Tinker.o : Traj_Tinker.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedLine.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h TinkerFile.h Topology.h Traj_Tinker.h TrajectoryIO.h Vec3.h Traj_XYZ.o : Traj_XYZ.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedLine.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h StringRoutines.h SymbolExporting.h TextFormat.h Topology.h Traj_XYZ.h TrajectoryIO.h Vec3.h TrajectoryFile.o : TrajectoryFile.cpp ArgList.h Atom.h AtomMask.h BaseIOtype.h Box.h BufferedFrame.h BufferedLine.h CIFfile.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h FileTypes.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Mol2File.h Molecule.h NameType.h NetcdfFile.h PDBfile.h Parallel.h ReplicaDimArray.h Residue.h SDFfile.h SymbolExporting.h TextFormat.h TinkerFile.h Traj_AmberCoord.h Traj_AmberNetcdf.h Traj_AmberRestart.h Traj_AmberRestartNC.h Traj_Binpos.h Traj_CIF.h Traj_CharmmCor.h Traj_CharmmDcd.h Traj_CharmmRestart.h Traj_Conflib.h Traj_GmxTrX.h Traj_GmxXtc.h Traj_Gro.h Traj_Mol2File.h Traj_NcEnsemble.h Traj_PDBfile.h Traj_SDF.h Traj_SQM.h Traj_TNG.h Traj_Tinker.h Traj_XYZ.h TrajectoryFile.h TrajectoryIO.h Vec3.h From 7b23265883199cfdf1663a299c0299bafe22d4b9 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 13:51:46 -0400 Subject: [PATCH 45/77] DRR - Comment out unneeded call --- src/Traj_TNG.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 36a42bc826..18efd1a0e5 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -253,8 +253,8 @@ static inline const char* BtypeStr(int64_t typeIn) { /** Read specified trajectory frame. */ int Traj_TNG::readFrame(int set, Frame& frameIn) { - int64_t numberOfAtoms = -1; - tng_num_particles_get(traj_, &numberOfAtoms); + //int64_t numberOfAtoms = -1; + //tng_num_particles_get(traj_, &numberOfAtoms); TODO could this change per frame? // Determine next frame with data int64_t next_frame; // Will get set to the next frame (MD) with data int64_t n_data_blocks_in_next_frame; // Will get set to # blocks in next frame From 1f6266d9c4549c47bdbd7fa0f087ef187a2cc5d1 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 14:01:43 -0400 Subject: [PATCH 46/77] DRR - Make values a class var --- src/Traj_TNG.cpp | 84 ++++++++++++++++++++---------------------------- src/Traj_TNG.h | 2 +- 2 files changed, 35 insertions(+), 51 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 18efd1a0e5..71e6aaebc9 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -11,7 +11,7 @@ /// CONSTRUCTOR Traj_TNG::Traj_TNG() : - ftmp_(0), + values_(0), tngatoms_(0), tngframes_(-1), tngsets_(-1), @@ -23,7 +23,7 @@ Traj_TNG::Traj_TNG() : /// DESTRUCTOR Traj_TNG::~Traj_TNG() { closeTraj(); - if (ftmp_ != 0) delete[] ftmp_; + if (values_ != 0) free( values_ ); } /** Identify trajectory format. File should be setup for READ. @@ -96,6 +96,25 @@ void Traj_TNG::convertArray(double* out, float* in, unsigned int nvals) const { out[i] = ((double)in[i]) * tngfac_; } +/*int Traj_TNG::getNextBlocks(int64_t &next_frame) +{ + tng_function_status stat = tng_util_trajectory_next_frame_present_data_blocks_find( + traj_, + current_frame_, + blockIds_.size(), + &blockIds_[0], + &next_frame, + &n_data_blocks_in_next_frame, + &block_ids_in_next_frame); + if (stat == TNG_CRITICAL) { + mprinterr("Error: could not get data blocks in next frame (set %i)\n", set+1); + return 1; + } + if (stat == TNG_FAILURE) { + mprintf("DEBUG: No more blocks.\n"); + return 1; + }*/ + /** Set up trajectory for reading. * \return Number of frames in trajectory. */ @@ -167,13 +186,14 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) // Print the scaling factor mprintf("\tTNG distance scaling factor: %g\n", tngfac_); - // Allocate coords temp memory - if (ftmp_ != 0) delete[] ftmp_; - ftmp_ = new float[ 3*tngatoms_ ]; + // This will be used as temp space for reading in values from TNG + if (values_ != 0) free( values_ ); + values_ = 0; - // Check if there are velocities - int64_t stride = 0; bool hasVel = false; + int64_t stride = 0; + tng_function_status stat; +/* // Check if there are velocities tng_function_status stat = tng_util_vel_read_range(traj_, 0, 0, &ftmp_, &stride); mprintf("DEBUG: Velocity stride: %li\n", stride); if (stat == TNG_CRITICAL) { @@ -181,7 +201,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) return TRAJIN_ERR; } else if (stat == TNG_SUCCESS) { hasVel = true; - } + }*/ // Get box status Matrix_3x3 boxShape(0.0); @@ -283,7 +303,6 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { } // Process data blocks - void* values = 0; double frameTime; char datatype; for (int64_t idx = 0; idx < n_data_blocks_in_next_frame; idx++) @@ -294,14 +313,14 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { if (blockDependency & TNG_PARTICLE_DEPENDENT) { stat = tng_util_particle_data_next_frame_read( traj_, blockId, - &values, + &values_, &datatype, &next_frame, &frameTime ); } else { stat = tng_util_non_particle_data_next_frame_read( traj_, blockId, - &values, + &values_, &datatype, &next_frame, &frameTime ); @@ -316,13 +335,12 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { // TODO: ok to only expect float data? if (datatype != TNG_FLOAT_DATA) { mprinterr("Error: TNG block '%s' data type is %s, expected float!\n", BtypeStr(blockId), DtypeStr(datatype)); - if (values != 0) free(values); return 1; } // ----- Box ----------------------- if ( blockId == TNG_TRAJ_BOX_SHAPE ) { // TODO switch? Matrix_3x3 boxShape(0.0); - convertArray(boxShape.Dptr(), (float*)values, 9); + convertArray(boxShape.Dptr(), (float*)values_, 9); frameIn.SetBox( Box(boxShape) ); mprintf("DEBUG: box set %i %g %g %g\n", set, frameIn.BoxCrd().BoxX(), @@ -330,56 +348,22 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { frameIn.BoxCrd().BoxZ()); // ----- Coords -------------------- } else if ( blockId == TNG_TRAJ_POSITIONS ) { - convertArray( frameIn.xAddress(), (float*)values, tngatoms_*3 ); + convertArray( frameIn.xAddress(), (float*)values_, tngatoms_*3 ); const double* tmpXYZ = frameIn.XYZ(0); mprintf("DEBUG: positions set %i %g %g %g\n", set, tmpXYZ[0], tmpXYZ[1], tmpXYZ[2]); } else if ( blockId == TNG_TRAJ_VELOCITIES ) { - convertArray( frameIn.vAddress(), (float*)values, tngatoms_*3 ); + convertArray( frameIn.vAddress(), (float*)values_, tngatoms_*3 ); } else if ( blockId == TNG_TRAJ_FORCES ) { - convertArray( frameIn.fAddress(), (float*)values, tngatoms_*3 ); + convertArray( frameIn.fAddress(), (float*)values_, tngatoms_*3 ); } } // END loop over blocks in next frame - if (values != 0) free(values); if (block_ids_in_next_frame != 0) free(block_ids_in_next_frame); // TODO is it OK that frameTime is potentially set multiple times? frameIn.SetTime( frameTime / Constants::PICO ); // Update current frame number current_frame_ = next_frame; -/* - int64_t stride; - // Read coordinates - tng_function_status stat = tng_util_pos_read_range(traj_, set, set, &ftmp_, &stride); - - if ( stat != TNG_SUCCESS ) { - mprinterr("Error: Could not read set %i for TNG file.\n", set+1); - return 1; - } - mprintf("DEBUG: positions set %i stride %li\n", set, stride); - convertArray(frameIn.xAddress(), ftmp_, 3*tngatoms_); - // Read time - double tngtime; - if (tng_util_time_of_frame_get(traj_, set, &tngtime) == TNG_SUCCESS) { - mprintf("DEBUG: TNG time: %g\n", tngtime); - } -*/ -/* if (CoordInfo().HasBox()) { - float* boxptr = 0; - if (tng_util_box_shape_read_range(traj_, set, set, &boxptr, &stride) != TNG_SUCCESS) { - mprinterr("Error: Could not read set %i box for TNG file.\n", set+1); - return 1; - } - mprintf("DEBUG: box set %i stride %li\n", set, stride); - Matrix_3x3 boxShape(0.0); - convertArray(boxShape.Dptr(), boxptr, 9); - frameIn.SetBox( Box(boxShape) ); - mprintf("DEBUG: box set %i %g %g %g\n", set, - frameIn.BoxCrd().BoxX(), - frameIn.BoxCrd().BoxY(), - frameIn.BoxCrd().BoxZ()); - free( boxptr ); - }*/ return 0; } diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index ce2821919f..4dbae2e1b4 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -44,7 +44,7 @@ class Traj_TNG : public TrajectoryIO { typedef std::vector Iarray; tng_trajectory_t traj_; ///< The TNG trajectory file object - float* ftmp_; ///< Temporary array for reading in coordinates + void* values_; ///< Temporary array for reading in values from TNG int64_t tngatoms_; ///< Number of atoms in the TNG trajectory file. int64_t tngframes_; ///< Number of *MD sim( frames in the TNG trajectory file. int64_t tngsets_; ///< Number of actual frames in the TNG traectory file. From 9d9faa706b227cd05b7d5a591ac187e9e0231c22 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 14:29:35 -0400 Subject: [PATCH 47/77] DRR - Change setupTrajin so it only looks for blocks that are there. --- src/Traj_TNG.cpp | 186 +++++++++++++++++++++++++++++------------------ src/Traj_TNG.h | 24 +++--- 2 files changed, 129 insertions(+), 81 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 71e6aaebc9..c82250c323 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -16,6 +16,8 @@ Traj_TNG::Traj_TNG() : tngframes_(-1), tngsets_(-1), current_frame_(-1), + next_nblocks_(-1), + next_blockIDs_(0), tngfac_(0), isOpen_(false) {} @@ -24,6 +26,7 @@ Traj_TNG::Traj_TNG() : Traj_TNG::~Traj_TNG() { closeTraj(); if (values_ != 0) free( values_ ); + if (next_blockIDs_ != 0) free( next_blockIDs_ ); } /** Identify trajectory format. File should be setup for READ. @@ -96,7 +99,9 @@ void Traj_TNG::convertArray(double* out, float* in, unsigned int nvals) const { out[i] = ((double)in[i]) * tngfac_; } -/*int Traj_TNG::getNextBlocks(int64_t &next_frame) +/** \return 1 if no more blocks, -1 on error, 0 if ok. + */ +int Traj_TNG::getNextBlocks(int64_t &next_frame) { tng_function_status stat = tng_util_trajectory_next_frame_present_data_blocks_find( traj_, @@ -104,16 +109,73 @@ void Traj_TNG::convertArray(double* out, float* in, unsigned int nvals) const { blockIds_.size(), &blockIds_[0], &next_frame, - &n_data_blocks_in_next_frame, - &block_ids_in_next_frame); + &next_nblocks_, + &next_blockIDs_); if (stat == TNG_CRITICAL) { - mprinterr("Error: could not get data blocks in next frame (set %i)\n", set+1); + return -1; + } else if (stat == TNG_FAILURE) { return 1; } - if (stat == TNG_FAILURE) { - mprintf("DEBUG: No more blocks.\n"); + return 0; +} + +static inline const char* DtypeStr(char typeIn) { + switch (typeIn) { + case TNG_INT_DATA : return "integer"; + case TNG_FLOAT_DATA : return "float"; + case TNG_DOUBLE_DATA : return "double"; + default : return "unknown"; + } + return 0; +} + +static inline const char* BtypeStr(int64_t typeIn) { + switch (typeIn) { + case TNG_TRAJ_BOX_SHAPE : return "box"; + case TNG_TRAJ_POSITIONS : return "positions"; + case TNG_TRAJ_VELOCITIES : return "velocities"; + case TNG_TRAJ_FORCES : return "forces"; + case TNG_TRAJ_PARTIAL_CHARGES : return "partial charges"; + case TNG_TRAJ_FORMAL_CHARGES : return "formal charges"; + case TNG_TRAJ_B_FACTORS : return "B factors"; + case TNG_TRAJ_ANISOTROPIC_B_FACTORS : return "anisotropic B factors"; + case TNG_TRAJ_OCCUPANCY : return "occupancy"; + case TNG_TRAJ_GENERAL_COMMENTS : return "general comments"; + case TNG_TRAJ_MASSES : return "masses"; + default : return "unknown"; + } + return 0; +} + + +int Traj_TNG::readValues(int64_t blockId, int64_t& next_frame, double& frameTime, char& datatype) { + tng_function_status stat; + int blockDependency; + tng_data_block_dependency_get(traj_, blockId, &blockDependency); + if (blockDependency & TNG_PARTICLE_DEPENDENT) { + stat = tng_util_particle_data_next_frame_read( traj_, + blockId, + &values_, + &datatype, + &next_frame, + &frameTime ); + } else { + stat = tng_util_non_particle_data_next_frame_read( traj_, + blockId, + &values_, + &datatype, + &next_frame, + &frameTime ); + } + if (stat == TNG_CRITICAL) { + mprinterr("Error: Could not read TNG block '%s'\n", BtypeStr(blockId)); + return -1; + } else if (stat == TNG_FAILURE) { + mprintf("Warning: Skipping TNG block '%s'\n", BtypeStr(blockId)); return 1; - }*/ + } + return 0; +} /** Set up trajectory for reading. * \return Number of frames in trajectory. @@ -189,88 +251,70 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) // This will be used as temp space for reading in values from TNG if (values_ != 0) free( values_ ); values_ = 0; + if (next_blockIDs_ != 0) free( next_blockIDs_ ); + next_blockIDs_ = 0; - bool hasVel = false; - int64_t stride = 0; - tng_function_status stat; -/* // Check if there are velocities - tng_function_status stat = tng_util_vel_read_range(traj_, 0, 0, &ftmp_, &stride); - mprintf("DEBUG: Velocity stride: %li\n", stride); - if (stat == TNG_CRITICAL) { - mprinterr("Error: Major error encountered checking TNG velocities.\n"); - return TRAJIN_ERR; - } else if (stat == TNG_SUCCESS) { - hasVel = true; - }*/ + // Set up blocks + blockIds_.clear(); + blockIds_.push_back( TNG_TRAJ_BOX_SHAPE ); + blockIds_.push_back( TNG_TRAJ_POSITIONS ); + blockIds_.push_back( TNG_TRAJ_VELOCITIES ); + blockIds_.push_back( TNG_TRAJ_FORCES ); + blockIds_.push_back( TNG_GMX_LAMBDA ); - // Get box status - Matrix_3x3 boxShape(0.0); - float* boxptr = 0; - stat = tng_util_box_shape_read_range(traj_, 0, 0, &boxptr, &stride); - mprintf("DEBUG: Box Stride: %li\n", stride); - if (stat == TNG_CRITICAL) { - mprinterr("Error: Major error encountered checking TNG box.\n"); + // Get block IDs in the first frame + int64_t next_frame; + if (getNextBlocks(next_frame) != 0) { + mprinterr("Error: Unable to read blocks from first frame of TNG.\n"); return TRAJIN_ERR; - } else if (stat == TNG_SUCCESS) { - convertArray(boxShape.Dptr(), boxptr, 9); - mprintf("\tBox shape:"); - for (unsigned int i = 0; i < 9; i++) - { - mprintf(" %f", boxShape[i]); - } - mprintf("\n"); } - // NOTE: Use free here since thats what underlying TNG library does - if (boxptr != 0) free( boxptr ); + bool hasVel = false; + bool hasFrc = false; + bool hasPos = false; + Matrix_3x3 boxShape(0.0); + for (int64_t idx = 0; idx < next_nblocks_; idx++) + { + int64_t blockId = next_blockIDs_[idx]; + mprintf("DEBUG: Block '%s' detected.\n", BtypeStr(blockId)); + if ( blockId == TNG_TRAJ_BOX_SHAPE ) { + // Try to determine the box type by reading first frame values. + double frameTime; + char datatype; + int err = readValues(blockId, next_frame, frameTime, datatype); + if (err == -1) { + mprinterr("Error: Critical error encountered reading block '%s'\n", BtypeStr(blockId)); + return TRAJIN_ERR; + } + // TODO: ok to only expect float data? + if (datatype != TNG_FLOAT_DATA) { + mprinterr("Error: TNG block '%s' data type is %s, expected float!\n", BtypeStr(blockId), DtypeStr(datatype)); + return TRAJIN_ERR; + } + convertArray(boxShape.Dptr(), (float*)values_, 9); + boxShape.Print("boxShape"); + } else if ( blockId == TNG_TRAJ_POSITIONS ) { + hasPos = true; + } else if ( blockId == TNG_TRAJ_VELOCITIES ) { + hasVel = true; + } else if ( blockId == TNG_TRAJ_FORCES ) { + hasFrc = true; + } + } // END loop over blocks // Set up coordinate info. Box, coord, vel, force, time - SetCoordInfo( CoordinateInfo( Box(boxShape), true, hasVel, false, (tpf > 0.0) ) ); + SetCoordInfo( CoordinateInfo( Box(boxShape), hasPos, hasVel, hasFrc, (tpf > 0.0) ) ); // Set up blocks - blockIds_.clear(); /* if (CoordInfo().HasBox()) blockIds_.push_back( TNG_TRAJ_BOX_SHAPE ); blockIds_.push_back( TNG_TRAJ_POSITIONS ); if (CoordInfo().HasVel()) blockIds_.push_back( TNG_TRAJ_VELOCITIES );*/ - blockIds_.push_back( TNG_TRAJ_BOX_SHAPE ); - blockIds_.push_back( TNG_TRAJ_POSITIONS ); - blockIds_.push_back( TNG_TRAJ_VELOCITIES ); - blockIds_.push_back( TNG_TRAJ_FORCES ); - blockIds_.push_back( TNG_GMX_LAMBDA ); closeTraj(); return (int)nframes; } -static inline const char* DtypeStr(char typeIn) { - switch (typeIn) { - case TNG_INT_DATA : return "integer"; - case TNG_FLOAT_DATA : return "float"; - case TNG_DOUBLE_DATA : return "double"; - default : return "unknown"; - } - return 0; -} - -static inline const char* BtypeStr(int64_t typeIn) { - switch (typeIn) { - case TNG_TRAJ_BOX_SHAPE : return "box"; - case TNG_TRAJ_POSITIONS : return "positions"; - case TNG_TRAJ_VELOCITIES : return "velocities"; - case TNG_TRAJ_FORCES : return "forces"; - case TNG_TRAJ_PARTIAL_CHARGES : return "partial charges"; - case TNG_TRAJ_FORMAL_CHARGES : return "formal charges"; - case TNG_TRAJ_B_FACTORS : return "B factors"; - case TNG_TRAJ_ANISOTROPIC_B_FACTORS : return "anisotropic B factors"; - case TNG_TRAJ_OCCUPANCY : return "occupancy"; - case TNG_TRAJ_GENERAL_COMMENTS : return "general comments"; - case TNG_TRAJ_MASSES : return "masses"; - default : return "unknown"; - } - return 0; -} - /** Read specified trajectory frame. */ int Traj_TNG::readFrame(int set, Frame& frameIn) { //int64_t numberOfAtoms = -1; diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index 4dbae2e1b4..524219d587 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -40,19 +40,23 @@ class Traj_TNG : public TrajectoryIO { # endif void convertArray(double*, float*, unsigned int) const; + int getNextBlocks(int64_t&); + int readValues(int64_t, int64_t&, double&, char&); typedef std::vector Iarray; - tng_trajectory_t traj_; ///< The TNG trajectory file object - void* values_; ///< Temporary array for reading in values from TNG - int64_t tngatoms_; ///< Number of atoms in the TNG trajectory file. - int64_t tngframes_; ///< Number of *MD sim( frames in the TNG trajectory file. - int64_t tngsets_; ///< Number of actual frames in the TNG traectory file. - int64_t current_frame_; ///< The current frame (relative to MD sim, not the trajectory!) - double tngfac_; ///< Coordinates scaling factor - bool isOpen_; ///< Calling the TNG library close routine if file is not open is an error, so keep track ourselves. - FileName filename_; ///< File name, for openTrajin - Iarray blockIds_; ///< Currently active block IDs + tng_trajectory_t traj_; ///< The TNG trajectory file object + void* values_; ///< Temporary array for reading in values from TNG + int64_t tngatoms_; ///< Number of atoms in the TNG trajectory file. + int64_t tngframes_; ///< Number of *MD sim( frames in the TNG trajectory file. + int64_t tngsets_; ///< Number of actual frames in the TNG traectory file. + int64_t current_frame_; ///< The current frame (relative to MD sim, not the trajectory!) + int64_t next_nblocks_; ///< The number of data blocks in the next frame + int64_t* next_blockIDs_; ///< Array containing block IDs in next frame + double tngfac_; ///< Coordinates scaling factor + bool isOpen_; ///< Calling the TNG library close routine if file is not open is an error, so keep track ourselves. + FileName filename_; ///< File name, for openTrajin + Iarray blockIds_; ///< Currently active block IDs }; #endif /* NO_TNGFILE */ #endif From d7f03a221cce9b480aa92974d62b1725eb3a0f31 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 14:32:37 -0400 Subject: [PATCH 48/77] Have setupTrajin only look for blocks we are interested in --- src/Traj_TNG.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index c82250c323..d52bedc878 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -304,12 +304,16 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) // Set up coordinate info. Box, coord, vel, force, time SetCoordInfo( CoordinateInfo( Box(boxShape), hasPos, hasVel, hasFrc, (tpf > 0.0) ) ); - // Set up blocks -/* if (CoordInfo().HasBox()) + // Set up blocks that are actually there. + blockIds_.clear(); + if (CoordInfo().HasBox()) blockIds_.push_back( TNG_TRAJ_BOX_SHAPE ); - blockIds_.push_back( TNG_TRAJ_POSITIONS ); + if (CoordInfo().HasCrd()) + blockIds_.push_back( TNG_TRAJ_POSITIONS ); if (CoordInfo().HasVel()) - blockIds_.push_back( TNG_TRAJ_VELOCITIES );*/ + blockIds_.push_back( TNG_TRAJ_VELOCITIES ); + if (CoordInfo().HasForce()) + blockIds_.push_back( TNG_TRAJ_FORCES ); closeTraj(); return (int)nframes; From c7000007cd6b79196e9e43f9a7b9893e36be5044 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 14:40:33 -0400 Subject: [PATCH 49/77] DRR - Use common routines in read --- src/Traj_TNG.cpp | 51 ++++++++++++------------------------------------ 1 file changed, 13 insertions(+), 38 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index d52bedc878..991828ac67 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -325,27 +325,18 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { //tng_num_particles_get(traj_, &numberOfAtoms); TODO could this change per frame? // Determine next frame with data int64_t next_frame; // Will get set to the next frame (MD) with data - int64_t n_data_blocks_in_next_frame; // Will get set to # blocks in next frame - int64_t *block_ids_in_next_frame = 0; // Will hold blocks in next frame - tng_function_status stat = tng_util_trajectory_next_frame_present_data_blocks_find( - traj_, - current_frame_, - blockIds_.size(), - &blockIds_[0], - &next_frame, - &n_data_blocks_in_next_frame, - &block_ids_in_next_frame); - if (stat == TNG_CRITICAL) { + int err = getNextBlocks( next_frame ); + if (err == -1) { mprinterr("Error: could not get data blocks in next frame (set %i)\n", set+1); return 1; - } - if (stat == TNG_FAILURE) { - mprintf("DEBUG: No more blocks.\n"); + } else if (err != 0) { + mprintf("Warning: TNG set %i, no more blocks.\n", set+1); return 1; } - mprintf("DEBUG: Set %i next_frame %li nblocksnext %i\n", set+1, next_frame, n_data_blocks_in_next_frame); - if (n_data_blocks_in_next_frame < 1) { + mprintf("DEBUG: Set %i next_frame %li nblocksnext %li\n", set+1, next_frame, next_nblocks_); + + if (next_nblocks_ < 1) { mprinterr("Error: No data blocks in next frame (set %i, TNG frame %li)\n", set+1, next_frame); return 1; } @@ -353,29 +344,14 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { // Process data blocks double frameTime; char datatype; - for (int64_t idx = 0; idx < n_data_blocks_in_next_frame; idx++) + for (int64_t idx = 0; idx < next_nblocks_; idx++) { - int64_t blockId = block_ids_in_next_frame[idx]; - int blockDependency; - tng_data_block_dependency_get(traj_, blockId, &blockDependency); - if (blockDependency & TNG_PARTICLE_DEPENDENT) { - stat = tng_util_particle_data_next_frame_read( traj_, - blockId, - &values_, - &datatype, - &next_frame, - &frameTime ); - } else { - stat = tng_util_non_particle_data_next_frame_read( traj_, - blockId, - &values_, - &datatype, - &next_frame, - &frameTime ); - } - if (stat == TNG_CRITICAL) { + int64_t blockId = next_blockIDs_[idx]; + err = readValues( blockId, next_frame, frameTime, datatype ); + if (err == -1) + { mprinterr("Error: Could not read TNG block '%s'\n", BtypeStr(blockId)); - } else if (stat == TNG_FAILURE) { + } else if (err == 1) { mprintf("Warning: Skipping TNG block '%s'\n", BtypeStr(blockId)); continue; } @@ -405,7 +381,6 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { convertArray( frameIn.fAddress(), (float*)values_, tngatoms_*3 ); } } // END loop over blocks in next frame - if (block_ids_in_next_frame != 0) free(block_ids_in_next_frame); // TODO is it OK that frameTime is potentially set multiple times? frameIn.SetTime( frameTime / Constants::PICO ); From fc5d446b346abb539fd725a4632645e996c65c4f Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 11 Oct 2019 14:50:04 -0400 Subject: [PATCH 50/77] DRR - Clean up some debug messages. Still needs to be tested with an offset. --- src/Traj_TNG.cpp | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 991828ac67..ad3938ef51 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -43,7 +43,7 @@ bool Traj_TNG::ID_TrajFormat(CpptrajFile& fileIn) { if (fileIn.Read(&tngheader, 52) != 52) return false; fileIn.CloseFile(); if (strncmp(tngheader+40, "GENERAL INFO", 12)==0) { - mprintf("DEBUG: TNG file.\n"); + //mprintf("DEBUG: TNG file.\n"); return true; } @@ -57,7 +57,7 @@ void Traj_TNG::Info() { /** Close file. */ void Traj_TNG::closeTraj() { - mprintf("DEBUG: Calling closeTrajin() isOpen_=%1i\n", (int)isOpen_); + //mprintf("DEBUG: Calling closeTrajin() isOpen_=%1i\n", (int)isOpen_); if (isOpen_) { tng_util_trajectory_close(&traj_); } @@ -67,7 +67,7 @@ void Traj_TNG::closeTraj() { // ----------------------------------------------------------------------------- /** Open trajectory for reading. */ int Traj_TNG::openTrajin() { - mprintf("DEBUG: Calling openTrajin() isOpen_=%1i\n", (int)isOpen_); + //mprintf("DEBUG: Calling openTrajin() isOpen_=%1i\n", (int)isOpen_); if (isOpen_) closeTraj(); tng_function_status stat = tng_util_trajectory_open(filename_.full(), 'r', &traj_); @@ -75,7 +75,7 @@ int Traj_TNG::openTrajin() { mprinterr("Error: Could not open TNG file '%s'\n", filename_.full()); return TRAJIN_ERR; } - mprintf("DEBUG: Successfully opened TNG file.\n"); + //mprintf("DEBUG: Successfully opened TNG file.\n"); isOpen_ = true; current_frame_ = -1; @@ -119,6 +119,7 @@ int Traj_TNG::getNextBlocks(int64_t &next_frame) return 0; } +/** Convert TNG data type to string. */ static inline const char* DtypeStr(char typeIn) { switch (typeIn) { case TNG_INT_DATA : return "integer"; @@ -129,6 +130,7 @@ static inline const char* DtypeStr(char typeIn) { return 0; } +/** Convert TNG block ID to string. */ static inline const char* BtypeStr(int64_t typeIn) { switch (typeIn) { case TNG_TRAJ_BOX_SHAPE : return "box"; @@ -142,12 +144,13 @@ static inline const char* BtypeStr(int64_t typeIn) { case TNG_TRAJ_OCCUPANCY : return "occupancy"; case TNG_TRAJ_GENERAL_COMMENTS : return "general comments"; case TNG_TRAJ_MASSES : return "masses"; + case TNG_GMX_LAMBDA : return "gromacs lambda"; default : return "unknown"; } return 0; } - +/* Read next set of values from specified block. */ int Traj_TNG::readValues(int64_t blockId, int64_t& next_frame, double& frameTime, char& datatype) { tng_function_status stat; int blockDependency; @@ -206,7 +209,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) return 1; } // Print number of frames - mprintf("\tTNG file has %li frames.\n", tngframes_); + mprintf("\tTNG file covers %li MD frames.\n", tngframes_); // Get number of frame sets tngsets_ = -1; @@ -221,7 +224,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) double tpf = 0.0; if (tng_time_per_frame_get( traj_, &tpf) != TNG_SUCCESS) tpf = 0.0; - mprintf("\tTNG file time per frame: %g\n", tpf); + mprintf("\tTNG file time per frame: %g s\n", tpf); // Get the exponential distance scaling factor int64_t tngexp; @@ -246,7 +249,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) tngfac_ = pow(10.0, tngexp + 10); break; } // Print the scaling factor - mprintf("\tTNG distance scaling factor: %g\n", tngfac_); + mprintf("\tTNG distance scaling factor (to convert to Ang): x%g\n", tngfac_); // This will be used as temp space for reading in values from TNG if (values_ != 0) free( values_ ); @@ -275,7 +278,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) for (int64_t idx = 0; idx < next_nblocks_; idx++) { int64_t blockId = next_blockIDs_[idx]; - mprintf("DEBUG: Block '%s' detected.\n", BtypeStr(blockId)); + if (debug_ > 0) mprintf("DEBUG: Block '%s' detected.\n", BtypeStr(blockId)); if ( blockId == TNG_TRAJ_BOX_SHAPE ) { // Try to determine the box type by reading first frame values. double frameTime; @@ -291,7 +294,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) return TRAJIN_ERR; } convertArray(boxShape.Dptr(), (float*)values_, 9); - boxShape.Print("boxShape"); + if (debug_ > 0) boxShape.Print("First frame Unit Cell Matrix"); } else if ( blockId == TNG_TRAJ_POSITIONS ) { hasPos = true; } else if ( blockId == TNG_TRAJ_VELOCITIES ) { @@ -334,7 +337,7 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { return 1; } - mprintf("DEBUG: Set %i next_frame %li nblocksnext %li\n", set+1, next_frame, next_nblocks_); + //mprintf("DEBUG: Set %i next_frame %li nblocksnext %li\n", set+1, next_frame, next_nblocks_); if (next_nblocks_ < 1) { mprinterr("Error: No data blocks in next frame (set %i, TNG frame %li)\n", set+1, next_frame); @@ -355,7 +358,7 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { mprintf("Warning: Skipping TNG block '%s'\n", BtypeStr(blockId)); continue; } - mprintf("DEBUG: set %i frameTime %g block %s data %s\n", set+1, frameTime, BtypeStr(blockId), DtypeStr(datatype)); + //mprintf("DEBUG: set %i frameTime %g block %s data %s\n", set+1, frameTime, BtypeStr(blockId), DtypeStr(datatype)); // TODO: ok to only expect float data? if (datatype != TNG_FLOAT_DATA) { mprinterr("Error: TNG block '%s' data type is %s, expected float!\n", BtypeStr(blockId), DtypeStr(datatype)); @@ -366,15 +369,15 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { Matrix_3x3 boxShape(0.0); convertArray(boxShape.Dptr(), (float*)values_, 9); frameIn.SetBox( Box(boxShape) ); - mprintf("DEBUG: box set %i %g %g %g\n", set, - frameIn.BoxCrd().BoxX(), - frameIn.BoxCrd().BoxY(), - frameIn.BoxCrd().BoxZ()); + //mprintf("DEBUG: box set %i %g %g %g\n", set, + // frameIn.BoxCrd().BoxX(), + // frameIn.BoxCrd().BoxY(), + // frameIn.BoxCrd().BoxZ()); // ----- Coords -------------------- } else if ( blockId == TNG_TRAJ_POSITIONS ) { convertArray( frameIn.xAddress(), (float*)values_, tngatoms_*3 ); - const double* tmpXYZ = frameIn.XYZ(0); - mprintf("DEBUG: positions set %i %g %g %g\n", set, tmpXYZ[0], tmpXYZ[1], tmpXYZ[2]); + //const double* tmpXYZ = frameIn.XYZ(0); + //mprintf("DEBUG: positions set %i %g %g %g\n", set, tmpXYZ[0], tmpXYZ[1], tmpXYZ[2]); } else if ( blockId == TNG_TRAJ_VELOCITIES ) { convertArray( frameIn.vAddress(), (float*)values_, tngatoms_*3 ); } else if ( blockId == TNG_TRAJ_FORCES ) { @@ -382,6 +385,7 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { } } // END loop over blocks in next frame // TODO is it OK that frameTime is potentially set multiple times? + // Convert time to ps frameIn.SetTime( frameTime / Constants::PICO ); // Update current frame number From 0fdf1ede57669df5664452af5afc2179140cc182 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 17 Oct 2019 12:12:04 -0400 Subject: [PATCH 51/77] DRR - Start adding gromacs dump file format for comparing --- src/Traj_GmxDump.cpp | 183 +++++++++++++++++++++++++++++++++++++++++++ src/Traj_GmxDump.h | 46 +++++++++++ src/cpptrajdepend | 1 + src/cpptrajfiles | 1 + 4 files changed, 231 insertions(+) create mode 100644 src/Traj_GmxDump.cpp create mode 100644 src/Traj_GmxDump.h diff --git a/src/Traj_GmxDump.cpp b/src/Traj_GmxDump.cpp new file mode 100644 index 0000000000..f387544c74 --- /dev/null +++ b/src/Traj_GmxDump.cpp @@ -0,0 +1,183 @@ +#include "Traj_GmxDump.h" +#include "CpptrajStdio.h" +#include "Constants.h" // ANG_TO_NM +#include "Topology.h" +#include "ArgList.h" + +/// CONSTRUCTOR +Traj_GmxDump::Traj_GmxDump() : + natoms_(0), + outfmt_(0), + longFormat_(false) +{} + +/** Identify trajectory format. File should be setup for READ */ +bool Traj_GmxDump::ID_TrajFormat(CpptrajFile& fileIn) { + + return false; +} + +/** Print trajectory info to stdout. */ +void Traj_GmxDump::Info() { + mprintf("is a Gromacs text dump file"); +} + +/** Close file. */ +void Traj_GmxDump::closeTraj() { + +} + +// ----------------------------------------------------------------------------- +/** Open trajectory for reading. */ +int Traj_GmxDump::openTrajin() { + + return 1; +} + +/** Read help */ +void Traj_GmxDump::ReadHelp() { + +} + +/** Process read arguments. */ +int Traj_GmxDump::processReadArgs(ArgList& argIn) { + + return 0; +} + +/** Set up trajectory for reading. + * \return Number of frames in trajectory. + */ +int Traj_GmxDump::setupTrajin(FileName const& fname, Topology* trajParm) +{ + + return TRAJIN_ERR; +} + +/** Read specified trajectory frame. */ +int Traj_GmxDump::readFrame(int set, Frame& frameIn) { + + return 1; +} + +/** Read velocities from specified frame. */ +int Traj_GmxDump::readVelocity(int set, Frame& frameIn) { + + return 1; +} + +/** Read forces from specified frame. */ +int Traj_GmxDump::readForce(int set, Frame& frameIn) { + + return 1; +} + +// ----------------------------------------------------------------------------- +/** Write help. */ +void Traj_GmxDump::WriteHelp() { + mprintf("\tlongformat : If specified, use output format with increased width/precision.\n"); +} + +/** Process write arguments. */ +int Traj_GmxDump::processWriteArgs(ArgList& argIn, DataSetList const& DSLin) { + longFormat_ = argIn.hasKey("longformat"); + return 0; +} + +/** Set up trajectory for write. */ +int Traj_GmxDump::setupTrajout(FileName const& fname, Topology* trajParm, + CoordinateInfo const& cInfoIn, + int NframesToWrite, bool append) +{ + SetCoordInfo( cInfoIn ); + + if (append) { + // Appending. + if (file_.SetupAppend( fname, debug_ )) return 1; + if (file_.OpenFile()) return 1; + } else { + // Not appending. + if (file_.SetupWrite( fname, debug_ )) return 1; + if (file_.OpenFile()) return 1; + } + natoms_ = trajParm->Natom(); + if (longFormat_) + outfmt_ = "%15.8e"; + else + outfmt_ = "%12.5e"; + return 1; +} + +void Traj_GmxDump::writeVectorArray(const double* array, const char* title, int Nlines, int Ncols) +{ + // Print title, indent 4. + file_.Printf(" %s (%dx%d):\n", title, Nlines, Ncols); + // Print each line, indent of 8 + int idx = 0; + for (int line = 0; line != Nlines; line++) + { + file_.Printf(" %s[%5d]={", title, line); + for (int col = 0; col != Ncols; col++) + { + if (col != 0) file_.Printf(", "); + file_.Printf(outfmt_, array[idx++]); + } + file_.Printf("}\n"); + } // END loop over lines +} + +/** Write specified trajectory frame. */ +int Traj_GmxDump::writeFrame(int set, Frame const& frameOut) { + // Write file name and frame (starts from 0). No indent. + file_.Printf("%s frame %d", file_.Filename().full(), set); + // Write number of atoms, step, time, lambda. Indent of 4. + file_.Printf(" natoms=%10d step=%10i time=%12.7e lambda=%10g\n", + natoms_, 0, frameOut.Time(), 0); + if (CoordInfo().HasBox()) { + Matrix_3x3 Ucell = frameOut.BoxCrd().UnitCell( Constants::ANG_TO_NM ); + writeVectorArray( Ucell.Dptr(), "box", 3, 3 ); + } + + + return 0; +} + +// ============================================================================= +#ifdef MPI +/** Open trajectory for reading in parallel. */ +int Traj_GmxDump::parallelOpenTrajin(Parallel::Comm const& commIn) { + return 1; +} + +/** Open trajectory for writing in parallel. */ +int Traj_GmxDump::parallelOpenTrajout(Parallel::Comm const& commIn) { + return 1; +} + +/** Set up trajectory for write in parallel. */ +int Traj_GmxDump::parallelSetupTrajout(FileName const& fname, Topology* trajParm, + CoordinateInfo const& cInfoIn, + int NframesToWrite, bool append, + Parallel::Comm const& commIn) +{ + + return 1; +} + +/** Read frame in parallel. */ +int Traj_GmxDump::parallelReadFrame(int set, Frame& frameIn) { + + return 1; +} + +/** Write frame in parallel. */ +int Traj_GmxDump::parallelWriteFrame(int set, Frame const& frameOut) { + + return 1; +} + +/** Close trajectory in parallel. */ +void Traj_GmxDump::parallelCloseTraj() { + +} +#endif diff --git a/src/Traj_GmxDump.h b/src/Traj_GmxDump.h new file mode 100644 index 0000000000..c5006b4072 --- /dev/null +++ b/src/Traj_GmxDump.h @@ -0,0 +1,46 @@ +#ifndef INC_TRAJ_GMXDUMP_H +#define INC_TRAJ_GMXDUMP_H +#include "TrajectoryIO.h" +#include "CpptrajFile.h" +/// Can be used to compare output to 'gmx dump'. Currently only for debug. +class Traj_GmxDump : public TrajectoryIO { + public: + Traj_GmxDump(); + static BaseIOtype* Alloc() { return (BaseIOtype*)new Traj_GmxDump(); } + static void WriteHelp(); + static void ReadHelp(); + private: + // ----- Inherited functions ----------------- + bool ID_TrajFormat(CpptrajFile&); + int setupTrajin(FileName const&, Topology*); + int setupTrajout(FileName const&, Topology*, CoordinateInfo const&,int, bool); + int openTrajin(); + void closeTraj(); + int readFrame(int,Frame&); + int writeFrame(int,Frame const&); + void Info(); + int readVelocity(int, Frame&); + int readForce(int, Frame&); + int processWriteArgs(ArgList&, DataSetList const&); + int processReadArgs(ArgList&); + // ------------------------------------------- +# ifdef MPI + // ----- Parallel functions ------------------ + int parallelOpenTrajin(Parallel::Comm const&); + int parallelOpenTrajout(Parallel::Comm const&); + int parallelSetupTrajout(FileName const&, Topology*, CoordinateInfo const&, + int, bool, Parallel::Comm const&); + int parallelReadFrame(int, Frame&); + int parallelWriteFrame(int, Frame const&); + void parallelCloseTraj(); + // ------------------------------------------- +# endif + + void writeVectorArray(const double*, const char*, int, int); + + CpptrajFile file_; + int natoms_; ///< Number of atoms in file + const char* outfmt_; ///< Hold output write format + bool longFormat_; ///< If true use the longer format +}; +#endif diff --git a/src/cpptrajdepend b/src/cpptrajdepend index 922255216c..86e2f83272 100644 --- a/src/cpptrajdepend +++ b/src/cpptrajdepend @@ -355,6 +355,7 @@ Traj_CharmmCor.o : Traj_CharmmCor.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h Ba Traj_CharmmDcd.o : Traj_CharmmDcd.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h ByteRoutines.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_CharmmDcd.h TrajectoryIO.h Vec3.h Traj_CharmmRestart.o : Traj_CharmmRestart.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedFrame.h BufferedLine.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h StringRoutines.h SymbolExporting.h TextFormat.h Topology.h Traj_CharmmRestart.h TrajectoryIO.h Vec3.h Traj_Conflib.o : Traj_Conflib.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_Conflib.h TrajectoryIO.h Vec3.h +Traj_GmxDump.o : Traj_GmxDump.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_GmxDump.h TrajectoryIO.h Vec3.h Traj_GmxTrX.o : Traj_GmxTrX.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h ByteRoutines.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_GmxTrX.h TrajectoryIO.h Vec3.h Traj_GmxXtc.o : Traj_GmxXtc.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_GmxXtc.h TrajectoryIO.h Vec3.h Traj_Gro.o : Traj_Gro.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedLine.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h StringRoutines.h SymbolExporting.h Topology.h Traj_Gro.h TrajectoryIO.h Vec3.h diff --git a/src/cpptrajfiles b/src/cpptrajfiles index 534e0a5cb8..600ba735f3 100644 --- a/src/cpptrajfiles +++ b/src/cpptrajfiles @@ -351,6 +351,7 @@ COMMON_SOURCES= \ Traj_CharmmRestart.cpp \ Traj_CIF.cpp \ Traj_Conflib.cpp \ + Traj_GmxDump.cpp \ Traj_GmxTrX.cpp \ Traj_GmxXtc.cpp \ Traj_Gro.cpp \ From 57d9cda9d08e78b6725f65929a9706c6346ff5e6 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 17 Oct 2019 12:20:31 -0400 Subject: [PATCH 52/77] DRR - Finish gmxdump setup --- src/Traj_GmxDump.cpp | 11 +++++++++-- src/TrajectoryFile.cpp | 3 +++ src/TrajectoryFile.h | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Traj_GmxDump.cpp b/src/Traj_GmxDump.cpp index f387544c74..36ec1ed54a 100644 --- a/src/Traj_GmxDump.cpp +++ b/src/Traj_GmxDump.cpp @@ -91,6 +91,13 @@ int Traj_GmxDump::setupTrajout(FileName const& fname, Topology* trajParm, { SetCoordInfo( cInfoIn ); + // Set up title. Default to filename. + std::string title = Title(); + if (title.empty()) { + title.assign( fname.Full() ); + SetTitle( title ); + } + if (append) { // Appending. if (file_.SetupAppend( fname, debug_ )) return 1; @@ -105,7 +112,7 @@ int Traj_GmxDump::setupTrajout(FileName const& fname, Topology* trajParm, outfmt_ = "%15.8e"; else outfmt_ = "%12.5e"; - return 1; + return 0; } void Traj_GmxDump::writeVectorArray(const double* array, const char* title, int Nlines, int Ncols) @@ -129,7 +136,7 @@ void Traj_GmxDump::writeVectorArray(const double* array, const char* title, int /** Write specified trajectory frame. */ int Traj_GmxDump::writeFrame(int set, Frame const& frameOut) { // Write file name and frame (starts from 0). No indent. - file_.Printf("%s frame %d", file_.Filename().full(), set); + file_.Printf("%s frame %d:\n", Title().c_str(), set); // Write number of atoms, step, time, lambda. Indent of 4. file_.Printf(" natoms=%10d step=%10i time=%12.7e lambda=%10g\n", natoms_, 0, frameOut.Time(), 0); diff --git a/src/TrajectoryFile.cpp b/src/TrajectoryFile.cpp index a75814e6a5..331da7a5ed 100644 --- a/src/TrajectoryFile.cpp +++ b/src/TrajectoryFile.cpp @@ -24,6 +24,7 @@ #include "Traj_CharmmRestart.h" #include "Traj_XYZ.h" #include "Traj_TNG.h" +#include "Traj_GmxDump.h" // ----- STATIC VARS / ROUTINES ------------------------------------------------ // NOTE: Must be in same order as TrajFormatType @@ -69,6 +70,7 @@ const FileTypes::AllocToken TrajectoryFile::TF_AllocArray[] = { { "SDF", 0, 0, Traj_SDF::Alloc }, { "XYZ", 0, Traj_XYZ::WriteHelp, Traj_XYZ::Alloc }, { "LMOD conflib", 0, 0, Traj_Conflib::Alloc }, + { "Gromacs dump", 0, Traj_GmxDump::WriteHelp, Traj_GmxDump::Alloc }, { "Unknown trajectory", 0, 0, 0 } }; @@ -128,6 +130,7 @@ const FileTypes::KeyToken TrajectoryFile::TF_WriteKeyArray[] = { { AMBERTRAJ, "crd", ".crd" }, { SQM, "sqm", ".sqm" }, { XYZ, "xyz", ".xyz" }, + { GMXDUMP, "gmxdump", ".gmxdump" }, { UNKNOWN_TRAJ, 0, 0 } }; diff --git a/src/TrajectoryFile.h b/src/TrajectoryFile.h index 785e1aeff7..5d5638e95b 100644 --- a/src/TrajectoryFile.h +++ b/src/TrajectoryFile.h @@ -28,7 +28,7 @@ class TrajectoryFile { CIF, CHARMMDCD, GMXTRX, GMXXTC, GMXTNG, BINPOS, AMBERRESTART, GRO, TINKER, CHARMMCOR, CHARMMREST, AMBERTRAJ, SQM, SDF, XYZ, - CONFLIB, + CONFLIB, GMXDUMP, UNKNOWN_TRAJ }; From d24aa9c186f8b6b34fb3990b138317347cab34e5 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 17 Oct 2019 12:23:49 -0400 Subject: [PATCH 53/77] DRR - Add coords write --- src/Traj_GmxDump.cpp | 9 ++++++--- src/Traj_GmxDump.h | 2 +- src/cpptrajdepend | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/Traj_GmxDump.cpp b/src/Traj_GmxDump.cpp index 36ec1ed54a..4b205b98bf 100644 --- a/src/Traj_GmxDump.cpp +++ b/src/Traj_GmxDump.cpp @@ -115,7 +115,7 @@ int Traj_GmxDump::setupTrajout(FileName const& fname, Topology* trajParm, return 0; } -void Traj_GmxDump::writeVectorArray(const double* array, const char* title, int Nlines, int Ncols) +void Traj_GmxDump::writeVectorArray(const double* array, const char* title, int Nlines, int Ncols, double scale) { // Print title, indent 4. file_.Printf(" %s (%dx%d):\n", title, Nlines, Ncols); @@ -127,7 +127,7 @@ void Traj_GmxDump::writeVectorArray(const double* array, const char* title, int for (int col = 0; col != Ncols; col++) { if (col != 0) file_.Printf(", "); - file_.Printf(outfmt_, array[idx++]); + file_.Printf(outfmt_, array[idx++] * scale); } file_.Printf("}\n"); } // END loop over lines @@ -142,8 +142,11 @@ int Traj_GmxDump::writeFrame(int set, Frame const& frameOut) { natoms_, 0, frameOut.Time(), 0); if (CoordInfo().HasBox()) { Matrix_3x3 Ucell = frameOut.BoxCrd().UnitCell( Constants::ANG_TO_NM ); - writeVectorArray( Ucell.Dptr(), "box", 3, 3 ); + // Already scaled by UnitCell() + writeVectorArray( Ucell.Dptr(), "box", 3, 3, 1.0); } + if (CoordInfo().HasCrd()) + writeVectorArray( frameOut.xAddress(), "x", natoms_, 3, Constants::ANG_TO_NM ); return 0; diff --git a/src/Traj_GmxDump.h b/src/Traj_GmxDump.h index c5006b4072..059d5cdfcf 100644 --- a/src/Traj_GmxDump.h +++ b/src/Traj_GmxDump.h @@ -36,7 +36,7 @@ class Traj_GmxDump : public TrajectoryIO { // ------------------------------------------- # endif - void writeVectorArray(const double*, const char*, int, int); + void writeVectorArray(const double*, const char*, int, int, double); CpptrajFile file_; int natoms_; ///< Number of atoms in file diff --git a/src/cpptrajdepend b/src/cpptrajdepend index 86e2f83272..91a2ec1989 100644 --- a/src/cpptrajdepend +++ b/src/cpptrajdepend @@ -367,7 +367,7 @@ Traj_SQM.o : Traj_SQM.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h B Traj_TNG.o : Traj_TNG.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_TNG.h TrajectoryIO.h Vec3.h Traj_Tinker.o : Traj_Tinker.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedLine.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h TinkerFile.h Topology.h Traj_Tinker.h TrajectoryIO.h Vec3.h Traj_XYZ.o : Traj_XYZ.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedLine.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h StringRoutines.h SymbolExporting.h TextFormat.h Topology.h Traj_XYZ.h TrajectoryIO.h Vec3.h -TrajectoryFile.o : TrajectoryFile.cpp ArgList.h Atom.h AtomMask.h BaseIOtype.h Box.h BufferedFrame.h BufferedLine.h CIFfile.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h FileTypes.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Mol2File.h Molecule.h NameType.h NetcdfFile.h PDBfile.h Parallel.h ReplicaDimArray.h Residue.h SDFfile.h SymbolExporting.h TextFormat.h TinkerFile.h Traj_AmberCoord.h Traj_AmberNetcdf.h Traj_AmberRestart.h Traj_AmberRestartNC.h Traj_Binpos.h Traj_CIF.h Traj_CharmmCor.h Traj_CharmmDcd.h Traj_CharmmRestart.h Traj_Conflib.h Traj_GmxTrX.h Traj_GmxXtc.h Traj_Gro.h Traj_Mol2File.h Traj_NcEnsemble.h Traj_PDBfile.h Traj_SDF.h Traj_SQM.h Traj_TNG.h Traj_Tinker.h Traj_XYZ.h TrajectoryFile.h TrajectoryIO.h Vec3.h +TrajectoryFile.o : TrajectoryFile.cpp ArgList.h Atom.h AtomMask.h BaseIOtype.h Box.h BufferedFrame.h BufferedLine.h CIFfile.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h FileTypes.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Mol2File.h Molecule.h NameType.h NetcdfFile.h PDBfile.h Parallel.h ReplicaDimArray.h Residue.h SDFfile.h SymbolExporting.h TextFormat.h TinkerFile.h Traj_AmberCoord.h Traj_AmberNetcdf.h Traj_AmberRestart.h Traj_AmberRestartNC.h Traj_Binpos.h Traj_CIF.h Traj_CharmmCor.h Traj_CharmmDcd.h Traj_CharmmRestart.h Traj_Conflib.h Traj_GmxDump.h Traj_GmxTrX.h Traj_GmxXtc.h Traj_Gro.h Traj_Mol2File.h Traj_NcEnsemble.h Traj_PDBfile.h Traj_SDF.h Traj_SQM.h Traj_TNG.h Traj_Tinker.h Traj_XYZ.h TrajectoryFile.h TrajectoryIO.h Vec3.h TrajectoryIO.o : TrajectoryIO.cpp BaseIOtype.h Box.h CoordinateInfo.h FramePtrArray.h Matrix_3x3.h Parallel.h ReplicaDimArray.h TrajectoryIO.h Vec3.h TrajinList.o : TrajinList.cpp ArgList.h AssociatedData.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataSet.h DataSet_RemLog.h Dimension.h EnsembleIn.h EnsembleIn_Multi.h EnsembleIn_Single.h FileIO.h FileName.h FileTypes.h Frame.h FramePtrArray.h InputTrajCommon.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h ReplicaInfo.h Residue.h StringRoutines.h SymbolExporting.h TextFormat.h Timer.h Topology.h TrajFrameCounter.h TrajIOarray.h TrajectoryFile.h TrajectoryIO.h Trajin.h TrajinList.h Trajin_Multi.h Trajin_Single.h Vec3.h Trajin_Multi.o : Trajin_Multi.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajStdio.h FileName.h Frame.h FramePtrArray.h InputTrajCommon.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h ReplicaInfo.h Residue.h StringRoutines.h SymbolExporting.h Topology.h TrajFrameCounter.h TrajIOarray.h TrajectoryIO.h Trajin.h Trajin_Multi.h Vec3.h From c49875afff92f7369c027d9e13a6937487cc6cdf Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 17 Oct 2019 12:51:54 -0400 Subject: [PATCH 54/77] DRR - Do force and velocity dump. Put gromacs conversions into Constants --- src/Constants.h | 10 +++++++++- src/Traj_GmxDump.cpp | 17 ++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/Constants.h b/src/Constants.h index 583406360f..1683658eb3 100644 --- a/src/Constants.h +++ b/src/Constants.h @@ -65,7 +65,15 @@ namespace Constants { * itself is derived from sqrt(1 / ((AMU_TO_KG * NA) / (1000 * CAL_TO_J))). */ const double AMBERTIME_TO_PS = 20.455; - // Pico prefix + /// Pico prefix const double PICO = 1e-12; + /// Convert Gromacs force units (kJ / mol * nm) to Amber units (kcal / mol * Ang) + const double GMX_FRC_TO_AMBER = ANG_TO_NM * J_TO_CAL; + /// Convert Amber force units to Gromacs + const double AMBER_FRC_TO_GMX = NM_TO_ANG * CAL_TO_J; + /// Convert Gromacs velocity units (nm / ps) to Amber units (Ang / (1/20.455)ps). + const double GMX_VEL_TO_AMBER = NM_TO_ANG / AMBERTIME_TO_PS; + /// Convert Amber velocity units to Gromacs + const double AMBER_VEL_TO_GMX = ANG_TO_NM * AMBERTIME_TO_PS; } #endif diff --git a/src/Traj_GmxDump.cpp b/src/Traj_GmxDump.cpp index 4b205b98bf..5b52364204 100644 --- a/src/Traj_GmxDump.cpp +++ b/src/Traj_GmxDump.cpp @@ -117,13 +117,13 @@ int Traj_GmxDump::setupTrajout(FileName const& fname, Topology* trajParm, void Traj_GmxDump::writeVectorArray(const double* array, const char* title, int Nlines, int Ncols, double scale) { - // Print title, indent 4. - file_.Printf(" %s (%dx%d):\n", title, Nlines, Ncols); - // Print each line, indent of 8 + // Print title, indent 3. + file_.Printf(" %s (%dx%d):\n", title, Nlines, Ncols); + // Print each line, indent of 6 int idx = 0; for (int line = 0; line != Nlines; line++) { - file_.Printf(" %s[%5d]={", title, line); + file_.Printf(" %s[%5d]={", title, line); for (int col = 0; col != Ncols; col++) { if (col != 0) file_.Printf(", "); @@ -137,8 +137,8 @@ void Traj_GmxDump::writeVectorArray(const double* array, const char* title, int int Traj_GmxDump::writeFrame(int set, Frame const& frameOut) { // Write file name and frame (starts from 0). No indent. file_.Printf("%s frame %d:\n", Title().c_str(), set); - // Write number of atoms, step, time, lambda. Indent of 4. - file_.Printf(" natoms=%10d step=%10i time=%12.7e lambda=%10g\n", + // Write number of atoms, step, time, lambda. Indent of 3. + file_.Printf(" natoms=%10d step=%10i time=%12.7e lambda=%10g\n", natoms_, 0, frameOut.Time(), 0); if (CoordInfo().HasBox()) { Matrix_3x3 Ucell = frameOut.BoxCrd().UnitCell( Constants::ANG_TO_NM ); @@ -147,8 +147,11 @@ int Traj_GmxDump::writeFrame(int set, Frame const& frameOut) { } if (CoordInfo().HasCrd()) writeVectorArray( frameOut.xAddress(), "x", natoms_, 3, Constants::ANG_TO_NM ); + if (CoordInfo().HasVel()) + writeVectorArray( frameOut.vAddress(), "v", natoms_, 3, Constants::AMBER_VEL_TO_GMX ); + if (CoordInfo().HasForce()) + writeVectorArray( frameOut.fAddress(), "f", natoms_, 3, Constants::AMBER_FRC_TO_GMX ); - return 0; } From d89ab233abcdcc40a02dcd688df86b6b3491f378 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 17 Oct 2019 12:55:16 -0400 Subject: [PATCH 55/77] DRR - Constants moved to Constants.h --- src/Traj_GmxTrX.cpp | 36 ++++++++++++------------------------ src/Traj_GmxTrX.h | 5 ----- 2 files changed, 12 insertions(+), 29 deletions(-) diff --git a/src/Traj_GmxTrX.cpp b/src/Traj_GmxTrX.cpp index 1ebe73233b..ca4a5c4e18 100644 --- a/src/Traj_GmxTrX.cpp +++ b/src/Traj_GmxTrX.cpp @@ -477,18 +477,6 @@ int Traj_GmxTrX::setupTrajout(FileName const& fname, Topology* trajParm, return 0; } -/** Convert Gromacs force units (kJ / mol * nm) to Amber units (kcal / mol * Ang) */ -const double Traj_GmxTrX::GMX_FRC_TO_AMBER = Constants::ANG_TO_NM * Constants::J_TO_CAL; - -/** Convert Amber force units to Gromacs */ -const double Traj_GmxTrX::AMBER_FRC_TO_GMX = Constants::NM_TO_ANG * Constants::CAL_TO_J; - -/** Convert Gromacs velocity units (nm / ps) to Amber units (Ang / (1/20.455)ps). */ -const double Traj_GmxTrX::GMX_VEL_TO_AMBER = Constants::NM_TO_ANG / Constants::AMBERTIME_TO_PS; - -/** Convert Amber velocity units to Gromacs */ -const double Traj_GmxTrX::AMBER_VEL_TO_GMX = Constants::ANG_TO_NM * Constants::AMBERTIME_TO_PS; - // Traj_GmxTrX::readFrame() int Traj_GmxTrX::readFrame(int set, Frame& frameIn) { file_.Seek( (frameSize_ * set) + timestepPos_ ); @@ -521,13 +509,13 @@ int Traj_GmxTrX::readFrame(int set, Frame& frameIn) { if (v_size_ > 0) { double* Vptr = frameIn.vAddress(); for (int iv = 0; iv != natom3_; iv++, ix++) - Vptr[iv] = ((double)farray_[ix]) * GMX_VEL_TO_AMBER; + Vptr[iv] = ((double)farray_[ix]) * Constants::GMX_VEL_TO_AMBER; } // Read forces if (f_size_ > 0) { double* Fptr = frameIn.fAddress(); for (int ir = 0; ir != natom3_; ir++, ix++) - Fptr[ir] = ((double)farray_[ix]) * GMX_FRC_TO_AMBER; + Fptr[ir] = ((double)farray_[ix]) * Constants::GMX_FRC_TO_AMBER; } } else if (precision_ == sizeof(double)) { if (file_.Read( darray_, total_size ) != total_size) { @@ -545,13 +533,13 @@ int Traj_GmxTrX::readFrame(int set, Frame& frameIn) { if (v_size_ > 0) { double* Vptr = frameIn.vAddress(); for (int iv = 0; iv != natom3_; iv++, ix++) - Vptr[iv] = darray_[ix] * GMX_VEL_TO_AMBER; + Vptr[iv] = darray_[ix] * Constants::GMX_VEL_TO_AMBER; } // Read forces if (f_size_ > 0) { double* Fptr = frameIn.fAddress(); for (int ir = 0; ir != natom3_; ir++, ix++) - Fptr[ir] = darray_[ix] * GMX_FRC_TO_AMBER; + Fptr[ir] = darray_[ix] * Constants::GMX_FRC_TO_AMBER; } } else // SANITY CHECK mprinterr("Error: Unknown precision (%i)\n", precision_); @@ -573,7 +561,7 @@ int Traj_GmxTrX::readVelocity(int set, Frame& frameIn) { } double* Vptr = frameIn.vAddress(); for (int iv = 0; iv != natom3_; iv++) - Vptr[iv] = ((double)farray_[iv]) * GMX_VEL_TO_AMBER; + Vptr[iv] = ((double)farray_[iv]) * Constants::GMX_VEL_TO_AMBER; } else if (precision_ == sizeof(double)) { if (file_.Read( darray_, v_size_ ) != v_size_) { mprinterr("Error: Could not read velocities from TRX frame %i\n", set+1); @@ -581,7 +569,7 @@ int Traj_GmxTrX::readVelocity(int set, Frame& frameIn) { } double* Vptr = frameIn.vAddress(); for (int iv = 0; iv != natom3_; iv++) - Vptr[iv] = darray_[iv] * GMX_VEL_TO_AMBER; + Vptr[iv] = darray_[iv] * Constants::GMX_VEL_TO_AMBER; } } else // SANITY mprintf("Warning: TRX file does not contain velocity information.\n"); @@ -602,7 +590,7 @@ int Traj_GmxTrX::readForce(int set, Frame& frameIn) { } double* Fptr = frameIn.fAddress(); for (int ir = 0; ir != natom3_; ir++) - Fptr[ir] = ((double)farray_[ir]) * GMX_FRC_TO_AMBER; + Fptr[ir] = ((double)farray_[ir]) * Constants::GMX_FRC_TO_AMBER; } else if (precision_ == sizeof(double)) { if (file_.Read( darray_, f_size_ ) != f_size_) { mprinterr("Error: Could not read forces from TRX frame %i\n", set+1); @@ -610,7 +598,7 @@ int Traj_GmxTrX::readForce(int set, Frame& frameIn) { } double* Fptr = frameIn.fAddress(); for (int ir = 0; ir != natom3_; ir++) - Fptr[ir] = darray_[ir] * GMX_FRC_TO_AMBER; + Fptr[ir] = darray_[ir] * Constants::GMX_FRC_TO_AMBER; } } else // SANITY mprintf("Warning: TRX file does not contain force information.\n"); @@ -677,10 +665,10 @@ int Traj_GmxTrX::writeFrame(int set, Frame const& frameOut) { farray_[ix] = (float)(Xptr[ix] * Constants::ANG_TO_NM); if (v_size_ > 0) for (int iv = 0; iv < natom3_; iv++, ix++) - farray_[ix] = (float)(Vptr[iv] * AMBER_VEL_TO_GMX); + farray_[ix] = (float)(Vptr[iv] * Constants::AMBER_VEL_TO_GMX); if (f_size_ > 0) for (int ir = 0; ir < natom3_; ir++, ix++) - farray_[ix] = (float)(Fptr[ir] * AMBER_FRC_TO_GMX); + farray_[ix] = (float)(Fptr[ir] * Constants::AMBER_FRC_TO_GMX); if (swapBytes_) endian_swap( farray_, arraySize_ ); file_.Write( farray_, x_size_ + v_size_ + f_size_ ); } else { // double @@ -688,10 +676,10 @@ int Traj_GmxTrX::writeFrame(int set, Frame const& frameOut) { darray_[ix] = (Xptr[ix] * Constants::ANG_TO_NM); if (v_size_ > 0) for (int iv = 0; iv < natom3_; iv++, ix++) - darray_[ix] = (Vptr[iv] * AMBER_VEL_TO_GMX); + darray_[ix] = (Vptr[iv] * Constants::AMBER_VEL_TO_GMX); if (f_size_ > 0) for (int ir = 0; ir < natom3_; ir++, ix++) - darray_[ix] = (Fptr[ir] * AMBER_FRC_TO_GMX); + darray_[ix] = (Fptr[ir] * Constants::AMBER_FRC_TO_GMX); if (swapBytes_) endian_swap8( darray_, arraySize_ ); file_.Write( darray_, x_size_ + v_size_ + f_size_ ); } diff --git a/src/Traj_GmxTrX.h b/src/Traj_GmxTrX.h index 2dcc2a7994..d845f1d32a 100644 --- a/src/Traj_GmxTrX.h +++ b/src/Traj_GmxTrX.h @@ -79,10 +79,5 @@ class Traj_GmxTrX : public TrajectoryIO { size_t arraySize_; ///< # elements in {d|f}array_; total # of position/veloc/force coords. float* farray_; ///< Array for reading/writing single precision. double* darray_; ///< Array for reading/writine double precision. - - static const double GMX_FRC_TO_AMBER; - static const double AMBER_FRC_TO_GMX; - static const double GMX_VEL_TO_AMBER; - static const double AMBER_VEL_TO_GMX; }; #endif From c0bba777ef57fadf282c54a650bd3f735b960fae Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 17 Oct 2019 13:49:15 -0400 Subject: [PATCH 56/77] DRR - Turns out if you dump from a TNG file, different routines are used... --- src/Traj_GmxDump.cpp | 51 ++++++++++++++++++++++++++++++-------------- src/Traj_GmxDump.h | 4 +++- 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/src/Traj_GmxDump.cpp b/src/Traj_GmxDump.cpp index 5b52364204..c0ec0e6dab 100644 --- a/src/Traj_GmxDump.cpp +++ b/src/Traj_GmxDump.cpp @@ -8,7 +8,8 @@ Traj_GmxDump::Traj_GmxDump() : natoms_(0), outfmt_(0), - longFormat_(false) + longFormat_(false), + tngfmt_(false) {} /** Identify trajectory format. File should be setup for READ */ @@ -115,15 +116,21 @@ int Traj_GmxDump::setupTrajout(FileName const& fname, Topology* trajParm, return 0; } -void Traj_GmxDump::writeVectorArray(const double* array, const char* title, int Nlines, int Ncols, double scale) +void Traj_GmxDump::indent(int i) { + if (i > 0) file_.Printf("%*s", i, ""); +} + +void Traj_GmxDump::writeVectorArray(const double* array, const char* title, int tindent, int bindent, int Nlines, int Ncols, double scale) { // Print title, indent 3. - file_.Printf(" %s (%dx%d):\n", title, Nlines, Ncols); + indent(tindent); + file_.Printf("%s (%dx%d):\n", title, Nlines, Ncols); // Print each line, indent of 6 int idx = 0; for (int line = 0; line != Nlines; line++) { - file_.Printf(" %s[%5d]={", title, line); + indent(bindent); + file_.Printf("%s[%5d]={", title, line); for (int col = 0; col != Ncols; col++) { if (col != 0) file_.Printf(", "); @@ -138,19 +145,31 @@ int Traj_GmxDump::writeFrame(int set, Frame const& frameOut) { // Write file name and frame (starts from 0). No indent. file_.Printf("%s frame %d:\n", Title().c_str(), set); // Write number of atoms, step, time, lambda. Indent of 3. - file_.Printf(" natoms=%10d step=%10i time=%12.7e lambda=%10g\n", - natoms_, 0, frameOut.Time(), 0); - if (CoordInfo().HasBox()) { - Matrix_3x3 Ucell = frameOut.BoxCrd().UnitCell( Constants::ANG_TO_NM ); - // Already scaled by UnitCell() - writeVectorArray( Ucell.Dptr(), "box", 3, 3, 1.0); + indent(3); + const double lambda = 0; + const int step = 0; + file_.Printf("natoms=%10d step=%10i time=%12.7e lambda=%10g\n", + natoms_, step, frameOut.Time(), lambda); + if (tngfmt_) { + // TNG format + if (CoordInfo().HasCrd()) + writeVectorArray( frameOut.xAddress(), "POSITIONS", 3, 6, natoms_, 3, Constants::ANG_TO_NM ); + + + } else { + // Generic TRR format + if (CoordInfo().HasBox()) { + Matrix_3x3 Ucell = frameOut.BoxCrd().UnitCell( Constants::ANG_TO_NM ); + // Already scaled by UnitCell() + writeVectorArray( Ucell.Dptr(), "box", 3, 6, 3, 3, 1.0); + } + if (CoordInfo().HasCrd()) + writeVectorArray( frameOut.xAddress(), "x", 3, 6, natoms_, 3, Constants::ANG_TO_NM ); + if (CoordInfo().HasVel()) + writeVectorArray( frameOut.vAddress(), "v", 3, 6, natoms_, 3, Constants::AMBER_VEL_TO_GMX ); + if (CoordInfo().HasForce()) + writeVectorArray( frameOut.fAddress(), "f", 3, 6, natoms_, 3, Constants::AMBER_FRC_TO_GMX ); } - if (CoordInfo().HasCrd()) - writeVectorArray( frameOut.xAddress(), "x", natoms_, 3, Constants::ANG_TO_NM ); - if (CoordInfo().HasVel()) - writeVectorArray( frameOut.vAddress(), "v", natoms_, 3, Constants::AMBER_VEL_TO_GMX ); - if (CoordInfo().HasForce()) - writeVectorArray( frameOut.fAddress(), "f", natoms_, 3, Constants::AMBER_FRC_TO_GMX ); return 0; } diff --git a/src/Traj_GmxDump.h b/src/Traj_GmxDump.h index 059d5cdfcf..2cc88daf54 100644 --- a/src/Traj_GmxDump.h +++ b/src/Traj_GmxDump.h @@ -36,11 +36,13 @@ class Traj_GmxDump : public TrajectoryIO { // ------------------------------------------- # endif - void writeVectorArray(const double*, const char*, int, int, double); + void indent(int); + void writeVectorArray(const double*, const char*, int, int, int, int, double); CpptrajFile file_; int natoms_; ///< Number of atoms in file const char* outfmt_; ///< Hold output write format bool longFormat_; ///< If true use the longer format + bool tngfmt_; ///< If true use TNG style output format }; #endif From 686c36f8da4fbf9863ee46de2e5b6babf7201a57 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 17 Oct 2019 14:03:05 -0400 Subject: [PATCH 57/77] DRR - Fix conversion of velocity and force info from TNG --- src/Traj_TNG.cpp | 11 +++++++++-- src/Traj_TNG.h | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index ad3938ef51..2c3f8efe45 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -99,6 +99,13 @@ void Traj_TNG::convertArray(double* out, float* in, unsigned int nvals) const { out[i] = ((double)in[i]) * tngfac_; } +/* Utility function for properly scaling coordinates according to the factor + * plus an additional factor. + */ +void Traj_TNG::convertArray(double* out, float* in, unsigned int nvals, double scale) const { + for (unsigned int i = 0; i != nvals; i++) + out[i] = ((double)in[i]) * tngfac_ * scale; +} /** \return 1 if no more blocks, -1 on error, 0 if ok. */ int Traj_TNG::getNextBlocks(int64_t &next_frame) @@ -379,9 +386,9 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { //const double* tmpXYZ = frameIn.XYZ(0); //mprintf("DEBUG: positions set %i %g %g %g\n", set, tmpXYZ[0], tmpXYZ[1], tmpXYZ[2]); } else if ( blockId == TNG_TRAJ_VELOCITIES ) { - convertArray( frameIn.vAddress(), (float*)values_, tngatoms_*3 ); + convertArray( frameIn.vAddress(), (float*)values_, tngatoms_*3, 1 / Constants::AMBERTIME_TO_PS ); } else if ( blockId == TNG_TRAJ_FORCES ) { - convertArray( frameIn.fAddress(), (float*)values_, tngatoms_*3 ); + convertArray( frameIn.fAddress(), (float*)values_, tngatoms_*3, Constants::J_TO_CAL ); } } // END loop over blocks in next frame // TODO is it OK that frameTime is potentially set multiple times? diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index 524219d587..669c544caa 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -40,6 +40,7 @@ class Traj_TNG : public TrajectoryIO { # endif void convertArray(double*, float*, unsigned int) const; + void convertArray(double*, float*, unsigned int, double) const; int getNextBlocks(int64_t&); int readValues(int64_t, int64_t&, double&, char&); From fda62a55546845468aa43d2781dd64af3594afee Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 17 Oct 2019 14:03:22 -0400 Subject: [PATCH 58/77] DRR - Add TNG format output for debug --- src/Traj_GmxDump.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Traj_GmxDump.cpp b/src/Traj_GmxDump.cpp index c0ec0e6dab..637cb564e7 100644 --- a/src/Traj_GmxDump.cpp +++ b/src/Traj_GmxDump.cpp @@ -76,12 +76,14 @@ int Traj_GmxDump::readForce(int set, Frame& frameIn) { // ----------------------------------------------------------------------------- /** Write help. */ void Traj_GmxDump::WriteHelp() { - mprintf("\tlongformat : If specified, use output format with increased width/precision.\n"); + mprintf("\tlongformat : If specified, use output format with increased width/precision.\n" + "\ttngformat : If specified, output as if original trajectory was TNG.\n"); } /** Process write arguments. */ int Traj_GmxDump::processWriteArgs(ArgList& argIn, DataSetList const& DSLin) { longFormat_ = argIn.hasKey("longformat"); + tngfmt_ = argIn.hasKey("tngformat"); return 0; } @@ -154,8 +156,13 @@ int Traj_GmxDump::writeFrame(int set, Frame const& frameOut) { // TNG format if (CoordInfo().HasCrd()) writeVectorArray( frameOut.xAddress(), "POSITIONS", 3, 6, natoms_, 3, Constants::ANG_TO_NM ); - - + if (CoordInfo().HasVel()) + writeVectorArray( frameOut.vAddress(), "VELOCITIES", 0, 3, natoms_, 3, Constants::AMBER_VEL_TO_GMX ); + if (CoordInfo().HasBox()) { + Matrix_3x3 Ucell = frameOut.BoxCrd().UnitCell( Constants::ANG_TO_NM ); + // Already scaled by UnitCell() + writeVectorArray( Ucell.Dptr(), "BOX SHAPE", 0, 3, 1, 9, 1.0); + } } else { // Generic TRR format if (CoordInfo().HasBox()) { From 6bef5448101613baf948dcf89cd210c747118f92 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 17 Oct 2019 14:19:46 -0400 Subject: [PATCH 59/77] DRR - Fix conversion of forces --- src/Traj_TNG.cpp | 21 +++++++-------------- src/Traj_TNG.h | 1 - 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 2c3f8efe45..661fcb52fd 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -93,18 +93,11 @@ int Traj_TNG::processReadArgs(ArgList& argIn) { return 0; } -/* Utility function for properly scaling coordinates according to the factor. */ -void Traj_TNG::convertArray(double* out, float* in, unsigned int nvals) const { - for (unsigned int i = 0; i != nvals; i++) - out[i] = ((double)in[i]) * tngfac_; -} - -/* Utility function for properly scaling coordinates according to the factor - * plus an additional factor. +/* Utility function for properly scaling input array according to given factor. */ void Traj_TNG::convertArray(double* out, float* in, unsigned int nvals, double scale) const { for (unsigned int i = 0; i != nvals; i++) - out[i] = ((double)in[i]) * tngfac_ * scale; + out[i] = ((double)in[i]) * scale; } /** \return 1 if no more blocks, -1 on error, 0 if ok. */ @@ -300,7 +293,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) mprinterr("Error: TNG block '%s' data type is %s, expected float!\n", BtypeStr(blockId), DtypeStr(datatype)); return TRAJIN_ERR; } - convertArray(boxShape.Dptr(), (float*)values_, 9); + convertArray(boxShape.Dptr(), (float*)values_, 9, tngfac_); if (debug_ > 0) boxShape.Print("First frame Unit Cell Matrix"); } else if ( blockId == TNG_TRAJ_POSITIONS ) { hasPos = true; @@ -374,7 +367,7 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { // ----- Box ----------------------- if ( blockId == TNG_TRAJ_BOX_SHAPE ) { // TODO switch? Matrix_3x3 boxShape(0.0); - convertArray(boxShape.Dptr(), (float*)values_, 9); + convertArray(boxShape.Dptr(), (float*)values_, 9, tngfac_); frameIn.SetBox( Box(boxShape) ); //mprintf("DEBUG: box set %i %g %g %g\n", set, // frameIn.BoxCrd().BoxX(), @@ -382,13 +375,13 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { // frameIn.BoxCrd().BoxZ()); // ----- Coords -------------------- } else if ( blockId == TNG_TRAJ_POSITIONS ) { - convertArray( frameIn.xAddress(), (float*)values_, tngatoms_*3 ); + convertArray( frameIn.xAddress(), (float*)values_, tngatoms_*3, tngfac_ ); //const double* tmpXYZ = frameIn.XYZ(0); //mprintf("DEBUG: positions set %i %g %g %g\n", set, tmpXYZ[0], tmpXYZ[1], tmpXYZ[2]); } else if ( blockId == TNG_TRAJ_VELOCITIES ) { - convertArray( frameIn.vAddress(), (float*)values_, tngatoms_*3, 1 / Constants::AMBERTIME_TO_PS ); + convertArray( frameIn.vAddress(), (float*)values_, tngatoms_*3, tngfac_ / Constants::AMBERTIME_TO_PS ); } else if ( blockId == TNG_TRAJ_FORCES ) { - convertArray( frameIn.fAddress(), (float*)values_, tngatoms_*3, Constants::J_TO_CAL ); + convertArray( frameIn.fAddress(), (float*)values_, tngatoms_*3, (1/tngfac_) * Constants::J_TO_CAL ); } } // END loop over blocks in next frame // TODO is it OK that frameTime is potentially set multiple times? diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index 669c544caa..b3357e0869 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -39,7 +39,6 @@ class Traj_TNG : public TrajectoryIO { // ------------------------------------------- # endif - void convertArray(double*, float*, unsigned int) const; void convertArray(double*, float*, unsigned int, double) const; int getNextBlocks(int64_t&); int readValues(int64_t, int64_t&, double&, char&); From 13d7f58f06930150d392b2b6c5cfff41a1b27d4a Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 17 Oct 2019 14:19:59 -0400 Subject: [PATCH 60/77] DRR - Write forces --- src/Traj_GmxDump.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Traj_GmxDump.cpp b/src/Traj_GmxDump.cpp index 637cb564e7..c4b400bc36 100644 --- a/src/Traj_GmxDump.cpp +++ b/src/Traj_GmxDump.cpp @@ -158,6 +158,8 @@ int Traj_GmxDump::writeFrame(int set, Frame const& frameOut) { writeVectorArray( frameOut.xAddress(), "POSITIONS", 3, 6, natoms_, 3, Constants::ANG_TO_NM ); if (CoordInfo().HasVel()) writeVectorArray( frameOut.vAddress(), "VELOCITIES", 0, 3, natoms_, 3, Constants::AMBER_VEL_TO_GMX ); + if (CoordInfo().HasForce()) + writeVectorArray( frameOut.fAddress(), "FORCES", 0, 3, natoms_, 3, Constants::AMBER_FRC_TO_GMX ); if (CoordInfo().HasBox()) { Matrix_3x3 Ucell = frameOut.BoxCrd().UnitCell( Constants::ANG_TO_NM ); // Already scaled by UnitCell() From 305db60d569262e79eada2ea3180bf755e9c1ae8 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 17 Oct 2019 15:08:11 -0400 Subject: [PATCH 61/77] DRR - TNG read test. Use topology in amber format (converted from gromacs top with cpptraj) since top files rely on includes that may not be available everywhere. Original trajectory was generated with Gromacs 2019.4 in TRR format and converted to TNG via gmx trjconv. --- test/Test_GromacsTNG/RunTest.sh | 33 + test/Test_GromacsTNG/ene.dat.save | 11 + test/Test_GromacsTNG/md_1_1.tng | Bin 0 -> 1347361 bytes test/Test_GromacsTNG/rmsd.dat.save | 11 + test/Test_GromacsTNG/temperature.dat.save | 11 + test/Test_GromacsTNG/topol.parm7 | 9070 +++++++++++++++++++++ 6 files changed, 9136 insertions(+) create mode 100755 test/Test_GromacsTNG/RunTest.sh create mode 100644 test/Test_GromacsTNG/ene.dat.save create mode 100644 test/Test_GromacsTNG/md_1_1.tng create mode 100644 test/Test_GromacsTNG/rmsd.dat.save create mode 100644 test/Test_GromacsTNG/temperature.dat.save create mode 100644 test/Test_GromacsTNG/topol.parm7 diff --git a/test/Test_GromacsTNG/RunTest.sh b/test/Test_GromacsTNG/RunTest.sh new file mode 100755 index 0000000000..96a76a8ceb --- /dev/null +++ b/test/Test_GromacsTNG/RunTest.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +. ../MasterTest.sh + +CleanFiles cpptraj.in temperature.dat rmsd.dat ene.dat + +INPUT='-i cpptraj.in' + +cat > cpptraj.in <6AtqDJ4Wu6a)k>vA6Gg zx$C#?y7&BXzVn&yGqY!AKYM1g4#JSzj{~5f2(+PVLb1C-=(*z!L=vadr6rXl)u0L# zvPx3Q5F{YV+R>B3?Wvu)(-U_JPIit*tlSWY#ZxCs2*l0O)xngT)xpWk$(8kqtqrTS zllx60la><0n*t2b2OZ^Y!8H))reFcoW6|FhPX6A01c3TMvfBdK9?vjaCGiVo1Y4h) zP}OU(Aw^{cNpVdDN%eoDgacZFEmWR5xmnsiF*dg`z50ei!1}w24zydk(;fmEKs`iV zQtkh!Q-UaQ{p(qV10n-~1;S-GuK*mA4A&LF1CBTpBCY{J0OOz#85Ia3=!so>_drkV zsz;80Gn5g#>XQS447keD5M>z%3K%O5kx_=Ag8e|mA!uM6METzkHPlofL_j?_zpFVw zFu-1}#)%2`aWhUV(775X2Lv1RZpL|gD>v4)haKX^)af(Cmz*uRBI1>aPBnb|P zxHg0UjJ-k`ZU`ZON|GE9CFs8)%3Prggcxip$q5lxf{=iycZE<0DcI8$%0MAN-ay2! zZorjG4!YO(0}8qSuPxWL`v7$Hu5J(%LIJvxH!daUUg4EX1-cSfJ&Qr8LA+XO8lbFv zwbWn&XvnDjTUJ`Yzg}uOpe%DWGa&h|hjMk>89?V|sTl#fy401&1bSlEw}Bb-q_2je z0bv16Y0jG)@$f%cyOy0)A*QsgRQH2&dDtR@&MaW!x)0F zQ3njYiqr+It0{u}A5{H6yN@2=Ur$jVC|^&}0PN#tinj;L)vj|hMI+F=nW8b+>UN4I z|L|tmreN&V6d`5+C|_ldGQ=DprK=mG1hD|yNnAfr5X=AIRX-3b0IweqYoL66*T79& zT0!^U7H$Lh*Hf|uySeJa4(#J*O7@@wy}BF+1U#i>pjVgUfH;D&SJ!(2l&`M`9uo?> z>i_mrC&0hHo-^3%)%9G!K5nk}6m)Ku&=vG!n5p%Kv>hW&w5AOPvjrub=uHpnQ9VP~2hhxb<`zpPZA*BFb=TI3Kc{MQ@DcsOsop@ZgZ&mAKr|-28_MQp<0k`bLbrydz(Xb00KEw54txw)BrZU&7npR zZ*!;#jJ?gFX3)LOp%&1+&7oG%z0ILE(7nx}cF?`ep$^c!&7n@vz0INbAYLtX7f`;= zAylCJ-`id{PDdHvyWr+ur0qyoyzUOaXYi?M;K`&9*o5 zkFG)?v;XLN+xrO6b;`~G$m`vuTCHt$RY^W{civO3OrB% z6+8$*2JaYH5AFhBJvb7O(SiOz#RM2s>^n>iFj$WVFsS%l2lYO{pi%$~D%c(zHx1x}Obalm^ZtfI;QE z!?FN_^#TBcDtL!w00!%Y0S5Ikz@UoWVX!?|F9!IaN&pP16u_W@?ZI)&0Y1p`0E4Os zFsRCRSO;LRUJYPSH30@y>kexJ4ECdYhxGsk)c{~njqb1&z+gT2o(rlO;Dc-qFxbxe z4%+|>svW?fIsyzT_)-e86X1jD0x+nqcQ_DWu-+YDP@e+~>I;BD^#d5}C+H3b0}Sdb zfI$tr!x;dB^^pLB8g+-$0S4=100uPz~H#M?r=B2p!Na`YX2Sn2ryVb1Td(h0D}s?HGnz= z_+USCcX%FPP+-6Ups;rs4q$jd5dcL5^xhpt0vH)k6hP4d#Q+o&P%J>P0mZq)xB%k= zN&qM!phSR@07?od8KC5V-UsvnpcH^o0!j-g9ia4pG62d5C=;N}fU?}-hj*A2U^YP6 z0p$Xe8&DoVc>(1El>ZJt0$31GAwa?NQv_g9K%szw=c72l;Q1&CuoR%ufP&|r0>FxZ zDgmktsLCBy1y~JG^*gKqupXfLfEoa52&fUD#&_5RU~@n%?yx1m;CW>WupOZGch~`7 zCqSJ6bpiA#pss+r-Qi~dy94TRhdluX&nvGx><#b>Kz;78FTj3)`rqMzJNy#hU_e6v zeFbPJpkaW9-{A;=qX3NtGzQREK;r>T02Dl*k^lzJrxbuw0Zjum3(#yp!Sg2<;5JOc12pdaq=7{KFzPTb*1fTsYRzQZ$j zcoyJ!Ko{=tBEaA|qpqy*?-!{iq+1gPhyfMu4*zQa)I+X20fWFgWo?MEwy~?T`M+ox z?W@0DZ>zwo%V=Ny4g0@Wf$hPIgA6tSuOt4Saf24v1@s&ZP=eO+)tTw_0%-sG9VD{SXQZ3yuXG_HBoU zkAaRM$fUO=&&>S^V;OZ-vd-_=XY7=+x|UEP1d|{(Y)XQk()L(+ zDi~BHq0acfR3vc1E}rXKB29ez&^vHHUn;foF&mdHH;T`9N|f_jbqCD$bG6l1Y%e}# zdw)B~Bt>RUTft`_hz%@jIxbo`JALQSnDjk^6W8cV)p=H-w3ZHLL6VZ6m%<76vD}NJ zdo3r@T1johGD5z_MGE`#lFgK=<>hvIh277TANydXj2s7ZeiklRUe)@1GDfRD%(U72 zli9jXvvCOLykZUqtHo z#Qv|gvP->A)l^5r<2RL;C_8Jv;D$DZ7j4LijCU(A?msn(D(>YzQD~=TY_a|Pk`q6B zR0DH2dy%8*ccK2`>!isxlcwdm!2*Tmwe*f>o})S0Zx>TrThD_yw>q3wAE&Dqr6L5iK2IDw<80dOxac@~mb3PQk(@Oql##n-3VF0WslzmqqmRh^|NrZ^aqaN4NsbG| z%J6%U;Clr4d|##6O{TSBF{=ww@kr3RHjitbu}woYlocryq3Y`Y-&rPz(j|(AFs`v< zAVtwKZbAEvMz4jZHfslVZH+zNpO`^PPF4NdZIu4``l zjF#QQf8xDIlKbj@9r^g~7|=>zP97OKWj}vbto*Iz+n0`$j#clmk|}O>uK(xH(F1QG zr?V2`)!s`uN#Frd0Tg`3Y02j?ye78y!%hqdZ4+46HPoPTlHwZ5YPu9sYEVT<3Ux`1 zf4?Gt4;lCn9x>l`1N?)-|5d>D_*!4G-@>g62>=zspaI;ZkEHQgqk=x4@T(6F51;H2R-*0`N`BGgHu`Z7=`^IkUU#9wgM`9`D_E(5sHFa|7#b zWILCm=eg5reK<3o0j!S#R8dR<`k#NpxVk7f^Z)xr%}q>9t~!N>z<{%SXMDw1pQ}D@ zQgMs0-`yT3RXSP7GMjvR4^c%~T~V&mS6VhZ*ZTnq)e;F20wTr0;7KRoX%9VOeaWuZgVa6H8Ni^PCmlN z0fRFIMjS*PVXFZOP8n$;7tX-xKFaa;^?$Hn0?YCr)hESOyv&~y;3uv^w+nh-#mwSl zVt|Bg|2dM0`+~*f7r9v#UWOr>di;@Qa%@5Sh&`=}SD;a&CJ}cQGE8T@t%e3P!T=-u z@@tr;?|$06cbq4M-*V6x&!FKH@^e!`XZ^B|BIntr^}`AjY~qbPe4n6_cvD4qa2xf0 zq^WvSPY?Kh#FG55{Ml|U|FwRG6;^u^9%4%prU5r8!5Bz1p|ffc4t;4vCUU+%|~Ov%g$ z^uH4fnZ&>{tIrx!np5hGLuRV-n&loCRLi>m^ZnT+JJ({J0*yw=@7-@1(iVxw<~%5i z_e#4IZA8;e@FZ6}aTGWCBp!+6xloiCGbJ!RH%VebbNt>Vk$N`4tBWHmuQiD4LHCJ@ zzfhb4V^+@xwELCiI)_I$s`oRVCP zhY}SkX67pXbTp?IDzw~~$ z;KsLM*OVc1*x1@W?J7|Y*%X91723I&JzmPh9w4b>=YA4Vpx+$&YwF#BMSqcgggY->oqg`ZJ9S68_<2KVSB=svo+ z*lNOa$a~xU9^;IFI)2KPsb2^FAHOBz^&=^-JzKXY zJV^v}%BsF6?AtUC34$>-HNt2v(G8Vt_TG-*8Ed-5%6D|{rc2E<4kr6g(CaSe)W_*BWlEJtkdtGZ7TdC#e& z3q+Bb?_N@*RSRL74paO{1}x_^)XX$|KdEiAN+wm7j(k(Ex_gOa=Xst$y^ovKC@V6n zV;V6*hB<~k3%l*Rp{QrMZGo-Up=FGa_D58rP)^pNgjJ`5$#B1@SoV$y4Oi#-(82A> zMdsL-&nAfabxn5a@|W}9<*>qUD!ncGR%u^_sW2$*B)ol@`ZLxsWYLDU0eyBg^F#Lt z9`ZbWrP1?YP61rci6C`6?^jT#Oe~*ggGN8=!@hfvq!1-nI%Qb&gN~_>6}aqCliPHM8EJ7t z%!`b{YJL7|9J`{2L(;kox)*PR9=7rAnfnWJutjmmkqH!ERCn=Duihhe@H;s~Bas(9 zzSKiP)#yXc=ypb+lwd;S8LJ#*Duhixn82?8GMc5xaYT@GDbGHyJjeUhIQS?zIb+3O zj%_}o=!YdWrNa(U`LAs(<3x`_lt8~Mch=!Ul&14I9N~#n-U0vVKumXsybv6@*$)Vp zu5F2zi3U7D>vD}9BHkIcdEDgn15}a5$)6cnDm)veM!jd&p1HmnMa-j?t2_;r77db-A@AHV1JU6j9nfGy9fg@CG;Cf9b`#HQ++UN%?0S?>)=hd(Cv`?yS zO6nr8)wE0>#m#5n4>|>nKjx*QAc_O^EU8y`eY_3t#V^g!=<-4aj z_LMY*J0rE|_TwG3DUQx`bkupci8M*aX}SX8v6`PXKNUmvcQOxMaAlQ+BB>(O3Z51C zKqB0DKB)o4%Y33z)kSCeyy_VFy(@(j4E zfAlMj?0hk0B$B$T(QcFj`zr>FPb+|h|2r*`#JFi92)2;6Iol%H|>Z2 zatt+LuLP>;QIFQYr&@bCHqY4E%KE@g_~YqrZMUp;cfpE&;hrsas`-WpeD;sv-!GJt zZ1OQT%8mSAbu7RMCgSJ>Zye1xu(=AiQ1r5WAqTPm=(d-y##IKV5H*j&Og@5eV8{CtI zrWBh*T953z+1l!>`Xm0nT-Z67VvNmM*+ridh?drSH&*Vvfe|@QQXR*i78Pk~y&`wt zgSTYG5!I#+EkCgX)r2QD5|i67-CWcBAqNh#`d`Jw7{TF!65?>Y1hhS4S0XIDql8V? zKPM*<<=gtBe8d-Avsn5;Fk~H2t6WlVwfW(X@1y>;I&Dg)h@B)ncn`CEaY2E>lT{bS zl7*|&Q@uApG9z3`@%wrDdRIOVszLC zyH=Tv3G%PKQyV%riS<9GyQ#-f1zZw+O`$BP(S`Jn(n0pntNuRwCihh8xo%C-WksAH z{kILvf^K9wN9UK5zjcUUE`B9X)yd|m$CBF+cki%mveyxuc$%9G^KGxL?+o4lZt!z7 zVOEV!N?d1E_f?z1uU1YP8SO4QT8SA9I6kErC8JVa+5xv;Drrtk`piM?sJxFhq-zqL zv#h?b(ELpoGk>h!U!zQ-u{Dpb;)s2`#W4P5M^2@8ng4j>g~x-H1IH8LgO3ao6>l*O zS9G!46Y7lG9k6x_4HSz_^8_-)xywQw&t?{pshJy_7`07-jYpLYKdYC6?xziLIOFhJ zK@ly2_@!=tFPB#nLsPRXNA5mn9l<9h%pjGIU5RT`@rhtX7!i)07Ksc=ssGH~9l+BV z_x(kE%*TqU-|TdIHC12kFF{imr-KKO%3Y+t48);WF^yDS^m>srR7_Ro5MuvbJDWd0 zsaU7`#%PuFt_EdKh<~WH9i|Kd#d~P;QXciGCJHeehjcdT*!p{!$1GJSklq(<%C{o;(}MWwGa z4;E|IxB^6ep1=Ig{hVo+^xJUT7^$vKvVe}2*3bB&TDrKp&w2#&heqlYT6?K&U))ju zQenlR1#aBu!N$2HO+J_UX!LW3R7+*i!>ol&Jk)_IKN;`;bhe3_$b)NWx;(B|bsEId8aQRHNO%kyq~R-~X@TRqo;pCtUFbd>+G%%k#vQA=Dd zq(?MZyzyP+$g5(1vIZ{5E%VxwZ%`&p~7k%!Gp z!OyfwoaVY|35WJDC+iX)Ts%kQnZL{lm9rB@Rq4d23G`MsJ&*+lD7Vq#j` zGME*Qr{sNwtH$+k)tUAu<6K_tlfoJ!X`6zSF{i?qwWA0-J0#kyaN-z|ti4TFf9dG0 zC|&tSDv>eYx>YvnPKO+GG>tA*wl2R{pD;#^c?yJi}A=fH2lJK z`?{A)k}_SVdh;DL+3pX&uYAu~8bv@hiF}3}E-8LVqVY`SwZFI-C)Q$z+jPc~jpz|SR@cd18h_2@I@G$1|B_?xBo_4z zXQe!kBW~)Msmb;?0=vw4+(ar>^`5CfbHti=V^jEAxD2%y_axC)MT9RDmp+UC2*!vl z)HGhK?{bO`PiAp~p{Vfrc{%st3Fkhs+3DoR{uI*P%oX-$h8L$1N{OiTX4xpN9_&`a{(72z14f|bDQ0l zZRCiOb?oWpCzEfg(J4o9{#3R{ap2A`bJ9yb6m=aW_A7dPV7sZtK-m?@4Xe)OFxE?! zii5KkYz3dSTR!#p9D_w8^|>cQRnRi0hPq^9Tjq}k-dr!@e=c$-Bg(awoW?x2&qU#D zZ7MoR`n^RlfVc{}8Ps()MP~5bKI56}Qv2fuhVCgz zHOX8PgJ%hNw(5kB;x3E)jcHl1`1u)n+4~SGBRiPrA4c5c>cREu%NBxss%c5j!(2dg zA>zxIID^f=*9}c{+Y$7aimL6xKjsF;6Ii6ac z;rQ$uYqzE<@0H>hToJ7ETygX=vBV{4fA`1eYD{E($~{loR2us~rqb%_k1l?%JGeJE zj_=DOMj)#vb!?88C6=r=)Y4`@$%~sP?EW+(j_4hPT&G*P2x&7}EtRr3Qj8e=DE3pf z63tore%&nA?rH8@`j4eAM(H(h@$yn}32M$46MFaJm!ECnTAXnNl@ku{IdL@lU7p=b zZER8>^DFc3V!~LCb;dZ9b*)<5AJiODf3WinMNMiXT`!>dU2}`N5RN8a%aI2fMDd7x zub(}f@x(Z1wQky%tW1|J%UYkbxj20!OD=8xG=fJsy^N;sq3^bLVgiNjQHMdclGkss z>@wT}6h3%i8hl!T#eyTW_Kb!V4V1l1r*!iMMc`xk=S35a@y)cW^bOJr+qZqR{ycXnjBCL{CF9_y%#+tBX;NJ3M zd^yyQ?(PsC)kzB$ewzN(Xg{d5!MGWYhXPl~;;`wR$zv{4VW^5&wu1e7=)(0~%YM}sDPQ^lWrc*RZM%!K!#6E^ zcLXlqxeexfv4pH!x)chZ>#Y0O_sTI9MuHyd#kjpKif6Z(8|C^oP?}8oUXkU;IFDcB zJ4IbLS2&oiw9g;1(0#bH{-k4V>}=THZ;8tJS@n9NWt=^Wanhqu9p9bGV7;~qQkoo! zo&Bx|=Kg~}CFHvf=kfEL)AA?sczCg5u7nm@gBq$t%W(w;7bwT|+zmggB?#1M@-$(! z68gmU_FesRzooT*?R`BdEHur{5)AF0plwUHl*Z;`hfh1+m$V|ehl?Z`qL zbjiLJXFRENL&(W!>W}kmSV*vpYe}YyfA`EIdpu5Ju!SM@$wyx{*}NS&Mk!eQ@aiA5 zRIb4R@`F2b_b^gEjeQ`u{Q7fC-~h&Poa^W-mrrT%4%O%Wz&Pm?TQ$_LX|OLG6r)DA z;`O1u+S%fP#tL3EGOCN0U6mi|)`(eN?>(B4|ElelCVH0FL$EihVbxS)LHaAugPsSm zBfcr57&hG>etmnjOPe>u&f1&!16!5K1r{X*9d`aE!kY(uY1D2`Mg*LH;>Bc;DTl%r zI~uym)^dh~QiKjjanho#2>!GNS`p^3kS#Y5e8-GW_QRh}X{KKG3JAiPf{MAOt8}`% zmg@d;c-LFVpww589I<|&;dk$$h{s>WRlKHB^>{o=y7H5DH)RK2xKYDl-u8k1QUT$e z_C`14p>2`GMur~;g2s>OQC(4OEn`rX`t4Cli|`u>&YeGzB@%QKjywp^c^^nr5K9}f z;F`MN@*AO7RW#}yTgMk{r0+D@?@WqVi>03{@XKg-j6CdVWL!AId)B}-;k<9kJ+Yd2 zZ!}vpLLU>W-SHPEM_`a0U&ko461PBFw{{6`2Q!~#olU^)l8ep<%ovg9#qtRyy^Nz_$F--#U2pK9;AO8`S zx7lT2Gd8^I{il&2A{X{F8TPLRUr2Znz7KBuNADbEY}lZBpH&<(*T5fPmHeD}FHyX8 zzVhLhhp+EW5MPF|Ub4BZ}WDk|Gp58u{Ca#SOlE0f8Ll9nwJb`jT8mokA+}dce80QtZ!Pg05~eEF!O7 zKMi|Okq+ByEme$9#Km8x+%KB>cHXBpsmddZTS@dHUE7y?D(Z2=+MN z?_Dx|=vYehko;3-Wl3bV9gYud_T*IZvFR)p@g~9W7j5Hxt%_My|Y0IA3@UjS4bGDj8?Hc+8o(&;_2{s<&~2c)y1ja>7i+ZdCP{`P`pnv z=&w=rN)#zIKeZH5!kAh-)wcPoX(1Tzr~aaCnxQ_M0rM|)*-uY6=H|k0iZdc5dQ6R? z+|FxO@MS;GM86$*KkrFeLcV3*T;WusWE<#*?8;Y#$443FrGla%t?i z5Hy9x&}e_9^vKaf#RXq^I_TkZ_jldp6E^VCyJ4lWdQ|4fHV0N{P^Un1_h9X{m+$2# zUA9e4lAFhO$i5NT;3b{m3HRrGsz_Mes1}#nvCEmsr9tXe&(N(jku53`)+~j7BPrU< z&|)}DO<>UJ`1Zq*QGA6VZ*sNOgqIqw9|NM?fRq#W>qn~4=SvZq$686MpNo(YX)>ru zvRU4C_Q*S%Q_BC6Usw;#c!7czk~AQnAu;|PqmMiO0koKQ<@114;r6RW`*R`LgQ2jI zX?r`_-)u=$EK8&8*M%K9 zmfB9fdo%S??e&MhRgvm91n7;k<5QX}Etp~uYkrea6O-WV#^sqR=v$Y=S*GFp*9hz| z6Je4mKpGGS4tS9$s~ogTf=)@WG+`{_mer*9Pjy}{l(4k3ri-{lh$uX7$8QSul1+h= zLYPiW(zBqGLw(j~)!FA9PT5mf7G1J%_$blqxpd@C)Uq7+{WX3PDka*IKLuO?Xs8=; zGHiPc1W>2ZeYpuU>vwfSNQog2D|Pp*<~DF%JNGFfEOghP;U~j0N!gjTuC%t|keVm0 zYEUvvYu2X04j{IR!ViD?u%npQ4F5bkTdB!E3h|5zJ8-yzj0y?zHE_27t->c{p_Ne2 zT(ofHm>TNV$~?qFub=!UPwjn=AZaIoOa#6?$4UX=Yv$%F6a0l3Cp=FJ(4A7m3ov`J zL|5vhGHr8AHZSg}BAjjGZ7c7@|M|x7-XPLR_Hlrg4;)NC8dUzxo5YiG8rD&(AoN+9 zJvTcUA`7oy@ghWx2IXI}q>1 z^J7>&&TB1mm>qJt`gzQ-y|vJM-CxL*B8gcC_h(rXYRnTY7IDT@BbcWcjS7u2#|j&WIj%kDZeCgoh=f-=z(PtagyKZS(P-XCt%;4^Qoz5g>BUL)*o<#j>(g4!=fX zQ8Oq!c|VK!RrZVWvs(6DWdWa7M&9rwghT_IsN>o z-0?Aj--&blaHPzhzGr4!sI%$0&tGuPAYwVeh{ds<7M^6JW>9((m7DyqTrjEddD$q3 zXr{dyTL?Azqv}27`!LR6-*lj$dwc0cjN~Mpb0L{)I_HYwuOxOHC4wz94+2`FL76!& zf%vVxy`RzZa5CTN2#9DR&Rq+ny<*^6C5BUY$$}JO&{>zBtOk+YPnO-x@V7X?5a#~P z77(Mr8fEUb^~okz&M?=7Avmfn>GfANTir=!!iQ~+68hAxFXfwUCG~d+vhrdwtlsc5 z53r}Y2$u=yRd);zWi284z>*M#rXC!@>}f1f9S)x-pJ-}emXmzO5gFT(|Miwe+b4l3 z(773ZNlg!BUPcLnIu9S|7jI32Y*P*~a>0iUiWFuPYjHm(hEgrzhzRm|rO*>R*@c(E z19E#(R%VlWGf8UlM2b1GRefo8mK42J!K5MPGf!E)*SuZ)L2{#n_@0-?FC) zmVql-AX0m|o|0;zO-a6n%>0}#mLL@6wexq#pQClhzYn#q|Maj zpk*5(T^i<>g+E8R@@*}0CB6*VQ?gXX>93@&M@8yXt5Lpy(TBh9h zudU#xpJ8 zXI1n|;yuyl>M7c~U4FFXIM|fK)VN>6_AEM;q%>c8_rj2*tPKjAMU@mTg&Z*J>b)qW z8jhqo-2Fl~gQT8gS{)E@k>EgfkY=E3Zx)(D*tC#C1hJ_$YpIj|twF0E-aVYZXTO_$ zu5Sl3GVs=GkfXELBv;DlVMV@{oe14BT39w^I%fH+p#HF~5F%*|Zi^wa{V9aRDO>8~ z?1t$~SZ`t4riD(P_v!ms58a}hU5kerRJtsX=zLnS~c zVs)8`outw7CAQ)>32K8z-rrJcKNpG65G!S6-bM_QFgCbcXwg2X(e%X23fLtGYHOE# zB-h$tu_^aErbbUZ5yAW}0i$smmKn+O z7wgzMFzrwmXU}K@*rfM*g-2MPcGQ=9SrIhry%OO@Ofy!2eCA)Pj;%t};%h`|m9n6BMDc@Hjn0CJ2YJ-0+ zFhlb23$m!n@qA@8>Z@Fd1UepAN5(!I(zK(*y zr=#=5$r`WvIV{vCFDI1VzJG2Jtf>4nRM)%$^LxYOP;3rTdId-R#GfKwSuBS5&;cLS z?w#`GFP(F=Gh6(~57{e;jmYhb0*@u@@Ejs=25imy$e5#`XgEX9rhKx5*l^JL4i4pl zE%yV}D6J_=s^!_LJQIvZjSA10Xwqq$*P7ut(BQngB5L8^U{Pu<%OkTLPByM=6Say+ zKw5LAsnjH&&Eg=8`aX^NUP1h^N^QtpuHd_br1owfeLs224;d}$NN-6@%>L~dm$*{B z)?8<09MeFgOc}gTb9ligAGZ?&5E38SB+MK9Y!eP}@A{Rwp z_gAf{MTsz99yrWeMr;zc@xG@enZ*Bi8c*{XU*O>^EKFwmJ)Yl!@1V>gD}uue3ux9x zP`B=tAP?O5SI{Dzh+QkyJjXur@Cv25Pj5tZRGV1^BN-#__O&0^7T(Z3NO3FZ=Kgyji;vg7q-A_`VlxQPN;{CAdA<;Et#%B z3&oRN`9A-M%A@^z{-vJBTnWS-Kqn8X0 z%G6ksj4BqDTo`a>fxBV4-em)yYDxSnRCf@ExCkS&s|I5GMTzlSF{-_ABgb)ZeITVs zPhp*J&DH{;Niw(WCn0~sL*AMiqqGMk>a-PYV%TUJ@9<+nDJS6L-PAq0KF(r`#`kLw&TEkcR0k?&it&+Kd=Lti3s7Vrj22v8EO@J=d5w_^cVgVQs;3<-y=3& z+8j*pQ1D9NtiZA^bC~A~c{Uxi@JBD#;bq_A5oH6f4w9&sOn?<#;QbO$rniDBqMm3*M7qNb%r!{e*a6pYlb% z4|#|cL~ShI>4JD`3%_W4bXcpPM2XCre#n45*x`P$b&jA{4noe`_XXJVGj$yK#zCGW zE!3~Q!e2`;P*N6?rjwd{M-E}6t$SnTPnFEs1-S@3f7^!Q@&@P8F1@Z75&bmM9==Oz z`P|2~T@4kuYUuv5u{ol-b6||4`gx>tVwa;2f3I5eXc!G%Y5!9f?w04SV^Gumkc4Eq zmuEHUyj+c5Rs&JEVbf9xpg3)r|q%hNwwmVF5@hw`i=!*tJEli^b( zo#FeD6MIbDDYl2!9kI*bieCOw8!iam+A%a~gB%uFXVh_T=YG!%b1n>;vj?-us!H+4`nxhnYjYP_- zh4!MPd* zb{2K-b$TuBwi(_Vz8Ie|EtHzZ>8EElZR<4$2hI}Wq&mrUvobo5iytt_Im1T?p*n_H z{3MFDC^M{vmej6gk;9G^ZdEV|QZ_B&Q_}KKWT>ij<^S2&zE||bpp!dt;=R!r zHuPyft?s5r)KWEGU!91C)0bSrqX#jPkFkX=V9TqtyAGF5qzoE9)VWV$=~>}OkM+9m zTPp^0SJ>`Uw$52Kw_V1<#h#I71$ZGfl1QK0MLRLY|&QU}Ecz56h_`dEP3n zT8p8?)P^mxIA zc%3Qkoy$X&dpOr8oI+Vs4d@E2Xg{R|}qEnvNW+tI;s6R|tR0Q54Qk@){c-4@%G%vfO_m zH1T|QAwjoBtm)HofH5~T9@{7^-hg|o*^rY9!8GF2A*oH+evK*3-%^#IeEzIzI-A;d z#?zX1^p3CRQhn6NQL{~SU6QF9_Mkm=6(^*k5|eNWIGz+0v2#CqA8p`LqP652>V`b6 z?!nEBWGzXzs6sJF)Q-Y(Kd{3Scu+Q0arGlTp|iCsSdO!!We7`~@`8lkrE9e(-kW1n*WCU=w1 z!=E?(m{8ROa9?%0(pfy35mJ(Th7Fg&iu<8|oh=a`)B3+p+=uhWI4NJGt(nXC!*9DsN;? zme|LXG9C&Y^z^>_OJYeRGNaWLNNRW_H~f5yt7lopeJjn3&ru+Lmbw&%xlm@wILHS> z(KJ*s0sogTs<^9-^*dsYP4CAQd1ah*h~mhc)p;Lw`R|__D*v$zmSUa@Iv(&X3)O;= zsZyxsJ?zZG7E9xpuBiRmiCaF$qNQj3Qz9bE=T|5u2eU|XWm9hHx@wz4WI8QdfP#%`GKva^^y@f0gEsJO8I<@7qB&?gPkiB8B;cCZql=JE{ zdmi?m^@|=a+LF3M|B^&7G;9?cK5kVZDtq>2q+QFA@??#rfPQlx#gzBcL&f2*`HCx% zk~;4GJg8{GT~2mqI3G(qifavy7R;NX+k0x85|rZc)Hk@O^l>OFVEzUilP|&zrR?w= zPagT=;%%Eza*4LRSu|cfvHzsR=op`2*!IEum;b;x(#E>O^EAm&u1RxiA>JOLM#sQM zAEIr0aeZg)Mo&D_v6m9yywC6uemt={igcA;mDS>KJJoE=+O3q5JT*6JU2EU(dz&mT z$nM!Om6+e)#rEt4$0N8BsGcJ}AzjJ?%g3(RsN0X_(mMFHv8~ETP#p5RTvuD7y{t2q2*r&H6-$}ZI-*_Tx9 zXkTA*@c$7Tj8DSj)2=-iY!UJ<@jqoSmzh#$8=-AZF2LR3DqbC>YR;T>$vy2$M?*)b zE>6)Tuu2n7{4%2_G{sONA(#c-5~P1aMx@xiyjUPrb7}4$23yM%MaOW`o6yeT_-d~v zlLV#Oc0ESB&zYGqV`mxvNd$ANG(Q*WukS>k33S3RD|E;o>sKOk{XJIAX0Vhb;CafB z63=Y-4klH;KjD%CKPF{NlDRoYH-*yvH$}te8pkm6S{~9D`VFD4;{z-*ZOJWzbzNcT z>1W6?&$~iLxfc{xikD(4p9J=O+2cC5sNCiiu+wqNFmNNLm0(q#d|)ASxCc*&h9Qa7 zde#T?JK3I0z3r%hOi>IY3%n5uu@S>vhMO*9S>DMPH&=a!)%^9sd$OVs?)(=^}0oL?kp zp?twdMlf|`v0StJP4>ZQk_`(SeK3Jhc??VA#id*qe!~L81OA2@WqvJ7H`CwipVh0- z<3`h3;UbtjzkJaO*#nO<&Z zy-^zHNq8nnXz@9Wj41D8-DD~C$u9IMhls1G{ZoYx>)VmS&YlIOzmt3YCgV@6k15*H zgO#3_OXfZwdCOicM6{?#&9`rcABj#9&egN|j_0~(cO*Pyg3L!?Tc~0kmyG`6lU*<; zc6QTdL8~QXL8MFl*sUWclCsab=`V*RQZ8UZuq&iMyB+C(kZ36EiZq8~N>9Oq;0Zsd z($6(W^?1@!O2cx}dm%Z&SXji5p0$)E?vKCxNp~La12zIjroW9pj=s0kCvSu;y>bk& zv*Eh;%q;RL_B=FXDUXMB&Px3kB1hEwTy_JDFpjEu52@ECHD*v*+KHgF1A#Qr4I$1p zFN`c?ld)nn-2_+jjECwryj_wv+z)Kc~m&`@X8Wd@ieIt(wcx zPA zth!Zs=^rO783T_bQfrs66+V($O@+Q&KS!-N*jMfZtqL!t?+HjO$@bRgKsYgLD^Krl zcdK1B8+tPNE+diBaP3}tNb(FW=2px|^pSNAsecD2@goxg+^VhCaL%UMSR9PrK4a}F zQ%QpHppHy-;KMt|9M%$KVZBV-z9m)}j}}xd3~%sW@)Hf4K3l=`bH%JEJ?*aV^(L$& z{9mbdX+qHKR7LM+T4M7VqfQKlJ_HaYnlA;g?EQ+c#(a}N8d~(dwjb{hXAB!KeJJo| zrPdJ?Vmzi=wJ`*VZqYYh!aYyK2)LKv%`ePr817EjSXfS4>7l&>rrfv@Oxm7mLnmY` zlX{e6#$^7tEyl6W(74BP<#e(-Ltk5N*u zn1~tdn>_%QB@l0%JuEGFpk&>*)`uErJ;WMVteu4Ni@jn^+6nRWbw8XC_vhF*HB?k! zN;{=|+~dV&;Jvig&K8Du(%1C{Gh8Ub=oO~xM4EqhzLCB-!atS%>bvK-Q}%!Xr$%H) zj6DG-mAzG{z^$&X5_ZX^i5}bItcj}@JuQb|yyycs5Q;uuCkZn5!q=4f;dg``_6l@E z?01U9mWd?TkZ_yuSTaBF_^2$5q~>Z-ot!0hZC7&=GEh-=Eoae;jv1;|XNxsotT-Mz zW8RNzJo(jD8~JAfZ{fxpt!qaIdWh&}lV!{*tyWoBe_v-$-?7Hk9ynw|2&QFWzcr%9 z9pB>dO2$Ah`CuJqq)|e=x>;AA9^Bd8hH#kiYFyt~6qA5|Yf8m(SU_zl;&aJi@p@dD zUfC~FYHjgztt9qY2@90SKtEOUV21|?xfz_!4mX!?fBl&XZgJVIAE^f z!kajaVt}@HNo$dYfs>avs$Yi*iL9EfA}8vh2#+qwkx~9HBq3dW`Rdqf(`&vXGJ?sE zOeOg(s$3crf@S*q;%ONEUhRpFU_;^>$CY*O)Zh+RXb-pU5w-OOm`v~zFlL6Q&hu$n zMp^d6P1GFX=~{4~TMDLmp$l2YQixSZHwpr_1n=D!+bn`e)*=3Z;AVQ#2aLjNu@IKg zzSCXK-^6hzBLZ?f>8qQF+1&1pJzx!JUUUNZ`zkuClf3=BA)!*Sr?$f6*rh~JR%Q$o zEh~m5*vhnG3e1(~ZWku%(#40BjXOwb&aOBJC6{Vxg0vEz1d->jNV%Ud0Ek7=Ne5xa z5g8(wX6g8ajytZ9=Xp*SYnHactYAah+ji=*h`r&t$hw5#O&{^Ya-Z{Ffn@T zgDZK~B|l+6{R{uYuwZ?;s`#YJ{?^#p4$q#v3c5^KJhFSPJWOpK3*=y()HRy^+g0&m zF~?JZ_>znnkPA=eV1zr7@9N4HxJm#>^;hjMVTCTS&j9iRHsoj&h z$>IAsCsQf>>zaOHgbzT1UT7N2XBEP@{ra~e&o;VmWg(+$7ILrxP5rHId-HyO#fq7< zCi};UzkNF=DBV4n6uRgJTO`BVJ@F|M53(XJn2mJn-+~#h(AnDF{4qB-W{9fxt0rtO$80QOoXSZF z$Rf}_U3p^BMP`y;5MdRO!qhGWQ0t8BP`2J7FGyv3uZFRk{O%=aHSb|M+~Jja z$V_2)xb~strz9~_q|nlD_g}&g)1plS^RH*vMbi#((&@MiAU|FkJi9a|>ox25qcz^C zEd!d7-E-aa;mzl)Lo3d-3K)iWIcM= zy}8ws9y1d*XF?cG%cu>a;GsIYk1zWImP29I%>_10pehr+uCTLZGz&`0c60*obRv#l z2P(FgF0~-pgAaZ|h|vAh$5KO-UoR1{`&^JnzR3}k8>h{bP$+ne-Y$!iNmJQ?n_8pi z$(Zy7@fQ?UP%WR(M2C>6EoiPHyl`{XU2xSFyo68Ga*YLp;l!HUoku|_);YGXQ<*!8 z+82=`pT%2jc0qe1o)nkx=^VmQ?Y1CT18)75O#a-w-ixpCKTQ zfS~H1+$-3HOWUPqDI!=3FrnFnNv>}Ph_skcgKu)6K$@MSGB~1;%vWPsGzN7gSk=)w~R9Cv1B@>v@7)ewxOeqj(jYA}1m?jQT}A3=sy);T$~zYV7e%fcfP<;Pqh(9#Eb< zS9e4d8(JH4rue=H6r3&YO=7k*o1vsu%1^jA7!>{nY*v_lHjQ%VD>hD~9Ba!_?TtHT zMYkoiA2Iz~weG7q;@h@*g}2KncOxXXsEW#neWm5iH0v8aQbi`Fq?D~>SKNM1mkpjYO}R)g-=+uOZXyCLww_uZ7_6q8m?jEQ?`Qs#PvE+Yi;R8f+wdex z{JK8kTNx2Pgb1yel`&k7@FoRkf0V#iLgCKOhA>j}zQa-~qz<{ev&Dse>7hmM zIX?|UYbcja;sb(?+%>Ti-erbyd&Ea-ed)DmYuUI(9_dL$Vm^nncfGCWmdh;ZQn6Fp zN9`1IMl~k)yo`mho@PFgEgA?M9Ao3z^_nE=sTjh{i4yxO7J4{{CS#>yopuB1cxDDB zKB<<`Mv`U9zGA8oA1;#7Y-7KFmd=7)0^Ccs-@-C61}r#$nN@mp$pz1?`86#8taz)dSS8xtzscv2e#rWA;dqU? z$Wod<$~phayVLx)c`5Fn?^DU|>7yXtuI+gnXvy>`XkfZ{j#*;$ zLPouqo(;1)-_f;XTJXkN6a26O;?n>>hWgXq?b=Asx-V-z_+A?Ttd=jW1m5`V=n5_R z((I~P+s0_L(Gu(jB3^YJ0KUYANXb@Tp$p6IO$XDehxf&s+(FnPSrXF5ZvH^t>|$AJ z{==$M)c0oYcV@Evm7YV4#=w#Vn|>!^UoAB|NH#%cfS@d9_NJ5z<-qr;v`| ze_b8RD~z7ErRC5@H9CLx$+;^eDjCn@6)6683#E~+ES*`Gxc|MNPdMt+Cwc&GUwm%< zLtC&~h)1S#m&zOCx|lnscjr+%2;3R}Oo3N^eIX-r2M=}Hft-&)FlQZ>TCP|-QO!wZ zZTM%61u0Siz~{Doj=ln6Z01e!jhxx3>x>MQpl^8#EPFfiGmv!3!q6*~WWuF^x3ScS zB`;cplwFP^$kCV}h4Fsxk(!Jq&!;RC@0qH=MM{iT(gna;uumIbG$# zrmYn|nk<|kVgW@wTQg*x93mQ@Y2E%SQ9EsH308Sj|mEv!I~<*_wG2c2TIe5KOokZXqdRAE#HG=zm#rIII&w zNSz8sRfd?S5XqeFeHQ;9oTifw6!J4A=?XkMxWhN{Fzl|XBmYC|-Jn^x>NgJTarn5qsaTS`5`?QckB!gE;5 zTy{pWOK07wp!#Gg@)w2 z@kN2ZsRN)9he6=H{Azh)`}WLB&EbZB7y+CSAL~e9kydpFm|N&{XtX$m$HcEsV7?f% z!S&k}shJNUbbdgPxG_C={t*k8fF_?>=|(Y%&F1F3DCBrrG$&sdlz_Sb^IzySP2yAF z!qGyoo}49b__dm5zkkKmzbaTdxL^*nirfv#VF;;PU8cutygnK_4S&}}Bnx=%+orP4 zQ1R|uU)D}taR6dIAGP>(NfEUbL>8A+08P|mpt5@$pxc|s3>Bj<#q5M1vO_9K=u!TW z=(d@jf7CdG^$9XvS2lURr8|pi=>B*r6w^MbeWzPkN`)+kTYKa~-2F+PU_8(2J!hOD zx`}Ysw$VGhb@}w1`kyv;oN8{5=bwkLI3pZ$D|D;b{c=^+niksrwfaWM)8`Y*I>Dr_ zU8#48f~1a1{)2LdfHwPqsrvoM66Q)Y3nPrp@1}XY)o(c-3cgaJh_)rjeM#}GKrHTS zG<59PNchBL9ige4(oGnJMg|;H=~J`Mt=oSAg#;AS3@i>Mnf$iiX0;4-h@}!2J~~D` z%!V2jwA?98sI(W8=CYyXsN?szzvHh0L)Nk56&Sd|1u;mk=#Oe@bDyE$<5wypjWkGu zJW5d4A++)4pM=-R*p=q`Zcc{iorv*6d9A5Oe3_1avotz)SBnj$9olOv02`p_H-Dn_ z*=WQ>Mv}GmAkmrqJ*6Kwi8O*zu^;5>M!et94@G}PJk-U@Y|J_*s4pNwv@&Vup;`yh z!Kd_-yC&@Uji;hO^AL*oHYUdh*BpbT&2!9WS(lRU#8KZSVU!Te9@~@Hl5pN$Pc)yS zxdszB#WQWszlt!#JetGv^PHzD#VuWEuv41m1u<*%{%O&{Io9h&bq+nKlGQ?*)1ACC zy^O${yp?8w{pesOI6bL$rRVe~B@? zq%sBvr03?3fByCuI4dh>4`@fe2dJ$*iGs!IjiNI4AYOoWEhf1A>4SGqqB z(7P(}q)Ch;B^#E>byo`sJKKI8ZWZus$MUjho2GsI33OL45UGS7n>~nNWwUM6ux}VA z{<2|0o^PT3u#Bu8$bP#($FKkn$nkdn{N$#Y+*RB{qHBe0Ly_GPf4{dY1JQx#33h8K4jDtMbnEFE&b|*NMF-P`3`t74tv94!_Sm*hbW51 zS#dFBulCwVRGp>|0x&az)5(|H4j?fua0xCMjcUp5vw!oibLXfR)*lBOOQ!6`5@B8j z#0G~P>s-|!S#r@uiA`csp{(Q3RUKW#9Q~85lrl*UkbTcWPfsrsO3QS#|Vadhc-{#Z1WpWk{5_eIMiox+KyL=N{Nv=g`D z#5m`#TSd=7_0tPB@7}G(NuXC9je|neAE0<0!?WH_qCs_)Tz+E4?f8VX6CiH~wACZ4 zMdH~YxNd>C4m9mbYTZcCq8iyJ%tW}P$kqv3xRJwXSCNFinI}xu>V}K0t&cz z@S+Wq=v)shL+F&rt911Kd>|oO_(hFNrVy-EC_UwoX5{Xg3>0`Q*Fl;UsO>dYy(4@^ zGK2}12{{zLfgf2Yx2CI)C-JG}Q`XJJZ2KAcfm@RMyovYro2YT2X>t!AFSruI-O8xv z4`$c|vdvmaw4cKt?J#>@Oe3z&CPl6h=gpHfNcGu$ofu6&Z}aKwd4Cmu?$;iPg-x~` za4>NbrF@xn>3R&*`@%WSoODl6W7IXQt)uZ%z-UU<;QAYJgZQ{V=|HWnZ|sPL-#)>N zJ&``nqJe3%S^wFJZ-=L^jLp4&Ae8!1XOc9Q+Yszarg2J=A}ONvwhG`yW;@XbM5Rp- z+B``ct2kDVYte4PL!N6mLPucn9f+zR!hC#!e)-l|?P&@8D7ez~ADJ0H2w`G-`0_A| zM*&lh+Tr&;1N53~Ddn zHXJsTIBanFdu*NS7I^prOz2V$V}zEl)KCL8O_+GtpV0-%O9;~s17>Zxb4E7a=BHxZ zN)jp=^Ao#14O>tEo}FR&r*kJ{O>lpr>i9n#pf^;>O8}f# z+wWm|yu5-&AAGZ=s~bOvfT)c1`2YP*1lFS2D&o#;Cp7$07BU-Kq79r&R%t zhRo+w=g>y4cx568M-(b1#r0QcJ>YGU9^Yqc)>h4ZbZ|2#zh*x91cj$M6rQKLt80Ww zqOgu-60NiATGqD{yC0F#xRk_%-@<&z(BYi1H&jYKwMrB{88>>^S1b|{>*D9Bcq3LjxiKB2k!v$erLvjzz11QQy$W1r0aIK+G9|9y z?^yKMKAFnqy4VQna zB=g41+eu5m_ekvhqtWZT3oTT)Yg?O{V8wXY*{AmpiZADxXq6d%js-qXL}5o6PW}`x z?F=hBu}Dl8s1MA|O~uGm(Z?`;P@4r4+Ls6b!}ZfB*$w&}CJgTd61NW9%~4G!IMet+ z=^MMq1D%RDb0IT)eZVcf*@wcQ1B|!?E-!eEves3udaOtAgE=%?rcdoI(5s0n(eUbP~unaa%Dn3UhD8Enq9!Dl%(a2YGH2vkDcs25p- zHETuBr23gL^izPFRPHXZ`=hUPHB-w=lA(WZz?VAUe&yuchVykr_UX0@{vJGw7cYf; zBIyTMjPmw$Eyh+wty16;lvR7;NZYl75CwN`>3ICt2AmEU*NOuQ;g{LpQfGhC8Lvku zJUJXSjj#uMQjm(hoqspRGA}btAP;cx#KVzuVEkw>^W~c@7fNskJGyfD3kAEHvb*i8 z@4GZQgYO0tu?L+&-eNGmV82OIKoI0Y{MYZ}2juWkg;A_2WmpbTQ(>Dg<4`<3arnvO z$kh3?ruG4_&5^n5@zMMpf0;cCCTOn)ut!^ylf-(Evtq#~V*RpMhzTBZ6bEP^d*j23 z<65a~ef@XUTATlQDQ)rW8q1M+f$9s1G+dpcI1xX5Kdt-)W)MEeNa! z+Va(6vHT=%HzmnZr|5RIKdTJEAdL)hg|6-*hK;FP?OW#XBBxNdNrYz3a9l{f8gEvi zYA1v2ET5w9%1hDzgCD=%!Z)r(hv^nEw@5;l)n@Z02$b50jJIP-mFJ{)MnljO02s5= z)Q;9WIP+PDPC-;3*Y;7qP7um$9gnXzI`BDd!pHxD(vhG9aD&8#^?pKO(`-dEqC3!# z8y^?`qRNxQ@tI_dEuUjsv6Xa+D%|?QW1u{nO{hPp9};cMz2tf4Nntzi!!aZZW)XTc z;tgs0qKhOCgH4N4{7ZgC`?XSxLB7QyXrz{R@?J2-53 zzOz-9qcVfdN>&t8Uj`|}#vhVjGs%eQ-^z4S4{@ra9f`|pu1qqqEl9KWa)nAI-psQ@ z=@BWnHH2Yv18^RjBU*wZ;s|9&Y73ySZhu5w?E7;3K0s6_Qn}t@gKJ zP5Z=n;&Q5CvZgB*f51Kdn{iXM#xkyVAOs}sun)hEvAu+pZAoWa6N|9>xgHQs-V5t& zzM7ZF3-Ex`!t;l=#MTz^R%K;>?0jS$Ib71l5}>|}Yu@9lj)rrzH>I#g89ZFi{+)|S zcXpHcfjH!MNO0xoMi#0zE((+tJ^*C8ltDAK?nFDuY#qdI3&urD5c=h6CS83C+VSsj z;tZ*beyk%rTL?0|l}A{(#ZdeRm2pU-`H>OpZ?J#9qiA#Q=cd>I)VfeAx+dK7JdPEd zFP51=5#3*^zVT#er8hdQMhdic!bQ!^R=FwXPZxReuPq8zi3*X*-$l?ZyVWcko6Qm! z3cWm^XS>8G2$hVuKzmb4yg)ROQVZgRz@O1|;#SN*5&i8|A25|AmT42@MzjkbAyLsY z`$mz4NtqQCbhaI?B-^(e$OmD8(_Xna5yRMh)e?6tF~8rD>2a69jhys*aGUG1r596UR+RtR-d=8{QRTR-B>3b-?5dupX(ICa^JhSJq$H| zbPMHUqsG>M*NqvUp(QF55xMr2Wpf#3Jfa3sdpL#h?P3TL6ZYLmBupFF3%(In)!)C; ziPh5c8);R}sJFs6hHnE@_OyrQQ+ z|8(9lgN4{oQJNMDiJt4uM}DAr1Ft<>pGVpKf$=_;)>%yZq&Pn>@3Gf&4y(3%Ji^bn zL_xRs5ilD-<8jc(uV;&A+ZH~g{&V>VNJhKIWoxZTpTI*neL-&2%$X8fz5-eFDv8lG z>y;$;wmHbF9`v1uEv;g~bO(0lDWT>c)sjUb37HIGF7lny##9!mf?2FGWPPr#Z-rh* zHs3qWB6sI#4yG++i?a3$WXbwQXpgjA=rO|`a{u8NDgYjeYre| z@1dpeBJG*9^0%3THzxOF;ND2rlK_vfkNZ_xZD>=@#kgi$%%@%}C^HSlA28_z_C$q_ z@JSY5A!6y6{s+5!2pr%=`~Q>budiz1AIM|1XZ-6 zizZ0AZV)#XKs91eP)ByeQ1HTj5~6_NJ{=ZTJE3XwkN?9op(S4!2G;GGj@x{ob0Nud z>g4~B99xtwL^dkWB0p)jN4c&?8ZZWu5+SrdWZ7A*KVZo2@X!PmS<~W4tO=sr>{=<> z?Dq`}jlK2$OFLa9$$uo4oDgFc@@4%TZZIyJlF%E;pLebXK2VP8a@?1e+f}bGU7(gU zpSP$LO`R!gM>!BY&gwX?UR${5J8o3vs53nvPt?+*^Q}|CR=Bd)g%Czy()DWj4)Gcu zA!8EQTTwk6(C~e_woM|;!YAwGgy)i<-c6$~Ix2SDlUR2g^ej)DG%LINm9|$;oR=~& zDEVR2C{mbhX{+hA3=D)^p`@XIU=zOIpGMZfa_ry8ae#!hd)60+o5%NEP6P&{_Pji~ z7w^r>&<=dpQRAu{i*;G&CFr-iI$kwPn6$RKey^r0MMrai`bMF*?ows4*z?>v!N6`R z-3H%kUWJTp9H92>sl~}FNYB{CW*$2-_9baePF8hzw&)`PJL8Qg?M6hv66BK4^kA&5 z-g2Q)V=Mx*&B~f;Ocf~`-~yU<`w!1j^j&8cn=+&3q@uMDY%W3Fo+pMp^*o=N+~E)^ z_C6Xba0=kVf(-Ahps{Nv>?CFSl5jwgD4 z^*GGv-BK`T)`;l7Tw`;Oh)WZVy~EGfG#A>%h!0_f))v=(0u5?cd;D6&L^gszhSf!> zwypC1By;q$be*1rCEDF%$&@C*Ju|3B9xbOBby^RuVn8f}3vGED;nW^XXRiYkAG>sk zxU(qwVf)*Fuv~ytWu^sjVEOz={H}6CH28;e*+@zH0b&gVYP@(=QtpD`p1jT@bmUo6<+k|~+70CNev|io z5j3k`r1!{tD*v(14V&b~$_g|hS{3Sr^RGnJA+9ri@to+cb8aF-?VFLp5L!+>ko^j| zaAGM<&C+%v!y{S@c58LT#ayb2nX#7U61E$Y5Uk!Gt)}(I}6eh^XsMHj~yJ}THKYnP{#dFW_;Bh zadT=yK0G_iA}%@L?M;}y4$QtE#q>uTkX{`7`L5F&NPG!}UX3x&oTi&o1Eja}u3NzD zhs_ET@15;L#++@Ks@YlD3Dj(Z{EEDw*;7hrIV8E^&`6U6<3Dxy{5Q#iSbm5<1mnBv z;Uv@6f!$1nBCQhIu31R89NhJHEHZ^HxV)z|c^oyQEBTM0>Z5mw&GP@-*i4%W$;sj#e~i%&*!$eW{G60gODum!RUoYE4YQ!?4CZbp zne7{#WRe^Xa~Ti{YX{|C$a2|S_zUy=3cHo7+E+bxTjQ*YH=4m*NOR_$Jy>zYnHQ~y z*`9?yz6b!(KNiZ;gk{FmSz~t*Tks!qje|pe7(>D$6&S*_+CC-o7vK7_f0WYs%Bo*e z8mH!NJFV3v-k#GBBv-cHSL^CQ^&%7_=Za`4;b@`8fzM&jJx!pEDQ6z2Zj+sCs4m{M z!b~JhTGi>butLW47V{MDg{~bU;6B6WR{I(qd3&yGZZKVoIT&CNq^K}x9S*Dc;^RNyy&_fFvwF+XBNK=HXtz6vVd28#dr@-lxr#OW zM#RGQmv}hB$arh9B^w)|A%XXQ)cQa`9p3-n=09=&|JeRfy=dLyv^IAx}z?7ZDZ;Lm*9yYX)(+o8- zG4mtbCa^VoYjch~7PGaE5^%(=5G{tM6}yro>MCYvg1V9yHe{w*7nF&Ar{#VzPQ^gN zIVh!T9I$VMDLh_tTSTj{W4x&y*|{0mu*F0BNkmSW(1z|;%S)iTYG+cKnGJV0DJvDy zV5j8|B@q>t$Gp;at_JDh*>&Xs@{60+N>Me~uy846IA5wF88X7t#|6hYvPxpGN=*(S z22XIi@%R(0lU5V^XJyq~1e>qeGr$;%ZHHfl)JJw5W73!4D}DsCMmbzi&0{sbUc76c zMqF`Rm}yEx3rglH8p~~HlP=%j)145WoBAdUIO*d|1g=Yqri`sgAZQdJI^t%USP<^4 z>SO1i*gx%LJNDeVG+5`l0}L^|N3 zI5pks$hn|t!a|Fb@Wsg3h!*kxVvSOo%NVYCQ>2KZt^oVlT9Eat3`)yfZKF^nzXlNn zVWIQxe@Rb3{gm8oj2251troKYD3-ntPfQPOkyVva z=yz`R1EjF}p`j;>pr*JZAq=lVZFekyc!bQUrV1;cqfwX0Lwf%S3sZT~>k6(IQ%PJe z+Xo_HP$V$6{lg-?36yftFC8y? zurS!yOm(Yw-k2#VO}xr>Js1VQS~`GgaC%@h%;Z5nnGjRQUQSvrmRIHBAcM@0flGlF zwY6=iBXv45b*izx0VTi|eVSonN+2CmRYBMn42}QeD`|Mir)7t%Wi?#~?WeL4m2cL{ z*DdPMwJvIJyNk<3S=J|Gr>Elu^AjfnRiTv^ksl3GnOuvw%_(t4%i;&*!$PFwL!&{J zoeoqfdRVO9@pm8#a?3?=nFw_ohl_T4Gc+9NC`TpHvG z5ndiEiF?qYoDH&vu_0Hh1Ux$=!4Exk^|m9;?NnuO7y}?lKqnM1o~bC$N1u@6S4uEO zS{(k546B*`1oJ(Pgf}>g!4UJrTg;M`g@)>lKa(AfLDjVFCUMK0*vvON%{R@26+9zl z{83&p$U+FLv|UlI%k~6@%ylGh^$E7Urlol^4EXnSs+AzHBH6zI_1CN^%XF=yQz^7qg<;)I(}A?DPH~5GmHP&id?}p zi}CJ$v=O;1xHiKfTU0jE$SHMGh{`vbKm#Vp$|nN4;R1ngAs2Lqql~R)f8;A12n)}! z3&gw52jZ|?XR0(aZ>68T+)>LeZJ8~suUP0p4?_ujE%&)B1V>; z5txz{MzijjhiMe-LABPSF;sTvR@s)_2sJ-$10mg{qBm12RnpO3yP#}!IE9K5>cNya z?ye#cK~DIX*d&3>&9M+g7JuF*-Vzu*1>7h6pUH4EGLL7J9msk)jn@`@k+K4QkPD})VFD6juu_i%2LdJy)8XH?!l zd?YU3=!_yDnZ@5rY3u6u9`%!2{7HJOP+3@^Rd1%`VQy*1d>~yzVwbS0^96iOf0wf383#qoS2_c}2L!#vQ zX5)JfR>KAr0pEj>QZ|W4Y%-I{PNqR?0?&aC)8YV6sr6(rDqtrD+6V(0Y65QkZbKV1 zr-7H1iU)I?1hh}PNn5n_5iJ=bXsC*As5)vAV3G#K2HOHdpsPt>8Y3V(G3*Bj)bTRI zX024queS5%@LoF*RPzPJsH_Ea7#O#g(8e2y(N)4fI`zJy;^I(gM5LF_)3z+)g~u(` z9HFL1aM$1@h>M3>Hx9?7P<8h08kIUz_Rx>J!pX{GQ9M3QEipBCIpeLcV!-Ewa4V`D z$ix>Byx+=B=@VDVZi5iWC?O!E835w1D7d%In;Yu}%gNkMnpqW`kCmsQ<>*8nT9E=U zA7MGo7RnD%r$MXPVejZB(Y5{shP%WFlf#Vjm8g;$Ud8kZjfjaHqN$^q5Qhl8gK?r+{|;RO=|kRw6jR<1zF&BC8Cs-F^lhtk8Nf z289l0t2C4mkl_0t{0l>bSC`dPC{^6Dj>ZC?fsizdsRVTdNs=SaO#&qrNH7U1e%2k! zLA&oJsUTJl05rK0^eenS42@UlNa?D<0%ygmk$gGg<4fRHZEX!kfx3S*f7LMBgs(cdxhtq+IoUqNMYE8xYe(Y(qjku%WH;Uf^B*WBA{x zWS=5t8EmW)HDvQ6bO8aQlpYEWSsP0hGx$CM6FvS&2NS@bIT zNM;F&QXgr6CDsG`ku?_6R)*;F+Y%qr06Z4)b*hV)qEngjG$G-LDu<9U`Lyn7D|m^| zAZ1aW^@~GapDLQy@ObHVD0CHWqzm!FwLA$nfi)$s0Z>+T@iq8@vFwuY zll+AK#*rOftFRCmA;lq+cB2b8UOjqFJ0{>gn*2LO`whh&%ovm+Q41ZP(9CUr(i6a+ zXT)fN>}O+NG<|VWpj9I*Sp8`Q`2a49zzm^q&KyT)Mym^ol)es9h*9@LQn0H?nu*)k zBz%^XPubEhq^Hc#aZEJ*q1oB|+`(swA7)qN`CbyY1d@w>0^zC3!WNT49C7i}1gca- zE0-iIED$GGFGP0wG*5DNOD2)cGZbvl^>-9 zH4}Zypb*XA;*y3VOUyc(AoE*dZnKqtka$DUJxPPcEbgLMtRotwklevj51rrNiGfpt zunM#Sk32T_AwZ2p^gmL}_l=z3K@e&dcLu32L*0sEU`gX!(daYjpfRfARw1QzgcJ%y zFJmL7FNURr(*7l1ih*8G@*u!T6w~+0_89bAkdb60@zdF&VCB-#sb+S&h(WWIu)&&W z)s*pJ_$3XBt7yj6Y`5*p!=L-WfL`v7Am}C#K9es2Uy-QBix;CaVGk^0tN0z4)tRD0UXSPLV=JsAN#6jo!7yNU`vQZp*6#A;EW|F1@~xVNU&O7=u5CT= z1$s&3S>;Ycx;Nl`3H6Y`tPbxJ+72~uKw~CtV4rFIsfNeS*E5mX}L zd!|2>3f_%o+^uJrjOqx)e^hA#}_JM*=9OLaE@*HxBFhhQ^_!TKpYBNs6ljPYAdqyqW+#xS-pWZ%Gpi1A>pVp(#) zFrl$xx7kt%at&bAizZ znC^rHmM^Y?=z#pQRaiJEXk<@K;juqpq^z#88mTs931G42A~bevV)%)y2;2O*o!uIB z=Es#8cTnxTnPdcT=Bx$h`i(%e#kqyM4vUi9Pe>z-A=n-8j(z&WtUO($e^(#w1WMLX z&A#l^a0`&D7Adm=RZiRk;PxAsN+9iKeh`)})495qDPN?+VEU?Vee94%Z84xh!61*o z0KheFgeE^#U=dKO+sz6nNWqi0#jbQtqHM+dKtt@R4&15Z9ERGJC-9#0fpjW5;aLp* zDR(I4Vo^)1m9f(y{n=SaEJ6PkOu-AdtKzoqT<~e*Wln*n9L2$A!f0;TLW%7>Tf!Q# zh7QgsLmsA8!QWt|QJMm@Hd=|Ss4fQS47-(;0amH}=?7dP43G<6#kTE(0Ke&I zot2#i5 z!psC;VIVIMd0|d2682gl@T|eo0ED8Gr88`zwp@Kcyj~kCR-S`N!2@URmn}CYalsfYW8&I6pF0`*DSK43kMUSa3^x; zk^jI=QYTAR!N7mF_+?wvHd#u`0DSQJdP+9qZF*N_0;D|AdF0YaCJI-abdhDK=9N@i zTe*IJ>hz9nee_@1?Bd4GYvs%Yc z$fSJiBg%{>>%pXYLZz|ZAQ5NN1I>iM#Xyg(0^-pyrLneF%@nDk#fYvUlaH7r{Q~NU zgU6munb7|GFM?~Xgr!bu#=R`DCXnr}t9A_(npnjw`P3v5f?d-Q(hQTcghxluz`H+E zeZ9RZ6jfAq!YEwnM*A&PN}Mm3Nd%eZ+;QNtL{+%qZM_iHZ#ip2j6T)0mV+iYEuhr` z3Xnjd(s31r{lgGS*4!Sf4_Bq=TzGlr_nt zcMjv2NFBH`Y&wK`;;Gveg`@>LMO{y^y99^wZ;yf{KJBu_mZ^e4pKqw&9xT)2Q1%o5SVIl)4tEHn!zpa?m3i^xG~kkT^M8N>K{ zV8)TjG(i-u4N5am%ykEejU>JV%!dI3Hp2Qu)z1D2y0*DZ&PBuKJv+0%MdSkC6;nbieC(VfE^hPC zMyjcq`#XTntO;_gE7%|m#oZm17O1-*oYCYAQRz6rUq?)H6eEaPc~RQR5@J=L-{n@| z&6aCPYL)df>{_mhK1|r&Eqz)1;q?eV(}X+S2I0;4QOwJp4)4d6cV@|UMNSh znm=K4&OrpX zRWGhgN9orha>d7QeuX{*1^pE6G+EuHs}gK71XJullUhMd;QFxIL_osggtT3gEC+y{kt%9r8XgieSn;b+ z7L&ha7bwy14C;42!wU^KajXdhY*{5EmX5G_-PV_rQ=SXVapEj2ECh?K1lCs^=3^#5 zlA^=6W3>&2gt!N3$>W+p&calQ9)yZJ3pQtTFdAdR9v~SeQ5K#m|%X$s1* znKry3=fG?>Fr3%8RP7=Xv(sg1kKG!>Ad-}=*v29^O$kS_K|GkM7CHtS%R#V zTOuYE^g7ZW)k$F$lZAd0Pp8D|8G>q!CxaepFQ37C+29@U{c%R4(T4QBgh5R)dIB&& zhUv8cZ*s%eiXd~vBToR8Gy(Tz#0#=gmYrKLi(s& zm22vYK2ee5N=CDJ7AnkIo-XbU2-(6&J)n#1+8RZI&w{usETg}mb{#H=gPT)vHPteWj!sfy{dHRSnByJq!QP#r{2b(7Ns3bqeKWTdkLql_H z#iEtDxPK>GUHK2ZGJLF@RFTp$s{>?Gw(Acfygodb<49vv9=v#1AR0(KmgKLzq)^sU8(@4=jEqcXopK|n4hHTHj9AkJ z{@9o8NC#SM{gdtyfx>drBkh_)~qN1Qsd8KLAoU}z#BZnR$LtaD>cZhLFm59QYuxg2(ojagyU#(JgskWd1Pp~r0t9$b@Awx1*6t`!`F zwFM!P36D~bS{ zMVJXeX?zphvwYh={;1HZSZKx|kclq;3=73bAEeq=88Qy_2R`oSwZpeaQz5 zr-r6JMC=M-PDmAB6~Jog9mRro9K92m`^y@(bx!DyoVsj^O=YUZlgH~HDKiimPZL5` zqlt&qN~T=;!d!n+F+o1EmMudsA1a*OVt5PUxGyWhbrQgGLlkerAxEz|2s>8}?uj<58fu~xHZy3&D7zpg0#Ihx6{fYaD z5xPgfB1DqOC8QfMTdO63qJp4wqH^v8ggLN&PLu;a3x!BJ2M&1E#iNVzMW3V-jk>qX zwPvz756HnrgZWmLyg(yD>j-hqrdquuW z5~W-OvRtb`2o(!X9&94sTL`CzDZZLJU8WO-DBR^UzBsiNoB)SJ1Uz*_&x~-SUq;-z zhb3N#lNY#zg{*o%R=jMgO(|rV8by+n-<~J>WfgCGwrisV6NAU9P+VuL6{v*&fCf5P z?ofzEJi;PdI6aVViDb+-CRULpne1NoC34p+l`s$iEDI&p7A6!eZao9Np~)4{PjDg| z?rBVJb|@&csgmMPPDR8)kb?Vys3BM=&e*?8r#9Jp@^t7=&sbw+UI@Tb^1fGn^qife z=}#^J89`rJ{S&8?{reBX#?&|of?{-1>}7r0+;*nA3_i@9Pgh~V>8j3)aM5KrgpLP^ zZ5)4~D)+c6Llfp)*;G?)p#7IRL#hG02{FVP8WzUr^> zxbwtl&>pw`o*7($#Zxx%x%M%=i_?}0go~OQy`UQh*4#Dhb8&sxK?z*}n|OvX5KoZ` zeV|~aW_cV4oHwp;zS1WLunH=Sh{zv94GSdoDoOzYQVW6CnU#KG`LPS(6|8^@?1eCW!$s znR$h9qr3#uv7^{0BpJAhOdbLgQ2b9i6iX+qT_9B*t$@zu-v}NTs@pJ$Fe(hn02`td zRRL=cyovazH?m?9?3U)C9@WXWQ$3?qSCsP#k1R|VR2a2KCLr=zN8)cRnbZIRRQ|}f zOA|Z7Li3_1;Zr(x?FPSSYWB=o-9C=Xg6!zX9JIe3j#;z5zPiDVrMSk(UwqvuW) z0y3D8jXFOkTvp6e_IZePAf#*x*RczcL=@Z-B`ukc9f5F$7U5801DehIMo|0DvXjoLW`Kl%&YIvE8aC zrK1zpTAER1asm2u%QJa0FSh1H$P;9q>}m={M0`n0u}Gn=(vGNDl4TDet_a1&>38Yr zst$Y(n5gX!1^5I#U?Gg4#St2gRnyXAr>#j^RI@RC8?525PRTJ8#)lbKo!mtV6%e_N z4@r+ch;<-b^+aW`?P5%*)v-|oQXC3@A|?feI59(!qUTS9vzSnCsz1J3nP6z% z#D;DABvE5AZm`U(iYM69iF^R34`qf&2ndi8fU-<)ZbW(Bq&gJEoej0{ARBHYK@ZCU z8V!H@(>*x3EY8VtEYUo#f2P1>#S3{Hg-21O7rNvBN;#BwskB*{}o5C#!- zXjocRyy)MT0td7=u~9B^Svg?%Bgz$UEIn=PDJuCmGw&5_QHrc+SH~+D6H^(9M9*Mu zx{c-_QZL|Hq3(f`Hr9k<4UN3LYC{-WB2grsRw85dQCR^3d^XyJH#eF36dKVmIIC}GN}Y;@r#f)?5ROjp-t8#aAu5w8sx!qPG>m` zEjkg%!1!5*Cj(eFvkRzD^V`sC$G&SIkTVrH@?}PFS*Z=MI77{$F@?dT8es^bAY%HU z5>!Qpm4jXD3nn-p!ueqKd3jKP!xQAI7X00d8}f z;=snsl_m#9XEkJ46b5t7%0W{UbxTPqE=&MX*qwr;3p1odhE35N&l){mG8=~u&}ITm zWzsTMrv_sUY#a>$V_c!TEL89zjkiZ3m`Lm#qbk}sokf8WKxwbIob?Qvn&JJDZ7rcG zR)a*bY9jy{)(;vD8BLjjf?3A|o6jo=Q6*g>Am2zVNnyOWaJ=2b_SsxW3~B`6=%b_> z1F^AM3*(&#K%qSc7jI5;H#wuQ2M_HP;SycM8zxCL4?BX<+d5RxgQB3%fB7>cJDWK$ zHwi14vDNOY&s_&LBFxhyN#xYQdi`vxlx+n0Rlpkt+b(g2QvOkFVXgUz^3R=q4i+P} zune@rNh9}k$Bf!q5P+Y5b3X7t*h3iTYJj<>Nj0 znFRjq~#VP?K2Cr_!1J zjRIdjG0lfGQA(o&*jADe=rv*|b}mZz8T#&tBEx6!5CCU_A=89a)SOH_!qIMXiTH`5 z6=%il?5J^;#0X_BQwRc~5{Xq$E5Y_{T!wHrS&^YW626l8I%8Gghzf*~l5Ybv*{jMc z4;NRs9de@4T^p;crU(NRwIDL$;Y$|XToE;1CM+*AllCImL17@rKQF~-e5qI#~!r7R{va)~Jw=p`Rti_k8Eu!tmy{Gfyd z2E0t=Qc2P%jI{V&9gqZsi=s15oO<&{VdLB?gxf(lr$V~dOgQC=K%p^C zD-IOG<~0U92dQGE24vU(Cop_ZFVT%m38LH`AQ}K!fz`&E4;d1yx)FI4qT5_meN9KJOO#qc-*SFNxhfwkI`&ts>kC`$q-NSrrOQ{kBf z$G}~hsWi8#CO$MH$<-sfMK}t8+>IXq9Bd&2@pjNSF`!~0^7!*;cPo=pu_9L)BdI;O z%=O2d;Pj7<(w%U&s{uLY351uwm2~ zFSAU{qtced*i^ch{x+ZSxFCAKtO3)B2{Y$PNx!5INX0^B8EF87uWcMXOAOIkgK?Ds z=u3Tm9?9fsiY!n|$>;z&98Kbz zQ~Fl*i#^4htszhhZ#6ON*G9JKE+Zb+$HoyAh7HMc2R>1d6{J0)%C$yH{@$q$#7+#d?lD^pXrh=4mfO69pF9HR`jG^pIda;NhtC$>sS&n@Uth6DZFh@=3Q2#@`0lVlatg{aUVx)2r3kF+zNslr_e{R-E`8XnY1qh9anN zn}F5IGcbTlII_8fi)&<+z-S9iaLPah?Bk9P&rZif#*D*=7JBdtj9pF#DzVwpQ6OOt zzPp&o5?JaVvNa%0F-g9mji=5>$7pEH1)c7Sk2MEGQ$}O5j_HH1%g1~HhIP?VC zX|@z1kYAOB8%gui7`i}WP0edp0q&X({uN6o!ds5QDq~1@^C*@xQb@Ebci?ViH|_R0 zVpOIL*Xkz=c3(z@LixAp*)~lgb$EvnBbfAK#v3+FJXfH)3)n+m)-@wGdKnObUy&Rc z!)CV*i);TO2uNds(9t7J5lh&3$Vy{kqwn8T16<3g>Xs- z$7{cSOF8vef{i8I;>i_l)in0qS3d^;JQHQ~r(O|)dxm#Hm<>#Z9uBC}w+CcL0g@Ka zT32(CiMdZDG>1^jCX=_z`V|md>MXSw5g@0PSx@~nS6i_4 z%7YX;S49wyaNy_iZml9tf)%fW8}jmUO&ekr1C~ZWIC5kRi|gDj5dCTZzzWdT*ORN! zU@o3miLC}4Vym&0!i;u0)@i7u6hus0@C}1ZTEVwSX#oqflIW2E#DNA)Arf_6D==|l+B0($ypkQ0<(MnJSrCuQltiFZPEOI`T~PawDhdqSGV$C^FeH!@gLH~% zpmCuyj0^@bqLii@INu2D5)|!g#387_P9R)@I5r5DAAP4hIN=Z@18#TtkjjyS5`l=H zenR?M?&$fgWILF)&S7*RtHpgx&AL^WLgo8|0)HHUq~OX2a}t@MFLX#%JlOhKnmRcu zP;5Ho!D~-Q#X_K~wV?HM!Z|RF`{5e9vI#WmEf5f1 zOz5}*!Gujk;UZ8Xs2*knjR5TYP3dwVva3l7medbq%W4H_kGOFSwF7>z12HbrDkUp+ z?|j6eJYOC)`h-T+&f_GMkDd$!I`CYhFnOdp?*nuft6ZtMzvCFAA%n#dSHLO^cVu%z zXJQFcc)EV0_69?UtegNq6rlQxJSh!_ZA zf(R#!Jez~174RI>3iwIb42aBoARzdNBha;06>elJ)&u0Ry-(FlFRo!77%$;)>93^V zjm4fNrL2H%R^XO>Dp04&AY8?q*3&by?3E=gTksu?q|BYoLZl&Sg~hr`$Tlw+t~f4@ z8t-7VtdDm#$c%llwR@Mn{7q7FH&Vn&ZUQdJ1?D`JPATPFfP@$3p*lO;9eDr+ise$d zTAy#vYx^x-7B=IDR8q+68wvCemMQR-3EMLKr>I?u@NfkXMZ(UepHQ<|Mv7Q3rb*D!uLTg){YgRr5MX!P2t!a~_tGB4W)S{p9g?*;?}%Dw z(0L>=;|~d-Mt_M|9JD_!%LEu;2(>$5z!3}^bni*`0hubN%S=F6GYFKWy*)-w6Grfz zhg(Jx$F(FsKsbZ}igEHn)+e?;DhE5v`2M+IKLEu|u?^>d(=cuq(%RC(^oLSJ3gX0}wZaJm-gAdk+c0ab5vbe-- zT{a;!a+uYGjqj4f7T1w2eo6e(*OlNae!T&K3{t5LJ|8MgyHF4S%s{Jun&fBfgU?pk zQ0Oc`xC(kxhQO%-rcZCfvu8nTu<6xe*)2dKb5fIO);OXGvZ3H}%SbBIj6x_$_YX^b zrmGoN_;~u%fi2J2EFLlIom4Rj56Iu8&KF$z*}hmcUnn-ha;V^Bv1M3=p$3IKw;Cg1 zcE(PKQ4AHcT(HsxA52$Zxcm__0OIE@WZaqB#-y#i3?Kqg+W0~d3+d>DZX(d^C50~skcN4fDU?kcF{QV6mc@g8f9;C zxKg;ZiZZnBqA}x4C+=4hJDHA!FxH8snF9Ve`6@GblIA$|QlAD+q@dH>UI~L;bCCgX zB5XN`$z379duAXz?4&}BbltD05CY!Qj}01S2C!{8X>D)@8;l+;C;)%@j~0z!GM z$%ld}m`b!EVcU)`k!A*M7vxIizZ8yiORHXseClAq)0({yx3OoH?K(JMX|{UN<%5yh z5L;bN#?FEAWf-WUyGS)%0lR?fqo?HSC3%K4^&yn&*;EjNUXfDuMNAbh$N^6gHZh9O zXm~@6>G{ka7L^f^?WiK^?D}THH<<*!_Df0Iiulz$1|)YBu4^5tUB#~S8aBod5>%!~;7F+H(uAeU(WFlejLO*-m~bru!T|tlkOK@iNP{d%Vh>jEKj@ z<_uT0Q&7BW0bMm|-QTPj4%!r9>fo2kOpAw7dJswb@FK{#-vn^HQ@WhtL;*^N+tQQ? z2(9#}E)SBbqSW!<_g09NEtT2m-PBqJ4$Q+0c5jP`4@tpwOIOTX^ih~2Vzmjbs7$pK zz{Zz((jGYEBuka^%@%dkqn{`1a4RlFA^GHxy87sT!i;#mY%NmwiNnX`O*mi!pY>?W z>6UB4T%-pppx6rvnZg1G>zn;lgQNi#JL`ynNs$Zm(?y-+vxnk@hu16h<%ve!#^wWO zLv=o`t(ybQ+L+ZXAM#*iY;e1ZC&rf0jtj}A%Kqh>0#prfY_bRoD=o|kA*8YJ#b*ND z9iU>v+*}W1v0ln$$-Nzs6|((Di?ma@4-qxTuHILI$4N&Q6;%^U`T!VPGQAJla`KR!5ndu&?<`-0AY}Jlw z98EJ$L`urKx;6eRzyjqS1r{bOalW2#!^ATvv4?OKNP!tl^i4uol-rOMo)1!8OUq$y zfV8Ao8s!kBW5~YHS*}cABMiy0!dB>o6{DM5A z!zXNzU<{*Fyp%p*!55~HDp>z)aLx7-?6SDkUK2Hzk!5^*xM1vjIS|*6d?9) z`-^6RtY9FoA`p^+CFbLK^-EMHaGwIb*xWPXEu>*UTiavOo5fS_4 z;Q8WdeKD5}f61z`Gh7R(-7*Qc1|2&R5kWGTVo|3E0jdn`0oN46?l2U-7;uxSg;y9C z&ZWKBa_UjbDG9}N+W>H?Gg^}FDn74jE*n%G+-$pV^QwTlFL2h6VCx%IiaTd9fxGpS zgAArECRI#U!|g5YKNwJ6tiAb7@?&zuVM;Jz&UYAPiT89{5DbpbY2Gen0 z0%Z#ZRL^C0kx}_mA}XzDag1QBwY)pA7mj_(XJa!eIuy5P zz6FwC6o~@gfO#CE?h2w(0W{{pv2bXJhbS0?z~|vRx=_HzgcikfGScbwV~t9ne+EHa zI_Yw>L7Az9V$uNq5>a*}vpwXYRu$1I@rKxx6_rXuRf)x+PB8w0S@9D<9hLyb9w=t< zXdoftf*?@Nef}%Mb=I-zPMvWZp1Ab)%1w4$sug`ixe$gLqs*pSW?(Lqf)B7>@!qU7 za|cLmuZ02!g`Crx_@ScaofhBfR&LaZrVi2r2+T@0HD-@~>F$riItBh(2Vj<%XNT&I z+403;G_}ceOCOT-Me}r(3JRLH3DZ!~{)jjeB~Ag4&iQDUmAW3C6`rp$;d-(VNK0GU zI}Ok{w3v{cCj+i6>T#hh+6Y|OaC?DM1j@%ro2T?v%qkG>@J+zLVz?eXc>~MB5NK*V zViud&Lw*B-%AsdP_S1UopB$kkg6EU38kYaIp4w7Ku>?7bB+K)8Zk}{3Ytu}$?l@mrh z|5Uq2wGnw&&p2fWAgn42JdGHrvy|Ke<5CzeaS{%`365vuXK34we*sC&4YRZaB?OA| zoCcHGQ4mn$6O7s}Y*YxPgameq=LD{bpHh-b>me_%)C$xymMS#Q{Xk+=o?|F8N$;4P zVBOIKJa+;g19ZLz3p=q(#a~?#l)^z>lxSF-6&9lF%%-aV2m-9AX#wEPRfCg|@1ghw z%AhKW$I3k@{93HOq861{1vuff2Su+rgM`f^!3Kj%ix*_@4%}8JApp1f)ISI zkV(prL-iMJ{?1P?AusC?(fX+#=9TGFzYvwyScx$O0!^G-xs(|eqA9W@+cm0yZApVX7DR=rDA zbPpvv@?i+T0x)<80CBeFAM>lS4{_Vy4rJ&q9mDFwec!2IDIF9L#){@n9BjwYHJNS+ z8srdaFDg^VWK4%?H>!YgF-%HF1l;e;kdV`{9kHGdC2l7T-6bJg7+^S#rF-jyZLvFh zo^k}0fapZgK0xy1BjQ?D;dn>2n%8GF+EinL8451bse^)`CsGaiO16lr-~ z6($DqLrEloScC)xKyY1hR(^Y{#y3&a8>V5a`Ynt*Qv{umty0sLE3nl~%60)5@q_=% zm6bv_Ak&mXf>@AkdbxRvFStu+8IBemhK5nnfT)9l#~-@pj)ii)?yK<65Gv}n!tNR| zgcJeBvT;TAr^u+m~hjAKb-j^NX|4!&xpn6y{R5+;1SGd zbOs~~XSnLZjJF6{La&Vy<>AJizS6qJCmYc!S@fV%Ai*JI3=%l|#sFj707)KTXQM!k zSs}+8SoJ0&mvM=W4Mfbdr*+6@CDQWmfNGYbLKd8TT!V=T7bv$y1tSOTF%^+sI7wE0o%L(Vfut1lva;q>0h+)|w3f#-J!CqZ zK%mLx=cuLP@bG6{flRJ0n`7?wwxR+QRCQwb5qu;pmi zbyw5|1ZprJRmnXHrGKme3yy>eE=^DEF4i}E@o z?%QDp>^U5anmbc3jID7a;~e~cbOhwtRos3Jg_CWGzV05%n3HMV(^@+p8mKG2DfGdC zh8$?m?X=FX0kd?h9t7b5&;)^DaDj%T?*lOug2j1)Oc){NdBB30q|)Zi;C*QjT3-k% zhDoxx+%5&sB!n<7)J_4aLO-kSFrgsXc{IS=dIVIn5m4yN=eoV8;xUKfgwRD2utW~t zx+G9lTsX0wIB-0S`%an-_l5Sf6VVK6nPp<65q!@7Qx5_4Ux?Rz$T7%73Fi9zADC= zmnd;7aoCqI1}Hu&UyHYLX`ff?7Ej zo7Mh<L&>nbdPQK6_(%MfEZMV*%@z9629$VKt11%M%yk4PQyYH168NO4tjMc2B}5#5 zQVXRVC_tF?#0x+WB+=i%SxqnmHfVZM08@g^U}3hZ^DHsjCJ310M_4aTz!Cy9>`V#B1uxm&Vp|R`g(0%dxYDTzaGtoWWPYBI5;rgv zx}yqg^)p~v3nVJiz{bW{J-;OGdFiP{t!J&W!tF&h@aE!;rYjaB87L$vjG~hyyR|Bj zQ6-*I2F#k17i4ts<0e668UZ;cF_c@g-2%qYESLN(eg;~_K<*Mk@=f0r{q(U!@U1t; ztzvQejwH!U%_*3t&M6r7*iw3!qMfNxbOc)LH3br#`efh1$>wJAez1iFMe65VXOV48 zp5~}F23u)vr0Q7gGLsB23l546Ntmsm>E~ORjDU=jPf$x{BXNn1qG~6B5InHk503Q> z-cAT1P031vjwM(X>J9_)?WPLWQ$v3RX%UtXoT_aCn<3Y%(P-c|DniIoudA|O9js@L zrT{k3_Y^^u;qsc1_>|UdSPodl?K%t_ea#o@CaR zVngJ8{?`#9kTA?(r#GYvP*8$Jj{dtsy<}U+N7tKvCJSN!+fIaf66(_iW}zp~*FEdR zG$*mnfr^_=H2IyMFs~VbNk*Id%)md{a9<$`BtQS+em#~ufkV2T>YiF(%tUQ01IY7W9L4RjZ!oETQtoa~94d7_u zZ?r^-2oVvX^*u5qvPY7mgsBBWu#!$8Y%0VLMC;P?2{81b8_nF%nO3`` zA(sGp$Y{MGXA4wBo)E5VU24Gb9b1JRYuBX{TQtIzGnnnmCKE8er}@_UaE)HI z11j5ar9ni4*knscDwn0y05vL>C3Zu@G|QD~{54$HanzBQI-3+X0}D25+6CdOu_&ek z`|>Cgfa&XEqVi!II-9U_niQd~?p(ig0Yu|l3^?{nX;jv+098t)9EozyX8}4xVZdzxVMvD|_Lks}P#jhu0E2LbkOERbN!HO?h0wH`wwQsNrVJy2p*z$n z(cQd*K@D+DKu!j)Gm8=p7(E6vlrgA@u~#)p4{{2#;qNT3s9Am=8Rc&O3X`YEl{R{BoJ|U-1 zUqi^WoM$Q<4o8A*Fb*=bWbT&nf^?d@kdPi7cCH$5VnkJLOydtfDL3Vh#<(;Altc*B z%f8x`J9gT@qp!x)gxtuH=+%=V4%IapPI*3Wn2n1^I!3|S52%%=6SEOfqTWY35$eEf z_KB@9;NK>>N_8sVIN(=T~}#u8N;w zIRWgp#lVPs!B%adQv*Hwli-{K-mCb1e1xjW<=GsG9c87JnjvHzs~Czdp^OAZ@jGyn zz*?&Q=Co)`)}-|W_!&GMi@!^SLjv9PSQ3_>4HQ(zWHQ$4A`f$rS@B|vND5H#HY?R= z!qP6X57dpCi$?K;-+O)E09yo8glM6f6E_xdFt&;{`i|;k) zGrfelN92VirRl#i4#9&;SWfW!!qGP{UR!jhT|N{*6x(CA2 zMzD{F0G$R%k#0w4{yt#UO4+o2VUI+EYNRSjJ~k$qNGyMb!<0&OAc$Qe2N;PTGx`{w zHwaYkldSq0PGXk|`oxk*)u0uOM>)h{La<`BW+tdq^UhKGG|7#|p8e1*G9Qa?^yx@y zP1RCAFyGlSSovjRA{W+DJ3~7`WI4}KZw>(|MTAn^FGrn5XQ&><=3b#e6A#^zd5WA` z(Ii-m7ci+Hq+m7a8qkStJsfphbpQYuYQ6o$6HI=wR9y1hSv?#~Sj&fM`oIyJG?c18 z@ZjzHvchJ*G~ zJwM|M(xh<&cR24&rUBayn2(hm@1Pfte*lfhssoh5f(3}zXiDE77Z)BnJ#LU%4q@EV z^A>Hg%s7tJoP@5|9G8>~h=Hl6Wf>hPuM(r7!nh$2WD>wCNmC^{O-1)lc^Wq^>rkWt-1$2nXa9%w0m7Vwv37`tbr}0u~f%^_zvM<|Aa8$}|~Sr1D-b6>>@~jQXVGQ%Yyr8hCv? zB>X7G*iA5J8ge5{HW>8q2$ajK1AKOT-K{pJhPX0TL)*eD2UUg`2?*6f3u$=i&BaTD zjB^wh%LC+jQZF}D!IDc*I|mze9x2;bEp${j;4+~q^99La;4PPNeE$LJhLy|!m@IeD zn#e$3F$tSWIjm%VWwQClI8Ja>`@u&q#A&C8JKFQ(fHJZ$q!+Jus2q|>(vZUGU5lTfP zLpvhQhzS`SLKJy;W((AD1Zf89Aojk$8-U21;GwAK8RrMEsBM*M0U-+-`BouygQT2s zC7QUvb$*qygJ2mr`cZAJuC(T(Ag(*2i`gb06y~cHq9s*=1rsb^CYLLfrN{~TDfCf- zx@#7$6HT zMEfNf_Oz)ae!_-iB2hCahDlPRAqB0$LAY2vizN|p=uQXbVjp`8M`jxNhVvDohDP zWZKtN8YS8Sji5-hjp6G%;5fIK5;$P^!3jv|5pNHOT5JL38ZvoB7mgT?IIXl28FcT7 zm*Zat-k+pX+K2`WZ;RJR+6%{mqD!68iz#u|^@+`;q&|q5sj>8>$d*4vLaqgsEns`9 zp!G=|(+dtYQsP{X(2p{A2BgHgWWdmx<+&J7bSstGT_7g_n1bstfKe+@q{qY{L$NTx z;>5NUxh5Lup^|C!WL?tv3RF3Ike2W z5hF1G07No0j#F45$nBAHS78jQpiWFs_d3%jjiGcgwmXkFcVSq#%vDGh*+{xno*fP5 z1zL#RqGaPvH3l-_U>%1$gcCGDv|@`9Hgc9)Vq=PkYp_68Qjr)FWl7>r^Cs5zH}&8$ z27!27yrmn3CplS2u^i*hb=cS_+l*__?EqM@36`d$2ZnSNK@TD)Bom4%Venzka-=uv zgD(iE1yv2b=h<7aZS>IY5^|gYa8&U$yIKiBRVj5lymDtqScX6xn%=F?6B$BtC6Y$3qr8^_Cq`K7sR<4iv1zcJHTOtJ7yk{c zkJOGE+&clDrs5j|W9wfh%oE|(K^Y{>5^N_5v=AjkGQajUN0u4JIR7@+`%g;BZm@u%g)0(*X$t;;mqauE;Y471U6{rA|yBS{F8D)|WwXLR{uDZ$q#F&Q6dv zRxc%DQ)}#su#@5MQ{Qp`y04%oS&S zNll_DU@8-pG&rcDG*Jks5EEr9y%8~w!~Ae@vFV4C_jjU=8PLO>nRID+xbvNM4u%P- zZy17<61VB+E9Oc+M3(p{v?B;&i_SBsEcXmaG2rS`j&-x#^3Jzh`ReG#2J~h+s+k9P zsl5?zfe&r`yMZpt2U zgP@?3ILZiK1XX58FpL@|cMff|G5sZrC~5$4w?#bi!6J<^n9PvuL7@~JRzx@jplgo^ zfB{7|QBltwrc2sV!gs_?8el#h(IFtGSlx}K|DF@I2m8`6u8_b>8m)M6J0r>k&uwI5 zg#d}2cE4Amk;BAmh%}Nbc(QpAxE@G`V(R*YcFL9OxF*Bp84^C418W2=5>*HQjEF!4 z*0Cc?YyU$y5Odf7MxMJPoMPVY-WfK*)`h}rE5N#*we>_$quCKdWy3l@ip?Nq= z0Uw~pByUN4t5r?FE;ALGY1gPVEu8|}Me4TH@a7am!=E-2;Ey-DK}?$Gg>#2V?*_FR z%BhkZa~CTcv~7=)5r`fkzJPLHN8tHw&os^73WB3@rSDFLC<|jT5{%5W(F-1Alctngw>O| zm81S;QOb1847r*Bax6RPYmIbKzL+4?C7dVLcm#?p0pOgYiYmQo$Ca|8UWTcNg?2=DA&zHf#WHlJZRY$$d~svp69OLTsH=lQ2ruUdOg= z+qP}nwr$(CZQHi}j%|B#zEo1VN#FGT0bN~<{j9YFhjJSi1>|%tq-a3eywIprg?)8! zkcwwmBcUm+Owmg8`IyaoD}<6xy7N6X6644`6LY_woz@IHp-XTmWyMZuQw;1+oMS&8wL4dPFmkELd zU(I%r;5E$2cZ^c*5E(T)L`xeD%XexhRiO@BfnGE0ES={>H>^oD+GNWQkfX&$)Lx<> zV?ghf3+o1MXj{E8Gieow6oMsG25alL`?!2?!71g~6PlvvHhfc8FiNp7dI15{g2$K` zbp*n8I%yeOLo^IIw<$KoEhIHaQmf(4WX z$Rcb%J}H${{rSy!v348~Mxfc|bizOE76oM+5#)l4>l<7SyF@v8 z8-Vdd8Il2w9^45$ERV8a9t)F7mDe5c!*pbBJ{~PBXT#o754Z%Jk-m1)g@F*;CZ;TA zMUH|a03|}e421NOwL`{O?4|@?k-6!Y)lw0N2GKZPDy^+z#^rz;?jx2!22iSfnqav! zdM$ODOKV4~(Q^q63eSNNywk0OQs^Wq)X6g17^(_1N{SY}V$nn93z(*Bvy~v08X=?O zoEXNW2et;AqT0KzZyHLV?B%mhxUp$M@WX}4sEqM&sQ|PGgAB4C7nJzeqFEmK7_YMr zS~nSFr5xu<6#IFh0wH*62{By91m?XVff*x0HM z$VY*5=sR=BYKa(xwJ3td4yJ>ef#SB^AuZ=FOX1M2wu}c&^T>MO6|MNDLf#DB zu?mdsO~q*Y8)UYQK^)JHSsg{!0YE~Tz(N#EfthWJOnxI`T1rAZBIi`3)L24=V~qjb z4zUZVVg&&JbJ&}~n1;TysK^p`%f2mO^&>V0@bQ-Qrjseq0Q!~N&SI#kU*)DFzo=CjA7kC%qoM?>eb<1dADMyuG<%QhEX=D*ieG~sm88Xt?hl8_A@1qF*| zwlHQtgm$Foe<`S2)84eri3>u4#}WSwBgm+=dM(uP0@J`Y76gM=(5+vvAU^As_>QNB z7F^m;4?MGu^_Hl(Mf{ZwQdTpY%zy9?%4=Tu@wVtBXSje)+(wk@qje3Vd=A!fhZLUAW0z{HR!~l6u1^>6`DNIOS4Ar z70lB$0Btr`TJL^Kqi9X-&_zH28c+${e5Fw;pjDGflE_qrQCNfwzOkwr(^~gS1`WC< z<)Uaj3wlwH#)L^UjSbeF)H)6qgvK1}6+hqrWFXbK)jQAt1Xomg|DpznDc4(FNaB(W zCAJ3!GagY>UzNT7s5d9ilNkysFtAcV<3Ik%V#wHTWn~nN%~-;pIBFE~y=2}4WTWkt!fJ)c8{9W&MV>p_7* zqGBRVQq^)3Tbf6tXkyy;2jxLEaa$B4ejo~@u>bW*hKiR{7g_j3j99`AjMsixJbDS{ z`J^nsg)b9f+&(@bj2@E^tse#xv2<6#X{AiF6~*~4A?#?6lo)CVY5=-Zh#MY_g@<^0hI;vjy(N>xhIJCF_6q=3+B=IH;U?Bp1uy4|M%5A|_nb-vILH^R z2r^W_3uR*mEF3q2A*XZpy+4G!Ity;2#nhkxj@bmu+Hq;H`dW-af(hx)7g2LRLuOh) z{O6(E`<#)&2~?57G1lHnuC(Tu&!{74I`7a5L|fxen2veyIpG*L?>cand6ef1P|YMy z8;0Zqb~xt_+k#ls!iTnfOj>I|=JS34i5GG570j4Sg%~jtgbF7f1H(tQbgvz&w{X0) zShOMRy2fwe#mvQ*Fj{(yI8f*A# z)Kf~rHKcOs{!w+8)qGt-U&AKita~Oa1B(dkMNLGTLSZuleO1L9)5z7Ta zGXxx+O%f5e`sD>^zG*v<28vg3GT;GBN9Y@0S8+Vw+j4UEO&&MRLguRM&hZzc!#^I# zBratNESO*f#F6+S4KzHI^T=Rh!$vm2#r#Ji?^>#a_k$GVwI|5X}(r z`rq0WB|3*F{xezbupn)3|2fF9DWdB1guF{qlUkd?Rsb$ZFO6)CI)3~Eu_$E5z_uqO zg;Eqab8IfU%Dp0=?}W?@xeMU9ZPCjm_9ly?kY90*v*=~#W}$f)?_}R#?|Tom$g}J zsw2`k;=;hAGz5Z>I%+TD0qItGNDK-hdyMAFzGvG7we!m&4L57M;Q1(sHca7477gz+ zbTO`_7NXvOGRlY%qBC=%n1)q#+xY~;Y|Z_{{024rF(APZ!sk6Uq`-?J6yQc8Mik>s zdIGe@`kFjPNR`}hEvW|`nmwI>ROkpHTuV1)QauQse_9*30IIEHM+5;Z%s~4IU_b#! zPs;`8`DP<<|AZZ-bA05Ak{y^Xy?Ktso0z44Wib)fJ-)40YFf;m(@`9a35_25H;`bR zf(7kZgE?(M&&O~%Woe}2uuF*OI1y>UHpj7i(uPK};6-QPg=5}G_ZO;DTnaQNk{7__ zr4hoSG}%TA*TPae>AaTtRg-$y!UtydnTm!r!fi}lFEgV$J0?XLGpYge3l)cUso*pa zE;o&+)csKJr6Pm`XaM*Tf;ZT@Ta;vgWtQSoK0rZTfnu6z4a@BtPlZPrvU`8+j3$_C z6c%m%L<_iKpa|8TsUQi^oq>hesXc5%Z`nlhNiK*D5j3AES@TF3EvUH4TG-tNBC+K{ ziXnJljVAa|E%$!gWuz1-D6{B^>mmpSRA*%Oo&|(^wSW=KEV%zjuu&_7{sVW>&qYE8 z_$`#u2KqoMD1w!hkxYV2)!!d2pkviV69sSuNVP$e6a&l_n*1=sd(c^r=g}&mh5eb^ zl^tpW(F)JG=76DwbtN6+w76tu$Vi5r0|ecy%-Fi4XD7z^&*!e*FjiOGWEughIdF5l zL^Q&bMm|Srs7D5*313vthBZ-sp_31MgXOdDKe?UB0!@KSk&@~prGCJ=OMadnIR+v; zM3BwMiF@v~Szv|EZ%daplr}uLWWt8QOq4+fr3dgZS8cxu^}q(EW#a@4Hos`h7+};} zp^hzT&v;F9MM%;J(Gw0+-9&`oITA@Z2^YEp>d_krA>EfVc`1!(OUY~vHtESHujV3b zH#AfVXF|7RO9@@NW-0}%86;OE@t~zQDkcLTe|s?R-bhd`qVn)i)pthjIDPi=FBa*%h zUS{I?V7Fq`0e@_zmF{A4g`DQ66-y*@e9oJI5E296v^-})i|yTjtXU~jv{OLnQ zX23c?URU;r*$%B$&<0Gv2uTbRpTuhHd@vB}leUeU&|Z`-hEj96ln|ApS9TXOi7DAL z2cxfx_n_+8Ao7*^2F>Lx1tlcqvZmyJLbL?tU2UWSrQziZ5&^Ra3uSOf>7M?#>Mo5m zimt3w_8lhLAP}*)s5}n{5b+Y2v4rbHoh&AtpV^ZNj4EIyUMeqaBKtCu9j1WN2HSj# zAuI!8=cNehi?SrEWu2InhsV}zXnwF1&b2gA6ePAP2>0rtn*RMKw}o`u%1y($^{JqQ zWSjd(#DhxBC%FU)!tBg z4FGzZrHS-vmco9(C}iat`D9lyJ{?bQK~#+6Y4px6~TioiN1DNvU(f1mZpsqjgJt`ODrZ6BVr&6F}D?ClQej7co{iN{-QkD(bt&Aqvqp z5{AZ$GGvZ1oGGx7lj7*%ZLGL9JX9BT=f@wS6a3wv5@ccs9uzOdVW$r(4U74}5tx|R z%2yNOx*G_|Rb+lv(1$Bh2FA5IOX@xziE-wBS9dIuN>-+Vm>7zwFFaCfl4=4@jn4!* zYuthQ^s<13>B5S{RrqGkCZ7(DA)+^Da9b7~%sjSFV9tMeeP~$33*pHiuj3kS0R%0& zgtW&?wcP-1xVztwZZMFJLIM~f!=NbmPaqe|=p@CavVYGLiZkg96Eb&V^?lr$QFE2F zjX(~Nx)I-sMQW*RBdOq}m`>Xt{Fwh%ojmIo73KAz5AOZr$0+vJp%gSyt|Vf){u+7~ zu%Vj4V9kp}fvJI98=Dc+uqLBOaKYJhJ84+7qu~DG++%A)m_c8>^v`OUw!cz;W(6R; ze{v9j17&f1IYcKxGa}6~e=-RV3#V&7I=r#!fKm867Ufornt-c3Wu?NA`zb0&aOhWm zkL!VEZMh|j_9_`j5s@310y`fy&aV*zt&a}->16bH1Jxr^tG)Iko9g^HWy($PK{Q3N zX=i{JHrNkW(@3d(QG{WX@T4E?Z;j#iegWTbT)cF@?>Xh^2 zjL?mGkKsUjkc#6)0!>82A;O8s36p>0`80Wi48n5&>C)Ox)6F!f>5~*l1)2^^k0NQx z`l)~h=}83?u|id}RMwA4Jkr&KdMbS@8qOBhY#GjZd*Fxxd4xfvwQaz7rWLq0BD(U6 zXXzjxD?P3hX=xMJAg93vZB*Ut>uA-|PTgeB~LVt^j5a8sfLI$RSRkzk29g4C2l(X)(Gb5YY zBnT)rZaz**j#q#HlzTa$6@bJAx0OP-$cjc;OgOOk)^wWi*YI*=IBg=RayXO~1I#s7 z0kKr)Z+vA)a9;CR&yHy6`E2=E1Dpmjvq08T#zt2KHTt3`emE6&$xhwqp^B08K_eeU z7Xq%PY_X32kLO5?4m-DuKMLx{wf;RM%X?%&Bg_+REp`)~*!mJ16if6&`m7@*rSD%^ z^1j|s7f8wMm{XYJeKOPi2xhhPeEUdi1q#hhp~Z0Rm>8`LaD+AELphC3O-R&l(nchCE7imFTZiH-EM~%CJJtbr~QFm+sM8*L_g^3bbp*rZUv@w9yqF zkB#qAH%4;8Vo4gamq{5d>!LK=VHk}OM5x@W(Uf<-=Q@c@@wKGGJ4-h4xHMC(3iF9N zo+CyB8&ssaP=%If=u|*vO6DtPgAhhyIc?~+AuGXv}C|L>a40$JP#dUBd zm8yj}JR4u@UAahKwLB6!RGFKhtfhwW!y=e3t7Q6lWl}L@1%LoW-<8fvC>{k`q;kvI z+*(S`ZBj%__)SWyPcrSPsB^B>s*5Cp%nwm}#`eF2?Lnr`i(gVcYauq^h z72|wxideMqcXnBn5hCYYYbLB3IPX9uwSCRv4_|{ZQTiZYgTy%j+;Y_fVsP9Y(7BgZ zSl3nF51%v40K$h7>OuZ7h~wm?TfmIgm~C(k?Q&2EShm!iu~1xlI_0?Bx1oaRrUhc+ zEN;}mt3{(7lJ3icD_@a534~SlW&jnS%_SS%7VFb?O-(MwL)8lsaIM@m@qbahlB z+E$7y#t#BTS#O`nNFjvqI)el{V(R93svRl;YU&O(oV+2>f_E!A@WdrSyZ6cd#1?Ox*baqLW{A?Rif@M;?3%z7sJxzo@nFMD6*6;5{F z!X-dQxuTJbOtsB0#3nJzqO&Xj?%VZ(dx-l<8fFYJ5iA3*G~USpB@dfYe^8}G*nmZt zT8JZ>B5q4G4<)uqEB01oOCDXQ_f>11_2E2Y8UtbV!Er(!s$6%-0TbcPE-0cZtisEH z&Pa$nNDQbGfM4;P3f$uV8bwqK`T@z(kh+8lBq95YhN2lpD?*k2^9B39X?75vEh5Q^ zr3qPB>MPAv@G+3J2&o%ps~=-1p;KonuUcZSO-Bl+yFRHTD1#y@}}B$=xV_E#~$A}GquD>WWO~9qtGI+ z2Aw;I6%HuMT?#_Q=u~H$KM>$REDQ|JD(4sqY)JMHoG^m=P^bn*B8PItE38b{l~nPB zs7+L|c>yg0(rbYp2t5WyIc)q@4CeUJAuJqDh(;#7| z7`OMVBiFVuXJaPo7hL0tbf27y1)w_%ufKX$FirMsGtq_7p~B307lfeQPbWLY=TQ*} zv3IG%AO~@3V%8;WGs@SVX#)4f_eTG|Zly)pyjjAIpaKs8KwiZcQB+~HeI(@a; zy3-X!+S07^YzuK3k=W3!U!zHiA0Gym12WF;2XBLH(dsBuO5 z_r?w!C*FZYx29=!j6wRoHkusM``juVh};@jzDQU6q|h2^*g~hPVEQicXq26TtrvCG z-l%-{!Wg|zhGSArVPo>4ikxgE4hHb@iin|z52oJPW=DR^nQ;mn= z_`grO%m=>8YC+qFt{y@dP7xK2Bz5t3x+S+Q^q6o>iR0DE^1hkq?X5X6vZI}$Y?c@r zrlOMmFvK0@aA-#fG}yxBEU*?7-qFxBSaO%z3Qj{4Djo#EO;0~)W6QJux<5d34aH@o zSb`EL-9Lg6dBMa(axbccwUnPH&|H;7u_%wFiX=yO|0GH&SrAVYrgM{yteYz@{u3GC zCW-Y>rkwgL3hnurk5UdP39PkUs>c zyMdL43bcwX510yT77_>nObW;$=%b+VN%@OQ#cY_=y%W<1e}x}l&>>nXIVh?CCfMm4 zjc(F6CetzX#>W%@tY*~p@SlTvpkSr0j>pz94lmLHJ4iw@8Vc-Z!!jxusR1{GH@thZ z@eRf)sv#QSRy3B*ddNT5DQ5^QR`cR%gpn#&8Lm3vB0*oy7@&{~z6)%n#~)JCXQa); zowG8bhKp+POugOW&sJVW`V%b${^8?8+nHT`MyI`Ao#U#VXLP^+0wZSdl*C zigkdm%qFl%(*i3KPv}6^5=Dx_Q~P2sa;>x&PP`ksiqx(mF|cH!7#C^QPiDLK+1H(d zd;Y3SzT6;8m~H*a2NYy5Kp>~LSEjLjXx@zIEBHVn*+3#Ga>#-)ds*{HB&tJ!Gp)1c zNJ?d3-j5d(K3i(3n$-1C({_U~aH(|BcTGIc;pc?{{5{?xaC#t{wRSyAZ2D9Ov<*JJ5%-k8q z)Wfl{Uo{@9oVX{t#bcQb*S@v|R5;-wJifLDa2{X|7#L|ufvX^xsN`x#z#&FlSY6LT z-zh{4eU8Q7#CIU%^@?q(lK7|q)aE?!fM12VLA7@ORW(DUVT@SD`cyke!t#ULR z8_(Bbe;FGD0Iv@6eSl7-!R$h5yZiOP3SOGy$^T2eo=}K;t72f3jNlJKk0#LVG+kK7 zjp6i3LTLdQGm^-Cz7;2U{d7t&0bx!w0mE_&BbeLlF77T8tuO-#I=k;zXp008iSx)3 zV)h&L^IUp+Q3ylC^dfD-yz)#!6WkPd8K2$hRHlLw!uq_cX-XeKGVy@bcXYy(#i>_{ zn!%tpS7bnf&XkkrX3h{*lQ>GVkB!5JY{wn|5RUXLRz})dxUgJS<&?~WZ0{|x_>kRQ z_*-@kg8LtyHr1tGqax@)6-h~=f>Nhho4Z#SD?9esRvG$nnry8;hL4A6by7t{7yPaO zI_&&bWHL=1xne)aFjl#1gg8%hh;xu{5hW!UY*S$?k|kce4=75pkBALK2(y!!w`4uP zR9E9mLhM5${oQZuFVG?`($0S-0vf7jfkpgcOm}0@cl)wLQ~3fIz2;Gsee9Y=lQ)_b zfZl9&DHpw*0(mYtL@sm8{G}7>$2>W7E=70}4}cg%O$qMFvDCwDGFE*8EZwNG&u%mr z1FTgHngp<$Y|gK#e~4d0^J}w8EJir+C9H!nh(kTCV%oL?i2A1%uH;ljfgnHho&DT4 zgTWLMXxoA2`HyQw7a|3vxtgvXOGF7)ABfpn^Oqd7wQS+R3ooB34W%plU;~M>@Xcr9 zr5ieMCC;MlqOYznads2mmFAU&Kw2Hx-YkU$NZ;#cQ&wYxz=-;8kg>(jP@aMEJtlBn z0)ijxc&d4aT)JnvFI*ENt17A*M398rGUG;<`jZs&JdyT9P_oL$_T!Mv9w$p z22`9GZNW6;E*%3g(&w)2HP*B1 zoF$M81dAYzL)Bam=gFV`*|vy)RPoL!5x7JwNzK^`A>fgf#YW@^oWgp+Q;q+QKK?te z$r0_)%Rl;M8Rf%}9##(g8F(zAF2ra&iO+yb(vu8t6+l%DA_#rdW8BrL+y`hi?Md-o zg4NGrI@BZK+CO|JiPL20?04&8CzPzLG*=gDt56XYQpCwa@BF8Q;l((bGQp5J2-7Ko zP&w12^B{4GM-2)x%usd;NLI8lX&gb&{0; za4cDa{4~csVW}2?oKQDaBLz~Hi5L*`-y=UBCIUzBJJV#cnTLR?+K`ieK9_1iBjaH7 zZyXjg%GE-^0LWC+hcnV(Z!HByR#+0EN7<&N1zonuXm8#L=Y@WF2vCsH(n(uFLqB8K z4TlFza2StZWK^iU87Wk^_(v&Jh{|QscHP6#g(3|*l>Dxo;ui7b>k8Y_5%dTGyE%8L zQ=uu4;!iqME6TI61c>;qz6`e>({4#m*Dv-xVLKdK_gKlN zGXaOxr5rGa+(AO2*C|S?X-TG9yFfh<0mo3~6>Fv{tT`3|)g8AuAgC>_)rmhvN@K_q{Eg@opg8E%6wNnDWVFY!NM^C&~OzZmSGH8AMltp z4!ohB+?^SGsKj$2?ali+qFqqnI)>GA5a-~J*`lZdgf=ah&|v~9G?+-JHNa9fi4O961g7U``R_uAlt;`m4yHQzVH8WcK^R|&;NgGlmA=% zpZR|r-~Tf_a$wTkS=Q}Q#z}<~%_JluAtXbW?tgZ)Aw$E;EGT}Ylr7CgC(=r22}=oy zQyx0iNs9`LRFEi3dsCjTc>eg#INx&4eD&|%y7fz`>1?8hz7)l3T>V%wXCdf^34JFw zWF^ma$z<2(V1c^_{B-p6q`9|mBgpLZ37sYUTfR_0{7!)FM{`Vtr?|GD1UJzdMO398VP_SX+>!G4+@x{zT7qqK;S#r0 zlcO@nrqAzLt?hc~!k6>P59YQ(eoYyi@hPk z#TRe#m@TxD;AkT+iXP7iTJW@K;=YZg9n@LozOd(#b{AFulK1SIT8WAEtRa`g()IFsvPgxeVyH&5exSowjUT@vP5a z2E^UsXxvJij2ikqEa&BBd{dyd&eW4^ZDCGe?RIK=O$+x8pruNPk zR{DTUY;r_K@dk&y!F8RigWIRBaD_Rj+@pLVF#^JQ!Ho$gR|_;YD8DDCkbz9Snwl09 z?3G&#_%g%p7h2)Bd~u-Ad29ylMviV|W<+Xlr3GC_G8w)XGaR_NP>1p@9d+{uTY9$O zoW@>I`eeOn!Fcn+Qk9(>O_&n{9K=cu?tWt&rqs zD-g4pYDD9gSuJ2p6J)5A^L5&_0lr@)@0M$#f;P<%aw32zi15 zJV3b(iFPBJSZPa2-{2^0xXaEw`zrjpL~D(P;%g?fzw+YjY6RnH;~M-s1U}5*^*4;} zLwn0~(Oc>3O2+xa1IxXoe*Rjr$MIIi#YS6oxRa(VKyugke%=7^wP$V8Tvv6_XTtiK ziies+-vJee$7byOM}4kvB`nSjKa}XdgPDK`nI2{ztdH5||$voi4^KcQLG}JQtiUqbHcm>bt}W8hNRK@zA*&7_>JaxuBFE zBrZfppt`snQ=VGREsA4&=xvgv|IU={KBf?seua$sJu~`6d0dJQ3y1s`PyW;TNMuy7 zX=weR)r6fp5=^r8WS&aBV0s-OycR;h>nc`K9m`-p48+TMHDZ1RJ+hkYEb7EOxP#)C zftNpZ40jgk+sLQ7=k-5Y`h=BmB0u#}LQ>;%w~`*kh1^k4c6@_j36ys&x@E8$){BaC zC}g(kIfcH!YXqZc;0CbxgjHlN5=50=f_aY`oGW`X03_@a?rj&x*_;{0=5n| zfa|z^3My6 z!-;da1b*&H9ctQW`l6>}dVIAc(|4=Ft12Ln+-J~sOL~TX<(cE%FjeBqCH#R0MUz9U3mjHBExS=CXQWH-oObLe)+NPv zF%Wg$y_s?w8-P`%3tJ|xJe`Dr_Fd28)A+|7ho?3YI5eV_*i(i5dzL&uOleVk*79yW zAIWKGcE~|GsTX!_boB$mCp0e_9jhpT*xV_aZ%IO-d-Orn&ESLn$IK`D4CQp`I{D=62 zHqU}}X#3l98t&H?P^@adzY@i&blrOBS^dOe=LeHNw*_|mLZ0yU$PVcsbI3v)D7VoP z2``+yZ}8$c>6Jo~Zl^JbExr7riXCQg3y%0W>m9N z5Os{<-&=MxYnC6cu-x>3%ZE7UV1zpq9vj5i7Kn<%i=Zaw3n{vdYjXKw!0`Vj!e!#1 z^ZDCKRwkDl-@gd2ELj(h+4hTfAu}H`+9hey&lFqtHcQ-9mX~Uh9OX`fGi^%t4R!bX z0^Qc)r_#upx3eCuH2XEkF#ZGk-0O!GZ%#j~aG4zFkC zwm2jk$-(*y1K;)3Ak#@BVDasxalZ^X&>Sb2Q?v|+1;-g=-a~eKlLh&6m!;gf0*0Z| z*xhqk#Vs>kJM_w=t#vJVe>4JMx66&{vcyy&?8mxG;R9?9=X=PkFJ)L7BXJ3zbWl$s z^Nv*`ng~ocaEB($w8{lewOmS052`*Vr#hVAW4pL7lXK6z3pQT&E#o!~Kd=&mci2eV z_{{LhI6)!iq_F5?!MuiEmG&P4*i{B6*H6z!b%)OElv8m8Qkbzknqq@YX{CF2;_BF? zljah0BrRshUHr=7-v7?xVTZ+My)BN|uXS!bh(3}(Q4y8}DJgafTnP6v^>km^YZGHr0?pKJotUHUe^fryATP&a4 zzEIIW42;ZAH5_`v3RF6UJ09=HzE#j=T<@jFeF7`R@4%nizoKj9Hid=OTv(SfgCkw= zs=4RGOlG;pb4JiNRZmNSVPJ2Q_$2x|i1y>7>2Kd7xFekr# zlEJT6BgfWYn!27fxg$EsnMW`#V zw&CUm%aV6&I`OH3>(TOkpCi15Nf?eO z*al$Mh6hhvjy+p~+7~LD6?48?jJ8gm+g+(oDsK%X^-a+3YFx+d6%D*a%VDTm;?6mZ zkeQ1mf?jh@(HY&K?n7nE3uDbV7Ox@A?DXVlu^tY;ACvDz1aP9CuugfL2CDMBt)=G8 z1y#(?u4{DD{AVH7SSKz;Yp8s-%foNce}+~{aB6=FWwB!Ap2_1-bd%NySoSZafnmX& zM^2p$ofIh6zG1`R?TOD?;z7VVwjS-i=oi1T8v`9!vE(vF~iB zY`xn~(SEYdB^J5K36@$iP33Hm(a-=W-c22zKZraGL?N5MH61S+_H&%>8F`#~rFVh6@8>@DhCd6;HKh48Sv@f!<{5x( zV(g);nbsHm1rHhYtqFEqt^$@>xW5$R`dBm4Xam`%=XBB?f3$o z{Y@6PG3Y%CE`w*Gj~UiJNOjjLXIG@mB>yGg%y4Q?qN#6(-!&~g>UVIr*?bVzs8`cJ z@e_u`HQ_G~^9b-7tJrJ(FlVgg;?6v+@JAP3(mXD7h+_PWfFJa%4;mkFaLC|wYZ2AH!r{rF0)uEqe+ZyTnFi%62dQ+uOtiqgT1DjWFuV$;J z>7uE_az}xIQ#lR@UHk$3O*6&ZiAbjRgma<<9k4qxgQGrgm+oIBd4fp{%+|DdU(9Dy+lz8$2+a z?7)_FW{EVO%(53s^+KO|Wf{H$pfW%3PXZ#PNrthG2&XM5-ZuLZaR1#7mCAB;tb9^s zT}~`ju}4$z-_!r7{fUw~3!TqHsJlgFN6l*+Yqow6(n8@)c{=|nPSXO`xQ8qUXZkUC zDA~(!P#nbrtNbWj?k0qGN?wJB^&sE&56BmJpDe$n3!jwj@8(QB7S~-oKB;4c(=yxt$IBS z2T%t^=>oLXONKC-O&u25rw*MJ7B{kNgi)!2-(SWFWwpAY`|jyQgwpql-VIPN*t?Tvy6u&+Um|zt zYqpFmKG4NN;DorTL{s8v8oaiI+Ktqhbo#&bii;(hO?$}cSWMYTRrWaf(_DG!0=*Hh zIWWKR*}f+PXGm;HOc@Y}rl??Gx@_n#SO@3wvB8(im!G;#`TdE=4C$BXi}y4H|1zD|C*)9+Pz( z2uy+>$Q?3eEG7zhHk;o+>XkhgKcb~ZIPw^!K-%>djbv4pX*6txme9qZ3-@jv?1;kB zd2vACw{RWw7=xbZ--R4qy+m(7h!Pqa;*er>A>Td+Fe>r+c?di*|kdu+!4FqM~c>hROP+WiWzS>ULD!Gg^_bm;d}HXQgy_*(u0>cxA@M1p&AauMJvncDt5DoSIqi)_ z3LnieiS#1D0C$Z>d@%H2y5SgHu-oLH@yMC*87MD*AT0!EzwWmzT z-?7Jf9?v0f+W|`UfuEVlo90Res!)$c`SW_jW5K4mNFO(6w2KB>E2%3*ZkKaN3Pro+ zCte!XrM>s@AOR)U2W$N*K{@FIyUVwm!ZsD?JuKuR+T*U#HgCqG+KPWvUnAN^xwmSti};* zKG4+d+o2hKqVImVnyVeUX`z_=$1b|y#1&%y2_kIc1Ekp(QF;wU-qWmyR&z^0pXUvW zCWhYZ@B-tPoglPMCT37Z=cH{`*-$D0$J<3(lbk758n1HiT+3y@#S%&qVxuN@g86q^`6r{5OFZGdO8=mlM>+0^FyGsaAWu2f z7+zXzP|Ol=mX9C3mw&{t`37aWD@(VYYdIDzo_n~UsVcO@!&~ED6fO>C3$!WhH5Ba! zb$(toU3~U7x(SbESQSiR7sn&Kh3o`5>Lw`46&W;zmj-TIf%aG{uXK10oZ~eLf_@dU zm>7yrFmsQPyRX;rEl3cO*&4~dRm0)7hipgdB?4}e9)0DTKd`JfR)K>LR^65}_+MUF zh$1Hhw;$;JfZDro^`BzIhfO?Rw@BgT2=8TtTzGBruteXw(1rn43^a{?^heY@#mhYd zTxX{SjP4gG2)FNEBc(bKZFlChKKaoU;B0~2mt03>Q|?h1NRnUyTpRg(c&t?F;lre2 z4VK<)ww$%Ig)Qsz{9T|Nm*}%?6IvRL`ydInvkO0N46-#!gR26YN|{YrGkw;isU}Ru zMD1CCtTUM|nqIPW6AX7h*I;))H?+L6YQ^4HErY5(6x_`!e5~4ek(CMd<_`~yarNsH z;<}LvqvA+U|0PGIF~-fL+Wy^q(f)vdKAi6#0Eu*7!;O_?ilPruMvlr*^b^SAB=*GV zx=^FVp&rvUq0{@>)ry@f;I;GZfUYC2%*S^s)YY(~Xgu%`46nIDmhn(%eRIQ?3Q_2> zerY39f5qMv_qA6Oa;*BCVWqMla(fr}K(J*O2Co^+ZC;;>3Lhq=*l4EXM04_SsgnGr zcyQ=4lX=H;2y^zDf3TmkXv5aIB(>C*C=VkV{+jo}VL9G2gAXdWnT27^pyu=JE=*XX z6OXqXg8X{gkgwtwKGK}F;*Kr3|$5KrE9pO_tR1)k?6ed(Y;ZVh-G$^DJP~GCq?M`I$ zjS)k?#Wf7aPfjkF47t6@upASAh%_0UDSGGHOdMYOlsV&suY*Pc7?0KHObzAQ11T@P zp=r@w@2?pFRL1lYJ!_*|?Q{wE>*<0GPUr9tu|0xHK7K{^ZFF+WePWl|b^$`G5Iz=F zQe9$zB?hF!g3I0eLi)IdFKpCnl=otl1NAMhM}RAsbO)MBswqt-jO%Oph1`q*;!5Sv zuK)6%syeeYOwfs>uKk9`y4M_R#mzs;5g9o~snh&yR?)CuPaGZHng~45f(#AGB0fzC zY%AzG{oIJn^f@K!S4%kG{Xk{EJ7CFgv*W9r<_XJBm}@)Q0_soLk-th8H%G@SgePH} zl#)L@Y@y_~xo~LvazayFNlj1=1`rkNJZNOImg~Kbie(j1aEb2HWaVjmUUiLb}R624mHMBu9oePC@kBdVEbYk*=Il&uWpDC8cv&$AW$ z664K`2-20qXSvE^gx+MN>!~a*{w5B7@?D&}F&I4e$$`i6Dh&7 zw|PbJPPrI3(Yh4p+mFDerHAMX9DqH)-EhWMGrH=Y0K?|`3C?#f0CmX&qo zy`!eWH~%ui_y2e{(Ub=Jhw$1(y5#$>_dI>$%yJPi*l<1_PG>xY3$6abt?v=SyPPU` z7-P-m@``-!=nuM$?Qo|&7e4jYhnpw6$$y+P6%4k-n7eby*ySfZS`;hh{#-BYw_D9^ zsg32I{qKuaJ=JkvQ59^yrv#%P6oAZx@6bpk$=)Nr}yBFY@yMQ_fj;RP#sOtrG%<#P_A-53>U`R&b1dnZ9)>LQrC zWhpFPe~&&EPZJ;0E*#hpNM#Nl-1}=!zA|70ZT(XS+jbjEX3QE(iI11z?tT_@XJ!9? zJ!uU8_E+G94Z1wH@F&D5YlBh4VBFyJR?zy>1$&d!ur)0RyB-wc^q3K8Xhsq}XQ537g-jh9-O z*fR&RKh8zp^NqAWYaiVW-%dkT-XgyvIn?L-YTocN4)?sZV0*dw`1|g3ZdN!8-OY9M zxpo5??udumBX7|pK@QK9v_o0IN0NM3W|=Rq$~VL}!Kn^C3fKHj*OW&=d(sGsP*6rY zV;89dB?}%jc5=N_5B$39AoXh6 zhmSWEmJiQf0=|Ea34=43>dbrvd+RE4i7Nox|563t;g2C?XED`}+e8~>&%>7Td4hN0 z4qo|e9!Dlh^CY(knExVAa;~5e)V#Cdh_ww~_nijWGrz(w1vMO@eHTV@JgMGI7f#<< zPB*U}qocbQa)Ou?k+@=y&Ps?I_Zn&nWbt>A3Fd8C!I~Zu=(Xr94hUDqR?!NIhfQEx z&C!^jR|<8NgV1brEN^d`4w|DLkjsE4P`5dhZgj?p86huV$lc{a#nfCH=TEqA-BWRD zqLmmDzKKtyWD1rcnwa<2n)Svy!<>LYTz`8Tq@2$r<#a7@9Hby_YKnrT%@1IDgexhY z?JWuFdm3N%9l}Ag4#2IJoy^hcGl5bby#7k>1Va!Q#c-9Y(KKH{p2by6_uUo>P zk!!fZ_a&J*x02?G9`yCgXEAc{0f|&X4eK1ghhx7g2pUE4c>KAPn6|}37ks@!Xle4Q2P538Y-^{J!jg2!3=wz7@<$&s>`9P%mUT^={eqF z9sN=~E|?d3iAKJ9=x&vOx(2@db^E`auUSZ0eIG*Bw_)HG;>bq#_kwhYBR(8<3`eM5 z;?J?l+`Zre)#hkp?`N7&H_()=jTEtDPB=KX?BV-Y24TpE1-wdaB_3~9=1CKbphS#? zpmZ%>cd6!I#?8_=YNwHok^v>8gn1_D=6bW9uGeC!w)!_ zdLV?E^sPW+!k#J!$;AANQr)6&<=R>FIi>1EsK*o!fv`!U|R*q$b z(GPf&(q>+BV-|~5ad>ri7#KOs5Z=$(1OdjMU|#=q_@@X^d#b?IgO<{}pzCzFt{C=3 zd4k`YOLWlXHF$kELkrxr&}8sh$}di*M1>^s(zk}btv4iNRrb=l-^Ork`5ed&zfS{- zcfiR*`ndk`Tfx=am3sfFEFaoXDsfNp5siO$QnRWAy1T7E;+{5*(*oz}qj9s@bKbO|<0 zF+vkJ4fNFTrEax8Y+vDFZ>TqfhnQUxM}!;V+iPKDylp&wZJ)#uO=(xK0leLVE# zaF&i2;LBlceE+rw-x~Xqu6&ONv|=*9R}A9}k{K++XutfGGWTVk7`9gn7r|#b-z1HX zr_JQ$u>I+!BaWB`3k&MS-{8ip0{L$DyNTF{kf;#mf&W@vsJC+;t!e5@Pej zF|iB4b^LrxxKj@Gy*)T$U_4KV(dWQ@QKWe-057d+f#4?#kiE=s*W4D0Z(N9&SS%Ty z6~G7AoTYCXel&dAG;}EIpt{eJvbz!Q1;61LtTEN8P(Y{p#>d^AlH^`Z=Lq|*!0Cwvrl__fi3 ztv3bd;#~OeRx?buzDItCjc{+&C3qt>87dFC3R_}5SapUYxE!2TR&q=e4@eeL^bS>V zkK`|m{=E(?`ah>7CoL*^esH6=PXiF|&qK@S34-w}e`<^=L&b@6ag2WmjlCJfvYvfd zmY#srPgCsCV;{Y70h;$q27M>ja*@=&@>wsJbKrsgc+ayp8csb`K5EZs?C?25p>hN8 z)AV|L^kqM_A9Kg(0tbE?;ajec}Vf3RIJmDdhZJWQ88xE?m-LRFQ z^RydA53ZxK=@%!)&utfT6Atk6$?|Zz`zaP~7pbQAAg)@a!yYyB@yXHsu=k(72H(h} zRbjh%wf+`X9=@FdY$cfc+Z=x`>4j+!E?8gkfB`XDShv=V`o+i7w;Rbq%k7u;*Q*;~ z{<@na{WAwTNR#HpblVqon&C9nTbNn@9FFQ8r{|BS@R_}8jMg#qXJ`*LdohJuoe;OY ze8hu>Ke4}8uE$|o7Wh>4HB1V=S@vu_qDewey!NldZ`WE#4#rYkHF_$H@9Y%%&fZH^ zdCDlGJqZ#sDk;``896R1#CT=FGECKAM$YMk8QPK_#THkqsWm)BL2Guw!B z9Q)C)#Y3@pupKLJ|0qt$s;0m90!cb_6HJM?LWY42<%iLhuER0%ni2>fk2RKGlAa{I zT%Hd9jbBVZPxQj>Gz(s={{*@mda-e(Ddw*w>XjcrMY|(~>jjzAux=FY`cMl!eMZ5T zyUDP~@(FbZ7SQU7z3dkBj`lv*73I7`V9FK+j4x5gt_xAPcrjDNM-y&1YRKIVKPgBn zT?EITylZnJJGSI7yvqZ*sXo}_exX}QpE>uP#)L4jXQmF38Flel2ZSJF?( zC?B=rJliJrsF+}02l2zkiyMB1V$GsRaooe@D0kTz_g^*SzLxI)^8FGV9ey7w-<3eU zk^yT;DWLfeIqKyVO|F%p=-i-4<~!8*Udt#hZVndauT#a!f}Z@}Y;SSUdK>CH?-PX_ z7IA}&EbA{Di_49!(u#0PI)33conD5lmnw~}eIIdQP%3MEn8yiP{c-o4QYezK#HB?; zFhBA=goiwpn15Z(zdyvI{Q2YDr0goJzBH3BHdqONAM0V-zJav%;uh>Pd@0S;eTAp@ zOYx+=cf}*UPI2D-i=g_6AfJNtjipC9BcmUWN@)_aV}{|- z<#t$Dx(61W&_ll&ku+NN1ym0XLfh5=-ub5mO2;YEj{~_-(WS~qmTBR4dtmN`7=O9PC&tr^8w2hT;PRLE!_7*B)Y9C6GAR0fSqR#*cG}CUuEvYgnymz+X#JL z_UsJ5Z%l+C6I)@{_(=4W)5F;nOJIG1yJ+C_AGf_U6Af3|@_>#w;mGM&p?{$anmp0P zXKqJ?I~O0rvBbqJ%I&9{8HdVcW;DQDA)Qw4KQ1)%w7`J1##pB*BPLC-cn$5`9jkiSfaBQAu|I>~5k zKeGjPTik~!DI>vE4oE{So_J+G4gJyaZTvatf=st?%lbLGICKZ%soe4K*bV<4=B;ph!PfqOjsw^a}js|MWLwUka zQMl(wN!ep@nNJ8MTs*_ANt*DxVkNvivI@KR8B?0M8mdgrfStOL^zorS=X{FCH$H>m zdXXX&2UUp3glexiw_ccejR$}AYA z@*j7uOQN>$D`@fjKOC^e3b*XC<$k-Sll)d?{_E(-p$3YavhgCXs=W&#i_PfHjZE0^ zJ6Q~|87yj8xMGRv2XgYxg=D!Lab4DAoZ}?Jp1pcOQ3g@VXhn#ZK2P0mDGf%flk2Es7Q%XnCUM;Y7&S%oJA-sOOXoKXA`_2aa7^PnPM!xyr^1 z(>+cz5O^SO5BFMY68KcCWUrPAHtcz!|2_(UgZyaf1~ZYN(Aj*4}^Ii4#Pc% zvpm*Tiu8_u7mFJEqIbega(QG$l2u8VxBDJ!nd;6%dhLb#H;nM+a|6^@$)uDy`{`MN zFXYP|g^oVmq#v*lg2$A>t@b&1u>LdYek`JkR}}eA{2(&6*eUe->B1}41z@CCAUZ5n zqh1XI`IDJFMQ?fmMyZvwH1q@IAG}0^!<>2fj0qg!?*qro#^T@i`j~TODm1p76{_=1 z!7J`RI@v7Gk1vK|PV6wzzi1XU*(~Ef%M8K9RvP{Eny6pcL~067;#)eWC6VcK#qoD7 z@nYXk^jOUp^IEduz-|S;=h#i&Ps}0IH4$^{3)w99z66)X37gKhg8rk!w>tf84xz+kWelrsqUuNev0LxG@X;n8&OKMISeon%znbOn@xegE zO$R`0>@fcLcLrJnJQBy8=_$TFuLSWv!_d2RFvW}+1!MnZ-jMbilKhCH6#e3)c+&bg zA8HK5pDH6@!zxQ0s=9{PObwz_iDS?zbpwcemS;cr==TY6YOFqob;YfIWxEb-Jo z;$Yl=p&w?vlZGdY{?H_sv#|8ZIzhMJH^_alok04rSo2T6O3MC*Fqpi(0y4xGysAA7Lgx-8z^y#Zc5zDQO*V$pNdUZ@{z zjBUgBz!q^LZOh3FHe z^>*4RxV--Yw*!LV)}%MWxgM&xe0hy2Bpe0K&TXsAa?#!nz|GZ^Wp#ueH$&z|*2)>WF2tOAq zk<@?|`ssF*KDr$g6SS>)YP%u&EAQpD+Q%^7;~BwpZP;ggRNOCrf!@l`#D}(T>C+NN zKASj~ByUU6webdYW-Nk8wcR}5$q;udP7rNu6UeCgGJNSh0eAj6#C|JMg{b5f>b-3( z8mqh|bFDix-q{NJ=H#LFY(+GE;|={D%W#xh47A;CrkBavI5R+w%braGJ@0t_UDin3 zzKr45zr!G6vWa-F!UPqQX5*NWKk%&d0Nk|wM!^yX+yb=_Ir=I5N;c+&%LLKms;Bs5 z)dR||`^SNk?`XVn8;`V|%31;*}H}7 zkFTL}$!pq@uZ}OT%;fP2Q)r!zH(Mup^1VUBS;4pfoKA0}?$SI^cG4mnw+t~LV=X+) z>cj4yt#JIw56&86z}5ZKFwgZM?&U6+V{OPgU4~%vyhiBUeF}DtIL`4jN<3SfOj_lO z@Q~{Zy43p&WEdJ_(R5YZoM1uvhhFl5c@gBc(2u9;D&W=9Tf%GU9k}J%UR?Xl9(Hd1 zAsjJL6c5-;z!uK{>{qNIeA+J0S1uhQvy?Gqdc%%T>S$R`{&bGAD`w%4kZ@e%R1eka zT@!PY^w4>Z1;Dg)nX?n4Z16aOY30qt5~1kcko1`bMR<>7%I&? z4o$gUMdDW87 zerf(Md=MYAk;m^H<8jv_6|U&66Mopa(!TXa@a(o#Sk(SfY_gciWyRXu>vj{U�s3 znYToXiFfF#t0fP+r-9aYcM6(+-@=6D2O;*+U*Y+!N@#Tk?gc|JulEAV2*wtMRCP0utnjUIQ7*|-uxNQgv|SszNWB71#(|AXgs-PiN+xbI)i;px0E%ay==4(|^ZA>hPy zDmXF=t|zHr(X@f6oOKDF44H?^12Yjzl5y{@;VfSn!~yT)Y1c|!8rpPHnzwix->F{4 zA72H+@`Px9|IiQmwg!-AMhNtFcgKNJ3ow7>hzjPOxa(>mdOEmqeCTYx6)}h-XAQ-K z%1E${3F4ClyWv6AUFuO2z|RLw;VX;Bi9_||@Xh2#;d+P_E?)HpzKM!h_U9~qdgsIU zY`n>Q;8FhLyc90o_LKB0dM;ine*+_x{e&c~0#0xHBvfK#TklA`UgFNBTd#3M^dCybN_hF8LpU<1FK3=912d~Qe11H*>dEo_cOmr+bQJ2>#dM($hS%Ox3lI9Pc)Zq?6(V;6(q{EKE`in2Pc zzmbkU%`54&YXv;rI+c^B8A>+!YI2`j$xAu%2j|s)z$`oWNP@TPWVvk6#Xn;TLK}f`gp`9uZWjrLi4^`$dqw?h%bt z`z82~+KDm;?m<+$7C4@9pe~FS;|7+|&*55ZyDl_uuL4>9ssvUSpv}|pMaP@BFQI*P%Cnmt$7fRT^+6V_U zd=O_G(B)p)krnyj&7 z1Z*3K;@Hi)6#P1uy#}>G$hxCq|DyT0Hu^dZ>%A0SU9W?mHQlKE>=)Xd5RF53?k8Et zVmOq8+)df}azT|G_$gS@xUo^N{p0|i`(Z!FpLK$p^5Z4dZ>M4SzRU1uf+9&0N1*qs z4Eo{M9ajdIL6?J!nBegh`uN?0EIHP}j&S{b9?lo+Q)q4iqj|itbUvc+JYgXsae8o=skd*C#y? z!_P#3!JU0DGPOS&T)hCxonpD*>~`KzrpB*tA?*w5gQ+>aX?waqj+*0$1qo$btQ1Y1 zFYXB6*J|O z&XoS}xo<8hZ2L`)A1h&$;{lYq`v@Bod?9F)Hy3)8!O(}Y9KCd*)KdKzFL^%?G()n5 zPodNBe!Dk}o$V)d%u>J_9c4C?uM}&0XThs))A6GFA2D#^c53f-l6thhqUC@3(69d6 zIl}!i%$TajI?o!Y+9wJ0ldGVs?mP@Vsz)hJ6JUw%AsRVfjS5nwtbSYtvJ>}9T7ulM zxW0l?qaV|u2qQc)>VPEkiWOdXV#;1WhEm9;XH@Zg17y{XfSad32zL%|0-fM~lEXI? zVMMqK{(7DXqy0OfHSGYY%FF>f!_Bn6R*rYEGOzaeLG>4RW7z1^kUP0j+_+&h?`}8_ zuiApDbTzZ6OTUf!-o7m?lfB8&zfM5?XgR(#$`^MI^rBDB4@q6}4sNRi(x10uvHHO# zZtXIlRsWo_N!=P#wq%Jv?X<}`(;VE~_QMs!NVGLQ%)w@Z(D(on}a5!!yPh0o5lWYJxu`5Pt(xAx8CTTy1v{m~?>>aiWF z9yQXf-RTtWFo9H>PQl-C&17GfF50K|fS$f)+_X@h`>jposbwosv8-H(_VY)p3-{@& z{a9StrjIdRA>{LBI1aS`OkeVI$wEekH+1b6#>!Pg&xm@ldW$Z~g}U+SzVY~6Ctu9W zNrh$0qqx|*n_!f92rN!yQtyLpP@6E3*DhYjTh6T&i+#qxeFaTa(shB1qo$bHZ3bG| z{GsbD)tFxa6mV-RjCg0yHC0Omr}z~3??)d#q5srn@BuYmdozU{)q0SVV-)Lk+br4L zY=Ux`Q_*O7uYRXlV;pmq~Q168s z=T|Agj5jfSXQv`QH4CM2kq2m&Pj|R-CK6T(b4xN-_>}?Hl?X|V z_l0*`rL^p3+(9(5IOE&C)CzuPUb`A>l- zZq&l7*H*fY51r1NYGwJXyFOjsJrgxt&tZv*DgR!s$S>U;SW9iAIF(wYZ9mRaWo07- z*?j=B!^OO9-3-`ZH-^KmcfglQ8JxM&9aat(Fzl!@x5!WDd&XP2U*!n4R>^@h1z8+v zz8POOEyYQTI>BkwaF>C@{+j~k}_FNHH9NQzc8(RiXA6W2goqqiM z*?Lsfi5Ds$3ho72a$T1)KDqeHlf5Wk_;XH zne-eqc&b$g{N8wx+}sDEXNDQCO}z-V<80~cNLPr790Gs$htZ(i*|0CU$Ccv9`!vn6 zi1cr5$Ix%3bi30G0tZ@Pr-?o4yj#pBCdKrv<1JSG_3{y-ToBuC?DkScX7)WU2dqnOU@Ib(eg$zc;-3$bJh>YO;Et9qyK#L zI1BX`WP{7LFBEw_jQ1zhi)+U}7Iad(vE*S5-O0LydO7c4na}`Le;wKNMIC96ROKI| zw0QL_UDvaxPJ_{FZB8|b=hbe8ythFWFT}1z$vs_Y>it4g8?!^OK9>ppE(5Si;Rksh zDI%M-b<}xH6$^I7Q0Hn{R+?TYJRQ>??Va;zSGN&-w_*{_a}9;n1G*uvkmvP>k|aBQ z4+xu=8`GF6qxhuFPPBagN5I*SV4<7^r^mUYs9}WDWi?qR#F@{p%Hmnq!qL&@5C@zY zAgVQ|(Ke|oewh%5vw}X;`JM*2u%<>BA|9caviZ2@W?y(?r7p}6_wv@J$7Hvqm*k0I zIJvKxjy)5aX!Y(TeAPgPGu?_{84tymd4_yvUo|DEK7?KYa#zlLJtRcTPm`SObr|#S zScxMR3wXY65&9~t2_D}Jc}k%y_SC*jvdf~xUR^G>#-S76qPLcHYDn=f3|<%tXP>2&=`@Hb{Ete5Z@r6*X?J|4uwd!$QSxADOd0-0AO z!IGM@lziL~R+K)ahc3NonMs})v9d4DFpB^yD-FbD?@2Z3kMPP_od#c+%6BHG;NrwS zIH%qo(|WJs0-?q=E!>9Z7*7{sRtY?`xn6vJC=OQl8pfwLPr)}mn}t>C66{DZE;$=v1?y9ex~vl>JLU^RsB7Px9Cr|@3^vigF@9^t8Eng=`_X5+tRwDNAbw)MD9vU zhScIR`Y(A6&RlvNPIvX@r-`p%R&gyIa$iatz8$@sp%8(J5qXeXUILnfkJ9%sJ)l0c zH=niY%d#q&aCq@|P&v3Ah2*2cotpk!{$&I$%? zSTIziK1Cns6?`Vgq8_}YDTEql9K`6q0%s?L)ATiZ9I>?r%G!J2&GU8~oYw)D>s|QI zvjzNlcPy9RoJmujgkWh8E%29Lg%>6sgwx3mm^yJBt6d$*-s>Mx=_Om(I>=u*w=*5; zhMg4_r@w)CRyBhc#szuHxOt zPKgH#opI67@#wI)4?cYG7cMJ}d_&d-`0cESgHZ{3RJ z-`-2tdFgZ4fH{2R$Q)FDphpvbnoHKrypEPNkx**e9}DKcqvxxM?mG|Ttvij__?t2m z=_P=X^fb=f`-}Fzl;y^~`nYLd6ZUob1wWnjS=B?IEMHi&F{oS<6J&vn7ys**^xexlNK6zfVx8Mv!=WR!^=Dw#9PK zaxS~IncrOSgbsy>)CZWEGm*mWI30EkE@enODfY82d*BU8wtNtxLkeb08EMG(Ncyo|z z-GHy}9unM+*+YZ*PDnB=rx;xu3}4t2H=1tbV?+Cb%?M|XJ@*T;SAC?iUrLa@?<_p% zGUD+cT-jS~EhnbyK-^m`!7|naRg7N2eMdJ8A7~FnA^Wk{hj{39JQSx67{?cvO_x+x zyNI!JBIQ3gMa`uV{7|kOQ%Br_vyaWOq}-Z~x38od8M-`mbO6`Y$nX{UXhG?Op*U0d zBEK=p=CVj%VYXxmPP|+#_Ogzlw==ylc++BB_3*OTVw9AGYaxZb|lpuaQYAVeO?#uMmjN~-;35kIl_|ur-w88E_VXOXUv9F~b&M}CA zkQh72Tx)_+$zwRWr++r3ER>3J-J@Y3 z+4I`m5;m0f=U+<3_^xOu){kld$jX)&Zk5GfLD3wNWJ?bMk3hzyG8pj7jQp&ML{F&= zew?I&-QKlbP7D}C2M=sQ=k)tD&O!!%IsQibVhu?+y-)@2R{v@`W?uB1knrXGBE}qy}BF)eEEogVjV4`Fc zA3yUP;*Otziz6q(IptyK9I=Z2H0qFSk7C;G_d+s$O>f#FJxh-!wX*%qZ5%uZSh{Q} z_KS=areyqvy50I1kSD=YhY!HlO(0l|?oIAK={RkMDQLZPV4wd!)2%@RA!SfM9QST4 zce9r#+ZY{uK4v}t)pwxH_Vq%6ogD7HRwXDbx8szN@vwH6242j(BDzS=puOS?y8kp) zyrmJyI{6y#{LUFc@Ymx$tCDH{*bVeLJCU<1&R3<*t%r^N-7rMM5L)iWk=dVdc>SOp zeXScL%!xXPHw)dMto}OnA8*8-(FJt8IE_q04Eb$W5$@j92Gg5^v1PLb$GIAFLUi$t6S4hdn;Q z*W>KTeCs5t-C>EHx})jppIOv&$PL{en_#J`ANI3t=385`sPxlMdTmq;molBO;hZLW zo!f+?cIuPvA}3Z=n~yp1H56=>2AkUaIOF|yXOCw+L2Yyt1qJ_tpiA4($zT{hZ*^d` z;OQI|ksw}Pcm;01ixp~WH2LxHV%QwD1K)*oNj9fW#zD=~xOe9_ad7wjm0`zFsN5+L zoD7HZ-xK+u9-hn(`YZ>ptQg6&l0=;9-Iwm)&7pVw1`EeVMNs3~hY%!`V1tJmtT6oy zWAAzLsTPFwAqAxBAIy#Cv^mf3JGD2NaC=7#WbFuq+-bI0n_eL?bvO-HGKXO*sB-;~ z-yjCuhuHqE+;a0P&CMPmJ@!o*$K8&lAj+qHBQ?SH+y}h$V>EBnE|knUoz6vtx8c*5 z=dk}D$A>;SEPa`&$v1~j!3%jMEc5sj{BXT3ZGYp7p=agTXw^bq94L$HA_hWMKN;3H zwPin<(>yi%0o`1@5&YFY!-S7&IK;{b?H&%n5;2B{`{PdrUk#r|4NFeKh2U=L;GQt(;!}P?K2%)Y|rz|*PwQp zCwt_kfWkj6XB76Y+GX4wziGFM+nR&0YC)=G#jq%B)K=h#u3{L~=ERAym997c{*r1a zji+aKd%*EBOZ>IuKWTo@8GPU3%u!1$;EA>y+og)I{i8l<+HLtYarLWy#VW9 z&ZDLM{z_7QTJYjyo3Za&1qjw}AHjANV0GKSbT@M%MV=P;@@89D*C}%))@l&Pz3G9cO%CEM zxl?p3-H$u|TZM|}ZSi-GIi4=jKOTP$F;CLu@!!- zUm*7GR|^$YXW`ZAXwC|DhY#{&@LWSRf5nm=Vgt@X9{^_dQP5)7|uh3aeu)5 zQzyndCyL1x|Iw&NC%Nc|2c_90Q$U~YytGjjmsA&FKh;=q%&8=HO?*c$e|f==8JnOs zRFU`FH&b!uG~9nOp7;NVf-1EHjNP~uMh?6{>MypjZ9^2!AG|@(Hf^AwEf=wQ><-*k zJqGWN2;q9SgPlXe!y%~t1+VeYK%+e}vZ^62=b3VLm~fn(p_!1>8`xO&k^ zP_>dpxhErd<%|O1Ozvx%v0=8b=%a+fmJEg<1y#)35{IjMRq|m+E1{>*lf`~B&@7{! zYG&E9^ll3*x4IA8gKr7?gS04p^mRTFl;L_Nx{8c0*<%0F>!RV6d(dl+8Wyf=CdFRK zu+q3tFkVIAo^yzjwZ98z+a?H`|BfQhi?<2AT!aNvV`=U6EbR5rmQ;E)(Z%8sJW6Y) z7;Jh7hK}l>r=?SI)4NFO_G>T}-HITM^{<4t0RikObkL{}6_lITpQ5j6@q~0Y45<9a zrB(05YDEce+3Z1Tl@c7Odz!XC?+`zf1_;-})8P301a`}LDtw$Qkl&sxIB9m6rdI?@ z<3vvkinb9a4;T$4k|H)5l~2=aCX?KzJz#0_06HEFg~;k;tXr7Jx@x7kBP<=)-v~w5 zH#0csX#iIl{uV2wg%miBVnj}UiZCTHe(!Db&N{=RBH z_UZfpt$FeEcSt=p+a7^$G4eQbbv(~=`2w1i8Nyc2UOZa%Ce;w~%PCi}GAUPVQc4y3;bSRapYw`18nlJdyBombdNtnO*2=**IKGHTU;t=6`@`Z!)UP!yZ2j zP}!`NA3xD&CGC48HA=zMLzCF}QM)u+{I}PGGpVQFL5>fOL*7;=9Z`K-xH-~@4MuDf zR^|j^Lggcx?r;N5{d=)A&4vlJUp5aHa{qn*NTw zx<=r0rv_3Pc8b~_Xky{l!*mtrVZ7Ec-0`M2H#n^o78$hC^k=%bE+a%3ZxqOjB4f$t zY&wqjUS>$p#&6cj*AX4Bf!~d_t>EOQ86Pf zP2%hTQb4W0vJ^La>IqJz)#Q#b@c+Nn)e?n4uZ+;u{SDPj{!V)(r^Lvay0~-4RdTjz zpz2*l`1V%<%D+6qcjQ-d$OKo3tKUc%CCGsH4?T|EupFz845RGWW%#FOD}GknF60D+ zv2NBSs#Ayqy?h_q{PPSKG@S;S`11&t{(#=o-aJX|D4o*Z2rZLarAsev=Sv-bDLA4h zY8J(yMv?)pixge} z#nIe(A`J!`#)vNeJ>%qT3%1{G4u78Y!l9RqsU)NOIk`e1EkB0dfE8t^0#zt>^Hd4<-l+AABwvlG3|}NPImwLc*X`T zNw@8FQYZ`O@+tRW(%X47wQVzmtWBf3`e$Hr%@%djv&4DNWVkx&CSC{_Kvh~D60_*Z zJj+qwCd0w#b7m($J*I*8qDEl$vt6XS=@4#hRAsHpHR9o`%Sr$0L^^HO1G5Ef&UWzN zWVb08`!^Bin}@&-=gF+0J%u-{%Ylmi&xInJc@!%NWqoTswEdffvc-xhH)RG*u^h+K zuEs#jxK!$Q)gQX8OoO?94S0QBJ!`DaqTZ4|IOSSA3|94kMGqCAwof{av66Do1{tnD znZYLtyQBS#qo6o=394__!@`>J;O7@l8nub+cqp5a?wRppkG*hEd#-5wq85(fQe4qz z9gIFQN>b!?L>&5J9EXhS~1(ro$n}4=iueqc&|eV?e%A3?;v$PvUE20T>X|>ulqoA`XM1F`8_3x zA<(N|0BbZ z68H3U#J}$jfP;91@@!pD{Y5^Gn|BkekEmnHwyA7r?F)_f^x5b{37KiDa(L_@SmtzH3~$EO2^B>hHp?K^bEY%H&iG39YLj*D6MVnE4#E`OWHn0-_U zf4c+-Mkxtg@$Qcx_unL;t6LaNeC5qo4Sxv%N!wV6@W!I<^J)B`3IQjN;LRGgUa5Y?@?s#jnR*GsZPKx|wUu1BQ?VNC8ZLt0mKKVrGQc%X5jf-mNh#3Y8j*2K~f<4L&eZl);CmLvTHQ&cE1!i73Lp`cH#aIe=+@N3NC4MjH8 z>*fRLu2pK7v`-V1GE%9sd@dG8jU)4O^*rEYU%WR&8K>MdK%budIK*TE6>555KUoW? za+=N$=Eh>enkc~6a@d&p+~t*(7s+|XL)W}fY+bjF61~IG=kqzbtdox!r!0Bem`Jfc zXd6>hrBr^e9&R4Hk)HkYh0B@&*ea_}30sYMf1DRv`}Y9LXTy11`x-F0YzQvJpT(YU ze^BAl7S4M+0Iv>Iq;<bQfYk;a#7nbqQeF6nU{jKTq!o@x`}0xq9`ZCa9G?D zKC1Cs9KPwbxLH~V_QkHexcLZgy`Ce{Eqx7L)%&n|@*rB6Yk_uZN-$U9tyF4Nj2YR% zq-5D!v^t^9>%ahu*<1)t+=*EOfxgp=lmFmrGO zrCC0s@tszn6?hE7O^dP2!UVSLN(0lbb^Pj4PfGbQfIAC^@I3!DFlFXtt|;ur52ot# zJg-QMmG33=v$z6YVHUV}+iQ4Aa%@_Ag*~EN@b<;wxT@})#CM4n3pO#r*pPJG_jnwA znl=;6)+_;!>yBvDY{{GA*GpX2+Vh)MKcT+*D6Gnp(wvJ1*lD$y50?Irj9RD7Es@%BSB9;2mW< z;B@BAb>7ya_?7Cy?>89AVyaRf%y< z2Fv>#2baf{;#(&_Y`;1WDla!l+ovuE-~CCXr%3Sh!+WvEk{s4QWsesXifGozk*Id! zFVX3p@Kw4SqgN<#$5}f%C-V+_`8nXzb;gvReV>>%i?*-k!}Pf)Sa-xrmJG}1YoT?J zHEIj&{V)>uPVUbI^UJaP+!eSGsx4feYJtbMO~)TD+WgM-8HE^nQt-I5&?SFDd}lg{ zjn&n0shkcSuseV@5t-burVtu3A~~bGCaPaQLPP9p1T7gOjGy*|RMwru+Rp2cYugjO z#RYt|BO2m;|D$uBj;vfWfPT03XY1Z+nBKJt>jqsA`flu`SN&8t>w7=c6wZ>S+eQjg zeM>s?2jB~((OkYbhOP!`^53Hc!m@=1I9th<9e*d5h|4qVZz1P)&uV6&)b+ z_6iM&SA?CX=9BZrZPb|S&J{kY;@j6nxGw&ZaOT2w+E}uO(bpU8Q;c!h&5vZ2xtezt zu46aXS=hX5Fd9$Lz}hEM_-x}U7DmmRmRRCQl_b2l zvOll2>W;>$xzO%X&L5Ho(fP9`JaeEDZtK*+7^iFMuZKb{0 zIK+?UXDHEk$qLpDo`i)u2c&AnGw_CyNWKB@Aa!3oxV&7$`{6s4&56KamzTo9$C02` zZO*@swL*c%XxG@DHasxzH~n<;6Z$Gn;EBek`AdZWzvljd9VI>Rzp7ERci6v;v|YgK zdSft7cmto@X7b<}+FTnlRj8X<0+&1v(zY|^?A&w>QWcI!%eEdxq0R<|+^mDn$qV@1 zRV$F&5=~~UPpN$Kb~^jd0mBs6a^(K?B%H9q0qS=^A@?7b)Uq6&ZPCZVdr zWvtv1&;H??Njc>>7(71-I(stVyZ9LTZPmlcTefh_PG4fJAFLB6hevFk#n*v3xM|K@ z_+}am(L>h2SercflDU-h#R!Z^J_vIUwm|VdGhXt;m;c7)kof8+rRf%szxDxC&EG2O z8sCD8RiP}|m@Xa~G!>p+ctWZt6)^nWG>pBx2vxp~qX&&C^!iSlG^}4CL_4am>=_S! zH#k__?jVm(MmO={H8PNPy(h0jsv*o@l zl5^_IzN$bzmnll{kzamyHnJR48?XUd7L7RB2#63e!oYBliSq5{HY1I?n?m0 zSLtx{wkfIPoxqWw3&mZYnUK3YnQt8%z!|+3&@Htts%XE4u6Ii4^@?x^td8bVw>bE< z#EBm)J0w}QX*hlxHA%8($#ITaumi%=l~~O{4~(PqSXbT&TLT3Atg!&{yrb#FWl=o% zwL8=_0(LkjhE;c+j^KA!M!9hL3FfV%50>2!v>E@v8x)E$2j4{qF2`YXH|4q@#O#K7DPI!9h;R zLd5c2aB!6#54UvTiWEC+w0966_1(wYR|K&AwHtW%T?pQG>x4wXjjwfNP+$FG@Vp*H z>*S{K<6sZ2>TAt+wl~6KjVUN?DTnh%wu24Ilk?D{0Iq$}XL|(Psho|Oy{6Jc*CatN zWd>iYil9GXrrgyuSTqhD%<(-9AozfD4Um7E7X`>c+}@+V-4QV!g74I#^;mRKu)0w4DIjIR?G zk-}6Xw(-*8yt`NEb+kE8o8`{mhJ2LV=}g2%*Nr@6_Gg%|<*PV%t|rR=7|dCAfgHcL z4Tik&6dLq?@TBJHV*24lII?;-+A6sTzv3-I>nWl^i3ZMp0sq|hm*&cc;iHr| z`f^qW{+{Z~F^!>Y=UyPWR(MEkd~SjJ?jE7c4@#Kaybt;}-(bTYrjn)ZU!e4sH(EWD zNBNU~$!p7aRQdCV3Z@El@y1sCTYnY&EcIdONiQ0-rMswg>>PCt_vCSV8|j{Licpqw zisat@WaSMS(#vlrP<_orTyoh@Jm?AdQo0e(DV4$B!dqB6sf=4+j|Tg$p1l2@H*P%o zmVAsh@Qs5GU=ni(94n8~w|Qq^;?7~PB*_#~DobeVqZ=efm%&(%SrjP_61}VB@aBZx zIOoO&4rV#7vs+GEuPqVQ^ztAWoJsS}y5o(hVfZb*7pmu}bJlRtLtwC!Py>z7Pp zXM=pvpuR>l{;~rnmuPZ=*LE&Z`$oS?l)>ObIOf$|rPwu|aA$SP<>@{5@MoDD)GlKP zb4)kk{r!i51sNW4`Zi3Db0YZ?MS!`hIdhOLr_c(F3Rl4e4FoGg2Z8$09C2RxR9N;l zjNiPB#tY$Xm@5RMPlKNhB%kKhqQbVTd%8PxQ6HvX7vz#Gm)34>?t0U2i{x2cAO_@u8g z>(mzT#p6fl$+alZ7`l=qUl;I?CyAE>CM2NQ-s5oZY7*~j_u-a?>9A->rTC=B8UFd7De1n_duHKkCmJ6@$=n*=yDt`v{+%J}Ml}Hpi6;8IrVj7o~SsMB&vZyLou+ zE@ABTZ(!Lx8J`-=;MaLpJZgxG_-DTi_e0$Y?$C)q>WWW z%z3od7@U8@29_4zlm6J9%=q+$81UDf@;$t;+3Bhf?mq$sxRt?8UlNiGM^RH)3QJN= z$$2l(Ncn!~bYZ9%k$(cHGy{fJEN9zO8tC1(JEs>`g0QJ4UH$!5{8(NAHBrx~B2gC~ ztcW1vcL#W9+#LKh;uu^FT!pj#nA4-onY8t=F?cSwT_Zx~LUVu0%mj4-1yninpprAFt+^uEFd-;8O7y(L?r%i9=LKvOE&lOjCsHkosi z&taWM0(_qlCq7PD#k+is_>JdAT(wYxFO;7Z9Ja}!&G~M4$RR^A&OVlst260kqX|cb z`O@R4=QO{tH^eSF$uo3wL9)FSRn5M_vA5q~dQb#UZ$Ai11|i(4mn+sMw?kt@HB+yd zY|^4B+%l_zuiba!u0&0?`w)TJe+SdebS1Zx#hWDF6$^0dC?7to^#sr$5nRBJPl?FWz6vF)LWqhYyj$f%C0lmr^SRN2h|Gl&3mgXM#!u}T& zy}884W*Z^oh@|DR9KW2%lb-xoCSCAs5cbWqW#g9X;QOvSAMkL3v>2p~3DZ!ur5VNt z9wm=6Qkc_!J3SqlA}+NU#8YGgDZh6T*Ica^tv@7G{dZ+Ds(KB_T1Okf)95yIl%C%om)nN(ix%$qwOK#c!Fl6|O&N5|HYXVAZWreKBJ(pn|M$Awet>KmXsM3Mb_ zY(%Q)!wp80h34Z^>6OPDL3W-7{#>`6*Q9rn7+z?@UQaAtKryxp*w_Z~h47ghSgYW5@JYnjyNWdeFmAAoCz zPldVZ(|CQtXi3wrDrgFQPD?e1v8zl7pZW0=5)PzdVSoWFz3C09^A&lEwHe-0H{ivwdsp#|M06uXYhZ7u}Q2F*anv^!4(+v`7-6!BB7IAdB^f|5Xcty_&_wm9&B9B|L zXt+QD)q1Po{eKz1n5&G+>f1ra|2{1UYT$|^@-##(LioA66>?VY1X;BM(7wqUyO#Cf zm!ovB^*6=swU~ouax4SDDG>@B6-s$XubfZeYikN% za?U0pdFC3l-*%t=>U^WcTXsli>OB^A?u~(f-L7mtW*5sWGUn9p9|d9lHRztO1HQej z1oaJm*rzr}V(@4&u6|Y^e3muBv3JA7-tKpWPbWG^XWejKW}-|5iilryOW{ek1W-Bm zh(-=MNWb3yrWaeRxTNuk)W;?XK7R1xU*_c?6I{*fmdu2E`)W1NmsckE zS#Ah8ZQM+$>w;nRk|NB0mrrwKV|ihuALkc_g7T=*cz$gN^*@wLiVYR8uol^P=mA{f zqDJ-IL-BIW4SKO|mUt()v1+Gk1kdVtD`aYSK+XOk_;dTe?%3(YDwA_5Z-P2(xKtrl zz4%Pw3bEn=MH46~dqJ(vC%8~?6TJ)H3$sJ4&@|Uv=&XGpxJW*M%A9xH_}!F$YAI4+ zogG?@Scif71T*%n#}MD;WWVSEd6qk}wULK-X!$0Loz(|F_KYAWhozi%MVFpvsp8)( zWj?XciQ@DuMGck1I7e}S#8`2(OaIqO9Q1Ys{K>y7w5sZH0T7;??F2bD)$rk9H}-M* z1i+WNiF^Glp$;8$lDz9@zMvx}sWVG7v#uuPiv z#%_$VgV-K64yH>hAkKQfwM3sv%wLQI9FaDApMDo^@ClTzxqLCYN1e!gEdz{VWA zecZ~YUOa}>Zlm$jFez+4@5H+&7ozXPY$2ulO`$&7mkX=vsQq4Fj04~yCuH&Gfm8ff zxG0d#8DU7;hSz`Xrw5jkP~BrNd-Tu%qe}&}ZRKpt3C>{0uwJyt&6FQXO;PvM zHF)wq4gBt;g6ZvGF7W;cKiay}2(cR8G<_qBWJ5A)F~Wy0#|mDmp%A+`felI|c;VI> ztTNZZE;|#>*y2xHNkFTCTB6yoRs7}rGo0{Oou}C5!(^;~)CcDkUv9%kSYluj4pH zvcP3MTo6mTqxIZSzS*=0?#V`rVFM4Kn{GeWEcq=S%>PAsk`_qY&=*el^y80{EJX4$ zW4l)g@GY+r4>awey}dkH_tF?X_N)l%WXHg#B|6;i{VZH{V>+G>xhiZc{y*>0?+i`BWl@ zP=gF|)rsD`J@&q66Eg<2$|6{JS_~geN5lH}PlYeX+Tod_IzF(rkjmeiL;evxY3}-5 z3jR_e#$IipA?9{4@`o#L`92sI2VSGE33G73$&b=m_UGW^es_v%>%*r^0^w%=1YF)f z3!lHgB^Z2N%6>uTsna)`x~le*rVjGeZ<+LG${23&osY9tu7OL*%EH<@kpkOdMV$Qv zzOE>xM5{XxEltKms}!!gw@vT}h@#M)I#}S`i+UBsu*0AKQEc9SIsRV&F71UxqD@3X zq0Gi}pCcqiLMkMcBqLEDSrttoNgGj-Br6$FJ@+|AkrLS|lohf^iLdX!aNg&2uIu{Y zeGo=F$e>?lJjzbF$~|4aO70zr6;}!A=oDq=JGtk{@8Xx_GyiQd2iS5H1zua7!SvUt+47gf!ig;&$+>8#UvXc;@0jZS zRzI=>^9J0gd_22JSgdmow5%nP;B%>H|9u?>H1vk|*EVrgf)OhR8*u0&2|coZO+9Y_ z_u8k=(SHA-^~^cK;o>HUElU-Jx$nVg)^<2v)`tgv?L$u%cJPfK7T~=9mt=-Q67G7t zmByzW0GUO_(0!H`E-*^v0dua>q-%SH>?H<`d;EI#N94mPi zx64aHwyBeClOYF+;oz{eSvb_`j%}9Hsq)(an7iqplbl&iw)d3yhpa5mci(`W;DYb_ zy@QbVuKfPL{%rDU4rLZ3(%jK2#M_PCxR0MQ9_?$(f5IQqnx4gy9RFTel@$-$?{{PE zfg#`wE8yvyQg$!N!NPb?+8FMHTL$^C_vaiM6!Z?xwTaaChZC0fsSsm^or1i3PF%1( z0g|E&g>>(Fn5d&e`9;Sh`gy-$r`WsXC$2nT*jYTt`M54^OF7BX~fe& z9_c%uz8-H8LoP&O-Y0oHnbt`sbD4fx9+6z`cm$sDCM{y?jyIAW4ztzdIs9up=Uk*uuSj(@s>s5Ia{ z#dSZ!ck)&E zdC43m`1~&-8G#R|>C{?$-hM*x-1m+R_m+#n zvqEXHZ#k?S;V!C6i-n~}&tuM&VX(;g7MHy1pqv%O)||h=Y@K~!hc5dgdI7` zg2X?KSD5zTi(_@g+hHY;`nX**Ur;WrSY?Po^GBnlgTTtU$!vJ(2K`ChDD;2z0A%|G zQ^}JK(Ce`VRdQzF{sYmx?XoThi`t~Ur90j`HXeJ%Z-kGc066EYus+C(Rz8)|i->pP zV2vkuz)%lQhWJ-b?)jP4PO;|OCvJl2ok?sm{(&H9&lHrm)UfI528r!3S+=+vib@&Y z)NHpE(zrL?YT5*QpWkQu(j@4ZX2;#ek3qA@o>IAPMtJA!2=tj*MAB8OKwjC82j^sS zL9Vj+daN;)g{;KuwP`dz^%j&w`@s32P)@Tu%Fk2B_nLdwnU#ObT>b!fE^yLk}bwJsONnqQ{ihz0!m{1)gJ)k|<+W{Q1N ze}mz$crYqPEPd+E={K*^x-FA%SNI>$9ihZ4XM84Cz1#G;W;UHT{*#hs_9xFcRcy=F zgSt64z`x#^W1qhl4J$vAN%efV@;*tNAiqi|tTo3yy6w`hYRZ_QFa+u^7LrnKZ#LLo zF7CKD2rk;xP?2GnH0|dX@{$c@qh+7z<<3sfGLpyqrCO5yo!L^`Q=g&IfZ@Qmp;#6p zg7Lk0TvR)auO2=}yKo2x25zJak$e9&!XLW%%pd=x%JSO7Q(uE-JwR+gxyccq`6iPQ@OIhhR!bKAdXZNoG&` z;K+}sVbrD+I6HS2EIhrEWsJgX<-VRHV+|d2jm;7-K5mlgU17L=?j}F+nu5mHZCG?) zk9(5RsM}H{jI$UG$QC(lZ&FxJQdD((Zr#}r}^Qsp0K`UFG~04!eR4)Sah#D#9K|o>dxKh zab!BaS98Yh@#8t+TOO(PFoCgmooL(3N)pfeb7^oKBvhW{$|Xa1q)Z>0qudGU+Ge=t z*EHbft$6?HDmcDO1#kA7Et&FR4-cw)L6!Qd!nrLv=&PJ0Y}+|d7~<-O{R1@l^_fw^ z7`F>}%_dEJxKy4#J@e)p)(1d-jJha$dNC(tt)hKbkE7|&co@>>tPs0nH=8VYN*i*Y zfby_*N;sAxDOFGAH)chWrd?Gypkoh?EBz_V^{ytJO=*;0`du7VFp(F9+i-^KBgu~| zDSYhkL_F`=1qw-rV9us}!t1drT&Ok_qg-Zl)4xW1vRR3eSJ`5XW;c=zJV{fR4}pUo zS+x0HprHNb1RC9~1U))H-ws%EothMe?TjIl!WxSGrNen0YG~OC*rVG8*xr8yr^((C zqbB|#rD6;8^dHZ}tK`0o1kjAH{f!zJ?XU$hy5;$R~a5 z{F)@rxS@{+o1(FBd>;(CS^;_eCv$+?2r)mWOpKRV17-fdsou0ZzPR~B)L#^gw$19o zgKx^h;M`W?-UlF2CS>TMRT`?8T0bKr2G8(b>J3;*xbE*->`04HK_C|v5pW8UgQgpsj0 z(`7f*PZ&(DrZP0&@i%mL7{d=rdg2?|TAnY72fe1LaQTQa4qaFRq$|TQXZ>*Zj49;s zYbRyA{m%U_od=!#DtI$E7HuCC(dn1tg)2W|aoK@qcYQdOx~L$YJ<$iL{*^G+S`Kq6M&dbk6>qN2q0&MRURE^>SJsF^R6=*OJ=2FT ztoN)GZ_dGi6VpMl+Z^utI2=iuz!SRV34y(z2&+Ez!!4nmU|g=i-p^!lvYr}6JEYRg zMn?=j+6V7G7ztCh7K&1XI2xn)OenB?M%ufTS=O`{UUb%?jM6YLdR9q$D~`gtqh)Yi zCZ0wfiJ(85C$U!De|)>|9D=UQwhJC-lKPcETliwM7hu& z{8;`9I==oPu^y<&dP0A;Uu(n)MPG%bS4{Y)mIZpP4THO;IRgMVl*>db3*(R!(ccViOUW!4f#@Ox5Y3e;L1>z<$2S(> zmM5A*pnDDNp3;ktpDdy&GKpZKZ^>?M?_kk7S#%lK33qqwV24#fd@)##rZ}I2!Pzm= z8J0!#VpKO&e&vChX+fY}P>hl+7Ybe8PxA2e8ZPfR3%6A6kY?X;+)x}%kJY!bV(@89 zooT^diZd~Ebuis&HG*azUFf}XJuAkYff(r)p?%qVcDX+seQQRGVS{#|&XLi4z&b_j zpJ0a52K$3sT)6C@+J zV(DoJpOcDL`?^q;X$1`G*M}?pZK(NjF6`5n<5gAjAuMtb&sI8*Ch4Dqu}yN^uPTzq z>LdsQjK|}skKMR2VJThocqM+`vk;vVmw|uVO2Pej9WAS|q@;=#nrwQD_IOB$ujN9* zUQ;}l>C3}?N8-^fTdDZddzfrrN2%cvv?{y}ru-U3gH+;pzuFQ!RA7ucTmf2N25^D; zICd=j4JX!V@IW02JW-z|3@+@2Hm<|?Lc5b-VysFk3jmgH&k?38{qy&8De$PQ5H@t) z#I@}^ICs}Qntt7mGsBx;(WP#fe=meb9A6|HQ3&SX^TTo7f)+SGZXD*-%_p;^ty0^j zIFN0)NnQuTsp_U3SH?}o=&mr-csGKQcGr`s|5DmA#|q=_D6>J2x1>|%3U42_gW}K@ z_E_x+PkO8JM9X-Tv)1I@Hbca23d-o_Z2`XKQ}Eun9T>K87*&2)$_42$eDKg5sCeN^ zJyI)aiJ~)ZoSy;)v*K~5wG5w*&Zp~tRQOP&0=NA)5guCWv(gzyyeS`o3AR@;XZ#(p zGG#8SMRsr8dj6_7vr8hvvaK-r=O3w-)mqli zxr(nczJpul2eFoh@}tZCy^y~>}?=QzSfn`wjw1s9H>rl#!sia!lBE2|ST__ka z5=)0&XD_>LLZx_tjt%LHL*i0sx9N8=!(yT|a^_K){c)`%t$6ZTx(xFUXwE=JLv+{Lae= ztKD63Vd)1U;FBCxELFrc4qu@#RgF6yHloul6FS!=p^T5={P4&by2z7hjKN{rcDoC< z{ThJ%#~D(K(@6f=`I`m}NfjGEPlVRaL(sfrDJaw^W6S=faK2yxr@k!W1FPrLo!jc@ zwx|`tuNq*0)KbzbZ3M#aTFS1q!-wGt{B3|N#svYZB`Tncc~72aK1r-{I0`#;x6tyC zG_=1o3wtcngGu%_d?F!|uih9TUhX!4?>5KThhL1B*3XXPdAmLMb$u4D9JB;$`>urF z+VZ^CCy?&`kf7BJ4PHAvopY~TBTelxfM+|<>d;X5_@`4``Q#PU`fr4_-D-qU;!)mQ z=L%+Lli6fYUu^4FD$KpxOAyO`Lf=nWbnt~8_L}2DgIAVuWKyGeXHkW;&O8VgHagJ9 zEiq89843&6S3>k{V;(SS3gEn7Qpc>buvGglb-l5t6KU}f*UN`q=Q8wpBO`2cp96o~ zw$q)AB70tWmx2>>!1=8W?f2B8L-Dg=Tbw>+&zpfW^%kL8pDl2`dl7}aI7l}ghl+D% zyrymYnka4935*XJI(g2TzI;*b1^KvL;6|S>g2rZlp0C+JOKY-W_q4n8YvDnDIcm1x z<2F(hZfwAM@ik41^2eOtk08;lNYJu7juEnE)uNzB*MwU)7xQYpfjs+S8+7-z6{ECbXd3LLxu&JqxY-!n zeX`)yf8E(%J&E+3d(l$AIJO#^MMvKcVUvut(#GMBU`*ytC~-)k`TK^$xLxMx8u|c^ z_K2e|WuvenP=n|9z6}$Kw0VF>IE~Ye5>l5hr7Hmoaoze`@T6q9VC43l0)6!ORE>ss z?uiEY``OdaDh=p8OdB&xhT_7jGZ>nyG4_)k#MBPOs)`;g#0=n<)=#B1r)IL8cOYpx zYvCmMV|@9W%{s`(QWYA<(w^03Vp&jV`sQ(gu$XSh(}K^m^tV>K!);XE%hx+dFY!GO3fM6`jO> z<&&^5`aZ3CY{EgkrqO)&w=h4?lV__%lT6HDejDCOt5>h(w=S=aVQ3N)l;6j4u>AQOLc52xOW$zN~x0cV>EF@8VkxME1*xk4^K{f4!cVV z==g?C;cLciD*h~s+YB@@@VG7A8}EqLhCMjZrY}~RG}G*aYzT~<#j0Ne>7wd>2x#d6 zCePyqmmOzF>7LA$r|m|(Z~b=2IB13=PThcr03~WOwZQv2mR!DRI(E49gWEsuK#6r1 z^{u%Ksl%G#-k4Kl{6?K896U`sJD*{|%?#G6uwkt(YiVbQ8&?OIpn`0p z#M{D^d*&)*&tWGiPx&=WdzVeh={rH;d^^?#JPH&LvuKYXx%F;b`oayY%*^P-m}juHz71+D zCbQL8dAL&ANlymn(5#|j*wudy-{0H^HoAsO`e;o?N8@wCnp;eva>HT7nN291U4gdu zC(`+KUOe4qHvb)ENY5VGll0qI`Zib-$Am`E1>rnv4Nl;hUR&tX9LK=I9ek<9 zpGUkI$=;h&p;|>zQhV`}XgkXaeL|0c?w;3JRbB~xhUrA(zls~5l?bI#qsd`f28&)z z$W)K{8O+g9giET1s;~7=o`ItzNOWWXt@#|YgW*k zI|)=H*@^d4FVW9N!^t=6bl9b?f®Ry*UWRRE%gHmGolI0+r_){JVCYs}fJ@YWc zSC&i19;Sq*i*(BWh>&_tl^2*!pd}Fs_~3U6KREV+RATQ?c*q3&uVXyb?XX1fy9FH< z3Yg(lP8G*>Sl%ET_m&&e)%>@xcFQ83zc_-XwmcGY2luDlb{hCC*ojTwzh$8@S2*{` zgVg1wVe3m3dTnik{hAiy7W5` zchkHPE7>kLOsv`AixYxeFtz5qc*OL<=uf;ce?>5_3e#cb$-&0 z9?@i`P)>mkaulVZLAmSK)5dedDX>D0t$QS~PJk7LzdH${oeFwRR_2nNM5*1)PY_pY zEAebe<*DDhBy$S0;LC+Zm{gqr!8XrChlBQ*B{?E4&3OgWi}E-s_^!ZzGiin2Yz+P} zjLyw5rc)aXusmrzRCUGR><3Bw&f|wT<={@fd!Zh>vJJt@&I<}!eeh(%KH-&e6CeJ! zpS`oUi5ovJ5!xqBgBwS;L&4#lsF?Z%RvFhyv|D!5=^poRzNZ0JkDdwM1GdozsV#46 z&J$ng7XH5v1S7xyq}Fo+`B>K{4N%+_9LB*8Dde^RNNI1 zM$V;GkfMJQ4{O{LhS`jxnZF}A@$C~ZQ+`9Y_eW9dgF-_0XnZ2Q#G!qLpnJnQdho~{ zE9AFR{p(0Bp1L2LZPlse<#9OF633s-pHjKy5xN*M6+=t&AyRIuR;FK8cOXM!+UQcFYcFuIe%-Y$KM&~kUgHWdc72) z3YAHH>^1uQJ4ej5+6vxlGttARAC5>>Vg0wRJb8Kv>7H?h%tqv1gEFKpqmP14#x^ch zh~e88xA4}dYV@!<58m3`g?3>xKDculR>(RBYWBh6xNWqVUx@WvifO!dx;QFjI@`|6g@^M8 zK+EP|!qv%Ea3I|mE)=?A?A$EcYc2=#>txyL{$f!!=AJNqw*!Pei4tm#g;QBz4j2~v z5LXqZ3Jdi&GFRn*;*sfM5?kYclXg(?hYN!8@^Mg}ABQ0^yU=s{Q+U-N!|~sKQCq4W zN6s3{ews2IXV+JJT9G6Cchp33De@9(@92%)UpT^q`O2Jhr7sWEs1^r%N3rs|0PHm> zjJN7frM{-#yfd^8s&I$!tAitot1ZCW|)n+Eq=o>DPYYr~Y*q;Ok7$x6e_yPETAAQG%=afuQ(g zD5P$^O-}h&>E$j>_BgwZD-ZT2% zzIi+R{-Q*ans&p0s8f&>J)HM9*RtoRK++BvBTV{tC-$xOppn!CcYi?1I zbo=520~1y*(czjAwPUNunm&AGp9c(BaYp#y+=Wy6-^S-22gy@zAln~3VE@7F z2sLCZl1x}%Tp6%OCLg5P)=Qr4IxtWq*Won6Pt z>PIOA2R8~^zpJvfwl{uxRt>j4?1Dahw~Lp~{UDEnkA$$nHe6CvLq`|BfP&a+XpJhz zH~AOoR^xpb@}`oU98?4srK^-TeiJ{sttq6ZT*BAcCg|&;$M62G;>Y(^kh4x3XqUy( zAIp>U`^a(W^W0!eOt*zh+mSHls|*kE>BBFRi|L}CE$fY1Ll#L>(6ncNY)MK0--Oeo zxNa(wicmRCt~axcljsoMDgFrW07tV7EcrMHKDW-LAs+L&VNt6fH)IS=jr&3)ItK94 z?$OwMZ9Px58;Apx1NrZP1Qozs*ZrhgEJvH z?Jum}HX1GEgWzG6C#W{u!(me@$#p~!$w_os@4F7}pVytwPmu8bZ&B2dsEQYkdve3F zRai9PEiC`|1SI;-;IUw!{ZGjuSZ?jcJ%2BwoSr9fx$+dY{o9Qz9tH5SPl#=;DMF*s zgn#~DM9#||27*mYQuuV^q z!=i?8{$-KA=(dW6{cYGj^9Z$;m4Ms&AUq>&XUS+8oE`p$*lZ6DO4nrB>dW+ErvV%b zjDXhD!!dnxG5`FWgNdVnFT1~ir#)uyka`wo4qk;_>wc0!SwBuRi-oj_vf#6|FUEv~ z)1aaqa4@|CYKw-5fxXgclz%)Vjm*I6mR-2@)-zhNYAQS3+aaxol6c{ zv-aJQa8|bliwyJNZ@vbg$vKi8p9xD8G}v(I7S4Qil^T0T@$rlk;!{-x?C8vfOB!ng zt27;wxg3Maj`>oZJCSs*e>y}T+K&xhgJJV7d9uk1qCeW-q>qHM=RA`V!SuYakx)KSyS}cU~owMPg>PrE*Z&#h-AeCb6+e;&X59Q)7hi{TwEF!q}v zZdXbsM_E<$-a8fNwGZZTtJ5KBwYB(Sp$>ICaA1>QLs&3-4t{xkTk7vMUFb1X9=7P# z;h23_gyI{yWO_uITf-ZqrT5C=VU@4WU8_Tgi@5$$d zEJDHd_KMSt$@GpZKk%Nnwx<9%coxsnZHhk&Z56rNoOK$#xaY+62)yxWnsPa1-E4{>i{d-J^M=X>w5xt?eP{K_$i9FH+O-4##J!y zAAu!XV{ldS0)9B$81!Z<@qf=JV^+K)x5t?9`aKblcV0@8_G#=rZ8RMU-3{e3*}}Kd zAJV5+Z^BI*b9`O@LmU&M#_Lt{aNAR+zzaHb!s#n@9Y}?Or2{Ze$CParwMvH1kA^~B z2h^`Bp$ly@Y3sfOy7}f6+z;?2=dG69y4+XL85Kv<+;(Hzu~ObVaRRth%W-t515R7= zR9t9umv&x}MIY}5l)v?nlHac5;WPKsrgk$5n$;cq-3j3Op?l%R9w}^5spHqfWhWmB z8%5*XdtmRf4`i`vKYd@Z1h3CY;i>HoaDVDgE}H2~d!{&{uWB|H#RkF89hz)<)({^p znNL3hw5a@`Ke#$t;8eeOP8*R)G(T@)Jp7)W_- zn}uk(y`rnG4CYF6dIem5awqpxXr~8i zRZ<@R&kq+TbALCYPvQA+W8({`V<{xL_a^;z73|Uc9Ws&}c}`~rFHG;oGRi|xWt;}} z%jk=}(`V4{nVWH-N|7kIm2kq~4Z@qHyD<9j3cO>eiSrW6#lp=MFw7v8iXTR?icc9i zX6?Y5zmKT%mK7RfBDGWmP~`V5bOt{@I98Uj4bz zQ45zAnPNuZSnQLQjt{f7#TEBnlIXUK({E>kztRzi`_@Pmc^W)sK|Sb{eE@x%9K3ku z5~q$<#HzjGu>Li*yBdJx4gBEyupD1=wxdO310orf!ZmB#{PVaHUx)PdYD3 z<{8G3sq9AFP&QnsTcyK^lb%RvOrVh2V=Vr#e*=dbF46TX55ysjI&5`yBuq0^WtYQi zXr_H1jLfU1L_c}fsVfz)UNeG#f!kr~mf@U1enNrQTyVA4r`XPs)6jGv^* z<@?QW#P6e!xhzRoA$bN5cTV8csK?}%qk^M07?x;;TPLoeEHohT%MHAAJjk^u;2kX*-ya+ zPfvWkaxV?J(+!s|4iFwFT4U|wt>Q0h58CtJVS4*DUDTtEaDVt`dK+9v7Ye?B0CiblVaplO5*jvJTCd3H(sazm@QNg)&i-}#^kKO&bb z1xo%B3}r>nMJL_U_^DGs1MOC^=&%Y$?2dqjg6Cq+IzNt2@5>!7`C^FuDs0p85x@8k zrHb5XbSAu3=oXp^IT>19yv;_^|6M8?_+KV%=auaA_8o<9?1qnv9I&lw3*S5HLodTN z)5P>Nye^+h@+Y0qqnjgp4Cp0wkMGZs4`0#ff+`5=cbG<8SO?jO18D!e+t4|n0W?q5 z3eI+#bolWS+LsqkN*?t@GrvG`vH`42nuZm(#t9}xYhdPyDf~0GMtp3q$<_;=l99zz zj9Aw!oVe1LE_&_am=g!!z|d%TY*0@duAZgybG@kR;2*erDgu*i44s|$*ZQWzAf7CF(ZTAw4(rs98#UqHfvKMRy#?y#FTH?B4L;1Pi8LGa~ zlkE-6(Bz}8wEfpeNVj_|%GQYB_CpPa9F3-J7j|H5KWpB2>l;~&)#8~R5#V;|8B}E( zv)}VT*n3w+4C-5gC7~j%tuw)}%*~wa`AD3);HF?_vXp{9IpDKxrd)h$GMxW-PHegw z!jYXjp?Q6VU3dFQ=s4Ym6hsGjVyuMw5>L{{Zt>XTt3IB8G#28Ouh5d@=iYRBW`R{tx$({FG8!9$QB9EVlCSh`*xonk_s}{k(XuC5Knt z4oAPeAEl2E55SuTpW5qn`vZZo0;-Q(BB^s7fd1_}dC>1y!aC`EuxOf#@@4t=1=T4!m7u4;XbhvEzn(=+kEj{v7cXVjo-=bPg*{{(AkS zIO-pFSFFnxL**_}+nGYD?3T@w_RL06MGK$jZlzC6Q~0UOe)0&972VF=uouT0@;VI_ zxY2qX$CM7{n?K^|?`3^%@*Xb!O509{|5N8j-ti!*Q^Y$9M)Mq*)54)}V{Q$*1vg55 z(fv4iJiJ&Db60x6{kaUknS*aCciy@tfgE2$wDv4_TM`VhVwu21>rpR=d2%c3uoJ|R^6yjdUC1@*#! zI&WIMGXT9m)mLtczK$k$AK^GJWu)0-+2HJQp6S?){|xV>{B!y|JiHv<3x2qHRe!4T zyiMgf3f!pl9Hxx-rSBmsoW1EBRRzeP-P9cF{pJClvfqcQMla#R@U^^q{Wx}9r^dC` z?POS_$m+WssqST%P?1oE+l|h^P^WCjxa!Dtd!p=f>fX^eT)aBkN-e-mwzW|=xCfXLk&k2rQpMeo_P6wv*=92_+zIo_gpxTi!BH82k8)LxL*p5 z81K%>_ht!xePUttffG>kYnFKUhB_>fO@}>JlW1+A9u?nsL+Lj>xJzpWBoDX1b0drq zzR1%^(;OP%aRMf-)?>&0Qh2_&gum{14vEKHK!4y$+|cO;1#w2q-FECc zBh8dcq5Oy4dAiwsNcoixz3;uHg`+1@RrFZ;bYeH2wjYo6y1HcLq0PTkTzGh98nkNt zWB#8!K_z%2JAOSbWa>^w<=8J!Y4{(s>p1XX{m)R`(Mo&NPYE_Xw!zmQ{&f1~VSZr$ zh_(mS)6fHxP=0f?)c9(5JRA1tU+>MwurNEAHhml4Dc?h3Tl!+0Z9TkA{!Tx;vP9j& z892Ru2YH`}M2juG`QS5Ed~r*c{f8_3b7DD|$Hts!(FAq@_3UguhW*`V2?ZA6Xs(q< zc=Cl9Hs=RydSrx4+`K5kbvE<6%T)C69KbhEOsm@gTOYg<_Ut!+(tEa`Sn!&Fm(ObOCNt<;fiSwspaH8`m!h%<4^6PvG?mpeX%l7sx12&Pry5} z52;G61v-&p<8A@t@BRA5X@#{U>m>TNT(-_}0^O8lq*k@#3vI2(fFr>9X@;sqvB)^%r0y=dLV~Rt&5TW^A-2P@J+tV=g z3<`n9cc18t?KnQ>bDS=#k6^pp05*mecrmd*?p6ShA9$1wxl9uO1`R`f`!AxNtB50w zFR{BtBWzKdPRU`KSfW3f^B4JZ>?g!(>qSu4-2;4Tjd0NEgFGtj5O_Icq76a-{yJHtABqm4T;(>n{Vu-!;ChwK#&*)2wLo16_O>+yp)D%!Ps@`WWe! zA}sGGL6Dr_MFyQ9*X=Q#@G!@7J^FCNI~mR&VT+%hf5FhI^F-T~c-*KM_DbI_EU#Nj zk4L2|t8*w_n|GZ)?3&GctYpxBtRs)el;PEf?$daUUi?p;ac+Pjy`TCS+;$D)O_OzT z$s8{@tWzQ?^e?CHAMMx)FAEb4vxQxIPQVwhjVR+5i9_xdfX2+(RA*C(#%ek|aOq@z z_uoA1*3~&2vNPQltx8OSa>$Tb*!W%|wbE-ay;-#n3|ANbD9_M$eyL zMcYra`Dr(Ep5TA}7yqR+?Q* zOCOt{ZlE>)&Fjs+M|be^>Sv^&ZUH{I{m}NXHYILL1E(Y_+_a`Q_LLORM2qj@$`!|` z*2#~RtOCXFId`G=UQ@K+*c~5>(_x2YJy=^=(C4XTT-$LS*Y35KIQ+~6tDs%{ZsJi; zJ2ekmz9{jaZ-7z{f6kfY#ndf#f3Da%B7)Z}lcmJMPO)X~1K5=N7TW*0YM*Tf z!S&oA)c;o)z20iDUfy`P5vu~5UJU{@85`!K`=R@hL^yWkHFqVS0pFH#Xw>S2j^PI6 z(_Tm3O?z?uhh7wry+QIe#uwA$FJnwu8!SB-%+7wu0ihrn(o_a}5BB2mb$?0bLKbZP zwF{#hj>F%VMxYU zc0pT}0oS604!v8(t+WCoqxL}U&|(@j@d3?zT2G(G&cf?&x~QM@i*Pwhi%0LPmbA|= z;k6YmIA1l3D#v|;IGF~q(DMM8H0t53rH6!W_FH&)sRgwg45m#F&OnS?A2>G00HSS2 zT)VM1EhU^=S!lqM%X z1c&^c+`VcZ-x@!W?TTN4@AF^a&T7)()r;_3Q#L#upohkJRvhwuB;VX9;oY5a@Uck^ z4~$;~hc;MXQnv<3(6q+YG6!kU{)12vev8MCl?7Sf4Ip|3qjk+(eBaGk=rXoNm$F#c z>U#iXi$i(-&6(6CdxVo*KfvFy9g=CI?Px%U2A&^26jy zA$vt}eNX)9HX5CA19+Y65_~j|!U^dnG#J^V~$y&Y~zWwndlb@B8Iq4ne{CBc^_oHv(h#4!f+qF)J>e?jPo#Tvc>#g|w zr_(~%y>H+#Z~$0-vEvP;`z6(9%-M4B8EClHPJu^safH`2JlTH$A8yeXgGzhx+5xkn zs`pIL3@aDT6vo4xmJ8xTEddWa86oC5Ho%MMAPl%LMaVQX0LScwY~JN4jx#!KOWTCUN^!J6DU!LUgf?6(7M*r&qAbw`m+f%FkAfN--EkI&I*jJf#ZO`1 z#x~)Hl9a4uQ^Cu#oEG+ovQ{_%soM zQnq1edktXbJh=9u5Y(S)Nq2nnVB3`W!YH4iT}X3gvmp8Y`Z`f5^)9IGk->%;P`2fo$J> z!l;cF=#Y6^=%KF4sjLrqjybqr#TTPHT=2}HyY%(MV0I`N!hR{HoZ*;2$vJn0J&yZW zZ_9G{Yo#WmU&>;^28R1+v#}~Wzct&}D&Vp_K?~wof9gLsa0vjK`6q*cH z@$-3m!EVkrYAbAondkeFSM*Jxc1k-;{yCD4ozli?jS$HYnpqam`F!0p#U9(JM| z_n&Ycj+Nx`*U|QDHqVbWst?1fOhxqG7K*d_O~rslzN^jQf<$jB zPk2kNZkiz9IF7QTFVmAEKkQOYrjb|(9cK@)cjQzWma!9#jCuv{-^${PXYDj_nk+s| zDFFRN8%W`}%$0BjS2}08omA_t;m*2om?FjqKhK$CNns#HPT84#?2%$r}xK!Q8M3uz%TgVV<%X!VwwX_h>ioKY57GoIK2@)lGyu zIsv5ZmI-ExjyU+^cQ}7u6X(Ok|6OlJ4gM%vRD3H2(g zVEgj}kTP8df1Gp0|LU#_gRFo~&N_?@=O$9~#R9Of@@A)7N)UfZo@~_2>F@9o9`Qd4 z&NHs(w~OQLqNP+wB|<8tLM2ka?>V6|5-FjKkh1cpLfWK~w9v3BWK~88rQi3QjO;{4 zL{iG8>~XsvUr)|;z0UPH@As3ltqZM2xN~@-FUFP+Nin0*_%hO+e{TP~ ztQbz0?-fmopHsZ-C7jBM{LOMPYGe=KQS9% zv;KYsdaYOlO;3uYTA%Um3UU*^HqTh9EO7o9dcIanq^=T+;be9J_BBxlO)< zS^3lHxVky7v()BA?{pyJh7IohaQNTfR;EL(g|PQ%B$b7nV8;R<&Y$WJeRr$k46_pP z^9m($zwi;vr&%D^o8iH501mNa(IKO;T{V7j|z{!Pb+Oi18o9|8nC|=0LdkP-`eHP8`Z(g#PR} z{3yh)?+?jW)!5JA9M-h0;SnlHq^$OpEIkE`x-%a$NBQ%P{2?$UcsDvM?8Un(4)fRT z{rE_N9yB(u!p)na`TNPFfA0NCcp5*LZWN!wJ7*V&*@yQ-agHq?*sg{9#P6coR9RmB zqC4;GwU8(E8jsgvifQBHK3IM(M-bnCfLYWC(-T+lQ~M0^w@~H6lh+`2c{H0x)QF)A zoFqd+h2&SieEd*xJVVp=_& zDj7q@<^r3aZeqCvdm-;+8qJJT#*99e;)AUws9he87g|p6*$I8{(pMjJPSq5Og5=pT z-HuOp>_tVhL1KB|#nk>|FGj34k(w1~L7UGi{(SNy4B7ZWP-rz}`F9`5B_&HtmfJ>U zqxJE~$MLMY<2I$`X3~brSI|F26+d`9r+wAw@YwG!^a#5|DqbhZ(La}ljp)S&{Wrpd zRcm>2uLDq+AOjU0J#l4_3{O3hhQVnAD7A+PW|sEn*$a12kC_gid3NtP!;C<`B+qAZn1m zAhygjl6H%b;SNi{H>q0u%vurr7st?4OKYrnc^L|2zloR3m(ljC$S=+Pv1;x}>~XJ6 z7&E}0_nsQ$oUHT-3OrT{yXRNZs;A$8X1W1|?W8KjPhv#AI}95Qn3)huIyEH_>HkYu z9CH%i+&Chrg;^0l=*b>GmqAU)LXsI0!zmL>sO@8hbXdRV`6=|KU!L5V&>95b9fp!24cX;lJ~V{7`c;HJ%^B>YqxWuWdTaxh26A zJp=qW_>frEZ4_L#sgREQv>8`eUVx%!+PpN`mmM|sQfZ$o_@ua(ek3MS<25%79DR%5 z57*;>2_~$+BnnN{y+w0}v9zhP6%KZ5hB>p1F>H$^48F1tD|7p^%>83jc~76GE$I^C z?r(#u%O6wp#H*yxaEVK=NO8!oILN)8h%IKuv?SdToN9-{1C>-RnYmB;^t3KUdFpfE zNL6qO9ZA^^hM1aUPSSE^m`GF3rPp@k$VcO+MiG(nBShJsUQ zEPc9lkDVu%frgqD>q+0j`<~;Wv(XkSk0j%VL$By$z#SpbtBOq3D{xy_KdIlBIH7s9 z3#*03P=@naLFuzA_lUX(6YK7Y?+pu3uDmB4kRM6duFA{jH^Iv3vEto@L0s~JX~M=* zVM}u=JA@iiL#;X&uQS3w^InK~_r`!vt|#t?6;dBJSMVPx;W6LOQ@q-K%DX=fX3SKF z{DOMHNJ$EBWX)08bt2p~7>RNX3fON^1GR+akW2GB(&)AyCS5L}LE8ew(QkKQRcjxJ zIQo&IjmGl(DNm@nVS?~CPJwl&tcDw|J+Wq9GBhSwkkQOdSpW7X^;8ak&__CaeTS70 zxw#wNekkGUziC)CZZmY+EXT~HpQyU;Sd=*4q`YKf-ZRpL@2bq91cRwK)#N>>?ApYe zYik8v)o$GFqCE}{n8jng&Eb31E>P48goJr9@Zdor@6LQrK1MR+m%I@Umu`c%%;MT6 zHT-K3hktUOqWo4RUfEA7#*W^}ZBviKah||m%VI=pV|~f9TZhm-Y6_2E)W9Zfkt}Y! z3ZJr*(c|G8QdqhfzRc_m(_1ufqGT(N+8N9|IYt>t*f z6#jUBFe!|lj;@vRcrd~Q8pFy3dwVBz@OdCsES*eq)3eB|PaoDUe455U$HDEw zW$5Uo3~JGjU}L1d@V9m>R)p)ZS->h`$@@n7v*zCnpL||;KQfr3+pR%=ww);7(}{ae zS%}LGtLRd{5xBm_flQv?g=^Pu3JHf?c!J+1-ZF776?Exh@Uf$?%B5P^9A6`zF*pr* zSBqd;^(YE{kN~xc1Mz|^@w;ie!S2XMVezz=aLA!2_c#1aQQ59IaH=lZ9I?dp@!xRQ zq%-iwqLZTai@Dp}_!Ak#vys~Q8ev7UC9 zT&1{Et64i_?ss}z`$c*xz+^NgmE?VH*@N=ZOKZAD1 z&t|>4L)2AjD$ba{Pdu6?!BL&FaYE54OxxO>cUxufU(+t~aYOPOCx=0$A>8L%H+mmu z$*$6ev^n%XRd|Qs>Alfn&nj6|n0{S&-eWF0-I>VZ)-*g;IF57e+;B~< z60+n{c|zTN$ls(Xsz%z=ywETdBW{6ZRF1Gx6u8hegOR@iJH{PrJ6x5BP*=q4-;q=i=@k-)uniQafFOKa) z$AM1lD>*|_hfgH^mx0GzqDW(h3CF26z+3sR@YXk%N)jzlCTa)YTvAGJq!Rkwuoe~j zsNuJekMy*o6K=mKpsJng(WTwtjaI+j zFPZLl1Dw_J=<~B3n7C&nEwOZ`2B$f^ElwL3xgdqlX%?-Gj>CoJ|FU!P5+1zP2s=ky zVVczhMdxeCW&b8vS15<`5_iyvl6VYS?#e2LYs53pSYdq;~t^Xut3@ z^|Z3VZC{$i9aHUi^mR{;X^Dl{PXu0Tp9!buNF=NL6;PcTVD@#U=kEUK={AJCCX|8C zkr>)xrVa0h=ZQnlX|vHv9Z+0p3gfPBCoVa`?%U1ib!j#EU68|Ojc_o%I2h%;`(W0* zH8@Jm45Ne6z&(4lxFNNi&bNn3@Ng_^mnM+x7hMW#|APrNqp@m8CKRrX;y>5jC^l&u zWE+m>s&rNEUS!QLrdqQ7#^b^@^*|h}JrEo zYOTx?r-dZYo*5s7dZXS{@koyIloUYIdb5ymeH1*o_J@>D9uw-%>!Q5Yc0TT%&yu8g z?3Q&77Cjk^_W}>W{I5gNYPl*HR|7ZseWaEhu&69z?Xik%Qd9|rD?>=F zK13?XGQ{NVmuS?W(fo99E}i?{0<-*6X-J8_v^h^1gU_wS*)0iJwyzKt?>6Q?2b-w( zybaJdt{YYd2D03bOX7@4DuTRH_nN!oWP}B$E^tnjD(*ZwUvg2!Qy6q*JARzKfW|&+ zf}h?;SkmOgp9_w_gU|~gy#EjNqZ{eC=#RsQ=WB4SDSaD&;BH+8hMhZc)dW+OHo6D* zYk(2c1EKbCGc@(Ezyg~CX z-l2&!1|J^nfcJa*qG7*$p0-pCe{6US5cdsCJC4&h=QyrD)dYJFpQWqLx5SM28Kmyi zf?mI*6glY*Y*UWrqxsEX_iH0*?fOf4eb?~$NBP2|%YSL+94plEuNJJ=>tF2id=Tg; z>eJq)MkrZ4n0XYzN43jho@E<29x)Oh_FhgC)aB98Wixg4RmI`ML-@mWC0-ky!=cyR zu?6SDukw%3tkzxf#q^9Aq-+3D9_yhqR|TU}GI*jvi@4^f5gNfAp z*E@Px5rQp$v(Vhs3&OIt(6!cq+_!opnr!QW#npGoK4l>5r$4NoQlrI{OzAra= zo8gEgEzIh?0}uNygEeIvaqY?5Qvc5R!r8#Hgh~G7een=voZ1MtPYU#`-(>h5Qv^3; zRe9K>%^0!s9Nsvdz@x{Up~BVjywGm0n3Cbb2j})>>-9^qy3Bz!hLF&Ft~cM`O2UZW zJ)m2|d9V%C!_q_J$jC8HSljC+I8M9)%M~sOn}^+lct0=ReXA!w>c3i&;B3tO0<`h1 z(@+d5e@I$sZn)kjg-lo1!<*m3IU)aznE01PwmeK(-nBSq%P{;j*%4m9IZFy79|@Dx z>qV9PL@o?{OLckI#g??*D27bKKgn;{Dt!Q5*kecW?Ik#+Um3;kFypM}or3o>Hw>^5 zNy+@W^vayURBM(8!^2mT?;rzKZ7G1e_tJ&(j@`Jq+MR@61KDYi4(GXiAsh91IN5y) zM;jWU(Z^hPJhMUY>Aw&A4UFWPQ6u>9_$hqDu{$ibv%#xQ=G<$f6`IHGW0U^(Idshy zQN70>Sn_%a28E?ioRcTcbk;(bVaB+;wg+Xn{U#5`VnJ_UkPy?O8k`4Tqh-EoxKi;d z*jlcHyRAdHMr$Vjc6?6rO=L0QL@vC2{7iiGE(Dqf*y6}?Ma(%}fr;K*U~kWe>IJ_7 zxj9&s8}iSJ4&l0dDNz-iCp;6%ovr!t%~janH-|s0cqOhK9mH$Tjz;C9P4MPY47jyb z!c(1IAnW0QBcl)T@E{%0UiJkIJEM*ry02-G|8Ox(utm)r8+4D~Nw*D5@No4Ry06^~ zikTB=iT^EnTN_CIEW2~-m`GUMub8DHVz}bzXwcBwi^JV*@#?gd(u2)0u-hUQ_grrU zPv;WM8<~QuZzYh?Mh&ojYs?NoUE*r>SZ-g^PRc?CjaNn7e7FL~+RNkG7&~^2drxQn zaa^|jAYrIhJm-Gh$Dtl+=<&sp_x+p&ddouTiB=<&wR{C~)nkXvWl&uOoKbEfNj=|6 z*FFxwM%8cP2T>wkopBuGi-*DKj^5a1P>SYH7jVZJCHA%$!EQ2I;IhCB&J=v29wTR= z$@dhY&1S!3YDqN@=wm?Le@9W=`onPMLr;1*cRKtWAB#gKIl_Vis@O6^nFdGf;-Ufd zH1Jh_dNwQy-40oZe>}}0^3Yjm8GaVhcb;P|T>zjJf}joDJ@$zQX?3{dr~S9{71@I$x6L@cr769B@3I=VxsvRh@-GN8wP+ zQ0)b#QNQ46WHrnv-vXEGN03p=BXoG_3ktHLnAJan`D-_Exqhs$;E)PC^!P5ETC)}h zdZ_cW8IFR}{DA=bf_qB>{~jX2?38OlVb^Rd?&!(W`o#+| zk4C_RFN?&<2h&Jtt|M=q`X6qo^5qI|O-M-{2X|gA!C>>+Yk zkp{mUr*Q1uJSumdh4x2p(A8cF5E(m?Z?7|g$meA+ula$ve^d!xzxX83W zhb(V_M$Iw8yte?`R}RG}p+-p3izT&?8+dbetKgB-8>TBvVA*l|$)TZ}Xk5F8wqBCK zU&$SmG4UuaeIE-kW1Z-}&SLI* ztBo~TPE#4{`T_pgEe{@DL;gAI3ihxb2oHTyA?bxN&ItDq)edZi+ui4ZcETc_;PDZx zHMH^Sr!lB;Z-J=oWG}t_qEU#Rq0DXH8_Da^HLj8=BfnvX#1SX&LpT4vFmKL&xEWW7 z-S#Ns)0%AIzfBW(#)JaeMqtK;HJGQ93qBFO(8hu7oA!0V6BeZUEcdr4$kToZ0lz|~C?TCU;0~5e@b{sBGoIthl#X{v^e_WQTj7!DUc)Op# zSAPYQ+y!ML=)~vehE*lFG1*iD=ye}PW*hkQ2cRhFZ8r7rEIlZw6uIYyt}^- z7hnqiZ6A(HRF6=4+E^Ups>4Hl*YWsAHuUYqETLF#kXU2g8wXqn#}9p;*N``&NAGy*y!`-nMehPs4(CCSC-9k`%Ith-E1dDM6>9Q_P=nzj9GY?fPc+0x zBwex`2A-_e^%N>cD&X)?U4C&#kDQL}0fRepxVT@NWb(fAG}g2WI>LVm!}i@4&sGk? zy28`q=YMm-pr(qW+GKJ2DP2tdR1fFA`;fEz7#=$y2Dio?lYY3cOE};r#{&`?I6pFu z+os-!v9E4J$BJ{XYy|0n}-=0*NXO1Oj^?2_2U8MQ8 z0Pf3QC51cgg6RlL{7{5gwr)J_Np2-e9UbA>Yz69JpGPjgjIsFREOz&w0CCl=H1I_L zPBxe0@Q!z+u`&b3Mc;vy`&HRx#}^9tn2t)mH$)ewE0V~rSjt!{i}m~O!m!uwd^*sM zudhtzM_99?g--6U_&RQcw46>wi2z$U+vp?^y+aqkjOSYFwOyC~aS?7-%MR?LS?Xh;gBieZ+_7 z&+CPKs$%G1_5)~Jbd-Emj|h?>zBqi69(2r|#6{9QEIF|r9K++_(5+DX;ASUI?DHBt z)O=vH=uey|&#C=#dE&O=*w6MhRK_O2v_4Z=t;|9w&s%`4QcJp+ox`51_mM{XbI4mh z5%+I;FFbb`4oCZ_L0-{F@I3yN6!y)8AuB4ykfE-?7ohff;vp=%0Um5@fYXU)m;#vLeXf5?iVM(A{P zfnbL!xL)(BxJu<2H4n_eq0iq4F;@zCN1xd&^YbFbt$qXbp8~K?kqR^|KLN#mHObM( z6;G^r4S$23=&QdopO7A>y08P}n!k<2fOy(FOAn6}jlesnE}~qy34DwRqHmKOd2wMs zmJd2isx@hp<<$Uj=N}0RdhBMU!#Yy`MIb7sNpQ~ZiF9D_457FD44nAT4-)&2;xz-( zNq%J%{|fjBscK!|Jg^GJmED6IHphhZR?c`!z8mX19Y#UJ6yGT5V!7LLt{mG)qf+9; zim*XE$x@N$)ac<-Z&}yJHy88u;c7HuvLYMHdx&S}pP&qb0^Yt%7i(QFhy%X#be(lA z4p;Vk0+T}za$}x3)$U(Nd#5H+`SGc|=Cup2j;kfK+Q|toX1K(>ye@ppnTN9+hU3)6 zi!l4_7npbB3oWbm#}yCuVE;8{G-anOZ>rtSm7g?mPVzHa6LM3`8XjyE zo{d)%Rxb4rb6;DcMZsavi@YoZZ7SoAXm@%VxE~ZkmS9$|Ws>`QvT3j22=`UqKt!P? zfAq@0->3Vq*V=y6wj`X>_tl9XzT4sal{;wr{1hCV@{k;I|a8Y6)J`CkAu15Xeu}M z`3=rBo@jB2K<4oY7#_DBN>5th&r(&^vB<>vL3Oxkk%^e`ug2A{JSZhp9i6PZNb5{E z&wp%B-v{MmTIm*a@~?;bgQv;)sU5V>?$5ObUnuOj9ZN4C6|74>xb(MjVqx+p!C_7! z6-R!Anp_j%r|L$ylDr>s(<^9@W;Ch?^r$hOsf0d<2Xocq-8kZu1-X!m825G<$`$-1 z3q4o#UFOa)D}GkTKGERCT`l6dc`cGvZ}-uwYk>L>48=1Ro3Pb?3g4DniC(M!()%qL z*gxbPX)8qV&S|Q!;mB>un(PbqGY^4VW+ZF4JrLdP1p4BT4j;!p7K=U(6f^hN!L*B6 zoO00_4^~-l%QnQ@DrMDOTVBAV{0tc1rq3U?*+UnM!1V`>Q6bqIPkoxm!|p5x2Z;iA z$@QQsxn8`(p^+R?DrrMh5xZqZ!}qm?;&{J}(oOT$(Bm}=;rxaq)UhuXJIlh@wpSxp zb^XWRpV{J3gG3DWKP&u*>Z3L2x?r= z!2C&FWMz96je@F3b(;(t^w8z88Rx`N{SHFl)G0hJTMiO3j5+Yh74qD$9pdaO_(4)2 zIX>+zq#7Au=msTBO)8~D^3EvTwVYD+1Vh%EV7@W$xaj3GfZO!UVRwo)C~O`LUw4?} ztnyIatT&JRJrdz++b(EbyG1ZCeF)84hvLrOdt6#OO<8$-A#6!Fz*S@Igar+aB-dXH zFCQy~vV`x|cYKu4V8vOwr6l68PcOw6`;$N+I)ZofSVsoK?g)MVxt`elJhV6H@QuD& ztTKN+zORzQRT}2P?%x~f_lb)%{k$ydNv!y-Ua{0>b|wd3AH^vK@x0r{8!x`Cr>*7I z@C@Xm(L79?c`bPS-y>?Ou8-Nj#goMzp*^dXfBQY zJ`~4!K7iM4H#z(9Maf>;NnMZTV)zkV{BCVPUy6-zhW8tKIb8#ncbmtND{Z6;23#iJ zX>D*xUz4P74C(CRPS~j)0%iw}(}+iL}@*K4_ z81eY>4a|8P;m)~Q7;CM9E@L8LkwFkV7~Twb64luB=}K%?SLK|^fn;4UPFS?s7#vn#^YLQ5u%gkY2R|O3WBJ!BO4RdB(=KXtmVCqy^eigD2YX-`5*<%G( z+IdVEI&8hvN{qlJWhrXshKLQ3qxsXxZ<2;#d6aE*pHAy#@}7w9Lae_I&Re&N$2hMQ zqhlx0iNtw0S!o(L-zX+snOR`$7cNeJTLj{xBs5ce2l(KCnDd`C%P4P!u4||0*2#l3 zjYf0Wx($%7`60MFBuDX1TEiw;)Ti7R18xw=F z-XY{W^Nx7oQ9CSCJVxi+q?F-v4_w}!WRt^AJizD}6$Nd^tif?`Ye+71jU}m}vK4NS z%tOECZfM`vhfZY|iM?8;k$1=~@p8U3H$ILNf7Ne=mxo`{m!HP8P467c%vnU4+XrKl zo)af7bU@cxUf|q1o6?5rL-SB;Z2i8KzXj(Asp*U9z!n=^UYSMly~F9@u{zkjTa9}L zH{l1(4`du@Rb6Q}k|!SSkFp#7K*D@)K7Aye6w)4p&FM?{t{(AyvlWcGIf>62zLcmA zene{)WKmtZJx7K-;ewFyERov_wecy~JTn(wZP`Hqr?hd7qbg3RGs5!TkKx4ZgQPxV zAJ#s-y_j=iXezDM+VotrZ1hFJ@VfjKC(ccmFa(_!A~aqOlrm}ZPV zM>AC}P?30zwN0N>bebQ2ohgUiqI;slFavPi9D>^qPlqUbA3pLX9$S<3Sb54Wc&?B^ z-EA`+q2=!-^bAH+6U5U zJ0mW;YJ_Qp9^w$;CT&rQ=V?vd#karra^fB-d}sofKZjS~lxAyG7;P&Y@R!0MS#6;u zdpKtNmWYg4^U-n9WDGfek23tXiRTUtr0EMfLFQ{TzYcDvOWoupU6~>L%QTVG z{#=5<^(xqO$8>X^&wpS61o?y#@OZg+FmLG(% z&Auq+Hc+&@fQRZ-cwYcNK)}ED3L5KS%2hX8;cT)xx{OF6b+h>}(Y+`38l8vJ{9>VL zrYt{As3%j`3xenDUxMkwWt`?K%X0#D;kw~5Xf`mFZ70s>qa$p2Yn`(&-Fg^l{yasO zmI*j#>0TaOxSO4>9_AOD`d~!-KY#k2ggZZefxC}%(6_o#+|`~hq{Qg3=>W}|&ggt{ zKj9#(Uw0ILEe-(tlbRSeR}OzRmGk+w{`hs_6{r}y2YSS&T}*G6XNQZyc;&Mln=cpw zC)PfP_P>7k!S?w7_dSbdI*WL+Qkq!%_6H5R(LghVXK=+$9ealz1*6?B$ok|;(tA`! zI}f2Q|YuQtF>5{C*b1QStROu-pI# z9kSq^Tl-^uh%6t~T@3R__oo>%FVUL!&tRI45nq<~!Xa%nZ1M09K8!+eo%Q99G>#uU~zlKFM)hJhM(nO8E<2+&>q9fWY$(n_JuBZ#OWBc9x=lqJ+(vYr=`H^AyC+c`pZc#yPpiY_C8zPi%B$j$$_nsl zQ{)5E8xXWdj&tXDa>tuEIxTmYv#tNo$BWKf6%z=$?FZq?bz5~4>s zZvP)>p1dAr{Pp9(mR6+quV3_M+ynk%1J}<52zx7Z@J73w)ONWa4)8j|hgRJX+Ar*( z=d&(>=c$e89MugDKgz^JD_w4Ustr|^6WD2k4CJ~8@mMD{2rMqA;KJ27HgYw(+Uin@ zJ42;$0k-c7#7o-#plcYwpMBL?CVUqZ&DP-*rv}mQYKbH;1@YQ~Y&yGS3*ONkEiUPG z9KM|h>|q%ga(^x4o~g?xEc34JoEV-58ND381%^nE%X?XA|so74sv zcwiVho-pDeN@e)zk223bzZ-U~S;xoPEa;)sfi}A}kpCwITxfcb>;{kF-BIx}7c|V9ja@xbNcQ(wY-%3^Rdd@R={Dlk)B;Lqjp3igEFSO~ z1>Q1`;L2Gw-g~o19DV*X_|9goT@%5>?6&akxYcN~{uz9*U5Vy91TgfQf~99VU~kW6 z>4$R}yz}d7+?`ZF28L#+WETO0ohl*y(-o*S%-~l;O8^T@xXOJqrYj9$KN)3wRML%= z@)LyRKD$9S&yp=o8Y#fX3;kwnM^%fbFef-&cvvRkBl0TLQ#zfEAB+%Z-V@=AC;>Nv zSgvc&ql|Vf+!=0<3%tCj#(gBeAE$_6RPI}f4>maQCC?^-Oajo}vK#Bf7m@D*RnE|8poA-yc>aYS zIv>9*)XdeQO`+py?1bZBJ6Mi2Zl4l2{4T+;Wi{aF{sX3Fyr+|&ifPZ9X3DWk;_}o6 zp<}&dK35*@%6g(FS@M7Ps`!X=97*pF!NQ_`IO~)Kt-N)HW`9`(M_N;< ze6=IK?6->(FRYcMzLn?NYYu2ve+M#LJtfvtpTN|nvvg&i4iD2Gh)$ZixOIL8!xv&Xh27IIehWEsglWcLJlO1ha@le|IrI04B7!P~ut_cHvD+r2f_JHTzCeeM+ zDIEWwI}C|-qnWx3d7ESg7`*)|sG3cqLoR-_;PeEDyHv_eV+C$9&!$PSo3VASw_x=- zPdq722h-zG_$(-iZ#w4<99%IjPZ{*T;pd36}Iu zxtfZiV&K3J4c8pKS{z_*%9o#QXJh3JT$ZH?s{OUdO0Jrsn#}OS4i(6seHmRU6?w7* zh4JmVEPI`W6Z&bCF#IoR+$#WI&j&m>X+QR~x5no(+py?sn45WbhAvN{agc{_vN^U z)g78!wTa4qT5y71lKA(olI!cM6YzR&EGd3M9$hn@Pnti3lWSJc4B<-Uf?0Qp&!c>DX?8gD9bM7Kla}`#8Q2uHk#P8Fu-oSj(}a7ZbJ<<+$U81Z z)i`0@ff7~|V|e446|DKLFJ7KhE^=p{aJn@G$8WbpgGYCG!v0zaHcDdSDn+!&w&iIL zU%-bz#N3G^;Hl9;=p4}q$Gxi{@0S$21!t3ba9^(4Xw8LJF3`ido5XjI0@(G15#Jja z!*kc~2gOh?xHjDwy?2#^t3y1LSmZ#+!9tq9J(LIRX@SYRzEP2Ln()-fkmY8sgKx@< z(0c5Dy8Du@u?~e zQ2Qy&U7SvylN-h5TP>jQbboFSYXqZ@srZc7J-T#c1{MEZf!QHBoONOYUoObSJ^#&tnXHVw zYb)D%`%wLf{wSQ?OC_5|L2ctMG<#P8hmsbfpH`OW|HXvn*lN>Yg+;tziY575*|Jux z2@CI)&^T%~wB#F#!|x=J&5|f`m|}^F>bdmp+(d}~Vunj*_jaB8xM+Y55bLyc@+OgEDxuZ7&M?vq7TbU4+uw-t6>w2_AU~Jg!U$*R@rM(L2+q z<5YKvZ?Fg7&s!(%+%yRFM&G7oQ(iz$sUg3f9!r)Z57YK5X52YH5X&r#Fs#>Q=#>2+ zW{!VMg)`&nrs+;$|G<4@s@g80z+-U2=_nTrKaRgnx`^*I6LHMX#azqU&`?n!UOJ+{ zvIa+KvDqz)lJ;0zoIU2aa3^U97||WLh5ISyg&}^ZJ1#sio6Ym4Y^GC9GsWK7 zMlh;t1g&Y+q4QSp=z2JVV_q9$q~{;8ceOs6zkf}2zpLq&syaRq_R{PHil}q=fsl6P z0=G7{QC)=rzx{m|Oh+--m*7CH^UV-$z#4{a!Z%yTMhS;|GHEyS^2DWZCd9(6R9L7n$qe9`e+@H<~i zy~&X( z;E^*_KF;Sa7qpo-hJObm^Lu6Lk0n&cG@K!{bAU@wqBNiQlT@9Z6$vhcPD`?@9 zpV443>=LcJ(@BqtyP);9JlmXbz!f2GoN?Bfq}|-0Jg*S)Y!8TzN^|){Q72?v>jg5u z4&m@AYX2hXHdS5LWQ~A2F(+^uTIvqrhMqWI-pOTjK&mwopV zt=X~yRqM|S->puLlZW|XQ@t()TaUn55eAqvW)P*Agkj6^8JxCH(bX`~O88K9 z76S$V_vzAs^Rj8Yd{VXO_;DJK_^HYDhViKMbOO$Q7)Vv^aol!pmtdeO3Uw6|ID+Og zjjDo6Y0miJyp%NJ(u8vwjx3`&l%77yaIx`SOjA2d&_-hxot`^|vbPstR%aj_J|K_J z&zZ2-*Y8wkJC~mHaNzSl(_oI`8G8CBmLDJ0#napf&mP@{cUxnr*u7eai|B!&6$SKm z{5z^r)#2BJlR4=`Eets}iw3{^33)lb(%HV&cumy>HGglwcP%M6e~_)Xw&3Gyfq~l(0F}(6=2PRa>Z~z^Tgrivb`gJ> zwix&HaKya{qj1TLFJ#|d0s-@Pg3rsRlsU?q=jm1AO_`abQ@4XO(`Ry6zOv-!j|2!C z`iHXgc8OjK!)U{oopj}5BD8j!#%)JWNHZ!+DgXIvn0HYNuKdmsyYD{;TO(7djhwpk zyUt8ne9{!omV2Z8x~CBOTw64eH-o@UpW)JjE$HrS4Cf9G!RWiYc=Rw;Xlm&aA3JWL z1;uMQOa3bjo8?OjA0J?aoOE1sM^>;IzX{nog68b`BK6%CFZ46_Nk@0+`T^nJ6$j7zgHaMecsSUyZ#SCxrIy>?UJb0xf|*q6_1Ux%Qliu|c%GaE`K zLGXnu5Vq%Uxm^7juzCSJtp01oLI)k5eQ_ClG>8%J`A(pqhUOuIFCBCV`-VJ18-_pr%~Z+V0NJ`I=GJ(PPXqwNu7Kld7T!0v$JE_ zpKmDh`&r0&t@r3Zz@Pa-x@SKm4;M96FOn z?!!Z3>*42V9sJoe33?2^-@VTzP$_~fb04})9FWBir|aVd_jt-UqKloYfJglEM+-}3)M=G+ z9WlWLJqPa+OSV0yJKr94s63<0hUY?kk)7-Qfc50)D$lJy*5ZM-TJexu zD-0d=j<(eO07dyT2PM$!BTNTmzotW67r1LfGxXI@g)UkJ6FPWBAwQ z0`iN|L_nn8b~S+IW3(D#X1$0{b7^aLsIXNu0D6HlA}P@9&!_lV_8>rRo3wvBY6& zo5efLwz$^2FB`@UgERgc$#wf`mbsL{4~JdE;VNmc+~+@G>0u?Vk@DbA6aQ(}Of4QP zeH#jVY@kd$BzBeL!^_bcmVf5>La{97{k+E9TR_^+06#s{b|GVYt;UG6rR#7b5^h( zfyIG;pryAg9h%lg1&=e(Wt539w0}ChDSSyAzaFE&@x!6!)pWMaeg}RQrr2IF4=2iH z(!GndRCv#tE0?H|%fTZw{roN}_C%D?&Vp!tU9$VMg{!3}Qo8>hQtW91^^XH6G=hMJPM}DUG}Ng+@;hV5wh4Me@SEIJnPwkZKO&N1eue ze7gwx8kTr8Po8&=y-7+@lH!Bg%INrc3m894MUsf1UO%$M&s#$Hh4w&lY)zm^p}xfT zE|cNO$--cx0Q6MR!u+z`Q2wTpbQh0?@ej69W%?*qS^f_wUmoC-|7L$`lN=sU_#ny! zRZ-rzyI^r30?X36q3`z$9)EZT^+*nay}xFnYLqP2EzBmXas>=}`XA{!>%sW(z0qpI zNoYLfCVsEtveM z0B>xCRR`p8%I3EqZPp9r#>w-QFB+WWxW_sCxFf0*c!}$dTql(;%jwb+OLS|CqE(Of zQDdQmTgLo*sQI%MOe!|B@_+!IruK+h&uVjMA<>z3Ev&vK&%>KHqhm@J)gO0-3s<9P z_q}o$Km4o^nI^?r*14{J()H}U!2&a9M+hF;FJW!>MD~Iw6t90h#624IH z_cw(584VC*e+}YXlY~uCGbwqBCzP7nk$b~ve4PGVY&aarbN86jw(Z^JM_;u=rS5Z5 zZ5je^!500Zd?B*2fS-HmBTs!y0aqMQrE@7nJe8#J6CzM`-8??flh1QAJWzM|7V=e7 zN8@}oPV&kpyd8|m_ay{9cU^p@rO6%f@5Sf;`qlT2q7oT95Kq>^*}LZWWvdaT*jIx` zxIC`7G>=E4Oh>Ac5tN-?!T62*5!!KCAK(n zi8K9qI}oA5oPFGHQ(qG|P(HAZ4;JOX<@dgN8`0|XM|q< zHhg>9ThJNuiEg#b60N$X<6G1D7@Lzy0|F%3^;R_n^przrY#~LRdqKfn@|D+$4AJy~ zBHaJ%2CCsoI6rl?7%#a4n`%7x>e>RaalSM@DQU-($)_2lZc_iYD|E#!4s*9C!@htl z=5M)z>_U6)_i7*CGZQ#ldIdzrZo;~&MS_^W8`fCLSGW${g7YlRdF@3v3agH%;K6ig;-~_f`>&9OH^!MtLz1TV145~I{LBkAd((!P{ zP)j$yr@tE=g%K;WJd7m=}UR2i7xgI25{CH1m5bK zxJ`R7s{ZVSb$?5RE!!%%Sf-}Jcl~Wldz^=NUd^FKaU^F+sS}251<^g3hdWNfY_Fd* zG%gpd2KFca>%HJ=+<|v-LPQkH_*r_7p2$E6Z)I?u1tEP z&TAeUK*PF3JgM3UDYhNd6ylD?X-9>0t&J!(r5F$S~4Dd2<9A4p|r>sR8=|w z`)O(8x{y`4(>MnX?e#|8A5r25pQG?6Qj3rCa9;Uco(p0c#K1T;uJ<`CD8!w?gWtzv zkH!%CnPJb9_ZNxxjU$9Qvo1<{m&Dy_k#M@k0`;|h;T%4v52~6R7B>uEjTPw6-ZU}l zXFl?%mFN(!h{gAjznISC6Y;4eYh=smZw-VUn=(kVK9%+;S#ok@2ktrk7CwJk1$SS^ zvH$1;bVfc4)-_6S@8W&5x7K7Kv!HsxL()*Ig(@*W^FAg2h zmEeqb=g-6WO;+Nr?%QywF%hP$l3}0Y793k54bQKSz_Je$z+$WyZRwQZW3xx$Nohq? z(>zB?S{gjVY92hSelO@%d*k%|g@W(E{bbX}ph8i;lqQ}yLbDIsVUF}(Y|Bh0`H^e6 z`-UXnyj%l`xu1pL;7*#_#o~jPKAhMUiVia0%Pqgn02}AgtaMzFPlni_)!~z5AR&)( z4@FWN94Y=z)W;p;eQ{H;Bfb1Og8NUtKxz*Z_-;WX=|vBu4JJC=qV`R^@p}#hkEj*` z+ggN+UD+^i)npug&ID(h?4)JQv2;Dbf@i4@q6+OcLD97v?%f;?3oR9)Y^E(Jn8vgC z@eMWI$mjdJUV;*BrMFM~pwW68tk-hJhx06O?6jqzH%^JSj$sxD1ctcVk=1 zLYn=tQM`I`DleRU2;^lS(>pm;KBj3;o)bRfyQ;?!_|u6Uj~MY22Ve!y8hEuUj1|m- zg|!ZKpeCKdZBiL9_eTjlcXPvs;%oZyI9nWg_7ME=GK9w)2D8PKsjL!Z4F}9;l1D%q zOt=i}fOOv={sS=rcEF?YsJ!o~YTd2~!Lte_esn@xOF!)A3fn#sdw3XvW zb+5!-^ZMbOjY}cOGFvELV?>YA`(V(adt%ekUF7^dg|5Ox{+yhLZ?zP7)nN-f6_rLM zqug-f)VD%updokuN#Z`Q6IeT`KR)=IC(4}*M#pd&zJF{BW{i--CbipQyIB(6+`WMY zX)Z+ZK@A=9S|b`Qwug|p{rJbSNuU+}m5yFogEcMtLBltbLkgTYd+AOv(zZw0vFGVapm#d0rcYkUga`{U2>kN0!iev!f&e|!;tmetmO zfJ(z?dbl+dW34)!>segvYG0@_HuVzQYn& z_w^1uX=#P<&LW{=+ExnBDuLW%@@~qHy1*+?2WM>iK{tMRLCF&ZR%$-ZqGKc-aczan zwedXr?@M@fCYD0dR^yVV3BsQ7arCQeB~+V_=A@2sWcpekiwe>NqoL}4~aDL znIVta?@jfV()hmT94&Z#l2-Irr{eXn|Ic-jT#(XRBb}>U>^o zycn@@C~K;|1NA2*5P7*t2;7{AfiM4}yX#(D@!DDx!&yprM!lvT zp#_VL@HRF>hv!&wLJeG(@EWb&AA(Ew_Hu<@6xXRK@_qY{03}&;?LiA9*L&lr6Ixi` z>jv1@s_H7Yr!*IrhdmM^Er;@y zsq; zf0n;Zn8Q1RrTD|!8vL_fLri*_0R1+rbE4!3%&Z+CME(xp-3O2G)d`n`m6Muqhx;Yb zJXfP)*jOo^Jkk`$E<*a|Kb_Un48f-JG`59QlXB@1l3wn~UzUCs%MGN2`WKcgS!RWA z431#fx`jNa_9APkjNqoRyJ1~j51fBfBjyIbg0*eS&~Q>Vr^$Q6#IXokDl2iXkruoE z%!icB6lfn?1eV(d^T67N0NauO=3NG(q^W#TEg6>C?Giry`?l** z@c<({@nH~UugC`PITtwA*@G|ASs_Bt2w&A7gPre`SvTATtw|btOSHrIb-Lne>$^N( z|1$Bw0W>{K6;B@2x!$_?4{k_lZn z+(_@Vb#a($Esj)6;giXcpuXxpP4M@^%^ODZ@}5l2=r%>Ct*Vvp4Zo6s#V`!{H}9Ms z3n9OzjZRxVgOd*?lEJ)nFl5{vxJ_sqhAgAr7EqzL+!UxJ~r zqfz=xI=LnVpn;MkPo%++Y2BNw7p$X&A)%rXJ*VpV9&DN8A&eh5pfdIJHJINn1G)Ed z@K$7~c;{Fo&3^R<+Uj;-g~LSjTG>P+oO8&}!JXEv-U4%dK2uhZCZC!2P4qvlLzTDp z!^@3^{4yXe%8g*RaCUmF@bARIE{ck!3R^VG6k z0Yfw1!1I6m`?E?G`hJ*({eAxko8&5K-HH2bTl&<*fhQd zJPlkht9b;MSu0^jV-9wO%%oq>hH*>(5N;{=#~})vDyr|Tqb1{AxwlCLq^3z#D#Y%@ z8AIAd*KeaxvrmvX?8$jyNp&_}?py=Qt8&;(;V{`rmr}i746OP409H<(0`uZG$g4?&!6vw%GQ(kWcgg& z`P7&b5;Zt`?k!rXb5n?#aRF+&5?p0BOQKC&t?;#}8+=~fV}(UIFlM>~K9i0^_4Thw z*1H#*t|#b@%z)abx9C5GXXMhMO#hud&n2qPuqP@|9P(`g)=kZZ!q0_JpL7q-kMo8@ zcH!LT?<1OYrHpz%c>`w*rwGpLM#1mB*B~hQI0T&AiLoAwxx~6R2UQH?bz%L)3gfzp z(B9YS$!2#P@$oDC3UlLMoeAQzl1H38eK)OWN~8%*O324OG3)nE;fM2NOzH6BlEw(v z-=mJ=o;FVmbbL;IHYHMc&H^~5WQ7&A!}!CffnwCO6?l8p2wp9A2%i$ai*YfNQ2vCn z_{uquZ~x1Dk7-pq>mX7a+A^(NdlxRnlTti+}% z`_Rih8LVF~q2FpNc$~8=2^WX(!HuP)KVUtE^wU9YVKIM=e?oGmYJ!(jy3qPBBXlSf z&=27))QvP|mz%w?QMZ7!=d8nzB_BnP?R~&xq&p1Rv6FW^I|?!1dUNfule8q@9Iku3 z22SgZhDmqhI0=TJTe?2Z@V-QLo^z@2TOxK?rE%MkV$v&j;-W(xka$-Dh5zbl*Nj29 zvpo&&1fRl(ALMb(#@Rqq;#uc;t?)>*m0VUnrn0N8bhJAL{k5a{O6X1DR7NiO>(0Z4 z!5*~Kdl4@`I0)9=Gl!XHL#S0Pg3BkrfV(zLVErQo2EBekk$XN14?O##S4uHVvRjKu zi3bIrVjo<1v=_?_-6`a_$%3P7JDqNSS#fuP4@aq==iFQkzGaYxxwcbKL2@6sczN+$ z6Di!MstT{dcf-oBN4S^4I$qIBnL@@-#jq6`s4TgM?)7>DZ+G=V>zh_sHQfch?Qikn ziXfgcc4x&WB}eoN^+pr%8by6@z#;FNDt;6_9l3yR#bbY=Qen49v`|nns3}V#k(Dq@YacZ_|H$7r=2jx@Pj^Rvu6lP9kzjf zi|WWJ{1^;AR7c%u?R0sl9!^X?4a@5bLAKQcmuIG-)Y3fKHuf@|-#(got0P5r93=^L zE!s5MjgP*#Ow)&HAYA?oGxAzsHNGI37s+tmf00YT4?ha+%D}N6uSCzm(Qw!IQ2F@P zWn>wm!W~DFc>Pp6L416w;%#TXkQZwPQ%*})8trKo-gq;)$VcN_lRVm!@ee$!93?;tA@Y#%P+H>b0I0X7+}h+;*Cpca47>>wya&T+v3$6@@)7 z=;K;NUMQ`L7Jf!z*tLAfn~}&{ou83+sXj}eV8~qE>bj$#KU_PihXvMmA>U{WM}C?E z3r?${?;BBAyJDZ{xz>dp<_y95dB;d`<0COr`y9-JLrPS?7Z z;m~=JWHxXqnUyH;yFf+0db$Z*o>vQr%^o=5Yc92IlE6QH1}qV9RM0tifD~lpM8oU4 zsPt*4>zGHwx$pNMs2_AgP_`Q@?w*v!ucxL$ol_9TSZZ=i?sqbIa}1YVlV{v1B~BS+ z!;eo5gs|5yNocr9HM5_?v7o6qO|P1U?Y)GH?xs->8j?bO9SvV$iCrgKVBgJId~E3- z`aV#Wb3UBKZ%?}68AQVMxB|B8f3xE4byGTcd<5N^IE82XSD}@e1+;z9rw`ImyhSOG zdKZ^M_en|4E36Y{M12s;r+8w5+j*F3Wx%cE&gv^3ioLs>To0H3a*6lrL&Gi=g2kC3 zsJY_?<|wQpiws9TZ#I@=x1Oij&zglNeFpG?W6F5n^t`ao%ZN2(VsNn5XV+z;OTg7= zAo&D-5#Rj@gN-ga>{VHV!rdUj?L!!Qza7Ws#S(D!n5D};18epgbVD@Nn}iPii}+P- z0W`Ea&?TpFcxT*R;>Vp}Z26B*6h+~=PByK0KN-7gPhr=x(b(&0E-ik&nm_H`KqKO% z`Igi#NAOrWgHj9gp|ahw-eXYFMNn zgj1A{MbSxP1>Z4T&2M(5!2zjn zF!i|t2IzOtm>?ZoxOOM3$tf0!*O>jwl+k#jx?23~C!pJ#er)UDD_Gimq1&><`M6CL z^xm+R>`IDo$My-hLCX>E)EpJ`^7`|U5ot8LC7kd2Nm0Lx2K4;gWZd3h#ElnB=vc`J zw)I;~N0PE2@jnA@o~?{iPw(cYH|Noa&(O`RPw-iPDZh?b<(fOI3DlksaM^Pt93pLZ zqfON?esnw6wQ1yfKI5r~e-|gvj{#rA*di@_cIp5qKWpOAt4r{hOdY)0tAO&C1x|eE z%+7QebFVsc&#i-CvG||%@6V<`^Q^)C)(tvRw+asU4yELjPxQFv5ST2{5epVCadl{1 z&H6XJ#yZE2rcwE;p}(FoNNlv)vp$awge>N^U9aio-%c98A&gr4uEeS@3K-JjOV_XbC558>U^+2~yaWDmhSMOP zHSZaGT4Im4e^p`?TqBoBadi9n6Pncj6D(Dc<@b9d___KK@#eh@eE#}8+Kh>y!T0vi z^3hAUAtMtuwq@|EwRI#h?u!_0AjdO!A0Koy!@pI}p!e_u82QbU)oc&JgJNyepZ&?z z_Dnpb-ug;%;#t%)>%}bwZE)vC2SprU2r?W7kt^o$?Q69-sxX4>Xbxv`4XwI91xhCj z#Ob>0IihnU7Iv$_v9Xp-ZV)tZ+$GTb&sK}srR7ZQYn3Y`hcv@xX`0(yQoR4 z6FPbWzr87q{Z5@C>shim#CyJ&@a?|%s96uytJUz^&q54qt)cp{F>odOBfT=#hQgwu zEY;=Cl1o0qw%--B-ZTT3e5nK<3HlobLDjGVI|OkbzC#oj$mZEIP3id+Auhr z1CGU!p=CBn4S5Ht!_%OD#67rJc@i`wm!kCh0{Ec6nw?AU(cqBYG;C#GEK!l*fd#qQ&xcrfrFuS(mKvD#G z$68X*&qWo(T%AdA%`pBQ-Bht+jysS0Ucey#orm5z;hND;51$wH2idNd@Fd(0FK@}j zxks!xBgh3!)l0dn@H5zbJV@aeyfC;HgeAX*a^u=kSRgY9hbK-K2b%5X`k~?ULSK#Z z&nw_7tHXo~H8I`Q81-&8!0o|OICtq;G^`C1>>Nv1>RFeXquSCv}U1Pc+bl&6zwp zY8wu+UMS8oP(z7QExvO+j?Vgz!Vk-<=!aZ9{M;z8-rxwl^CpEek4>P5CHk!J{j^}G zYld#$?o;Y^RXp@$CtHMi^IE$hw0YQl@JKcn6g*_uCE^f#^mD-R@-i4SMjj1LRG^Qn zA`bsmK}L(K=-U`mzSPT=8k0Rc5RegoX77AB=}0M z2`%5f5RF&u1HXRx^uD(|w&nd6e_P!ajYBJNvvLcp`jrCu`a4CNxSQlOY5{2~1#zDq zEunbcKKv5pkHfm%xwFubJ$tM;MokWne{3KppOfOy!N$=4O%7M>%|sn58{U3)KDIkA z=ZgEcVRw5hNEiPW-p;rPYer6BmxcB);kp!7)u|x_2_$pviJ0!S6HXfC(uwMUY(07p z-kkA8T)%h_d`$g7>%XVd$BotEp8mF6XQYg3^VZT!`5wVL>;f&4eaED?Ot^Dz0Q$zS z!2D0eG~9k4y>A$U@!AWx>pwj-(z}S`HjhTNvGJt&__mnk8US^(%SkO|I}1jQP~^CG3WU7YKA7mj941o{2*QR~f2UM=-r zu<%`iQNwP6_QWypH8d9nJJj*_Rg%0@-9dP_BN=0V_W>QH@6<8oJEVFlV|s)dZ8?)c zW54#{x6LyI{ZIbny3U4z;i=HmV~Y6$Q~6-xZSW7dNkdicz>nvDgd6(GShapI9v^## zddm%_0qO@ZeB2t8Jo%VURL0ZPuw=3cK8ViRYk0~D8}7ZrNldwDiVI3VxHdMwp!}m3 z>FeY3!qK8yVe8}F^z+~xF=dMr6hFHp)-eUWrw(+zmhE`cw8l)&deCcabcPN()A-!!=^s!{fX)G=-jbe4&C#MsQ74 z1MfJbh@RfV@tVypYMg3>tNkNf^_~@T<(|uAa3mBQ|5L~LRsFFfZ`-+Z4tm>zSyv6q#>sKQxa&m!Sbo!lcP@#o+E~yr9_K%b<{3J3 z_{`NHOmSF+hn_wac;IykGs&wkD=@-<(uZ{D%qu)oB7qgsFTf%7HVyXG;lQ-Z)cu-5BJE6ls!C! zYQsl~!6A9Ln9cdztDR(#8OB*-d!SmYo>sdXgU5Dt+^5?IYdhkgsZ5lgI-I|K~tTRFx4;`4TRp%&-a=zZB7VZdVAGXZ({+iR7#^|wRIG7%3F9PGm)Fe zUFO#_gD~-M0JNNy#hrs9_`j@PxUy{)o*EG=w7ox!2NrF|Tc*uaHN%zLN3>GH$&q+E zNQ&Fesk8G5Q8ep!onW&fmOQwGXDy`&L-n}-bQ3cf!Qi0 zbnt{b4{8BQQSOhMZZ4wBi5fik;BoREwVO=B&#=l+XVgA6hEB}s5afRj;_Lb^z)8v* zQ!dNVQ8gJ>H@txIa)%&rNiSUccm=to{h}8-CxzjmU#a82onRim2ur8E!XchVVOduh z^;1sffT7o6-uE*kJ12#GB#hJ(UuTOQsp8*_B8h`s#tVBN;~crjcO z^y)3BuIm^-GI~VyK9#Nmjw@rr-$}x|OnYk8GQj_gPlIdwa11@u1#6EEXDf?bS~I7N z3M|#|>gWPm)msowkSC;OZxcQmSFw+Y4yNWEgQ=nK!Ff$zmiB0*ud=bIKHgol*Q|$g zA=9}*aXQ<4v*CK@bKrD11?EST!}Vj1Xp(*wPMT!Wq<@*@qswF%`JzF1m=wsLa;L)| zZ-WZ^q8C)$Q%({q4?}~0Bro-zgt6Z&Xmg$)W=Kz=(ZiJ}Y-y9QHE$xtYMF!d(vz(5 zaXbY@X>wVrEqbe~lAdW6%qBYaM(k;6Y{OM7x_=QdJ^TiXw=d;m}H&BV(WwM}D7%!%7Nre7`qHx}! z5O7K{Z7af(=_mOFM`Q7 z2;#6LY_Y#U!#`&6ui^+k_}Y`=e)tL}LS$&q!uv3%pA+tgT+0tPbx`zhX=K*`RLb5| z@iDuIYIP=qev=e-t2m0M?jGQci_7rTn{}eoqMzb|OUb-Lb-0*1KMgN$_8~*>vtoSr zK`@ZIz>i|hAXoYaBsn@`M8H_`d8N(Mo;1Nho$tbcY5VYEg9+TpdIFo4I&+;_U)b;2 zEZ*ymC+*xOV&fK3+#QGIv-4Tfs|Rjh)uk!j^Rae6;*R@AdF7aucskXa_Iyx9lZ^>< zbbUMDJnq7B$$iP+W)*I#KMu7!=HXpa18gj*MOTZJR5|v#@La=+Yv3rPf01B=ngAZE zY)pO6KL$G$393kZ&W(>1xZ_zp1b*I!k{ybe?f;O<8YM8Q?4kD75+qEnYniububd`-^kP-yo52Wec0#8HiSs`lHJg6AW9NNDcd3DdJ}= z`p6CCng#o?C;BVBE>(uHQX4t^QVuw455RMANM@?vg=JPTm~VU*w-0|uhRMm4IB*4T zwO&g;3+z}hQlV|rdtvhp4cxsmjw0_ou24!Zq*HEyzB#YTUzaZ9y;q&+chqxXU)Nf+ zi@Zm#gA~ztvM%SW&jI`LY@uCtCABTc7gxGop&N-dqLo&#AbzPwnc{Es#&;y#*HmQZ z2t%BEhzjwytRKF2P?zGuW153t#phW(;iEOCKC2_!<``l4)Ie0|70wNF7h}z; z-(v2b#prQapQdh`&6e|$#H&A$9VhOeX@Ob?u{|Z-Xg(ooYmHl&(U_(sa>9!x&Yd7KhY2Q+CElsu}3Q z?fw_wL3lp-4DQQ&OAJV;zfBLm-ewznf7-QtFYNW)jgpGL#gxar@yJdq{A>CS4k@L9 zi-JG9Ow;6=<&R+I19$Yktcsr!7xARjmC(C<7MMp*!Sj7guvGFA{;|JI=2s@ugb7=D z_Le8&z=6FO>ci=_-aCkX254(`5Nw*4(73Yu;(Gfxv|)Az;c!EK(%LBwoxYcUR87Q< z@uRr=YhP?IWpS_dL%5UH3{Anac;c00sI31&i+1Qz>-||I1f3N^7yHrlSBf-d_ac;? z6eX@TxkLqXcHuPT5*$=B8AmLL;+5@=oI9aIw0f{#oHfywhsXu7(epxjyZf$u8gnESe;eQIRXYzxoM0AP$X(`eUWltO~XMi&#J9hIq|7m#nY#W1}&4Jh$IW z^m!7`&n)u5Vdh3sWIgg`ENjXOOH?o)AIAsrl}XgGvWE+&#Tu+yc$aJu%9wuPfiHXk{Th$; zj9fT|NZ~c#!0Q!{5bZOTU>2W9cRHUbjy*~Z_osC3p5rK0HLo3LPv$HuInBk?sDoyl{T)+_^iKA;wbWE5T`oMzTa7VmUMd4gE{*I2--IHl@B+Hf4SDFY%KrriU~xu<;Eusl)B?{ZFHu|KB^ zlyzkbl>=_%4pS!n-M98AeG1w$2)3#kbGJcP`&Dv8(V5`wm!rP>Mwir^f2}yoGkXfT zv?k5(U$A}gS0LJ6;zn(pq7~eNK;(8-HE#gHFv=?NgS8zGa)1l(oEnMEPA(L_RZBUp zH8FVJNx9D)jjD7y2NP@3&NtUw|9aBHf#)WkeAuO;o^xtEoi37LZ1dqQeQMO}rh%}- zweUZqCvxlZq|Wq7*NlHFfR_mU3=(t5xI#IE7OBMv#9sMmHol|W#>5@-$ubniSy520 zy7mv*elL^~0lH;3J6vNh`sWlCjxW&xc7f`3E6@rZut0xgT?t8Hdf|7OfYWiR!R0*e zICLp+n{7V@Pf+@Bm>!dVyCH5r z)Gdsc#x0v0y8_P2#ULTa-4r=S@oMWSf~?KO^vBZ-Y=16BLEUD&Tpi``+p)nP2~eyY zo%|w2M~Ur6>$u*noJX1?H2+s?hR_#IErYdxId(3gjIDn?2})%#gd%{g-9uejB`7%W zS>`0{KlT|WXJb#NT0OZNy`VZI&Wt_eo4IfOu<%)aaTVj85oY@ zuA!br?C@Wdu*Dri2)tE<5<8a`4aEH-CTB(93+7fxFTPLlNyUyA6G|)e-RUu#IX@xZ zL9^`jEkny4sxqH+!J1-oVc;ifLM@UG&mZheynEaJ6izzgQw;gH{W&=t>s>&V8~Xy= zK`!;qXU_CBsV)RiL$~qoGpH!67lqmmZ2S%)Qx9ciGL~jYRAw zCyqX8F*X`2b8LU?MG;;7w4bxp%H~#0f7#gwvq8koN8Kp(A#eF%k1=capUnOX7r%eQEH7Wdew9CTQe3ZIU zVeMzfU7P|HeiKG;HRBZS?J2GOun0kf)z&1D9HUhS#GyuJ4t83W)FHruw;Fd3uo2AE zZQ_mm93wYGrJ|9)<{X_hEBRQd4tp>Bf>mHpO%d1e6LAzb87zasRg#k0@#{N)<1}< z(0$b>{{=I|a7%p9Tlb;;VV&0A%@2#Ti5p(aIf`AO5*#{tA$b1QQ;y{sDrys%!0o)l zyk)qa)xCsvFS0C@-p6u*yzZ9rC!kUatjP<-uDiyFv{=WC4M13Ke!)L$i17 z2K*XiUmdAaxRoElc^OD^?lpfdpkHLBucY&0=}Bv*U=@!7CffHz7To*r{=4-dy8}#R1DZY9TN!-PuqvHbINaIivL-PC(g^ zniB;)UB}gkmiXH@)KDo~pq3iD3Y{Jp)_*Y2{?lefAl-QRNgk`yX?C(4BFdSVfe>D;dQ}=PTRX6zAz0G-3qBoJU^4=Zop?7Gj zD~ns8r4jtAfY6+^FS?`a1{!kS)6na0G zeoc|wt*Q3VVFQEnd_FkiqLq1oVXxJ}lq+X}-He)*TH!7~u=N90*w8HeNp<9i{(0eC zmCC_+pS4`?TWtX8d%NP?43D+}`smp^#*K9AXm_C={i7W_MJcFYUzOW_pAK}x3qO!$ zPUq-14{80q;NC0NG5r$&WUHIv2rwus`;8r)I3Law4&3iW7eMti$aFeeIBD#35yepT z0@E9?ggegRnC+>79noHU925Pkw~&bbGVudzqv)$E%Z<)mWUcgf+)X--AQJ}}wj-4u zcf4~1Yd6~on+?)g9?6g|{O3Ia9!1;yB`iu6OTeU_=i}e%zZkvyWHh}F@pUwt5{q(! z16EdG(OKD(D^`i@&Cg67Fq@D~7cBIiLNL+2jJQE*&jYJr6Z)AQ08hVH!gN7B`lXap zO}%+#2i&N&9>ar^oFSpc4sx)u+rz!n618-LtUr6{se012hDfigEc$h0-R#w>js>D%v(}WDqbOdd?xgp zk_mDt6+$=ht(TP<3+_ti+~wI2r+O9)+suMsl%JP_=OM(Rqq-zgzY^{%^*KO6HD`8o ze|i%LW1@6o^uwxYT4Qe!We6kpem1=AG0jI_b!}1R%qyBEel+9Fqx08HPV==DFkg>E z1vU$)?tF8(T4k4nw|2`IhS%e#VgY(e1gJ3b2%JuAtr??l6 z8%3(l7X6Lab!q);uW0SNgVW#7nKV4m3Z`n*b8lQQO{KT`$A$t6j-!!>pUdx-+>GQ+ zUM-n@sfe6=olW96qJ;H+y^PyL!OCX5L~4}K2HBrE$Lly^*qF$S1ji9QIcc+asj2*t zf0zu4Yw2!#(FRpc(b{dRBZ(g0sArv={CS0l1v*ZksPnP}nRN1?a&fE}^v9w1sYMM3 z;{eku+5+&dGNwVtu*`91gF*RR2Wh>;&}d2x64ie+Jy^2j^Z+44P3|7sph|n2_R4x( zp+$OX>_w)OYNw$~8v#SKe;!$--#yf|*BRl>WMYKNU@h}GDp~Kgs%Ueuso}Fx@ng3gVtjo#p~tvrhjL?{ zlM(E5CtF?Hp=2(&&%;$ms@tU-yJ!PHbJ*2FV2cKxWBype(+u;}4z&|GK;3>^&Pllj z3k)t&e>hNxmTMY7qFY_v*BLN??L_F86$I%t<((v6JsWHDdGNMO_!73Ibk^_9DkauZ z3Gt*D#%I0L`F&rE48>(Wd_>*cz0Fytc2x%wJ(=>G9pP;vJ79S+#+(&b#Q!25UcV|Iosjsfr9L({iU=&K#%$`P1G!xyphJ;#FnCya-1Mqk2>hTGowrXqX z$gknXvy3YujY%vZ+5z}A!A30&p@jy}cB64*rx5)QReDJH%gTzj3Kf6BBza3tiI{KC zdN!_yWYC#|5HaYHPdY_)=cd8eQm0}_MMH(m6i>P?`@B;vc6=(+$IC42rQ+aKdi3F- z33pP4%nRJ|d89<>C|vRT%2n7pnC$-iQw6lktSaZW)vOqFYx?y$*Y|rJg{nI|%3q`DoE*kCTcawMxPcZl%y+Ft~ zv8LNl`&bU17^2BB{cBn;Ud{9I#BO%q)O4VN_XJ}vlu)n^WK-2Gg`FxmgPu)eNFM#T zm_)Gj*H+=Tj|~QDCLg?+mdldi0y||lIXc;tKOho56k1kVAUVt!J&UOhsZ%(Pv5WBo zS^-v%O9TX?A#r3Y{HLW>?VcWSZ^}++xpqtSrbTqeu(@UM$0ko~Jit)4?HXUpX$qU> z2ZDz#mRR%)6hgdjC9wWK6TYf7n&AyIw<0D||4MTvj|Azw<4d^cmyPRRyKxr-&J8}3UCjTDk|b#GPiB`&dIJl>A>Z+$*$x85C)oMEI3K5)st_6Qvhs5+L@~I{ zV3$_g1O|Z9Fe1r;e{AE+8-R|7rpR2nhL~ zO~C)b|A9Nc|5eiXKlAR{(Db&h`usqE>Tdv|1;9(}|5;%B|2F=YRD|MMf7%P0{)xjs zolwuVkW116GJ?VaO8=+K|26#oF4IU~U;iId5CFjcHF8Anf8_n+@!v+WVuDj+G8wy? zeKBBf4}5gW%PC1HOUTLo9|C~^|5woezOMgf!5_!}|2Oh~SOWk+V*L-LEGs7eU-W+| z4En!||3S70f&Zoq|3{(xe}nXYcP0S=0fI3_Ae1Z6x}`p&XP6D+rLuM_rv_u5h`cYb z<$=x_)b+~%sH&*Xm&gXNNziJ-$79IiG;){VfCNRV zy7K!d#DEkOh&)2JA{-7X!i_k<%keFYO$jU03`KJoA&8!t{~b`ZhycS7TBxx4PX2IK zn(-eVk)vS!DNv{H!nhodMP(SfAIKX3ci3q|ZCezv2) z{xX6@>J>n&UJxQ^u?Ez5sTqTmHUq3c>kC8D_ogVxi^84k6ebSEl63YkRa;WuOm|96 zdAU4=@!DdOHo^xu3i$S5Nv2YAOx(Tf@iE8@Mg_}D8zCx@@wS6sUsK=}mf$GjkZiYv z0Hk7oFqZojBB8D&&v&egiENwC`3ExyBpuj=to{U4@Tx7x1QjlpD5peI?Btcz7%Ix;8o4k2Cs=s#iQeM2678$+QVN-W3e54)wR5^y�s^q$YGXffp_WBf;@ z5$Z9@CIE=mgrQK(k5rF_Xy}p8pE+2^l7TfmzU0BlJuQd?jEwPy5;l)xT5#+4KxzrC z)m@I$d#hSB=cDin9}h76E*D$)$?4vlr2TefDy12)rkcxpY}%@FidLU^rTozj@pqKF z+f30RPN=qfg2`Q{hb<{NdByeOv_?TE236{+E1w^aZUQUKwB{G=&r7Ct0Y<~%u-6--?yB%TDJ>^^^u zi6~1_DQl*3ht#}4M%a+bsLKA8P^>%GZCXC_Ifzi%5_RZ@q%9ns*q0sl^5V<$Yj^g+ zk%yHAb`vh|YNCqN9JLR}lq2+V#m9o1>m_qDCLIzlmSWYwm6?aCg`Q!muO#k1JJ<*% z6Vy0=E2MyGw3zW4{Z-@R5O5;e919oA-gPPyInRDz;bE{m@w@xYe7XYiZHkk3f~PPY z#Sw=3_*>V1=&u|GkayZnNcuGxK|BZ%;Td~~b77;|=4nr)uwmkopqi!eLr?v2yH<&R zxNgIgkzyciIOw8gj3L|+ES>CRLmMu7()*%DV?86AZPcPC9X5*W`Yk9IvwX?fF|L|(ut&6kvXnfI6dV}g@lMNx03MMW_W zY_+Z+!H;v2IIov$G4`vI{&?I!SDy8UArom5>I4owS0+itUbgL62vvc5) zHpx+vD0erSW2Lpv4TK+f=@5`a92n#OO*;r^yb&#(e=vym8YJ(`8r1h6j!VLr8x%ml zv}|1*&u{`i!osI3Q=i(cU)34<<|Sty&uJp*Nr72ZNZC>+Q7nF-0Ix*N7V5B8Cu9AI z(;9D+alva)Y)_J2k_u~z&{Yh5V3q=>`pcqlzW?s67Ftd|h>_nAKkokuaw)`!85DYt3?>wP<0SX=itA|)~3 zHRD}<1+|XgD^%-NfiN53qqdguJhN6{UMo zR1@G|n|Ftm9NC~qcNuy(_&iOo6c^7 z5w-wZg3kRTLf4*X^)0VRRlzR$z(dAH<$t{8p#2QuBB+(O^3qOXHXy6~uM|(IcvdKv zN3#{#tuo3X{H8T|%tC$5+03VYzQ+>>bL2t(fu|+OzmJ}f=$pDktssN>H;yoy?cg;} zDe_Z{yQfTUWfJF*Tx;q|C3)xg<=+CchTR=n+d^pf&rncqnF`iryZK^>6p0SAf>;9H z@5-zij%BW@ych9E0=_nY280rGp{LaA??^thOk*&jePV3WPT576>Y4=6fPCJ{@W`w;+ zS@7H%>6W^g&ET`i%MEW(U*i6S>|Ci_QGz#~?mFK08>c;)C}0aKT5!^ol85&;3Q+Bu zcB8!Za2ma$^j}hzmXgv=%9?HSj%jBekG^TtAqE;*BN7ck1$;n*1S1FmEBY!39k$t{DitXqC*ww)aD*4~uR4 zRIP0CW5XcflstUpIZE9J&7zP|M)B@Nj3bptd(p0u|*)&d^`u=$hTj z0@5%#{&1`prH>DCT>vlQ%G)f4t%_JMQZ`v|s)hE2je4dVrHt$dNNxi=h%|u4fxA2= z%;(ydX@lzxezz|o3C&6OUV0w-iuXYmvI#CUhiL^4YH(z}p53LnhWo-iubC4#FRxm$x&ymDfAXYQolYE<&$L~ zS4Wtuehe??UK{bGMQbdC{~WR{#sicUtzVrz%^hkrUC&v=xJ(^m_C@GqB0O2vdA|45 z0EOYOJC|oqmpS+ie;fP;#n(N18f|@?DU1C}wxNiU!5G7^-!{s_Z?&s8g2kND?Fgkt zjdHwAr~-3bL&>jvMiOj@G|dGRLHj3v6dii_HpAK!Vb#JlN0b9dUNA|X8v7%MHEgOK z+|=(Nm#slvh9;B{bZrb1 zg4t=pM#B9DbDOtl32!UdepQDVewo+d&w&#I^tVH=R$K~H4O<)yUGC#!@+y}~BP~Ll z>gkW$nHnrgu+QYnd@N9QakMWp1t3$Tf65=KPH{8OBZ_EER0-;C7v$Oc(9|0n>Z!xPq-F%%jWA)t;_!+YJCRrZ=z8&uK__@L%!fH zmTCsaa2tj5;I8kiA`?)@@GTPpWqlw=o2 zZM&2=Gztrs!BfWPN0m?Zwzo-vqwba|C zRtXGu1DCB-`@T+q!oejlMD6!m)sxs_eF%@CK2lHb@T}`YVblsu3YYpblXaS%J8-n= zC3s0|`F$DS6vhv1jFM>=I;JR$zBd0|a_fn<{S$vIj;lFVGj~-P?k8jBMvE?Ct_vBD zj;J1u`ABlygB~-4S~cvuSFe{CeyJm+=E~P4<07U6(-|E{6(CSG`<~Zp10dpRd)w7o z;vTf_uDcP&>Lfln#E~n;6dOjy?wB#6?vffoR)@1yJi>C}K~T!507a0O@OWN1_RwPlp5C5=5EKpW)}H03avFur>4jg;I76^wO>R z3>V%y9-s32c&ti7)H7U&*q}_xs~6(;7HyB=swt z0xg(G&y&(_|1D)h6w6o_EQg&ecvbcz?eJP;xx8rr{)xV17E~JxEpK$0A{iG6JdSb7 zJKZRg<(l(z=y53-I%zXdHe#3hybipSrdMszAT`dUP|=7w3o{c_ zL)!pxv@Bj6aYbb8EBCQLvmAo#WQ8C39fd~E;V-1GUjvH_$cq)yu}UpGbu*^6Brh(A zc2~k0C9M&TrJ-kPM{(6IPxIY#mpSOF~Gx!NI8Rbif%<>a(me|F?c7*2u&sciAFqMmd zOU*6wJ%cRYl+Ks9E2Y#8(y3H3uVus$w6qR7&e*FTxA*CLm{Qkg80Rjy>J3-V#Sru& zM5icl3N6?oUWL6Ktt99-@mP-+Z=Ppzv8^N8U{|H4gPAZ1X$|E;dbh55vn{J3yY{@s zlXtaAxs2naSj2@YwzA0!Lw|v7^LHVdO<3Cv@fU`ddF|lAtQao#Vd_OnscA8GTVt7! z{p*wLjtf;HNe>1r`mFD|4M&`esTgZcqv;Ux&!m2lXq9@jNeB^r3{L^;5{)^d@5=src%>_$R}+lc z<1_4^kMIW{L27P}OBh%>9{N=THo?+MT|I*Q^Ko%`Cgt#RpY-#A4^FS}L#A!5nJG|xXzOHf znze87Zq9AbKQrJ^Zwwg>xJ$3Qf;w(4eFlmKUy%*n^g8mli@Ce0^d&6`NY{=;n=P#V zf6BtPHn%mlpkAFPI1y(3o*A9TgLQ8$(EHIMFcC5syLJAEm~tT-=+jYxBIoVrV1A@B zA{aW99~~616PPexNIz>a-piBTs@vVOVcB$PYem#`Wg6I{AwJjZNbW{DG)t zOD_|QxohQ7S2I0){>iNe{6n?m83eNoK2Xa5&>?1@mN|tI57fw=Y&w#&sS@l4qH1ll zBHc`^YJ1D5Uf`K;K*es;nR}y~2&JaJ9hKrG3bjnM_LEQ$7DN=z%8J@mG6*c)My<{6 z9tJ0UO)fV?rn<(nMVR5WHk+0Y%B0lPb@{*xT0`NA4EI$cxaAb(L`?UpZduGbk+B?^ zN|9-BC)(>jKz`L%nU_``WPNuy2ZY0V9R7!6E8C;hn!5JwKz=$j8;O;{rW3LDyu!gR0S7IUT{Am4OoyU1VS&ZM)CP!_16k<)r7G+`=?g zk_y!%;_sv~FlLJ}7H^tmQ7{zanKHDd8g8|Baj3rNng^$EZHE|lP-?LZ)j^Ok)NJ&Yxd~mwjOXTh4pP!2MmwXt z8SHT6@P}EYb;~XmHQbyfMXQ%^Yj9;Qz?x|?ATBt=Z(cQ(9!LFhdhmswDuq9dRaTPn zT~vQYKhsf3XSq}C_JuW7Sk5@8;j-_S4zDXM3YmCmb%J`9P4LjFi3vBq z>+|Xvx?}#I2e1L8c)0ecz&)7c0`mpkE~v9t>2)|U%YcMV;<-10%Vxap4g;&mZ-@== zrDqRmxHQpgbbEOk*^ZFen_q*WhG)7Md@uQ2L8MiCM^*V$qpm0KT= zb_|yBZa+W=6$A+N`a-?@@;scs&@<|@1q6`bK1(w9#m|unpgl<+E6t6$*ggS8mnGi7 zIjB@OO>_su z#}i>-z+%&wc8E^GT(IKG)V){wIR0RI%J<=$Wi*i1M%O^S=aWfEI~n&tQ3sjmbu~3^ zKGJ-ZcomA!S6NL|Il-V(zQ5kC=xXH^26G*@^i#HDbFYr35wi3%40 z7}n&FV)!5n;Fh0V{76Yz*g3)S#5E4VOwala`jJr%^!7>c7LlZ){pED@@k7|`uLvL( z_Tp+a7_~g`6(@e7B9l0Fgx%$`jN4s7gxXAfnMfzXOUHN|D~ATwWc=H_qbY z+y5~;VY+l8d%@ZGeOzhS;53`H)*CEyDZPY=zrQ zl&ZXfe=n6XNp;Bl7-9&qoe=o;O_kc;Hpm8fD1t;#tj}f$8`sC zh_gbfX#8NN);h!)TRrlI`P0*V&CR10x>^`d5iXZP`B-dBe>1C?c`OBeX6?mj0?P!} z0|nlmZAm@O7}BnMZMI|Y{sH1GC-CmmwrmaDHM2$OlMb?M|1$gc1^Qlhr-)Q)jT9qs z6bWE_>?1n-u6)`y$3>V9UsDed3e$e#1Cgs81-VvMX0PP z^?}I;r?Kv4LRGm++fZGeXw`Qt`w?%pML;y;$??IJyEE z!}XN%ydy8hJBHZpMUJeC*EHY8kAx3dzdm-CrBoI(Y|zaWNw{%b<~D5N{knv$P3%PS zOx*2BP~GeS;EMLp>DQ=k4(g=~5KFTqWp!nY-pPe);Q9rBdoYXS2`UF&*>aT=u}n;n z&ArKgr4HrtZZ$VI2XPrl1+;@qMuA9c$=OeoE1j)f+Ij6muc5A#Eo>|VEjNUMhBB8D zm^;Y+YIS4U7f(&0Qs&Mdw>1y^2jCl#4_baCmx3O}9HGKw^-##!+E#g}^N*I!fj zL6;NhehIoRqR>5`n}T#AENbd?M^`I(v>k+hq1Y)me&347{o}GKYUzFN51>yF$u1Om zAdtogdbV&oBApS4Q>tcmLhx%;xynr2A-(<*r+OU27gVj*>@qdmT}%G8xtSDax+ahB zJ2kJ8FuuAD*@1q!Sf!Ma`z7wY+!vHeH!UNu|)~bvkejFjKvi_BZG^G6d z>jxK_{S4dW?7h(-RBlR4a+sQ*CK01M%FOfDwZgjQCw9&aIeXSv`S&$*+Mxkxuejw# zq8|3-P417f;?%5JJ%DDx`*}Y2GtyLXni)QcCW6lo^Tq?4JmI!mcFU#7n=U_nw!0?v z`1eC8@}zm~plK=-`iI1m)lNaIt?^C2`deJ1zMo0rV?plIzdzju;$EVjc;3-=tyY-r zdDCQ~1unoIrA1j6zsyyNr?w$+iZ`U94udU&3BCGk(vI$^Ct-NHhe^Ikw)oh+AbqQm z>p2FU1zVDD+puXdQWhD5r=N|WRX_|TQixc=!_jQeenKBa#mZrfdd={AM;`k9^sB6j z6A3>J4p3L@Q#K%fdW!YDlQ0{CkcIv=5H8YZ+;>w3zxMY;i)`oReYLKpQGbm+pp?64 zw5p8!m-SK0-sBOvtxA)If??&CoQqzYM#zN*SM5EO97x79dlXKgJ=Mx(J^GG4^cYZg zN%M9v)%WH$Oy0W-{N9?2gg^=45UehIxNQ{JVregN0Y-!tc>fvt+iPBgfX(Dnvq!KXhfqVg7I7^xSRXVKIOxfu0SSn0Za?sFK6 zB%&2|ql<@lepD3=AVPYAQB&VD4&tp;`)eiBqE(-ha? zI6kn!Zk-~fksVedvu>A(0`m)Oe#tXCJ*poA^!TZ4@54(uz+bO+P#IQ`5%4r8Zl{Gym&fEZ#kBS5-8KRZ4d;yKz}N{_tAz0_6`{PrU_4K?~ciF1E05^J6cD=x?C z*IhxsAwLOR01Ys5b{>Y~z{SFHSz)}iQLLd$QAv5~q`+e|ln3{m=3^b$V_@KbfM$3iq zLgZ4~zNBbj(^gQ|w zXIjd?uT5(D;qvHNp?cxmo;Rr165d;|C7IS^z-h)M!~KSi&X+IpSx96_HGni(W>kXx zP$m0+><^Lz6gb*fU6t?ZGU)5d0&wFZnc@(Dm&w@a{)E_$iMeIHw@Pn3=5uukIMc8_ zfdRNeKiYx}bjod9XxZ__A>&|jGvFwmsG|RP89^&zg&Klg@eKXQdH39!ltyGVrY9@$ zc{rf70WB{s5k$7+bQ-*_X~|iFv$nia?~5MjBz^K0PIl4JD^(pa@;?j_F^IOHUQ=(L zI-xSX65>Lv3E4zRQFKXY^^!)f&X%V6>(zC6KOO74iRn#KOZBWtLm|;A+vT4175mQ= zJBc09qRlJ=+$;>SW6QXUar>u(#}Ycstl)93D}uqb8QFs8pAfBIu=04~!~i{Jc>|hX z`P&2mPZ!3y8(nvNUh#iRWTL1{JqejjrCv)(AtB`l9`-;i$ZC@31C@Vpl5kImC%Caf zpywGCtha=l`wQWXwye9yUL<3=)kTP9!R7izW065cP18SwImZhZKMN5RUal0PB;y<> z_<|Y+9t@j^<*(EMjSW`o6dycm;(XH*L-L4Joc(QqD-&#X`a>G$wD>Bo#>9Rj8oL2) zf>;X&ba(nv^o#Blj$o=k(XrA*EUKWo=@SQ9Ytyc6{VUW!T8WIR1-C~XBby{azZDEn zmFl)e{HpRtw228b!2F}qA(zuU^2p*$j?>v<(WIjpl$}!Yr%lw|A72&Jc#kUtE*s<| z-w~I!Di?dL_shB2vgo8S^Y2~e5y9Gt3>mJigWtVm zIDR({cj__9DiCSkm6J3u=btTm8Gkg%lr_S$A{Xh0Ql-PLMm#r5d*GpmsFDnMn~{!5h{;}0KU(d)%)6!{kCJ{t@OoO7 zt$eGKPEyIgyWlVb8SOYiWJ@iEqHoS~Z&8U17gBw<>?>wsR)u4t4XjX}YSIqnwJfW> z=yfO^8xO;wEJRqL9SUD7Vht6W*)on|jM5t-Mx~+jl%g9EkKgddhL~JN;n1L4U6=P# z&%TF(-!><4y$+PdiqH&^Gxwgm{s1R3crXLnI>wlA2`N-oXkT}{UF{Uper>edg6nP` zPOF3T#+KZOX-uT?T4uD2wXH)HP4&wd7*42#g5bnmK-6e_N%gb+Rql)i=Wn^BfoyIK zwM=U8JJmgwV}7W8;{zM%q-O5WGXY#;UWn3_e_F|OIva#hX?}M+gXo!2q{lSUf7~|8 zQOBW#B5iK%z;E`bPvu#@=bwJYnnou!C2blx&i;ZWHY#O*O(b*m$@^Z!znq^2IUql6 z0*G=XW@*8G?vy;dqy0;1tA)$6Kyn5{BOc+@?LZr2L~GZx)d-fTiyBDDGRGH21(!AZ{5pC3^5rgL{|rD5&*WEL^5+aBlO>LRWQ9_QCy{)Q=;-sP9c1tIfJDG#In? zxsv5ulUo8v!?TssG!+K~iJ#GLYtO~0@aDUx^z@P=s3;fNc6Y|(6r4tz$>Do8a$)k^ z{O4vW&zvC;)!jTo73IodbfEkB*jF8_XS z&~763FeV%^atN%@k>g-#>2P^9?HLQ8{QH(A4=D5dCg`0P9C@dc%|#!Ai2HcI(h3t5<1N_IKj@Gq4HYiohqyX17qy1IIhg zE^gHI^ES}{)jB2!ccyPJPtfjFC1od{YG0LikgkI31@lp0Tw zr-Zdh;LFoR5x_^-#<|ZvS5Q-A%h)kHJG*I>@jGM8=1TuuS);JlJ&AvctAf{SUQr_m zf5(L|;C&S<@-eN`@D4KgszeVUrLrcGQtcfJ*1ONuE<1Kty4A6b6-~-vX@1j4>%w?- zH7R|V$BtR+%B-*M$C~o=t%okn;ql~hiAX_@_m$EVXDt z!(@OwkY=xAJ@xpT#;hLxM#5!jSs}`(0=K63ts22Hu&}L8uXcf^>CY~EVbXXb=|{Y%{j5hRT;YbGz2AeY~McR^Zj z#C;`))?mT9YeyVX&As}`l!^Ul6L`q1@@^UK8u2W7QmP#qgoJW6Z!jcN!nn|`Ss;qM zI>LY+x?o1KSN6;n#A35#bi-lTHotY+(t*+EWCAT<+Td9CX^{$Nkbw6+B@=Vn^0_#6WwPUcW*sI3CSgpQd8$L>V5 zcC658S~7ZnA?y^vuY_*$$Mb%~$zEmF^6jIhIGNk5X)q9QfG-*%{xyD*i;}YofNel+ zkJ_Lu&Z2dH9EjF2$3yB@FR*SJwYcSnTqZ34AiGq@be$BwBp5-jr>ZNjpPf(j zH?w$`cpZJisQLSNGZU&BSu6Srz@thmE+~y zx&A(Gv3H+wA))?ycC@XhMB;d9^j%~IH%Ve{BXl9qcJuuH6|PZ&YR}+|j2A+N)*&>R zmGfTW8tvG?8SAe~NKceZAeG0khl^!)Fn!oAx>~~B zOPQfxzC`qJQ2fS~n$x;4a^30fMp>+zi{V59oB**35!^_c= z=|IkMA*@$=GS+oMX+m-GeJdJ0v}94f@+$EU7kW`?;U5Ry(BrU%vYb8L!B56Xb=UE1B1H+y%;VZS)qMd+#Whe z?0qOVawMH*@O+0-q{K+D>CXBPefn$v9xVb!((`j#%^{*h|8xmo6<(iF%>eQM+LFOj z>dnD##`bBOon&znBw`iGqrdd2O(qO2aR?hAB&gPPo#2ftMHz+Pb&^4**8X$S$Zk$M zSro|+-_MkAr>0Z6B;ef=syL|Mk$dAyFtLBN>LIA2hXK+B4(&Cts;Dz8+U?Z$RgU8M zN3r?n4NFXCxb_e>%A7nUZ~cU$A7aKJ>nsK(QTc0T9J1$tm!IUZeyQ_u;w@g`uyERd z4u4hK_Clrk(UsRa9T*5emGk6r%Gc|gGpM)D@=#;0Q+AHL?8^^jx?aPgOx|BIrQufus)YnZ;*`ycXh1B2C6eZqn0H?CAs}7&!W)L ztul5AqJzbeaP3`_^Ut2>LA>4Cy(vfHcd6jXy9<{Er?B?_I)dXfyxclN)2S(PMMgiS zw%##ofATRXhFn)_P2HGjDCG$Tg+}nF3cB`3-pqONx0B56ehS(V$SyD>3A}$?le8q} z`9}CaXN6(c)dUvM1ZC&<7IDG6SkP3tagL7nWnBwoMK!crHMy0}Ol&DP4hi4(>>r0Q zhSocyubXEIsGqxDq8FD75$t-~o0bxB8}l?ltoN&kn90UlMg{#ncL);5v&}a5-1LWW zt!X>X?3b)J?k;2{aKq_s?%ExDvc3O*SUacgOqgih#>pGo<{R6#Z5thTY}&bRj&=O3K9sJg7Ws?=;Kd;a#mfs`3oCN7)LQvZGmat*F5O`C;8?J5f)M?g@Qph7#&iBlMUY_u z?ME|M>gQv*;7P)2rU|xYhNr46nvxZEyg)1CJpH*zInKAuzcS-!UiSg!Mr{Qz8zaRQa za!wUqHH^29-rM`}Yl}>OBL=*ydhmVtma4UC;TnrsP{th;3fx9Qm6nCC?zZm0Ub8aV z=`X&>$IUtp5_v<%2YD47`;oC*9ZSCO9#pxcB@M%&_pK*8t(71B^R+_11A^$XkqLW- zWu`AhEvIyBuqI+2Q)MWf8Yh!C8HomqZXExlBT^V__YIRf<-FHBnN1^s=v9oO9Uo4^%5I6h zBVpdh?{sQ?$*|6Seb%=Esg2({9RA$*E7Bwm)bE4NyoQ}wl{|JW)Y9%FGXIQCq&+lS zVW}s~VL`fq^k^m|(u$Be?mK%pENTzsv_4p)wfynrxI&f&PSl#rlm7LU3=imRVAA8Q zQZ8vwx$XVO-N=`RAw#di)c$N`h#jKehBg~$U-Dg7x%^9arjgBs*B!T-uVPYOg$+yr&l3HXW5orYF}@ z*|%lZuq*D%Sd@v-jALew2Am}6Z-ctHgo6VvS!0!rmjbkokAD8mjWHkNK1?SHt5fp! zr5G4e8s>SR{wf_l zBd26?%b4K#B-A)89yB}(H3BHiBie|%DoT^)X3}rW|0$Ksm^<{J&nX@5MUnl}-QoEN z!XkcfD=nB0h>LJ~VGVFYNC`NQsf{b7K0+YBk^pr5#YXns{Kj zd?ENch>WhNj}LC$O9pwUKT(W18FU79W*7)5GXiq6(Jd#WDG$DEIWbe72m;c>C}G^F2Q#)OW3>$mB}$ZrEHXS4aIDdn zv1Eg9Calhn@A!5QdNQ_A3V?u!ab^kDXBrYh!6O$fc}-R`g$ENu${4RD+pW@-@o1G7 zzq*!UQl@kLz{i4$+{%Oi*Y;P>P_oPN^(62FX|wx?u5q@Nrh+!d3@`0far>C@3!7B{ zZfsSx;qrCzp^;(6{nnaoYKgJxj%0y{Ks8-Vqw0wikv|$EK+KA0-|o?d{LNbE=0WM% zAy9;CbOfb68!ZywXCIp-n20*-LbD_rL@)u-Uf@Yc?(52c;RRaE>UnPpt*USMVsC_=7jL4HKuR>`XU z#G?~bbXvi5kX0MEZj=ckSp_jVRW4N*p&VgrfWPIC9>pXs(2@@bQ0-PL|GU?@g72qH z+H`x_h5iph8v&*M0;ERp(u^V;Ch|$ciQy(CPDuhE%!k} zKR&eB?e>ca7H4ba{`8x1hA(?rNRQ@xIhjbnRb_yDz%G0lgj2dAH`db4&rsCZvA5)c zjs3HlAKRAH08KE-*{KG~-I$`KAR)j*VAJ2V{|_{*Igx~<#1O5&Jr{b3)wh7TTIdMr zy1V^qM)fZTO409$hiY;cx8|$4BKPh6s+cu(gVlDL*Z{i{SN$1#@pIt{ft=N|a2ezp z^Qr?|cLDh~YE%S?8w2^k>c=+rKbh>4o|(%m8GZTX9*_#(yqy-iG9XfB1D4ACcWmhtVvicI4o?kWeX^o14~}Kz5@`Q8RRvwfkVH_5DnoUXf$c( zk>g{?&uxnoZjR^sm6B&Nvfy3^)_{}=%7VTjzgk+rQKV?_@(vy-R}33x?`tjCnG2ya zUDH@m4Mkpwut@oC&5FG&Nd9((<(zuNjSs+%ddixEkV2lV6#Su9JI1qEU|k5}eEh|6 zk!0J8T}$T%3NACo}9p#=^0VXOGE?rGL9B{i@6S)b_y-=5>j)q7XtgkQ|YH zxi7c2gY_RR*&z?6$dp}kG0u5=v@&xgiSW;q(T%=>ay(0shWVfA9;P?JtQel=hiAp8 zi}83l)UoZfIgKFL!lKnK%%DRFkJ*)wXT@&pGzEfpVhm@{T*Dt!vwnD zf4BkdpK+4F3LE`OqYYm4ZUXvp24{0-rZ)ILAJ<6x&~Q(xf|(m^x5w8J;R@mNN@sVN zqyyIW#ZPBsaDOia_@iK%uh3j@^j818yoJ)P3R){{lK2b`bTTh-1J!pclaj!2 z6RiCBg`ByL9}n%ig#?PI?Z`0|73(fdcd=7+R0sxVmOmXH!nlCWwa)?J;1NdU7F%u5 zOCDPlJ?T;m*y%~HN~7WDXV2pmFWBic{?hFcFl~t4q@*0ICL1>#j$oV^>h$YwF9>N) z2k)wa1~w}ctSkCC`B5F;^^B?}JjvD!**$#GQCEH^|7c=(;~pg0t9In*@=D_&o39rj z4?GJZ-#=xTsShN@db<}j84A_O7;XCPihCty>ojw?Uyi^T{z5mq0;6TyPO3Sm4A(hD z9jJoWt6|X}2OqEfw=1B+|<3Og6xMv|p zl+j1-=z54ya?tP?u`NAh23p-i7ps|QR9zIY3;>5!&Ux%>Os*vEAzR3218#%sZLsq% zOYk)Ve*1GSqc{+?yOH9lh;X<#8m?mQTPGPef|^LFsfvw%!`a>Q$dT&kKPHa;!;}f3 zny)F&@2m@hw_E&883H5>UWn#fG>F9rc>{pH*$5bo47ZZ7a9vszs<|b%lV{KOxOv65 z-H4OEA`JBwd{(IjNVOt&k4&r>%WG|laf{#85Bxr$oNFkZUJIOQri?LhSBEfzcm%bt z`jylI(WZ72EQS%5FVK0^c&2IgD(5=*Ivmsr=%+jnL@_a)TwbFvT3`j+ zIeQ92SMymPnRdP?IamitqM(96gaRakS1bD++ee${XUtr6Ge zRecG_D^{4|vD!AW3l$TSAqi(-$^s&x>@1~gR{XJIws!<-nl)F2M(UdO;`ht;XF=ZkO+9uo7=H;=+u+TKn!#gD z9L%b~eA^^ESX^Gr(0+iyW_!mxqtb(8h{=te!Cu|l>^jVUlY=p&-kfn*w~Jw-fu~N} zHe{CDplTk5Qsjr z=#MgWCg+E+eCiI+wt{V^ z{;^RS5*kw6r|sK*-0e0mjX4#tvY+pq(D|k`@Bo;2^I$@`&W~V0lTtI{o+I=MJKFP8 zMmL1Os3XnDFwi#hIQ;1b`Z&&gj>E~|YItD?PpK>mdAqcrW+&?AP@FtJyXOcrBA2n3 z!$}AX5~XOGs4>G&NbXx2mD0S4aHGzR6!a+icBd7F>$Y|d9t+?~+GnK0yyX8k8QXm` zF(qL`3X#WXch0rlq7y#7VRTa5p%^Rpv~x{2DM@7@bv8|rz{u~0bY`k7| zR)|Q?JQ#<-*~#rbcy~Y+Wa2Xb7LzFk3sAd^=F#s5murR+6kZ{S=?FHiFAVaHs_j#;RZ!69Jml(-{M#eVY^rcJCV8 zrQmO{M8jXR!S$Z7MavZX7EDF^(mF-LBp*W)1%+%* z%s4n5HItCAK%nBMDU1^TxDh)0B6q{Z)z|R|H?qT6Qf>&AX=k3Z*(@+ztppkK$BrKy zUKgcnH=eeb&77ZI*&l9LZ4I1ApZN2A(t7`AdgnthDVoa~T>Xn#lwD9a)tLBO>N+21 z8Ps!FMq>eSWmtuCk(*g9AZ**>KbbUhoNnl9>>bj39JAghL2}U4iLi?u9z3;lk{L7RgzrIf6$r zjRZS5SsqG%u=M_i&#aBUzQ#)1>!=Q-$)8ld1uf}8Rd!$tZ2_cp3({SuQsYMD>Jew| zzTdW4O~>Okt9&i(bGdy*NVL(2M8E=_(t#p6pkjuuY#`SD@-g}fHcByb=9ZZEqA?*E zvNeD%>q5X|GFr8R6U(SPFd-;aPw-kVH>e0U@l+Ck-2heGdQWzF!$6bmn2Wo68jy=i z_IHpcuEWE{6bazn0mH$%;cJ}z8`BHRcjO0K93q38M^fAVVsOn(*C*ao?EE{EKrXUb z5tmszwq(plD2R1U6iEvC@07PDvb-6$(lYs4+3M1*S}bXlE2_#rw=)ru`|&Hwxw-G# z`B>mTbgXO*8d32@gJ~x#D@e!8#`NB>mb*wRNVuARr@y{dMaIrBEqay(oN)OHN1Awg z?kEPp3c-2aOb|PW)SDCk>tv@fdDO&7b0M-Lh%iaqV|Z;GWAZD)AXIBf)t+>NfNjeo z0EvW41hcEhLcma6%_c}d${od=98gP>v)#_e>wEbsLDwh$eA5fV1R}YZc>Xobm8>$> zhwJ$CF>%$+T@JPlv{^xQhW8$)oUfeZ{xc@TkR2MsN7=WClXnBWXMkBp%~d}B5!6+) zbe z5*rDiF(T#CrVsYe6lxJ_^4dvDtO3;mPDRM<1@M0?-4&d*km-?30IKqpgvWFKJYK_+ zC&UqtQD3kq0oRbdOw}N4v3pAjLH_)w-)<%tAuOUC+w8Fg1blO0DNUjljsG#1T{Zh8V({ zNE(!%$zUYZx6lg$R%?!|$c6EN;PJpmo7D;~_rRlhwU0iRWXSz1ka{#SI#<@8l02i- z-KY_o_E{}sn@EFJVmvIoQ@%BiuERB1h7v(BoBwI|*E z-$>)4k3IJwE^&y4KGH*r2JCsOCVM`yx%4b94*M9koEC~;!Lef{DDc~ ziyc@|X|!Z04MD3tfbf+`cFJYUdf%COod>H7y<057KzbiB5pkLZP)w|y%ZDVp5OixS zP)y6EiDzR7%u+2vC+qD3X|W0W+uPNTYYI68RzQ?f52i+R9f{UJfCaX&r&I4r+AME$ z1mB!Di#mlukyJhxXe=*j`Xw!p z7KT9V48hDBl252Q)hTgX0S5QF!Sd$To-SF)Ic!BGls$aDV*wtsNe#Q-*aIx|KQb0e zR&cQi!CX%KKU*rrfXt;amg!fhC`_o9$ta$o$P00CV=13P>X$lY?>qf|wq zgt+jOYKZyzXHMRTk)0U)z!JUDvrPOzwWKteE=?Qdwf934j{IxyItf zFY{SzEuo5Oq-pafulW=Q8mQBt4bz6c(k*8-*BIMcB(GTo8O`o&9RHhY!Mj7CrM0!A z+o&s(lqJ^4Hw0H1JThyLT+Xq+S#<`3UD~tJ`|47gwwS)Vk%}l+eQvX&K<0qI`&yXzDeXuVYqd`7yDXo{LRi z0%J7IifGRU%^QqHSsqB(fw5}%PJOUmvWUz4=Nh(t52$V`Gq}JP^k3Y$K-A)9MAlg6 zStx^?DAH^lC$qV@rLcJ2I9!bKGP&tr=z|X#H5h5@2Ht>x7utsEd&GLIDqMt}2&1IF zSY=5nCl4dY5Piu-XB%^;#4(sw#;YpjUWqjjH3m__)?i9Ebv$}_Q|OWF?GVZ&NGDDw z?}4F(D@+lwp_^>Q>@7Izl)PZXl2YY+$2mS~7P<)TOr$d?Op(I^>*j7t}%phKc_03q9C6CK`7t~BIWvxZ%WGp4n+b+HkHqFC)=2fw7u2_{ZfWwfp3S`(ISP>(uA zZ+(z!-((FMv3N1V=*`>d529Y)M91M<god!nH zRFzHV1}#^bt(vN5$hFaal$PdI!4-fuOK0mLRZIL02ymbDN}UqrGI<14d1$^nj)oip z{?MuEZD(3UYS~t@;6!g$;1Gwf83z@L3wVZ-NM9YRjCY(Qy^Vsy6tUS;Lu57P>_H2roK?#3@_f$s%$evPO9ER1WDE zz>Rge^D&{Ikm-Po>S}EdCE|qw76}MwZ3-7E)TtdIlYE&$EnZfz=rav5RQ=;6wh+Q} zaR;VH6cB0JAs)7g@#2LfIPYvFADJi{+)&A_DUwA-JCo$6a)V+kL@r4Qm?4eiS#c6p zh`&)#1kiBP>cD2uGlWC8&;(eaYe|)7xKkGO*^MpLiUZkN>vlT>)N&@05p;MomXWFg zEa5OztD=;vYs4}}hfsjZv_|?Uonisvu31fJj***y5ny87!h@+DLO4D$;SGg_vt zSkLqMwHTX!4m1Az(B%2*@*GNoU{(g8RO)*`af$m9OOk_#*qZD!^ipFBkRgF75H2%{qgA_<76`w8?hcY&Zpn5bm0uJD`n5gLKdr>UB|bwWg_^#9H0oCRzLnyZ z5ow&HO_cX_%xnZk#t2sYOIK!g`Z6X5Xa!z_<&Vg*qfB`_{Sc;XSi++60%oux()IyVaQ?X33D@3Io+_O|%d)f@P7I9eD zrQEm2+!*&WIVc6yYO&`;xo(8xm)}pySi59bp=kW*$6q($D}laf5$kDM+nyk`s496` zp%D%t{2O@CG%(CcWPD71S>hx;8o@rt+~4Jg#|UDkKL6eEgv7ehi}HI~Wvx?vBdDDsLYnhP= zqVWG6-Igdf+KsPhR7Zp>x5G9DX{clXsO*cw)gu^K`v{tbvyxr%K$$I}-23LM!Cm9Y z7q!gS;htn#s5I(g`kbkQ6Ajww_+zM90gk+}#NY`C;KSXU`{Y&h4R!T2YyMeHzp83x zBp6zqLhI_r#KVMjMvzdw9sF`D0|L-P)ECh|ogme##8G}T$Dd&qs4^2MQC0V2*Z;}e z5El0mvP6=l-b0Y(iirMPGMs!nd@hV4k>KKLxPqe7N~++g8rb;>^(F#^P0@zK(mVwT z2Z*0ZW&3jYfqUex4E?f9fq(ZHeDSQGU`Wc@KI&V)!6yZe_YyPJ%F4b9+LkUxtAch& zu?E~J50u`b{B#S`W3y6C?t^0(m?$P#!AgheD~v|`kK%T`sFJKX9-Q=RVnXa0gsbQu z`nBNie~?5xB(jU+bC0%URPcVO`VievNL?L64LKhcGuP~`%E(g5!ivwGt~k*0-Kfgt zB}eJ&d19aGDEJF)3yL+K&8krixvzEzL^A~A(algE#DA+!?(t?jBJ;C0y|RKsov_8D z1XTvJxHVWKI^{d*g1g~THe~DUzy_5CKh|Ao zQRZI1F%M=ojO&1j{oJ4|fhH2P5dE@i5DYWu94Xk}MPRN@np=s<1!(PJr|gZs1iD-% z=Z~<|rEVOal43sj)M{;W81I>spqO$!`ZS`T`DJmh{l9Y$v%SoVldVbmxIv>M7het4 z?M-Si)LRBwRw|GNXn`};);6xr@)hW|Z#Dr_E}BN2efbKq^+TGL&SIlEd$rnN8?fb5 zSEF^;L3lp75*47gGl{9c3R9>dVl;hS;aH6s12|}PYUrMyONcc^;>U#{3UX+9B4!3T zvNb)z%ep`M^s?Ts{)X})coc&`JWky^q7*XN3H80iFG0K9G&=ffW!c;`-UH5M1 z&D0cW^UIwmTFYMdjky_v5F;wnHKP|=7N`?UqU8TWV`KW4IaI7z$GrD*tH0bIQ_{uF z!AHD+@iIk2H}0Sl2=di_shr>=db3%b5 z8-)DB5Dysv*K}VX)xF~srx}k56Fi?E;#@mV2M(dB(Pk8J51RDmv7zHE zHR-zn4^EL#c|*=J=jWRu;v1ne#3b6oQH)aIFbu&pOYYQtiJUP(wn;eu^zm`5s|$J8 z6%z7#w^3kL%?e3B-wC7#rbevUlS1y9Y#>wb!k(SOIzf~Turt5OyO1%_TTCrL%0K{? zTP`6&6S;}-#sd-_k5-eW9#Gml!Mc&68RDq=B*JjLcX%>eG-=wuzHYC-lV!F-H<%Du zk|jm%tD+wZ>@k*_T48e*>WmT+$7SDCukcZ@HAw(Zy4{e2o{+HY;P8WcliPTBPg>=|KRX zQGIjEgyzBxF=m!8xL-Jtfkc%;1_EADL$?Ih6EqMy$bCHx8yF&+D!@5TIhy@bQv{+8 zbXBRja>;m+=^@2?Agi5ff6A3f>&xihd-R^ks8Hbs;6NLDB5l(5NurQI!-unq>J$z= zka9ngYXnfF$1uxCblDvYR}wA@wKx4&^@%#3BZy>t!Qs=%rB8!rMEcV50oY{( zz=J&!=S`C)@8)|rH{7V2MwFXIg# zG^tfA!T5xC<-_pY55-NSE&h|Dc!eLQBZ z6DCzbQQ8{%gk@62>%*6lFx4-j#W^1!uk%v+ zDC4uvF%>BZ4zV>vaBx){>Q2V;nNFed;kh)*BY1&jEW?gNw!$WVpy?N{z%ft43v2n0 z7n3mvJ?ll=EWPKL`Ecn)LgMMCV0C*X9@mwjS2Ib~L7zv|u1bkTm|~S(BQMH{YZ$at zwcN;iB6PBg$hZ|_wK!!Ehk;RHqlTGF@YXEm)Yzric_+zm@PE7@+I)GNN4jHC}* zoM^Ny>Rp_VCku`?GpbPSuG_2hXgkHgfym`T=^e1Js7zzI)2p?Mow&<0M=#i9&VuJv ztD7W13@Q`bT^a{)!*#Pi6q>~a|^1RQeF?h*O4o-h&Y9)WNI=(Kq1{4`|Nd-*1tO3W`yZ zX0Y~2@JUW~_tq6&X|$S8B-Fw%u)Mc>fsk2WqOH60%Tfp-=njjP`#v~=lpFTW;U6l)0|dldfQk3m%#88BpSl-2(!E=uhey*%&DI?0o=dEU6e zw+o21?r>||_6MidkkK6K$jF?zj}iCUM4+&je~spcsjjVWhkj~H%G>>l2+jbR&UVSR z$?_cJog0_5U`!sd47BP3Gc;XF+N^Hel)9w#e~J)ythw&x7fz}5gR>emci*@@dS%w_ zVQd43Ge9eQnZr@#xUqMgWp>hn679&Y$YlJqA+Q@0)w9&lPVFU@2_!RZ?sUlu6os?f z(1H-!v2G)fU?bW%Gz!qQ;bc~jDpJ6K)%8kN`1hv|GG;NY^=C~!aw&rhcFtbm-_Bck zuQj*WzjAmDVR)D9hF_Ko%cbW*U3uNB(`R0Y1spJ_6XK=M$0H{o;_{0aTC}cqH%`Gu z<#KYuGQ?5+ue``oR$ex{8v5T?2#%gd=Ko=nZm~D>A#1%dpNcB79&A&iw5IT{Joh^J zy93*Af4{bjJ6K^HWh}D=6!rgIHdWtrV6^>|BoguY$0rJD9m^(CUqv@-qL!wYL#me& z@jMn_tb9Rc6yGzYqETD|$!s*^&_`AN*r#`~Y8vY7xoNC+GYVpE=*lOboqY3Ws}Qpc zB1trMaxavYQwBSaZygpnd||i$Y^&CJz`1(G^r}b7f_wh4kzgA7f!1?6*{abGUV1IjKdC&wF_;H=uto-&HD zPFhWIjWS4kV-tIrfSQzwiaKPvCT(TaT~GSq&DQHx)`f%Ia;F=%|6sN<)!(;HOVl`-|IGFdhzsG`h_7_9nhT(J7@YwVpFx5 zIy^VkZrwAc@K@Q`8DF|9fRHbld*Tnk($|ytS_+A~G~H%fUoDTDE@~B)8B1 zfX@A^MR!as#=rs8lNvdIRa*60XgXTsWazV5c#B_IqvrHf7ZaUK9k~?~UU^)&zmjBG zA2~5^m`jJ7pWHWs)70e1s1Rl6l?41PH8D16i(^M8lY7h+QOJLxGI>D~LwG}E+oiwlUSNLQ75hsBcbwSM&RuGv7w+?iB>^Z_Q#u2tqXC z$KO(tUNhR!(16O0^J%ICqEnF1cS(R3OasYYXlvq>qN!pe6Ptcpj+ypWxochP>Q86B z5mowbGYRfE4iZHbZ?0+TJ+!7$=-%O_s4M!UK8BtPje%#c*KVQe{o-kwQE=~!|8_Rs zy5Nd8@%SI*a=bF2XhShjIo?~#@N`qi!(Pjj{*`aW+@xW?(&^SrOaTkk*lprDt+pOBZ)t%bx=>^rNOlGih8k1{GRw7zR(>C7T_Q}h#xAE0)o)leJSNIfVC@WV&KdmwN!I;&aEvo z&xw9NR;wPzKz_~n#w1gs=Dgaj-#s`Udi90b;M(PIk`!ZgD}zTp>G^0WlDzQ>R*x4@ z!)d$32)Nn_+|p~^`f(JhqoxOVMC4Tz_k(>AfIiixf#LeFOJrdtJ#o@nBOBa#Lhd+#Z_Acqz5NwVpGi$S$dRHRYDjM zF6SYAo86gMV{^i^3AL1qhp^juD+?66gy}6L(95apKvYcN@(@LuzW|Ub!HhMK`lM$X z@u5DtNQbRFEyCi&Loj{ltI%2fqT^m|dB@%frhvvKZ0y395@4QQ=HVc@vM4NSuXBaO zL>*nP1FR3ZI-|6R>D?%{a=m$={u&v26$qY2QfdfOFYy$&OaWK{(_kubk+xZCaTLIT zr5X1G1XXN-CIF_`@;59RaM@O+%=i3?Hu)nEXn7H*&Y~&r7|VZ=^apbsijPeSZ~of3&F$3et4jW=h{8Noq|?N)EN2#p zkw=xP4K`sb8X-%G1sTOz+Z>~V=sgcUoTq*yu`lhXj%dJ=Y(z~e2clK>wZvTItVqHk z93ZMNagr<~rkDoZq&MDZ7e(UXQdVj3n(06ZO^Ib%(%ZO(}6V)QQa%g(t0;&ma!3;LFkGH5aJFV^g|==jgx;Yzo!$%|;T?flUx8vKAqY zS>~RRP!$REMYW%9?Q6@|#7}d@_E!^2^^HOw2|Byu<~6HRmXC!5!&h}XDFQn`!m(`) zP;N`OhZliMUB1d}RrNkv}{oSc3|2Nd+ySUv?GiTmyQ;HZgY00y(!{iwaIz2) z=?&-cchXgW670ixe6YH*Y409&beMY}U-+8V)TN40Q}%Odol0VRSKQ``Dz0BUD=WqAE9NH}k9zF+6+0 zUdy(g)LcBOCR`|DXw1XPu}1wNOwwOx`KEXdyx~d|`MVf%`ah6jf?^_VWufxe!tWR_ zUO^s&f%a8sOAh&fk909%q1rXykG#|^=TI!-nPF6Fk>du%%=I$1^{VTmX?UOmN~Lb9 zYMNiH!zj~tk8;6q;l!BCE{09$vV(=g8i!BmOeqH!L4l;Ow-_P>F_1e{G_{2NG&t%u@ zf}nQf8HmF-bR&yhum_j4+|P5GL_!P_NR@cw=62K>N6k2on=^yjLAa>=3wOygWo$xxmab{NNSKU*37*yWlS&Uu4 zkq~hkIY*P=f{^5WWn?1tGz<80f2%^%YW4fh{QD;Il~^(w!Ej zocBT)j!O#V3PSmr7s&0oDdTg#wS$-LHzk-l(!m*_g)0^jKF*9QHVldg!-%ZQK?&J? zr(a0Apna4QB#~IWRbbp{_N-0}v}Fl;7&3fGCgZ*!(1VtjP_RM)kh>4bNJwwLh!gxk zQ7i&d)@F=St+*;8pz6VfZS$1(VGhu2KZB61|NC{&6&E6t-Uq8%)5ZAM0GcHovNLJ5 z6&X+4mJo*1T{|(VOAa0Km5Yjf@MKFnx@K}jGb%cLobOuV(Q?2xKM7I{+cym_LR^mcaf9%(KoKTG;W*z#4vm1&u(d z(+2BgidM@zd%6>)rnr{1GZd%$sMkr}&JNsw#znCC8Pvi~Q7fe>dZDH1Q@lAWnkMM) zW2zWk5ShPZ)kqtZsE;jA_~R@zF(K5%_V}+oGT2)rUNI`n;VWTZ5B=zb-Gk@qL-WoNiWHqA~PB8K`64G{5>z zq*#F$WWgvhuZR>5>~&>Bf6z`yj%Z#g^DpHo(UF46Eyqt3+Y?k4Sy4X=Nuynlk5;PU zO^6xdeVrtJ=py*xNS9b0N@($kJ%v)RxjZwMZVO_oB*Uw&QjK$0p(5;A> z`TN_5Y~itwjLC8)-#x;;aJrh|;=b-DxWvw~543>DOY7wvl-#pGc?01E#@`}shwOCU z7$bBv;(p_5@d|#sw`y2lu_EC`^7Tr@t3}6>8P$iz9XL5rh-DCfWXX4`l}9OzI;Y^F(qe4%19mNPf74$+}}IOevKKgfy{mBh>eKklq*c0pj|HK zozCbO6ZO{!sP?|9_XL?kPD$-h%WQ4MY>)>s(MGC{Jh|#R_8DK@saw{f4P=)|t-#bn zm^ttVux^x{ovq(IA>6Pc?vbZ;)8RU4=BmR;%!EC_GrJ3+-4H8#B{ac(g zyT7BPJ_D>f5;aN57W~dEbp}?0hxiD!>kHOUL}cQX?X5H1o)dJgkU9yht6d}^58_7v%v{f=bqxD|X=`fRsgN19+GK*mzUzqD6hgunnhF_Ynb=Vs)#T+R^ z71`4@s@V(wvufXoDZtb@rw1=uSh24hMh=OJ+Q>zLz@1HUQCgwJ!4%%k+lBJG0r{m7 zK-8aYfHCcZS7=>QZ>BHF=jF)MC0D94uMl`zYo_0DopfQT58qsRG~($KRKbGnCR|JV zE#8CK_Mjp|$@p41&aDA6 z_W*Fjrlij_hFO*QkN-Y!UbqN(xfW1AfGtU?)81DOiA6xDHV}?^iY-Lqk*x*!Xco99 zOR@m~nJN;~NdFXMomXu86(DB zN)kF7l@C=CfmdtYYdQFAB}fh@rZXCf#5QW=VSKZs8DrD?=C6vifTf{nHn62*Nu1Y; z4S6Ru2iAXoSZ%{folB6NLRjfkVcUvl?BMSF$D2jT2>u=FLflX<5_iXDIjh{Kd?MxU!qXdirBjH0%?ru$6n36@GF9ltKndi7}05`T?Y9%glJ1LLiqUJo5RC##83??claRdSh6g zgdP1toV9jyyMw39?q?fC!t~W+tWaY{smWr}DzQB= zqzi$5Xt;39adIwhgRF?L>&K5a%sZn*UFO04b^Qjcu|^Ib0f9k23{79KvI`{Tsa6VX z=n_f+u^Qw2wnUJse+9@pw|PZWu}3Y0dnEaA9<`uPjiEuM+#X=?kmss@S6LzOjuEhy zN)^~HnHqZsl1B7mI}7tSe<}J5$&Al#L=r--$xd+3NE=5!DqIWwgXG|(I+wmjaaGbu zs7P2H2^(ESEI>C{1$R<6xcZyayt-B%CnCc-!lOM_(R8Cn0}qel?;}dS6_5<>D6o?X z$w)^&^nU<7K*GOf+n9IE!H$gL!SKXn=JHH`$ZdwQ^33B!g9g2#(9_Ibgl_;lJ}I1o zSkTC~c)17xjutcx9m`e2pNN(T`e4Wefe~kw&zB2>V8Ur5SizNqk|Zarxsp^+_ri)- zw1D1M+5Ufa(Z=8oK*&15f<89NqZ>&AcMEF5AUdF*U_n$-e*hcLqZBkXUQQAbKaRw3jT)UM5*|ID*(Q4)n*m+t)|}r%RasM)Mw?P zayjXd1q|>UboFZ*7}fQ!Cp_3Q9?`+5oMzSab$WMT&{& z2b(h4(IX~B(t@F|f*gsAx8v(~kq z03M^SK0U3}2HIEB!WP(^*P*OtmDELXaY4YHfO1s-Q`cigQ%6JXpDYhZ#Tjd4VO$Om z_-dW9OVi^2oQFAqHWBqI7FF3`4b!Q)RF2aZ@tD= zg*&dQ0D)={3H=D^_#3`iZK$1d^4i>qgH(pM?&fHwix(;Nc#PdnQ2@}0lvk7GPsZ-m z(sa?GT7~;EH=Ku`Or1b=S|KH20-XCXVttIWp!y+*Jja%u7jYcvkjUZUq;3lVeQMhL zz@<%ZXe)d2{J$W_!W79GyGFwSbCSZOeoXOqhvP|eD)^E0N!T72%}a%hc<^tnjPT)< z{qv)K`+7JbV8*2wo~PGVBt3^DU`A1^mqcJ<%8?ffC3Q$RSo%hE0GX{r0F*Cad<7zV0V8dJY1lQx zp9~{tbaaW=Nx+#ajPwJeF&w0ga#iY2z_<7n{W}2?$}loz(x3$_Fu4E2cdLL#j6tdY z;KH_s0Oo%d38)7*j7B0s&_H?eAV;E@r~Z^WvWVg0#fpTDanDR{_6S2^BxW*E`XzA* zwLQX&b`gqk)w&r9Q5J?XZB`a7gb606IS9lSu}nVd{2hxlA@Wp1?cEwk7|B3cYt#Xp z389WWVRW&Ax(xh=q+0@_x%bL3IR64R_%Rk#n0f z$QB7e8BvnX7MD#OtDYl(9g%K9;HR8!E;vhhc+!vV#zuu#(EnKtf$= znGYCVxeK6}KZq^T(A>1xi0Ckuo~2aTeWV2q$$m65yf!R2bxo2UV9ee<8U7H3f??RD zV3J7HK7*)Ppb-d&WFscTKvAdOl=L}4NHmK!IdDa2PUQD7uxKEm=BNT8GSY{_XB=Gw za3ek5qcdLms*_)^${O^%UTht)IaT_6!0>}WU}(Xx%}{F4)y-??a*h{X+nQ_OLpgxf zUOE8$@3~4lVgM5fM@zXV0FhFr6#AtlFW`Qg#FZmcwozVW0xzSodQ#zqk%Uy$QX>Gh zp_bkqdk0HPx@A8C?W{E;ZM(+-%4}o@X0ZVeMRU`LnJA8Sc_6(h3~_IfHL^GPUw~gU zDov|Fns6z50RS%=v2&h)JE8&lyg}Xz!c1#<0i|4TqPm*Q;`XI#-4RXl@HBu`N+uC` zg9jiwriB>WQ!Hn2p)4^&^{QD*=6L!p60{YtLx=0V%za+v-D>Ze^t^H zDsS^f3SE)73^fOZvkjWAhgcMIcxo)CAp`@G1#TzAk z!omte6`@ey59xFAAhq5k zzQu+B@waGBK>+u%<_UbHPjK$Q61-p`Yp6uRV z4q+J=H(!9HJoHd$kaW?4{V3U!&!vRn@zYK$F7iP%EXdS9P;>*zD&zo-iGyf_L3lDg z&xHz$P}Ha6VIee?>>(RdOUN27S+AK1LqN2Z9iawyNlI3M;2uBth&qZ}epH+P0?iP&ebU(6t?;9pOrpyYGj?U$zz8}5moT97~isl`$EQP>dNBJ$0;Zun0KPIgV6=1u;UGXA> zGEq5L{V<$vRw{~mP5kS(G{;#5h;ul101?5^XH4Ww5D4mi zh)5qd1uevROr*u~j?&EuCxrb+(7FXtgk>iU$_L0h& z2%C!R)6?9G6)qZPrf$ICscR2Q(SFx1j0NCxdC}Hs-8?jCRs887l3ltareE?)$85sz+rcMPJ!t1%F zs2|9rjjI%Ao1B5CSl1k#58@EyJy;GMLHCAFaf43P)Z#sf0;52%OsgJ+Kmmhs+b1a$ zn#b~rJh2g1Arq5sKt({ri1(^^8)|Rpl^Q^j$;VQ~qV!Ecr=P~U;5^V0lcH+{u0SD8 zA|5n_2?`K1YK=L?EJ&T$7jO!kkyh1zPn`^%L3HT#{AGmz0pMo5MSAMnsy-@1o6x6 z8$E%RSR~2YsZvLBa<>G!-z_*?chGC1N}|c64QkMaBPad)#p$k)m+FGZE>>RgvN8<< zr;Z)srH(pKm?P988>huqlT;33$Y~?*j=Zbr_t9Tj3r@S)vf$LhrDQ;kje71YW?0;o zWUV5CkDTXQ#^MsFQ&@^4Xu)+BntUonujQ(Qn~dVViwqR$iY)`TV$#OjA~$Cc5a*W* z&1yaM=T=GNkE^hgAY#fr8}Uora^oseI4s{C8qr7>3?tQ|RMSWR6xv$xkE;Y)_M(o; z;|g?Ju;CCAS(LpnCltF}+bt5$&AD=ExgAV}_9|jEamZ$9>Ne7D7^W+Xp4pU0m0osX%ca~BLe(>NOsKg za;GnsO=@kZ7LCqRY&tPtB^=RCxVI}=tmMZ^nta#cqy?3T;)m!}9uv{+A}Py24JF_c z$;Z;u01SYVRFr9k&KD)AF{0W*prs@G48%ga7!;@EqB0;hKZ@BPrjJ;hfY0>fB;g4H za5GGcVzbdPtCp1#O4Mi>Vacqf4V09KyCk%1IlxX4CCA^pq{3N*7(5G_5@{p`h+hd` z$}n!q*=XWP3~I$su`vxJLWCeBo4LS`tR%%x?lK`OtC6>mzOl&+2BN1F8?qh=`8Yxp zf0CGjl$MC~$s$C{wr9_#a9BIz(zPRq7t*(ITzUW1M@p!{3X-)PCwF><-ceAhfsG6+ z;Y()Nrs`$BPR|>0vs=pq>wvBeGYnJi2pVYc;HQ=Zyh7DUYCi}D zZRk(VO_pJb$yeBFpwYGDCMh&vRQ?|@6eq-PK&nW!nkVS6Y=j$p_2)4&n_?-r#dgXv z519@;1{KY~@f0$k+RM8((FZJk<2=(&9{o-Vt2zhKvl6tUX3`YT4Mq-Tk}n8HX5*H4 zkTFF+ETb914w+BT1@XYZr_HRTu`Xp2sV_mJ@pjK?;GSDRC^YG@`7<9GmW{?AIY}K^ zCaNIdxOaZ7(C<`N%*5|<1Y;#iXR~{(dw~}%+i|F5C~17VDQZ0Dkv$f z4TeD!LXa_Qij?1WN(Iz3E&h>$)@{_%l&+d4RYdG1o{%$4SfnD;W{gPEdr>0I`P>3_^#D;W8=HGF?dF2NA-O@efcg16wl0)J5hIXCA=yu%k{M36hK- z2vwv2l7a#%048e_B&Zqs!SM(B3QU@q5>0`1!86Al$zxDx-$<#>vMkG{9+9++EP(~x zTm&za%y@mus1lz22^XwF(ax1gGOntNxDfJ1%=>COBAZTAgt`XG7_|HHpcFP?`=Gbw zNYhPFVj;IX>I$S6vRt!;wQ-D!A3V2{tL89H2 z)I!u4p^S{Gp=V}Ja<-XjrmCisqna9M9*KU2!A9i~Qne^QJymnjvl+`BV&)X-^u%wA zSTgBkpSKGrxPw9f?xgs@OLTFgItpw`$Jb2&)?eF_J6*GN2J25yCInSMO$8BRgCu zwypGNKn4ee@QUyoF8o|W`%suMa9$u&5lagg|GPz}%tv8q}b9*I-Ee@eHhb%4! zA;=UoN*+{Y?jg@YX@Lmo$)ru&YW1d@=Nj;LQv2#&y)Ehl=za$ zyFMoR8esjU#aKkZfvookl27Ka2kO7BQoc{Lxp*8`(ms={VzET95l)~(hikzsn(q88 z#k5Ckchuo;1V2P4usvei=S9W$P^@BcW*W#;oOW>Cke?c8v5fRas~J9Fcy2Auwh;b& zrjt>+*Pt19KoLU`|LQiR1QWGjLW?Sq34$mI>kx$s@uUF5R_TFkuk}X^PHv>UkUYa!nbo?m50npCiRZTQqPElKjkR90-175z+8qoLB351=2*A}a` z;QV`k_y`R^S3$?-JA(N9oUP7zXy+ocN}r;G2ycm$NYSr7)A z!QVj^E@XV6GX~in(0M}xjwX~HTUR80dO$L&sOW}10LdKaS^D3G#UF~B)l4Vqxi@qa zh{QS!u(vPX7YUM5q^jfFmN_k4od?JYYjjr#y2Q0$0|^K*t%tZIs2aU5CZ-w9f%XZv z#l@5R@kfIO#oEvVI^}V~5Edj6I12)dX1lAJjU^iUqKa zNgUy!=MYF+^zFrNeAoFBLF6Xa1%zlI9B7{PL~=y8ZJ-kNuei53z~!Rf##0hOQW>0P zgPIX(F4g$TVNoG!2(9A%NksrUT(OX$9sP9R*F(_4NenFxbnH}5GmH4*5RF*csg?$o z#&EVsTV^dA&H$#6@$${faSQjcbbY0GtzW=T>XS?Zm_AJml{Y$Q85a1 zzG+lWkY!g!?ipC7=x59X__grEUlB2uT2l! z!Jb$??f6?`)L?qnmd+Yxh0jb#xv*Ptfrng1(FYb%%B7}15@=6#@IX!}7Bp>$BnFe6 zB9cQX7i898OB5UUoekzRzA7H5l4928BUk~fN@6wGsX`TR12GCyxMZN#PMly~GC>_q zp@YC2kXlujkV?ZO<=kGCqikDje=RCQBcNgaxjU_ z3bHoVU++>p)*IJ1jbVN-y2-Vw+Q1tq!FP8 z3AmZMor4abaSyP&8}IuUw*cIh83a(VY?wIz`h8sO3nc(OP%qz9jJe#o>`?~6QIDA; zRC_2Qz^O-+&=5I?MF{QSfazT<^1teLNVK z=`86^kqdb}Tko6`=P{HNQ}A4~AKIGVMM}j*RzbJK6K~@ELE_LJGo1%*RVZwcK1esZ zNh>{D6PcSzguX(H4RLKl(M~le0$4I2-WZ9@5;*@a!s-A)QD5}gE?hdH$!ME*)jE@8 zQl^FsTrQiP+TYV+(|Xs7CGDKSy<1!zsjAi#@@ zkR`GZKw5PaHd}VMB`k47_opgQ!Q{Ykq02gW%<4ovK>FYrSce&g0^7RuH^uD$ALGAU z=<9Ra?*8ZyF}ny_fBQ?!q>5|BIyzjJ)^H~eE}#&hF`RBMR&EtQmkL25 zx)|MA*4Vzmk%$kPsEeCy2?Y%pYUV~x)zw4<9--)QDx zPZm^=v~U}N{XJ=y5HQvTCiOf`=dG5YiXkO!cv#WJIe97{;lTu|ngUB}iBUnp!I18q zCyboa=EN6ZKvs&Ox3bYj-h< zAAyGgDK9z0VHNwT@{IyT*((k42{7=P3zJIqIl-jZwMi=_sskbth^3B4!q)(qPg_Ho zZ=Ot8*UIN+v|ayb@4RQmyK#zV42o2H$5%^)lFAxL#Y7s1iHeYbR47^87uQV)b z&`gMD^nJ~gk1Rki#cK2(Mv@w+fD}^ESv089P#l8F63POGBkU1LL2!6tvT3DmW`fdK zeck9vF z!hC^-g+v*@rjyYlCV}3*=E#u~z9Hy1NG3T_@R=i_H|6#Wqcz*05I6{}4D>dR;vTX{ znryq1`5H`Rf}t1sN@f(Bxiwr4pFv}qqJce+#p3IAmNP+YN+FZ8)lp6sX5?M3j~^@wV3G&sfhR)sYhsbjqIqW@R>?kBMg%4%xCSes9?$YGNOi9u48qrHbovKDuNh*Mw6ohFePICT8 zge_+-5Gdl)_d>z#1}CiR$Ymf&D|Da_4NEa9!{=OWMC)Emw+gG>XVa7ZQAQtZf@e@H z0F%ln|0>ERQCK;yqym1xP_WJ^TM98{sbdb%hf8TsJMt$%seHXiZPTmsQFv0ubD=bC zXgPXfgv<>p$Sc4y0|IqwfN6;Dq77ons^P{3xupX}L~5wR2UrW7!g#b~Qg;GD#V1&x zhTiF*-YEC6e4;&pchrA&0*x-9c!BTxph&6M@vsUYduTsu6 zRkdiOf^H|gAw<6c(Nez5VKLE}kx;V_yZn4Gz}Atn#TJ%PSMLg^!?~JL3J#?$&QoDw z+gOGv)2$Rlm>?-pqva`BkW>Z3S19862Vg-V6czlD{(+(Y!1J2Iu4^5&$Xwbcm(BEJ zkh86u9;{jMv zgmSps?i&nIf8(A_73NfNAeiZ1X!*x_&NB}1BZT`3{C?*|uVZC`gc4*;DyzFSiIXx2 zz!2YedJMPu)mwP$6<$d4fuO;&o^e7(qyG}drG2MF2pqn76@7EnizDTdjR6m@(~909 zGJWK+ZVMnLG%I8dM8k`j8VzEmX^>4g145W=5WM2ygG>Gs@>YSQu~SfsM%;nXbB~HI zjEsTPfgF7jOffi}hE^arm+Bhe2?*GP@Mw^1?L#>HGNtQaJRm%^kH{R^J$Uc7{$e_ zV?~R1H5u)2lu&>a^%R7ov=zhaZN_;NVyqzwmP`V7i6Ug97dYRk1d!lIFJ*lQf83;_ zExp)4H^g0(fKC;Xt&j|Y0uKt?EhyewYE-($xCpNaVc$Oa?Vv_2Vdw6_Eg!wd#NZCdT>u zAKM62@aqZl*hIes#n8{@R3RDMt`Uuu6b+0Ga~5$Q9#u%A|2dF3XO$r z&!5uZAw;)su0t)&ndb+_AjI-gpV(|^t@+t@{20Vzoa`~-xqXd&Kz9J5cBuvydv(K0 zT&T#LST=PCel=d@2NN0cfK% zZYe*a>E55T5XEUGLhq9-#QALfWVzg?;;N1mr9N+kRCLEe59n4rF?pTYA~NDQp0uqK zRIUyr{tyTXsfw8j`Nox&IH~D95OgJ>&oxL*>*8eH)s%%Y)ge|pE%;RIk$@yropHk^ zWh{2AN+qGY3N<4U;0l#=h@sJq2vb#5>1WEpl7{`jO^j7b3md=|kh_-vV(myxSjDzD z4fT=o5a2ikdYRIq0uYWZFU|fuk^;K{>U_9+OU6(yl{BZ^@uxDc6hQ}FWOy7Ap~@;P zh1&}cO6h_94=kukSI^1>C*83W87rIX5zR?7j3-%hD(wwqVSX8$g@2rBu-y{yHJ+7M zLn{r6l>!y*U6O#Fw$DiRT7=_EmQ9#_1mFonJR<_q`+x5nT6lWVUs5nX$A9V1&P4!u z9X~ja=5~}oDIorogj-N}%|n)tYGXYkg1|Chu;2lp zz)zO<&;>O`Saeukunc$9?ncM@mMs%8pun+b5&af4Pc=I>OVBIao`gH#K{V3?NDNgr z+USOe`}gWRWUx&bath`VU;z+W4_)k`fbKAKwM|auYWF}KJ{RSE1H~Bno@MbQrTx=w zha{*RWquW)k*Zu=g@I^#dM9BjF2OM#Mu~h_dakyz>QE9rWCJ&l!|Y>whk7IgT0R=h zrOXGbYD%vvSrlAIB&TqJ0=F(RN#wb?MF=x{T?r-=Vd^ z&_VF9riy?BEDB$NX5rcSd|DkBktqnl7!bSi@^x6XP z4eG>zaV&+2TjE6H)86tZE(?gCG(3>8sts8(c7P#jYIaePgnMU=?=M{aHPXO`Jp!S5 zwW%d90UkiQer4tzO<6_rRkbATBxZ$RPeBb~&w*Wo{Vl`pN$la6ntf+BQ5tsTht^(4( zAaW*JT!t9k7?-+=7Udvr;q75G8fn;33`5BbghitwaK>Dg||gml%$$i+|VN>&>7D+V)&t}mi9VMz48zgS2}qW~`o;p028 zaAK)x$Vx15mqIuzn+=VN!sQIBR?{?CA7zwqboI)f3;cCl<&k*zP)Zp-!lgL-FIJ3}wVzzN3*Z1jH>xy=Xt1In@j7 z?6Mkcy3p~XOapX}&^rw=760WopS4sELl0gFdmGQ@@|Fzq^J9)2d< z^^=ACpK7ZXSif2|6-pl)%+w)jRv?;o4-2^HxTr$;DOoiNisDqF1yb{eBtpSrBNKIk z0nSM?Fu+QD8aj?Mba*&b65a=zaXMf z9aB`|B54fSgO_Nb*7>s=JZTXFCjAc%N=Rt9?XZB#Ekog>RJfumHyqmp!B6#Su=$VA z0Pw zRn6KAfp{NxcI!v8I&TfYCp0a@e+6qGgll>Q!ss#)53tBC$Lb^s1`cxQ#p6!_YBmz< z%8dksn9#DU90O<*Llemqp(V5mLxg#Yh8gB>*jpGhHcMdEsXdR`xUSJK^p@C z0Jj{)5u!Ct+e}0jFMP{@JdP-~@CC&qc8aO$Ku&gJ6jp;OC`*Vuy?IsV*3sh|aQ5Oc zPLO|wOnLMdAPpN}Z%xg~e)OsiCtyPUXWGKCGFZY95=22a|6yEcWMr-#LCb9TjnY6U z;smn1)U`sVoM0rH!Qz6}h!D1Phhhx$LqRWw&>Bv($djIT7e=^p)?<|47}k9OYg(1g zM^Nn8cCiZXR>Q;I;^ec_qPfY&b|)Y8dpf#U@;INX$fK%Unvc>J3p^$CrtvZXEoOUE z0og0`^Lou{!KCOThO-{rZurY)}h!>nr45)78lJ-1C|k0*{x}J09;Lu z2O(&zg$(1Vt(;GelbE2KJEzsTC(#*@}ZddW+DgQ|?LA|cRFmv_J;Fts{G zX7N23^c_s*x+p4~g&uxOL?5ZingnZD+OsN=pO|_zUFh=&DRMVPy5nTh;c#%Dp%ViX zVPN0Q`b66NzzAuN;i(}S30`8exD)IV|01j{v`I0X5G?|Db?6S|{wdP)E)j~?NMNpD-;=fIRAa7sB;-mv9vhhyBNlU>0xqvB~8xcFvG|-7`CuQM=!faF=E#QnP>Pk%69yRLTT7*D@ zK||m+nLt%V03I5Q6f}{GfrMkB24~`IZ6bxd}9Uu7vX+0AEC=8Y^f$;91olmSDPS;8TMw_zOgDAmEFS;oeO3+9evF z8Vmq?OsmKgfJs(>;Y%pc;Y=I~kTViriSUKT64!1i_#9COTcLpx`(1LuoulZF3darZ zmC_6>QifrWE{Ej>dyQS$Go3;SPug zoX=|&XNd>GmRuR9M%SeL7V}j)9YXpV7&x6peQfn~*fdPoR(c2-qeJ!O(U9lBzkG!N z39gbBt=WyxMQ}>@8wvZ6O%ekn!)bY!$q@~cR67wV=VM9eeD)?SpnN{o2~k!PWlY6j zB833f%DAoopkXYiq(n1MhcP^S5{w0{x(guu13Arzpt6FRLtZrBYpk;0HO7dDxw%$rnM)NUC35&NZ}}XP z=?Ys^u%;-ins~!AhQv75LMB{i%vC+U1Ul*MvBW?vZW+;M?1Va-K??9(o#wt{iC$`?< zN@hlI@u2cfL)w1)6PIvk`j+Fz1kWgYfJz_8Epn~Hq8q1hcRgHy9jQm&$^=jdtD&|g z%kDsMN`IeCM2uQwaUxoV<*?b}FFXrS)+P~Xs9~5CVy9<1g#xkiD8vs+02BNsl7dv- zcS43IZNR~=_V8V?w6>M#hKmItnX}#f?^p)uYp^mp{y2DDd z*OEHc!cstxvgiUaRu>zo^Azk-7mhlRQ9`8zl>lPnGsh{4gkG%D*evwHW?(u@QW)}8 zIMB#`4l-E42GR_}_RiDySldRFzr&zRgv+#1FBy@@>J>8oM#yr|`Zf5;DF9tY)~P|_ zH-W-~{q+cUz662VLr@AjwwK|%f>4UeNvnbu#X&;oG8p6U0{fZ0qospwP+sR%mE$p#IZy>D(m7i?L-zSHEZ+;bJv4@YLTolcJ2c+( zVJRmU_G&xWZQ<-e%8OIuPsW25t}W!1TjWZSoh((NegmIX!_xy<7(vVH8jzM_0TS=n zb4D;;Qm+$4z?(Wku?ur){lHB67KC&O!ag8tswvZ0M`}eK3AR||$YF(nWjJ%dP?D18 zBY99j`uB##@3%omlb)Ej0z!aI!_|zAB|F8q$QMQsN)=$o5EFqiuRsa;JxqxK)^H(l zb1ZPy=tUlAn^7 zY)B0O?MFhZ2G*F93Iqd5CSiCo0fcl<`vs0I1PIB?LA(|q`|TD9v_42L!~ic+Jqfx7 zC<+50g$j#pf{|CsuFij9{gz>hu1izn^AwF`vDS{>Eio`9L7t>TG#rz9yd0Q*ySFeF zgnCQqXfBaFEMmo91MCgCENJ?S*2Fr#h@dbD%D$S0A<0BXP@APv1%l9~cJ`NZHH~0- z2~R^d(2U^c;Yk-zK0zslPTS~VCMr@xy$xc&q$PkB=8K^+Cbp)75_r%sQbUc5&3%l( z*Kue#^XGP~fFrBa2n&zcB2Uc)HQBk_2n(*<=;{EXF%aNKvzaalPhI?D>>H5MiUpTF zuu?--wl|0`5_AI}x^#ese36qLI4Y>oya~3(q#|@|ViHL|v6l0*rh`;Lq&OSJEv|ma^$TJ5S z#t`Tyae@v-gggjv>JVpxOoi~_UobRy-U>NWGndLc>eVA7Fqt@~gE}j2!6Gpz)C4B+ zPA?*T2(jqCgIqDenYHwCnPo2kicB#oRM&?eY1tro$XVn#Lgf(?GRw|Jf}ZF+N9lS) z-0GnMKkM}AZE1li3-3|4sO-DUUTeN>XA$<^lg7)N=BS*Mk9xoLs^vs;6$RUGhCQyN^LPN4I-h)a;iPSgLWThuI1X z4L9I&ab52=i8M^|ew;=5PdqLpenpi*N#~A@@`oY&7r|iANP=h|4wL;V$pjAYG7_SF zX2UccY_crpdmy3>_@E`F^g=&qZxT4)z3wp>iAqa;kqUZqiwCVi2muF$`9cw9f>3sN zUc|JiK-H#SpT=99mL1~Qt)STDxWxh2#W|#uR%0aIcGZJG)?_~;%m;va14#QKXn)rt z8JvCvTLunMs}6+wI-Fv+y*+r85KYTF4Z`l)AZ_WzlP5tHnKS(~F9(Sk;Q;vM5rZ-; zz~P=JW-)7fg2NC&x5~-PdK+`i*Y0Z$pnm@nmI_BGR|~}WHIuq7!eW?CDVqsRmXHn7 z_9|Rgc5^yF=v(TD6gxYd0=U771BVO)AAee&azp-PNTpgZ7Yet-1(Ei5WrNml3IEPf z*x6J=l0RG6$HHN*zzA=Fo9>~#5K3lY2zga>!klGvy)=kkkZ>P)ycTtcOOL^`00l!T z6~pL+=yh-^8Km59i2&1;0KUVXdKEa`% zY*GZi%g=)mip2GdhOXA27?=V%zf=j3;M3)LjD_ewR^7-g7d<1ukTS)0By_wzqvmfo z?jUeqsMm7WnA}PPZdFSI;ebO`w$5P+x~^jT2S^`50A$y4X}+Gr!0vH;PG$;245TH( zm?Cjh5pHz@IS;5ECUCY9SQ|k~_$5=L^Y6Nvj$yd38Bj0*7CnkDB57S$s3^!6vXT2` z4lQS<5=g!(lc#{K>r~l#qm7{a2$FxP&~z5h9f+F5B4-}uqi8}Ts6`M%{n1*%mpI}U za(LxMjLM?{UN#fn6liP?X8mfIp zA(fO8iD}%>2z0xL>QPeM2wYgLmYF7Fm+L_OtQf@=e3~)hQfe#hMG4`|dXj_6pGO$@ z{)=U-7>o^WeL8~kRP5X4ui#}$9jYdYpr(@Bu;NorV8y}dfongfQN|?XjK;3PTxZCk z#Hk~kcnrK8deo*YL;pzNKoM^zH>3;R5~ksv*M1TyOM9^x(`Q0Bvg5Kc+F2nsh7)rO zaVD2CtnuO_kbqku6OJaN^tTj75#kqG#QVzjBsc5apdr%|iK4;yC@TP>i>{1HP9lz1 z%?-1gma3Ntg!ibe!EYN%ae?G_Ku23ETQeXgWJuNHlE?bDaEKzVu!{Nc$t>U<>awxo zAa1BIq#G)2kDtb)>QdKcX{Is*@ZQMi+K4Jgo)GZ;Db@?3R8HVGrq+u_NZ>H(!KOw> zrYS?K4#439)QntnyY?cpTb{jErPnx1lcbofdiv9z8rP&jdnhX3gehZ{5ds9d;C2!u z>JVjrt}Kc2wYQ8EF}|pl^m$n~i>59EDgcRG0@*=U`ZFN!O=Y&ShjLWgL-kD8ln3dP zZY~09#w%t7ti)Tn7J|p#p7DBupg?&jMn2Yb+5s`lR&*CC+Vn#bGDjW=)=L5?hW7I9 z5EpmijWtDf0W~n$0B$i0k~MJIVgQI6Y>?6j+dLO|5yM#&u@GB+CrM2aJru-61?nZI zmADymvZs_O=uk4T$LKdOS+v}%wa{K{$`NM?@lpSy3QbLvwYKxz%4-`~wAYA^vv zlt9u?=8}?ytAjGr@O+%ezy^18<;+n}PadR!pd0UiG%QjLxLV0qfxy)Q?rYnaYRt9` zfF+0s!UQf9O+rC8#l$r1wc>+63WH%9HRS*fQurw)n7Fl=sA)Xi^mfrAIrZwrRCqq+ zvH*o9%`(s;CV;90evXM{-uVK9wnXp+9YR?i_zVgWO@?kEAc|Eq?24xV4$>p4LmX*H z<1*jmgxzUz@M7$L)Nr$NKLT`M18%TQlei}eQyJu7ye%C#WUjcr0$9~_;*$Yr`IKuJ zi-xxYn#kQHt`wC_eGpBPr7Jvc*%Y(zKrMjE_|@C}k+&}9zbRFHxV zJUp`op25(tQiK%32Gjh9TLZ(%ZD>C~Xs1f>y1}?KB^)e2P$AW)in8PXBaJd&XeThZ z4Cb!co;ZWW701jU5QU3IgPql?Not`Fu$RMD2VJNEMWLWh16hFjN5fPBu6QSSBwId2 zQfTKOa5&P8(yZ%xZ815Nl@o~X7mG&;QiR3f1jNda0DwS$zv-8@rU?!$kn(Pye_mNG>pxf^r>hW@%@Rl zHWcu=95yiWKdLnok)|0$C)MSt4H%?q#a6m#6cT;&1-UlU8Yff&4pBf2XAtrc2LvZh z=WM3dgo_Z4)f?M}@-7_w&={J9N~iu3K`j-EW1zc%ydW8;m+u^Kr3_6;EiZ$fC$QK# z#M*c#CN$9*9|5NwNZbjs(FhPJT2%m1c@rykWxG} zDe2ln-pH%SblnHECB?us32TZx_t31Qrc!C1LfJG##Q7O*Hah=U+JI}QD`bl&#^@fL zZ8;uaiT^R|RQIA)3RTil7j9ACMxFb)xaY zaMcm(MQ!*IS10tj1&Cg-gA&!@bUck7JB(8YRYRc;nEX~_3hxBmZMULpV9^&SsvW`J zV^AvT#C04Ko{c7CdGgvw3Vl5o0IW3z!ioY*srJUxklK+UjT&3tnd62g)LS>DsF2OxG5IT4 zie}`Y1ql66@^@q@Jvz&@gwhdPS*!s+Fhs}GJ|P;4mI{h5WAb@l#2IGlLWpYa$ikWX zVO}$dXRRBAJpNM|RzPuFduy9wK;MHImTO(6(!Cd&04eq``o*>KBOO%RQAwoO@!N{c zRh(jUJQleNr0F^(VBuT=_ItZbdFigW_z;U0G?#8n;S zmx(_p-^(KlA~^L%9I46Ys@e8BLVNihexe8dS_nD>lZD z)1AA0Fvqj*t1GNnQCOPd$3a5Gf|Gx9aLkp~FvC{XoixyAK^%2ujCF(_0uYV+E0Mj0 zlMK4Pu@FJ~XJWMN){tc<5FxWH&+RXz+#(A0(002>WWB4p-$fNA01oCzN+VMiaBB0$sd*qh z8leru(W>_hvrmTOCUFY*QfiGK5)SB+FcAxpMq;>=){^G~!*lq;tU$yBjIWTW-K>e# zi(*S8Rz(7?swqEITz@SQ7D6jLpnDM7S%m0hxn(f9=kFyT<^`d6IR(M1jAi){>*&AQ z9xZY=h*+S|h@eUqImH0)tJi_sVb%|)>~c~36mwBWCPycTzKc)As@c|td2~RxE>w!S z?q;Q%h#ai6flO>6pMcn+38d3v*Q7)BV6}8*YNgN)pLk?)z~2N+<-_6v z&C~vUN@)fu<-u*^wB+d4ts|H6DMw60i3O%Bn3_roDHLm>hBVf+h}HaFl1mg&68KfW#r-3VX}nYM|K z80l)BrYfCV0Jb7kATwr+NK@}=HW$H02Dw%B;Gm57zMWtySka7)fTM~vPdc7llQ9(8 zI4%Y4p{4nv(Mp2xO+O*-XDIiTAud@_SV3HRZSoo7Us_lBcn1i7iKwei29I@8LIef2 zC)zJb@QZqr1P7)1s3FzQ z5}bi8Au*`e1Y6+&p$G)N_Mx%|+O=F*GF95o!}CJ;Rn{FNT|(txwH_X zcBd4yx$pMzp~vFZQSpq1Xh)|)m>nXP5Xx!m941D)2PpkNlvM1QlF`h>n>I74yt5Y} z9JKFjy^w`=k)SFBcRl1p7B&FOl~WenPLP4UE@4oHY}BKFF3ITveIH)6{x2CzRT$Oq zFbEaR zU=vj{ID<^V0Hi|W`z{v#ERBLqwy-c?f=7rN}8k90RHJLh3b1tqfP7oy>r`!SO`#&k?wRRLuiWTtUTR zuD>fT7KAT`V1Cs)`-zj#fKF_i!09n&2PH=SwM#*^_d~)j9jH~7yt(3U7MdWf2Wb& zlxj(zIBLtu>pXOZ#OEbH9e&`H|C@OUj+uL;&bUa z(Yd_Cr=lzi1QVn+1*V~Yr)ol=*t-z7LF(*BQEd_7yEYQjc`UW%>*J525*&t*F{veh zuwDzXbjHiG4x>RkZ=l9E=*>mE`mC@c&G8r8yC$&IeCS8ArNlTgzx51mA1EU0d5HFt=un85Z zmZeBY1u{Eni*zP)jYe>N20-@-KegT)&z=X;IP%x#^3IOt)AZ^=J;|>-HDxwq3 zRPh7z;>P(zlR&`1kOP8sx+wG#z_tdQ(@LULTDMYGEI=Ei=$yEo5lL$&*i{WPChatg z{$(L%J*jNoSf)ZIG9I*sVb@%1zL}JwE!bd=B5ycAJ zl28!JND@NHa~nkjrm6HK`jmo%kufeZymPdfp)a1#VFe+^9V`P~L0_lQaGl%-<GvXLlXu`M&KGP9_b4=P_9?9?ZED#)Hh zWDIS8YNxv!NsFoG`2;_3;H6*SyS?ur|im827ki7->glVwH|JVvriS z#l0PZ;*>2Px_(UBW<@~Yg7P~A!C*1NoX|*m;ohqF8=;X~T7%k?_L|NJV_K-ts8RJX zL-f+ULO>KbdULI`@GeZ<$3jq4Rd2BK<@s^9%Z7kK&{>iQIqj62rIO$sT>(CfV#44^ z(G-;x_WHnFmQ0%}Z}*R`OaLYbyPtaFYQF}{qOs0M+Y!XCR{MmCq;#&9I1t}fq$_7t z{tZcth-pz^5uQmM!8dRXD^OUZ+OnXb;CXuV6eVdsi-fT~=MpSdfX2!UnAt^;j#67A zpo|Zin!xr`ocV*kwH!P2T=eQyJCWe)fcjNzffl_0q316fnw5>2-Ldv#{A>u3st|un z4h0oz(&FO2uG!87(Je$IOfK~!0xwRZbAhLx4+EM~Ar2NV2^U30GHYjIpm8<~T2vl{ zA#y*cjHeun<&}xPuB5D?Jd$owb6bjz!j{X1k_k5Fx`sO z3cT`)R0TuBvsQsvQgFlr`)bm_3gD$IO_a9sHKcuP5Z&JB)_#V9&Y&mt3Ix6|YwhOQ z4}+SaX?pF69zm7dItaW2leE7vYU<6L6yV+KP<-WXPf?4=9T^MSb+c&86j~d5C&)x* zhfewzJ5ZdQkw+YOstXQFi1i7nw~0UwB5aDCEiNOsPoA3_OR6X~>dA&js#JA5uIG(b ziOhsTs+K;YpUbWVm4Yy%1aO%=dx4aT*{z(>VM)Mz^>14?@%}&q<_}1CA3r{Fr8QAQ z1aJU<9*2l7uc+`a!;Q}Y6a+*?qLRI8zd6;23>0G^oWAfqm859vIhPCNc zHW~*W7G_#Mh**H|<}~VpV3RYAG=XYjRxE29cEpNPF2I2&MAql8zwLsb}n;!CA!y?nSa&UQCJeEx4MqFXbYDgX~9CqnofToazOsat`f-CqM* z3SeM~4w?e^1GmT_{S`i;VB2$N1hQaL))Y+(Mm=G~ml=^BrA*eOmz4n3#3UTeLIvxX zgA|}3OSE>z)!lOi!r6xS3O;Cck5Et)t&%-AqB3rU(nO^d$i(e$*DQ;Om$hO{hPa6$ z!k&XK+q|@K9pRSAZm47kr`?o=*I13}R1dXmUXNtCz*-?@Exn9@9v$hyp6zPnCXEpc zhD4)-O+N;9N~22e0Ip2hhX>)72PxG09C@}%jsenPBAFN(XWo@T=oF#~m~Z*ju02^y zsX?yl6N4SvnO1fjZ)(AmR*KY{7vQD}S_@(!D%c^$Fp<^QbsU z`#kkGFzJ{QXozCg$%0`b;a=~H(I@U)9WfOcsj=MAPL%^xghu4Dp#%j0MnJ;*OW}$? zQT_W`D!Sf~88b1lbkdj^0jPf?FcKPDaE}ZRJ1xFAnj_pfx8K>C&k#(XIg+EoCAF_u5>xX{{)E8=zPO-2nTOTJ6ARgwZ1o zjLPjYP>F)$J#kg(hJ0A7qBXENpm7zv7_jK*2s*e2QaoB1N=S}ADKSau=9CZ+h!VvG z1Vy7`_*UWxOn#lkR>@oKgK{q$m=9Rf@%Vmc>5+7>c3mtAbsq5C0F78fLL$N#a>V(u z%auizjo7I`gEfe|D!}AY@o9wPfdrtqD!I`f#1;~eTsrKI1K`K8h6tyY!=B=ac!UV1 zmM3JkPrJ6Im;h^yD)jctpB?pKTAHbes0O`q>r0>?3RW9B5uYdHsP5*zdie5i?N^!? z4pYodIZ=38&P_NV*ad*V$~4^#)F>Y6m2kUEgKZ(Q92x2QRNfYA9mRH8#MpNISHnk@ zqunM8kdDGMQJEX8R=Zyspg={Ad_z(_iU2wLF)~79SuvnaUV|tK!3jYn9UY_;!p77` zoaAeF=?t+vnyVuR1gpRIZC#PJ_eCxfnaOB}g9x)1+>c~8F^Iw|NsP6`G_z!EUV_Ik zB@|KPVGPVc8TMdT;L-A`d$`FmQytTOHy(ET6ZXZ8{3c%B@t?O>3mtWW*iDRA=5?^hrlGFX5%su80}>MK%o&=6$cU=)yllq5C{ z{5w{G{#ih)-g%YwQp&^pJ*+Vix_FK_Qkl`^HZPu}1*uRG7slH?AdBXq;FfU=k)g@4 z|KO=7mUz0I?RdYJrq+Tgj833hwLa7+GX(t+EL)V(NZ)6C!wC`S)kA(r8*WIDYV$xl zUVRrB4MwK?U+S4CwM$UM1%T!s*l}`He&J6T_fxlE+&4|xcQj9*coCBdiQ;=K1e2ho zYHautqli!f)M4D6SYo47%~KJ=0hke@7I6B+%7h4zukMHvMfNeM)VsY<&koU>$_5HuL%AJ zj!qFMnL78TJQ!H2F*Pwy8!97*fs`=!5CR5?OBnt{;!=fzmAnPB5>gE@q2oPjd55ng zEDvj;G&1z+W7+*{bVh`!0kmk!fDo*4`J+RCPY@-=U+*^~^5k>9X8v<$%>y*y+gj)d zqNLYQyKX5r;4kiics`-D)&*o0_M5{!g7Qif7zBes^u|$83yN4Crvx*O^N+z`rI=cx zOWuuXR0md^f0bhPf^z;~akgS%l_HK>fE10;rGI%rOwj;MDPFN)5nI#DG_bmD2XAc{ z%SGyuQ#qBIm!*`I;!;OLp{z;3qZCy zAnaO0YAN51V!*8RL%9sE2g$ni=5_$0p7v+}5GqP2#{)&&3?Wj~CzDB2Cn1G0+@)oc zrfM{bx(WflLNR!1`~EkjYknU9hbZ(S=_L|m+R3K!Z<@t zqGPnR>hqC=$Nq~3{P^vbY1wyho z#{iEh9Vc|yn(fXA%Mur>t`VS%tjFvc3S%BqK8H=G)-~rJd|G31;NRC zbrhl}%|KswgV%zT@w_x+DUeLk(e$rE?pNrw^e`*nBDX*)R{pfHA;B&!=NJhBP<`m- z#rN%?N{yn44J*cE$cS8)!$QJy97PJgy~GGk5lQHVxB>e>)DI*l+7#fK0JH`ADJTPr zt@vf)Cji3YqFJRVDu;2R^byz&>0-tu5*qRgy0u@Xdj1eFag~ysevA0o+3)ES^e{;l zx_FMhK4RF#E_h{D@gcn}B{K_T9?cP_1nx!QGn^uP>EK3IP+~dRiTDe0Q3jI6$Avf; z7Dbv71sepQ7Qm$`Soc>MG8pX=4{BL+B(3|il@zJ_9tN3-Jz;VkjJ%dq36ru$UVMX~ z$A=N~LyKpWV%;W&QwpjkVsM~wBaPWLI~a~6={mtV<2!`HGWiwj5P2E)Oqj2RlDzkU zm9;J#qA@3|&IrgKIOnGEu`Z1wtu!QeYItq{ibs?&6iWY_GMvTc(2#x=#5}UOnQ{4= z;=`R7h=C87-(QZrs$%__=hFkAo`f*elaLw@0A3LoOZVIGF<{GWJa|n^fdjl#KpB5v zx$Jg?n3^St;gEybgkCeiNX0-CxO`Z_!3)8^7gt(>(gqh=dtN5mcNGGDO+qnbHOAB3 zjj-Ayui@VW`)cnP9#28f?NZE)@R_LXXed3133LL2)-#yON%HJ~g!?vHluTM;JRXpCek+;?_Vij~Q$`)jLq}W_v8|CcW6+{6lv83UmN=ROxn&g= z8t$GUeJDi$j)GFCP2u~5hgeHT9v@2Kbp;}T2uT7dvw3oDccP|b-YFshI-`nQy-aE> zlJhZ8$|L_QeGL-U-0~=mMmVc<#EdN?=@BB9OrdjHa~)YQWX9G+Nu1>%!6YaGIe>XA zaY;09^bMJa^WUoAcpglK&;L@O^BGsyD%#dk1#(7 zG;D=xl)ee4-3{?=O(fB%km3`K+0q{Tj6OWl^lH&?M9n&{B*2j9yn6_l3~59JR?{Z4 zVMh+Wh`Vw#UY8SwomMdqLC#lvONm|^m4Yq-Dv1V>6H>`Jk&^)Np0O2AvcmV5*0w6U zI~?VBtD^qLr$msgVWrCx{SxJ*k({aGN>|_;$CMv)M&Xf^81~+@>z4CK;(@YYy2R%& zNaxn<8n`YZ2EOVDc+n^&2&oQ2G}x*;>*H5JK3GreNj{rxOtX|~i4sq(!)HMzQnw

xzzhbdsftwQWYK$n#RWm3WW3u`*saTF1=)1 z3f%nYV8=3-;y=9Nj>1-3eQ3SKaV5iftdip*a4?&PF6@C-U<0Q|{W3c)7?x05CmhA~ zm<*&^DJlgd2u5h9iH1P}m%*AwiA9>RtwMbm0!t;A({`XY2pZgIv@U@m;F%LM}?uZF9Y?{ zKa8c^8aF83m~Il?=<5R1+rn&1L}&n=Rwr>L@FV*J>O8~PDAAi3KigfLsNUs~rKiA( zvt@8Hw;^)!sOD7-GN{n)E==6`Pe>CV&`CQxm)z5`IfHwF4g1huI|!z7wKAC~$aEBh z#VN`COqHrqTOflJ_Tb*ZMq~Kp1B4E0a*2Tw8U}99~ z-+IL*JnxS5;Jm_HETs%BvC1N$A!#Lqo+J64ezRl|w(1w!dVs$O)c98<#PZ(IQVO1* z_gp$r>vS0<4&SE@04Zk0LrcgDxpK&KjFoK7TKcGdJcI~aByCP6-!16%Q4lY$(?#{< ztWbFj>+DyoVpfGfM<;Mu19w7fQowYksW{(fjUf=Dfb2-w7mF4NQQ(+JnNBT)N(>^a zDkTgKEgfRwjE@H$MmCby!Xak^q?Uf7KdHVkW)$5DUo^=lF&`GH`fI=nW9=#s#I< zOCXZ4adOZiMRhstkI5q)^uk!|&63J<+E6Jrhyu>F)#rpmZb{0pu{sH`Gw$Xat=Ff+ z3!14Sl^L`gekuIRu~6JEL}S&NrIf~ef}Av85_wG=AQ73WRoP#t?#fp7SII5S{;hLK zYO-UVk?O1g*FwrX=C1{cI=bk+0f-cYG-sHMCt5jK2x`)frUOmL--dRCx$GEvYCw@F z;lO&3AnQXJ7{xFJu?pZz5{7bZvNPwNTfS~3X+*k<~KoHRI^(0|)MAJ|!wZ}@3)RUr0nYFCw zMTf)-W<4eu!(*0I`9)f`KC?eu>16B;*hCfH+D$ksYmUCsoaxlB3TlQS%G%Hpc&Gth ztd-EY49-bBV*!&*FPE1&5S`N2?1=S&RmUozCW`33ec!>vWlxQorlG5dCap`kRQoEl zOHD7y@Dy%1zPbVV#*TB1gaW+Bb!!P>MN_j0W&uGp2Tvv@w^b|sgfLn}n_kN{)sjp` zWF)|M=9WA+DLyir5U~Mp7t0t*bXkwYp=8-PQm}w2ZKEtZLp&)IWkcA2em6&1TB$mf zx|cKjnd>HCB!a-1BqhwC<_(5}V&EmLLwqGeYnrVSDw>N?1Q;+nDzo(9>By!WE5&dw zL0W3NM6@#25RNa=djeAntCb7SpDr0A&;W1e_Ks^-Ok70t8N*5zIJ*0Uyz-(>9wf@M z6y8PyVOBw>U%fg6%d!Fg5h?jj$zy>jDG$23ekb7e!+Wu@I||Vk9^u z#w*C$G=UdLXQx9w92qQj>N5vX^&l=!v3m%}c_rqw>k+puN{N>K*$i*!P3COz&5tB5 zIRK(6Gxg<}pYd}8N!{{KF~ZOh7T$5O_n$=lF3J?PXW8TIqHdUmOcE(7&8RQR*^BfJRXvxz)L1{z;<<#Zk7_fH!mDI7Z zZe@Sv9QCoZ!;mQr>_B#@I0+vSpdZe7)Bvpv!5mzC8W9NY4n&Nw(SKsvR|$gD$^vvR z(a{$~wxCdvyKFf{4B-BQ6~#el*y|NY?*Lho8Rupwqp|5kbw7Myi5R$uV{oQV<)wdn z82DMfcR>JVv;3fKcSBPsG}yfeF^q{sntY5sFc17wCJzg$Pnbn01gBuufYB7djU~Ph z?RivcK$cu!1&q|k5(SOk=_&3gtk}y08{07P6nr!?tOUqLj8n~}EEhy8FEijcfn{+R zMUdf&5QAi329eun(~%RvSt@IkAs=XXEONbZbrUJLTxL2bFtp`2#4WOvf$7q{DO4mf z32i0_2%@NuU*Z-3L7oUV<|#TW$~#w?tFkJP+1MNMYY{piq7e$sF=6*T*?HcHsRE4wSc_e>S^4)^56i-rfX`ZfN3B%&=tB+aFF^1ymM9_#+13O=;-)ilLxJrlG_Z=5 z(vLcT3$-WXh;s)`fL=u^w#eD8;ol}MB+@D4sBTBkzX-4uWv?ZXY1gL7zzKbOJt}=BC9S;wuZ=3BQ;WJa4B}bP16rEY#kK(k2V_a z&$@IZTRcp}B?7k#B(NsMRt&oHV#(R!jr~8$K-Z~U}9O|R?;+61TJ)8sZd6wYbJZ~DjQJ;>60j64$9_0I9l?R z9GJmocm^i};pR+&Kt*Ecm=iA&ge7vAN&TAggOmCU=BV1N|9pY*U3DoDsf+2IIZeE< zpOTmbTIz5Oi#m@f?U8K<^s%Vq<5vw#(FOx&mhNx?fLpVNG2z=vxFQ4zSYq-rKdB)g z@u%-1@j&ii{9+o8dsN_ZDIQcf=6pUw^A+W;5ghVtab03Yk;nOALn0y%N#wjlIB5>O z0^u)52f-#Sl@Mm4y0SN-csH_9F_A@P_ag)#)2wZP;Lwyrp(X4{yf;zu9s^6kwjmYL z44RTX8dv_qE*|S^x(T2nEbq$r`6Km*?F^MqG7<0hY`_#MnIHWNFhoJVa66N5saF5Q zaVhuEFo7abrXVa-*;)q{dDoPHCn9s?0upebp$b&+)!|ysH@ zfZwSJs@5Sub*U<#1J;PaSSY4x9mgC^DB@z04o6iX{DRf8HV{#ucI#rVRUOJB`XHQL z*(v6UmM)Qf!G&F5XE6fWLegAo*U7kOtX$hv9&z#)yPOh(SK=ekGC zy#zdg69lErX|l{NxuYn28I-nG$lR`E5{#uTP!+foRx%;lru9U}`X@5GsM5gKOoS$l z$)%0~QxWP6*1@8FAt1M|64I@=L=gaRF?g~kh@px_naogpOqKmlH<(M}b~>_=Lwz#P ziChZ}!$GX9tEe(*5(=63qFpek^!0T^<%d?V2f+9T*_v;z`+mTrn=>(VgD66hhlkUm z$0PxvM_Nj5kSOL=h`KHCicXHKET&>MOBr|<8swr6QCM=0B*HC`Eh*9+H&(19`zQLt z6U;Z;kVnlN-w01eNgpBc_#=4`I~NtcF+pqH=mUTw{jH^xHO%GnB?S+V!a@CK7HD59 z-{Z+^PUux9RxI+9McPORWO_MDdwf)_JE6Au4Ca901ms z$4EI6@sUp*CP6^eTTaF-vOYuRMMoj{@NAR#u|_IR0Sp+N0JS66Rzdn7BAx-iLNSI2 zdmAA>NTWd0>S`*bMX6(*IBoQ!p540d5(KK1$#~v1zR)lPlLhnRAu5V58+;5U9D-Po z(rnb_5sj-OV%V)@0TMbv?*M102oHf7>ZG7I000000000&Edc-k00003000mG0002= z+w{9)Pd2gCbSE+LByR*pPf|lgQve7600000000650RsR40000000RI30000000000 z0002+KZp|m000000Av6F00000000000000000|oa000000C=1fmxnu+4;zLf3K@}* zs6<6(8b&GabKjI`QBoQjw1lL+WG5k+i8PeVG&B_6=e~t@8fZv+&_X-){l359I?m%d zPo4KuK+|^{7#y0+19$8N`zbpizGJiSZS-!5a4ro*BV|Y&bXS16!ytOsP@4CqiDi1u z;9+~@xObNh{@5sYS-^Wzv@~eWkm{kEGN;!EWoQxOMz$J7X0RNOkHx>lpR)84l#n5_N}UuiEB2hQ|@ z__vk#vMrTuoQIR)g#++ukvsHz7Y>(wQQWyBlwB4_vdVT#Dmb;3BcvUoy~+& zOjs!VHE0uxhC~ZXb5_I80e=BM=TKfzF#ZcnfcKVRuyVU1Th=Zo?LbpBS=mQuzB61r z6dpsPn^h_P;3b-9wpwTm9l-Uk>LfW&M#IMkjgr5S-(bFs2fnsCPR&bwc)HPaTD~y@ zuI#!sP?T_%xi|-JOTN zw8pjn4AEf8ZhCsjj^73B1_f^y3iZ+#ZI)Z|>}!GOCtHj^q zM8?sm$t#6%nK$X;#bz$DR1mf$uSKt^TD0!x6hSyS8E?e&=B|;csNiYH$@FiN!c34^?5BmC4dj@RCqg_mAxy8lW9V&51ASeR@*ga|WSQ2RwP(Kr$t6>SO1la=&^eAYVbOiyf=^SOzg zyhHv8sAlcuda+qdax)XIO!TFKXCkQh+vDoa8c@t-!A{Jf(iSDMogald#}@IQ%`3&R zwdsV9YoX81y)aYXkF1(i=>F_(&@pl>=2pEEGIcDm_1}HyYzT&bYa2v$wBxs`Ds&*q zfvyg{L95EjsegO{lvv60S(6=Gw9~aRl%ki-LqM4XuA4Z1^v{6Y*o7#7t1h<%9 zLh(2UD9$f}Cq0j%Tw)eayfm8g>u>Pd`_+Ql+$EfN%^J>_#$s8oXlU!SfERv;sQvsr zT2)|+_td*c&C$Z?fcsIwK{pGA#prO=&K^$w`{$!#opp76Tphhs%oE3^IFoV4Lus?p zB&r%Ip-XnVS;jgF2PKci`x`BJ4!q$x?zb>=;um4ilqlh?qra&3Ld32J&!{cHVO+jNTJauS#Znq6bcIV z3Mn%SM1|@;l-x^}=f!o3qTV6u9gqfrdIHJIIZ8hr`5^6j>FYRn<7H{!+;y-qY$a~B zi^7ZFI>B;jJT0%aWY2v?)V-=ZO0VzY#8+*2N8u=hPZ|l=yUX(Ti9uLC#uXom7x>@w zPeNE#H&N}$G3k%1^Lc7z4=7YMYEDg1uC0ed9I!_S5$;kj{dkTe=F zbRUX$AN8(o^V$YuI+Mw@cO6*$N`blibZ}kh091&cDqixcrlD1R9Pj;H$ zH(p(Kfs_6^z^rgBcHA-oTg#8&oWV@e_QAMn$N^I0WGX&wO6zkn*lljE@Uf+tW{9y6 zqk5kXdn)su%z^l@M>)+!54JlId=h;-4c~kN%S&>5b`;*<40^a4a31?0>tUjHwpE6P^ z1i5=X@bS|NP?GaWym5a8T94k1$3Nzio%MFKUeaA8=|ka0-EDe#cd0OHObj&_$BH>I z8Fc!7Fyu-52nWVRbJ2$;v`A9L6>}!wvac*W&>z9&Yc`9l=)xnbBJpJFeQC;cS!h$A zC`NVIg66b~j;WcgR4K1799Fr4R#Tak-c2JF*v-{9W?){*eh?;wP`#2Z>N?rurFGG4 z_)Jkar2UUfc9sa)clUvNzx|St&k&!O}1lh zXE$za-p#FsY8+vC6y_W;W6w<|s9Z6vjZ&&hw;er-GhaAA+am z5gHY1i@%1-R!6H_uvSe^>4Dw{F*|Pu{9jA^<7nGOFX+hz68f` zIG?}#0zRt_$LGP_(e8*HuF5`&0}o~3>zM*q&o^fOMTfcPr*Lr9kLIvVHPZ7#HPCaS zD&}lW5{9}*;Bxbo5Ok_HYQ4Ed@sE_b_k~R)t^sb2--YW3nW53faISuhl%&>4j`xhJ zO!7XE?1icH`Kt%U?O#uaCk*28-&4_g(FO53Ou|ohqA23IAE?a8fW){cHXhy`fA6V+ zx~xOIwd#Vnd_%HS*-H+M7jLEVh}&e7+82GVsqtRNUFb9Pr#NDp7Zguf&I{UYC@k(J z>@lzv=N>sDT5M~gpfkC6RPiy++5KA#g=xHeO1zLhq5@`mXVMG1!@OY8Z9&b-8+#p5 ztG?J)Lt$t8({H;yIOW$!Gz(DUhqIqU^n;_A@vND2B7O)pCL4K?i8_2fahbHvr_&U7 zTU_>VIj9_u;l`Jalu#$&nA3xB-y3g8%IPG`S^>W{_Z03e+)qo6B+|zeEqvwe0e6bW z!KZ+##CO1OWvh$Z<+&U2l|3R=nT}KB!b&V5%wgw}CDZ1`ad+KI z;5`36Rh4}cKHeUTQ|8B@S=JiLdys}zx@#%w;$~Q!J(q75jpeFtPo%@s0wlYy^y6po zDwLP6=hUbfNe@RZrOP+xaLXelybgPz>sStNN$3zZJq^ck1uJ=*<_qEXr&KN+v`d;a zFH3s5N=@v3dJ1M*m*WSYCcaUkC%Eze_SkSo9CLQD(BLzl*Gvt^n2-C#zJuS;^`hI5 zz5OH_E>DEECwFP>c~|b%r*Xo0(?al^GmR@tN>CS~ICt_-X;(lP4RNp(X1TrttKkbd z$MXS%^lGIL9ZmeZ;VYF^9LFz~uPFG6IsMes;z=jM1j|`gSo^a#hX>AJ9eaT^>q7-$ zhbd69GwdwnRu7BhWZy+2K`*elOlrYhjrJ8vQ2 zk^|qod;eMHj?eyzgSel`bZBummK(8!QSCXU`5O!8 zZZ5^GKTlRZvVRK}F;>tcDnc46QwZIiOK{!c)4a<=!Zr(g^Ob-?@W^d}h;AmlDLoj+ zhF9~5oj<@at3|4RWC4EKuLU26)WH3IR;W0@j%}U7Xz`4C2v;hF8P8%l%UVjMM}L#t z<$s{jt({Ur^Ch=BbkWfC74O$w0#`JOMgJ9+C~MyU`(9s??)QtwNh(9xX76dyW^@kU z@P5vb0lHjq+5*W&1`W%%;D9qS_gEu^<9;O3ug!x52F#JDH{qjj1ejozsV_(Cf zkOZpvCScy&KK$@uD#!#GpqKhle%fD-zwheJJ<^xq>zZQm;K3tsO{pKc_1%R1`VGg< z9XfDuc%ImIPXt}A>c+aswmj<66Y_C;E$p8#058OPqy6s^q^CwaFCvs~{xD+mK`gX1 zYV#J$RvJ(`hU1$Dz}&ic+;Djyj{f(ZO2e}0&)rDT)!c>h-v_dW?@k)NR>{f5^BS!^ zeGx97e?i^m2)O;sLfEaF&0*>(;{FXgaNc;}1l-Htn*{#2?U$fkG!exM=Y&PID)?}f zEL?t*$=jaCvH- z2Ei=5-?VsE=FXyOZhN;2B{%e7?DqAj`*Jp4JSaj?>1HvYd>Y*-OXbyDY1SezyG_3l=_vx@9E|^NNj|V4bFn` zkyOx(3#X+fv2^}^7Nqtq#p-Wc$n0P=J^b5;-7h2wj;{U`<72>j594X`t2N{tQV9$9 z+VSF_J#cQ#R>|ox_0W15FUhG2#YPZa9l0mkmN~Q(L}0 z(U?KwGA&vnj|m4f*kgn$&G;HEiIdrnx8DqB`(6D}^ytNbFcY%B>43+cA*}N~7u-Wa zIHKen#;pdlS8Wg*RKxjhq%PNorGU7=ilg`_B>mI`WrMNUoVJ)#Rq`;tc`9$~nLy)i zICAZbEa940I2yR=@`uDOZ!Vy8}uCR^mk%qui-R2*p0^|cF>qjpM+6z z4w%*S6z$htg4N-@xo=H7*+(nVXVa%*+VxF*p>;klJnzr`y3a`V(J+)#B(M)ZOsASu z;mWf!&^l`(7WGP}$2f~$@C{tQ^gi^o-;M>p&Qo6C2r|9VDrS4mmt)ao&*pNK<@#J(}yvoO#F05kkP*li1!i3)l5^rOf8Jtm(aijP8k!7B2*j z)V(I0nlcTSF89NNs6sKx(}yRY*e_TdQ-l6>-Jx-l9(Npj2(LSB`P9}2aQnj}O0>KM zzB;$XWdJ)s#J@fRAox;0ywkXcR?7ajN4_2=^jnITdiKV^U(Iy-cQ(E6X9H&k#!5tf)fpaF?y zV!#A>mfhvUMq@1LaH%`k9M2(-X*oQ$hc(`Mt3!v?Ux3cZQcB2p0VD0Zz${XOVb>8< zpZ^^+^LAs|vM6q`u&ry|~K%K3&g|AG|2-qc>udIbzWxPD{4^*}+{@1f9v0^3tU=p53j9~!o|Z0E;vM-rQ2v1fo=(iBghYLs*`z~mCS{ z!gw(FAjYaDFm-P12Yzs2^-ao@W+_AHvJyK>jV zDVS&32>$$MeV*>C zE8s$n)nxzgDYVoCgF>nW&TpHCMZ1(?WpW+;Ym27n+paX;XeiY@|3~3l{CHevx^(3W zS;Y8s=-z7&^m>v&=@a_mSNjZFd@;oFxK1=*z4?-6+ZCYyPCvBeGWvb44-NBEL63E2 z_^N9q7b*;7m6aB#WMa!H%Na(hhVqWk7HBH_47y$Kgv(AnvD>rLf^kNx__3@2Z~I+= zrM0hw_cOcm>S3PrXIQ2%L~#&X=8fmnZR&Jk^GICuqB~j#?xVtjPvk$c1mtuoz&O8} z?yWe9e*;3%#8(AsBI9{y(_fmt{Ev8ckp;zSisZV%p2|zT@m}pXRG@GF#k_iJo?GF=cV!NNiI{;=S}ORcuLk$7na}qp zyoG|W0XTp6F;Wxt*ly-RRG6Dc8>Lz}r^$#vdwviyB+7KN^BUC+N&;{%{v(^(gBUXKAq=y<3`3J;SsUZ|q**o` z2^+|dI;$xzR}c4@Z$+VC4~Q-wXm4mgZg6h|RYNPtE@`1R7W=tZ$u-nJY|3`i7l>v- zF1%=uJeymG;-uQCT>GCtSeBMUaF7TOmpgL#Fk8B`rYBE+GaB2MEhFX9RCxNN6MPoV z=Z7t`sH%?%_TS`-*4;xv{bC>}JuHG==5nk(YYnSz%H?2#Rv~@BEMBoDAFc&!i9sVa z;3wrNn3}YbZbv;9PwYuRCw~*ZJ>d(ni6N_2Bq5M z&^_il{lCRW?+?Y!JT+G6V3;t`nUgAS!SeeJw8CvE-T8GAlHc@zQ!fp~p^^LO(4qu1 z>hlufeyL)c?_i#(GoB2#OcL)k8t{`=WgKUD8kVF?WRsjAw$+_U-A1e60^@AB_tRQ< zd|(@@Mt0-Mi|cTE<7gphvl_~kmQm)3OjsZu&oXsPb#L=%PH#{mUgHgARfFv=CwkpO^ORZDo*OSH zpW+n}w;4d$6;ufF8b|4TGh!e2CUym{yH+SnxWi%UsRb zRYPEU`+bl`+^4i(hj8;(f41G}$8%?t6G!+7+XhTM*XY z(sf$c%MDy(HTiT?F@IX*jP2=pq}}C3cau)?9dj9{_>pZwVTd1H%?jZ;6-JW2uLCgj zuP-;Ij)h*Dr^LqVDcn6L6qeVgK~sY%MzxwjW>7Zb~LK8b-L5&y_@YaaRZ9gf*1#XD-I)6r+yzEM6{GjfvNNxysa&ngVxn??4#i=K86q9en2|qsA+yM$*|EULE>-fPRr)p$M7Ay zXmfCum=NR74<}oL(~Sn$%gLl(X~avrwO46Hr*qs-bL@=UC`x07;J}o8kfRdlm@*H` zU9)Mq!G1n(dyfO&s?c8PbbL^I2un{E!BsDLNQv!&iFwvs9yky!merF^kL!X(M-^3o zyfCkL8s^@OrWZrrL)gh^+`sTUoLW8@GlL^(!KkZL8orXA2hQX!KN7z6y-Fp^&Cud; z9=j`s;SjIeR|qhbbQVb&fTZ?lX&!aC@RyF1qoFA{1gs;chs2zpbt7+=qP4z*+V!j|f6 zRxUYC2Upq(S)h$A2A6~*S^as{fu$&yv4>wDJ;=5Rgw$bctuuHs{Ur9cm%V6jD(Y#|r z4{p*wg-r{!c=+`oK0b2^dk-HGU) zrOo~QDED$57SHJt;`arCB=tLOY?u#Q`vAGrxN&^PJ<^lE31Wi^n>5>q&J9PXVt@y1 zy}uXwg{o2K<~X=>B?U_#O7KEuE&Iz}@7D*zULLm56Jmj34guVasbh$mZu(#n6Nn+4s{A}RGnIEQd zzteeQlhls=_YWXZ)dbC|7II|SeOTi?M0~GdgkQ6|ghPh^v43VT$Qh2~5WP9vthNM= z|4tyC-!EX_fIjSd*b8T1?tdo9G+Ccm|-fY~pWp_{uRui9?R+1^#8 zE&CVTIvinH*$wjPKN8$k=E09CF_PZ1_i@;rX0cX3LD0QF0WW(05;8;b$l%xmQ0vmC z&kED=M0aDdQv3xLZzpiByNPh?z(%2cT_IhNjRRq1JZ)c7MUBBv#O9U+TsK|`?~JM; zm$vita>pzou6sMYXzR~8>CXKOFEw z+8|iGz>U)@>*#W6F}^h=>C8k$3^{GVnhJa1%r`p@k9Op&?HM#_Od^c)KSfP?KTx(y z2R;P%1Jm&t)MdX7c76>3{j3t+s#7Bxor{xRv&=%-kR_blV(xaXM96>?+IZOZ|eJ=X=jefQDb3Fch1{4>0qs>46u9mVAG1l;|zCucV) zv%N_G>)0BQTyp?VFFZ&?9A!|Py$44RxB!(e@8iO@7`_@PLzV$d>;9TUz5I20vVAS@ z-*f}AU66{r=3`gDKwcYh8gy@r<*`4N;7Q#a@u1dF?wS>V{{lX8WlbTq=qU5S|5_tf z^C!jFEg<?ZVU znu&g|EOAvKzV{{bT=jX9-e=l)u>(R&*YMwKiLi3@PRh0)$>URl zdBqk>I)CGd5IA%udUjL8fnGAWH^m0zTlS%!;!%*}VfZ-o3GIHph9>7dq9gA;dC`kS zLQD6(bl^%3p3XI;mTeR8Y3&$xNiT%%vxbmziU!B2ousF|WY{v-2-nu9;=iZ0GY=2W~^LE6=|0M9*pCN2xAq|{d#D2vG~X;w$i^+SbgK4)R;_F`eQ zgBxc^M&aG+xng@!2_Ey0$BqS3@YtTneHJ><5`g{xMg}T-g5RhkyMu@^^?(OYzW3QuVx)X zJy9dO8In#p;QH=6p?-!2FLE2r9Uqs0=g z(DNqo)lMd#*YYr6YXdFV9Kg?qRl?n?;o_6PaIEX2!A{3)DDw;Otn-C1Y}!zA8fn2% zeG}=^zVYbl*c*f24u$?Mw?wT)<#hG;HgKQXM1Q8dp`D8(`S^B!?&_m~&kb}@Yu;D5 zzIp(^J{=C5?E#NMA=N5$fZE+$*dk3thwTAEiRv4gw9A8)Jo<9wx+1~q)kFHTs{&mg zT!r>`2l-~wF7}xnD>}^XhVunw*wvavw<7*Pr^|HK9Wj_kt?b1OLE0!k$qRKJJ%IBC zk6=!42*p225sU9`5ZYH=rxBmOlk;j7N*{3u?n$r0_QmHZC~K6^II&1L?2IU_94pFC zk3(uf9_nvLtCa^acYScw>F*12ar%7g{Y}0Wcc1dc6Q0`@h+@B?>*;Y@UMRHEQ^D<~~ zLOGmtn9SpP>*K3@U$J3}2NxGE<+rIa)taUGj`59^V3z5C=lW>#f#=_#z$^kke47Nv zY9087^Cg&El!g2Jbg^Nwz$^N6<6Ef*U{b%);-iD}`BLOgb{~CS6#bnz*v1B1B4$EE zKp6yFs|DrqCRlPf0bKK)SiN~IJbABz?tu?rmhKU8^7;6xcjI!Pec~C3dcZ%jI9kf* z9@xY5>O#`We*)QOmDtaz8*a1ShR3Y;Lhti^#bbF9cqS*8R!l#FTP=Ijp1)}@{^1zD z=|7+KCJ&Ro3RmTsrk`9kpWns&EQ;tpPp*`}4i;`Z&p|KPSxD&S&OpqVdZ2@NTjjwrux@Ripkv z$lGVIP<|$BT6X7Yi{7wtfvoUHw?AdJg`?8vTCj4lM8{wqbUP)I!pjDn8164ktePQ| zOg_wLut@y-B@WJB>&Kdh&Iv8jIPx!9j6)m~K-iRt64y0sR_ZAo^0$q;%G!lczeJIK z=y2+y5iI|>7dt;|5Tys~n94URvSGi$FmXndFP9yA!ROSp`07FbnEn9lIz|^Zj&_lSKlR&k$ePph0E~1VrNLJ$&~be zq>3@U+DJ>ug={uCi60z3;=^hubUO1uywq(mkA8lbth6<7nly^n&sd z-+FI{Cc`tF=W&n@zKp_svxcC)7!65*{yfmO8}40xMw~Lj9jv7z@J!_q4o}+6e%0;t zSVjY@4(HR-ByVBcLnEPI@7;LMcL^81>4p5I2+ErbF|l4k3QEq778hs0*x6sj{);Em zAElFM^I8Q*_t*i7_RBfR`5WD?QV|Vy%5y~3Sx{*xr^BA*;9@t5HhB-i1-U&XRsPvx z!z_`?COx3~kZQO$J&tBJoe=ISEZ{2(FL0m5C1AT!t!iwkEIyj|oQ@@p$4%2E_`rQ5 zdn9Y~{xQqw!_cW%@gfz1w(KOsm5Jcqw-8=fsN#2X1DZO&2X^&f@K(}-p_kUvjqZN5 z#O$1Sb4)(noG_g(#l6Q~(_As}i5n=cUc|;*x^YcyEl8IDA1lzN9@ScWcxw;tEZ)KU z+b(dh^sQs6q9r!?O~L5+pK#NRVARfMP@WmLJaR~dK`6nuU$-q2KLmuxdi?4Jn+0XL7-`>zjl{-$;oV2-|-Jn7Bb$|F` z#S5WgpB)shPQitH2crMDJo?+*0OcF|@&%W(=RsoEk1hW~Ob;)-tr-N(Nz=ukTjThTZ83VNtp|+{ zx8c^yPYA9 zd48HJSFcdTtpgtjC!7a}i{|L?eve`JB2*2kN6B!N|4ABCUxk|8&XVzJJzQ6_j2~%_ zq*#SxuC3!b!=(q)@*8ya{w9nUMH9 z7B~0WLoQGM`<;YkYo z<0A|Aa@%3Rq2UZM;ke`K8k+jd2a^iwDPhe|a#7ZzpR>xyH!+FyKNezb!g8sOVG+fx zFkzFkJB0-&t?-~-4?Yw8S?CX~(vzXG+$ukbi%uK^_5b!t`lE%@+;-Ca&wAjpQ!2Rc z31c_UY3!b|1kVm^f{aHKVZmunR(e z5A+ClPBRKRp={Gc+7xJp!Cx+mH{&co(`o?4-pYZ0UNKUuC+|q-%vj06#5MHc-)s(u zl4awF4ea1E5<=!r$7O*X5c5$Lj|M%VKAm;2`L7vU6kdewb`dzg7h|v5Gh?W(S(17b^;7Ft#I(Qap5VkHbH-DvCh^wFc32 zW-iNm{uUZE9O*iqBkNU>{ID<$P1c-+;nUo?pJNbjD(k}*zD2OyWGVfre+c7iY|w7g zJ~TI~1f|_;rAdn396GJ4vU+ztO?Qr>nR}4s{RYF9#1t4^Zz{%=r(u5mXK~oR4`Q+0 zLo#tFuaXNr0Ms^|zui58t4>VdjJm7PIjjditTo1pZ7RHb?6Tu61#0a-Nm*I%kDoS}7 zBeZ=#NCP6ei5jlQA+N299v!~~QHN)fhg6%*dc6>2$9nM`Cqvv6`+$D^G)8$0fz%g= zAR;Uu!YZb){CizIrjP|L_6j(8aSka??SvsOHwkWzUrGIxB^Sk9;!mOXVbH)6RoPW( z7^uICno&Vi{VBpp{aku4zn;1~wSdQ^33x~Cnl!h<3ud)kr`p!f(lfGM6!uY>0|R3q zUZMgy2afW&c8*6SLq8eSlF zu2#gV&OT^;P=%daM+q)}KY(18F0Rdg2NJ^#R8}#NenelOvsRzQSUnB)Wo5u>2V7TC z1V)Z&xNz+ZK6|i$F0UeTm~Ib^?`BKSt^SWs`Ai(@yp93_3wiV7k*u~~5%(%fAtGTj zbp}qL4R^O;i`O5RV^Sv_CpQUy`?r#Gad+HdY0S-r@5$!ZWg4U3ooky$arRaX-YI#` zPpt(?*|{4gSL{Kv``fTl^)`I$xe)Ejwh6r&w}I~ZGibN@sn|YXCS8aKk9$MDGijW=7H`nE|YS&N%uuD&8Y^DV)&Xp0rk;{dc=@Z@~?WD*wPl4P(0VQVG+o z9kHa}3%FLJj4zwV5Q-1!)X^kZx9!t^P4J33U)ghqSqgre)|+*kcEfD<=QQeZ8Z3XB zBL-#Zv%B=EkpA@;^)E5RE1C1~*6s#eAqf+4vJM+~kKkKY7MxOjkZuL|^N&a6@Zim0 zcsjO-2j*)@WaGbrldBdQdK{rs3pBXDo&iqFKSu91$HTtayV z3ho*Mxp~Lo?Xj!a*Ix;>&qRxssY)#OC0fYtc>$8t*R$U2Q)FmgOxiw4uyXias9utb zivsk}Z;7LH%a>{jnq3EsIQ=i771+oj`#(Vphqb7cn|7$}fhfdLP`k>PlFVHTWz z`IeS1`z?NdXv~j_SAp@MB ziC+BBehS3umXg(uCEQ-UgI<3b!b_a3$$Q>ESgJ4-n+83BKjY6xs?z;nQ(ddnr)(k} z{@kCZyu656b0^VF2N!AfiAetZ{w(yGH5jvY59LSsQ5cg^&H?S|uyC{~&vooBO?C4X zt=B$@a|nJ(zrg}CYfe1+O0w^otZ>~%q+;#I;keU7)Cs#P3uqNRoyhM z(-<%GIO4=@6pUft|G)=#IWAse5A%NQ2HWH9AZL95isb+XZZ=~3*Rpi!>|3%=x+z{B z?@H^3%*1_RW|$lF@IDB?eOsw5rIWslX3&lI=kUH7 zbno1AY(1Mq#hdJ*$AdqlNwF9=vr6=l8_j!znxOKcEzT~V$~~U<{WkS9`Ho>l@Sr}z&gZGn13!7f0)4=@(G%2?fl>gMxxkdvv zIH17CJ(ptFMq51nD~PkSU0C8_z>hz6lMd1dp{?)Iq`!tv#I|XRaq^Q$R2#4dZ`t%@ zpGRZ3%wRE>4|^^2yOl*NcUZFOc6(BxDZITy3(HpR5$3<021*^8ba0G4t#Is%wHx}e z*VpCzYG4vPZaXZ!9r+P5YjXtGwrKJ#*8HzOW!cTn6vkEzhlP(Hamb4el%L%twB7s$ zarX!FvxGzRMsFW#E^3FojmPj;oEn~b-3McSj^d7*=dj?)EI!&bl=nYyt8|lZ}KJI{a-=$ov zHxw6-J`a8lL z37CCS2iKL3$0Ac_F2Ph#pDKkDE~zl#tqH!#+zsDmKES_@`n=v@8~vOd$VRT_VjuZ$ z!sO5g)E4WE@sqMJyUqh%`t}y$Z~dS%{)+rr!G#ax8F0}!ZHO7?j|*=X@Q5uLsHd+% zs?9U;M41kh+74yeZdc%n+)7S2&lesAD$#k1L+BSjjCNME!HKV)ym-Y-LB+qE#-*pw zrU)mBe)2yG&ciRH_lx80B^uHY3Q06kB3kzxqoG1V5gCb$A{C;YBn_dIQWO#Ktt1ud zo|6?xp%9Y2cQ(I%ulol)ulqdbe9rs*dfodxrP_nYkM0;k+oK$4v9ZT0ZxaYnsDpW3 zwy=Fx3QYVUf&I2_<+>TcLaEv!8sF~&e9w^Krl1>i@A6BSQ{aIyNv}ENRI#we(}MSR zzk?TkYLxO#f{G>uqW|75!7zR=E>uWiyLso))7qFqRxT2yZC7wigd^Xr9g6A2%G}zz zPKx3EviYLFuPlEWmIP;#M0D8J53NF##1%=y z`IJ(QSZ;Ppl+|(Ovlgl1-tmp(o%urC*ir~LR*iyJcBjPU8s*en@exL{AH134#mho^ z!C!M{zGd!$bGEqAuN{sM`eP8zTh~Sp6vyMrTY-42;x?^Ys)ZFFE|K968 zOJ1u(#r|Zm_q0%6;x!rie%;F93+{rjq5!@%E8@|0AK~39ORheyj>0Q*)EhN}leWu? zo|C3h_5^h(H;AO_M-qH#)IdYnZYQf;u11Fv)>B2T)X@WH>zmJB! z`=+6b?|wFG^rCwY?}6nHH+1b`h1;k4@!EvN_)2RLt<=uIti%-h5colCT=9gy_g>`i z?#yAh(BaGDY^!0sRUjA6{Yx#~>b&v7U`+mLgm3ILAWtO$q%NGTtC}7Np}BqVm$xY% z^UOvw?H;CaX%kWh^#qi6Z>;>`lOTO$uU3TEJE&3uTzx)3MsJ&F0T z7ig1bIlPKp#D`DJ6tjzbxU58lU+CT@Pqi&Q-rr6BD>P8XU!C5KFM%&!#e&PseI$M0 zGi*yGp-D>ybd|HPVf9?)>aZ#b9aH}0S{r3YZ*G+*vIyPe~$Jm6<-kZ7HK5MV-- zxc0+H9Fq41LN+IpjsFpPKe`JZ$k$Tw?F>-wx0T|JFAFcawcwyeES0}egtZ^<)4B~# z|NkBZN!f-z$GGs7HFj+I>MT{AHGpvAfAnm!0(SS`h70Yoc}2rlx^}fU-?jQE+*~vq zttZ|m=ar$jFk~p*pMt1--_#+@FPi(V8x7hAWa*yrJe1hCmPhLBrmFo3Q2TK!PI&4s zmdoy^?N54UUY`8^Tvx$=*LGDx~dZivxi+m$<%L<*I$Ys4w=u{IXd+B(O;OE;m&z0KVaq59i+44 zA_cexFr<#g^V4?;HzPwhWJ@#6MPtxDqRcaTEya?3d(m`S6f7O;z?qHO69Ev0971UeUJZw4o=+x=@mnNA}e4Z$;j|bvyo&`vT!O03PMP5I0R9!nb7mfbDXB4z40$ z)S6AGTs?s9-yDd!VWau(M|l|bfXKhKiJk;55f%n}6NYVP#gP_h@njd@8}5qj*-{*7 z-w86hgB-W%O`@z-xuCG54vm)Vr^qjy^UhAV2m}-ah}f?J}#%EjT7m? zy|<3jJ!IKPZ8>U;m;(8>XYFT57Lan20&IylMI0u@j^)+V=dm-|&y0p>_YL6c{+GI| zGljZ8k3?OS8?-3!Cf)y%LLNqq_5T_Z_{IIRbm2sj@GSQ#9InYEGsVaCOXM!Y(M{4g zIb$=tKbM9D3*9(yk1Rjhb(B6DU4_Z<5#V)e4f}-T!Pv)dVT<2D-n(oOiv!Hq`oA_< z81fGeOzZ`f0rKebO$&`y*<;F{G+HO0K>G_V_=e(Ncsg=FI9_@|2X}Z1<+X1pZE-NV zjM2t9I1htS`)c^lM zJVo*yX*~0lj<`BWS9F^&lVg{tVyAR8m^~YZ)g#TR-M^6Zr_F}H_tf}a@>r~p26X=U z1F9R(((T;e^!ubOryPnW$00`i$^NAnW23_l8^S4Y(R#GG@C4qsTfm(nV_MVkTwJ2r zC5}j4%u^D(ab#R6$gfq!mkT_2(S=jwe|IF^Xb9w|vDwhorOp0!**Np%3}N9QJ??+= zF^%XQU*C9hG%j9m!hVXr5V~V5{GKm?UfsLlRLN}aqZA@6TJ~Iwm_HngI-b*2eI&`Y z28aq&<3IVoXsyc$K~7c%YtO}lPgaNMY+U4czNQfdmlgx|PvHr1u^jky8F!ECsI$0{ zSl=(_4`hcrVPX0JwCKs=aLvy|Iv77?+6hrZo5@Yb4u4F4jJ`Hj9J**SYuCk6j)e>6 z%4`+gX6#{~-hJWNr6PXuH;~5#W({nyqsCu zqmFLhSEib(m2lfH4@$SYaEz1%K6C2_$^&BfZAS*oGw3<*3F~2UbP{+4%<0J+4;

jIJ|8^7D`spB_j=2WiUjndc@>U^p<{%zAwLc&7 zRmZETCmrg`25|MZf&4AJkO~qXqm`#JW_}%jGiq$O#y6b2^2@2-DVZ;u%wm(xtN3Bx zNqotqFa0$ii+O8{VEY>v9CAFcUT5WHFiGjhEg?R<=bt(Hrkodh&)35bMOZJLS^zWJ z@*qfMAfH>ll6P}q;J=CW5P9c~V59a7WWUSd`wA6yeo+qX$MtaE>UCT@H3ym} z$5DOa6#TCFltR)k(&F%k5PCcSV*jhtdL4JO>SyCek9Q zM`FvBk99NGY~Ux^v-qq2C+IskLa3@Wz#IKGlm2ZN>^mC4yF?j%&+G9%$&GlR_9$dF z7~usvMau82`Q?{7FdpZ~TmHKO)fscJq0@&PcK&s6aGk(MkM=^7y$Mt#@r!!T>d%uE zV#(>(Z!n&&gVt6@U~)?yg<9QBt1CXjKpxN?wHtZ~lUK{w7ZEj-_5c>9BRlX8v~S zqT_+A7-9Y!fd|ah6#D7CApe*^-n{%7)=ZGaHRe|!e1bc#OE$$FiXY*j>QEkS?7;2r z_vyIb7jhci3Et6v#Y?JRrtYDQ( zaYEqrf$T18K(&f@z%|vI{IZhq$&+kq+IO1n6y0EZm252hdK-2{J%&~>m>(Y*#TpGe z(N|8Eit5dAJ8QOs(e8gB zSLz76)ka~Rei687wo|>4G1p$3h5qT^>sMbKhn-=A`TC>=SUyUC4XPvA@`*Ix`uUWF zv*);vjtUNQSd6{zOhmIz2bP)@kGee!^!jQaOse}2ej6^Ox0hCm>&cAlI^+d6+s)vz za1|ZjXMq)m6Gbb(Q}``sHeX+w3WuW}(~jLE#1+2_#r3m|`OdX7U~zn1y@BxwYHAq4 zDjiLze!!T!E*}QD6Yb=zD2H-uehX^4v$*y2MSPSdkJB|p>i15TgZu#&UmA;+kNtU~ zn-bstlthkV0ruN`3hIMz^PcWFVMy6;$1P7yv8KNvU(}Z79XdO3d(#;jGwA{k%s(d7 zR87V3H&5Z~L>-8!Jx=@NgV3W%f=;YHK^=bv^9A=zj=RZ|Uv3(20WoqE9od^C#K+mo<;@3ZAl=``6uGcHF?88Jb zQ+E{6crDkYO#>+dYtWK71@Cq(#FKYU2n&OD)YZq%WtZq2alQQjT6XSzy|(oO4DYSe z!-5)IdF(zd{;_$E(8Hk7yP?T`mpHHHCr#E=pz}YK&}Q`kdY$|XDg#&Hs(^5IUZ*DxA7S0Y zE~`k1vAgVmOK^-$4$Xqs0n4EGF7H>_2orArF8^_;3Y>Ya- zSee1sw+!ZmbKlf^Sx>~EFTaFL;WkOFivqLS>u@x41m_HsnWXGD12i<|i@}vAIHx6< z4#EPIsM|~%dbL38`_ruGa|Y~Nmf%vO1y~^2PE{^{#h4qX;c?1%$Gvv*czN()PzbO*Le*g?OCAD}G{Cvr?sHhu8d|ywER}?v1Yy497f&hwnYmt?C?YIz|*Qbw8=q$3afGJcZGC z-gs4?e-1f{s?mo)Dbfp1W)0@B+^>Ryn>Kw`k>SBx%V^8o{ZRimjW1QsLcdKHNN=H} z5ZG@9Ib_L;xp_gTKb`26+DV%8YA$v~NV3|>AtWgG;?PUWpm}LuOgP(@XIQOqth>Ei z=<56ihWWAF9J^gOZKTCx2J6EEyMYvFt3;MT6LC`4SU%J?obL|b<7gTyiDPG)<754^ z!k}H_K?B3!!t_)1Pe-Rihw37fJ${Y0H73x&IB!~TwW3}lc|0s$Yr@Mu)PPKvG56~{ zh*L&X@j!bIyw%Z2O|{n8l=wmv{OtJPaSL>oxQj975%@X!Jzc)PnWC>{(v;TYg zQ^essrRpDGYB9MTi^YR?GgyAqNf0Fr_(s2N_|b5t_~G_24!D*H39BnG`e-)%KH1|g zb3Ay#gkG$iZz-&8|4BE)<~eRs3+LQFJNck@6I@KUrkCN?aJpy|A2o@AH8#F@CRSE> zQ)69saOeWI{IZSuHV@#6Okdc!1JHEN9*EcQz(vuQC_AJc{EVK!U;Qc^udWU)2_+D4 zNrw#&lsj};ey8*5(X2hRvfigi0pDs@^RgE=C_Z)|`wxEyQ@3d1DoJx;aEBF|o&8u> zU}6Ke#y7FFg9NXe@fh9*zJX5n=b*9w1ew{a!@kW&>QDO0apL|A+&O3rJi0Omqb{`3 ziLGlXy~#(MKHr7we;V4A2Lio0xzE}#J{mq=$45z z3Jp;NqxPXf=_$vyk9CgI69PCzz842(XMpE2Ab(3q)bUgoe=Sz${eukX)`s(tu1fTsFf2ukS3QxPOOO#V`(!bgQyi%r@*lX_7d37r>2Ag+fB%8n)Hw z$za0_u|3!ywU67QgK0msS!m4XM$MqXDUZqf$P0Sf`H==(Rb!L)k0HZe7N30A#nVCQ z6np;x8RVx3U8Xid|EdIfS9Y66&)AA}9;e8lD-Mfq>hR!!cO2KbcS5OqFVbXPEYn@V z`7_6n>6utko!JZh9Sv!{MmKC2ng$B9`a<)o{$%MZA!eTc4Ks=Z@rh<%yuHPNhM9Dd zhH`KI@z{X06mv=Ez(z`XJ{X652%!fW3Bom(n^chZ6lQI>4Zrhl)3y!sAZ?~IF3tK+ zEL)e0_ne)1_t!ed>b4*uI^Kx~`D)YnibMRwP7Ci!81bjAn|a%*5uE3?0N&J0#m?y) zK{E9c*zLIvFI@9b>+umbNKm35CnfoTzY*SP?x6RX68tv485T|$gfHWBIdR2iLHm0i zeIHf=Ck|ePCZBwezBm-EzIBlI!VJMXbOu@-h=!j|g)mvRH$RyyMJAHFh0WiN)3%`R z;!$lsivFo3Y6iQa1uWw)+VSw_)-UJ?I$BqBJ&W8bvq1~EPn~4I2Y%+TCic#O1St@gKPWj6<2Gx(HgfGR8lzw z<>vYF!jr?G;%x#Cnb`t^D#B>HOQ?`_Z!BgEjiXeLFtjkq!yu_4VB}!MBb;MsV!WE; z6UTBP-!q6M=NM7ArVNUif9orw%rI@wRt`^5ftFMq$M$=@q3H9edQ;Q&J&ZLT{XgsC z@U46B>f}*;>S~K9W0t_yy5`(b z6zF<2LtHkum@jKR0}tOd_&tljbO1p>zQ47s_%(g8*+06)lWw-jB2OK zvu|j);W+pjWDeh>S5w#3IrMGgMX>wkh;LQqvT5Nt`k5rdi&RZ9K<-|>lFJr~KH>~x z?uLN=ZwUmC1GqJ5Fe;j#BDZ&|`00*;{CH}Euu=UgB}ZPMwLi4jaMn;h@ja0{3d%s~ zPI`Ttp&hudd=G`A=Hh4*TdbUVofZx81{=3waHm5Zn;+$f7d9S&aYtU&4?FOV3>RM) z>wesZL63h!d}}o)*-qgH-rEG#0}?3XbO)x_ekRL`A!wX432#m?bC|pB1V6l{PLqQ_ zl9$B*{G+D8;cb1YhzLC+i`$%#HRb7x3ily|UMa&*FpfsoB+$01Wz3S5P;gq0 zgXPVs_wG};cl!vu`PU2=KMiKK(-gOC8xG$8-q4A1L%!6qmfKI?M$e`sXiBSR?>Pf` z&$|QEn6eM+Ci}8kt&ii?HY5qf7+iU#9(FZ)p1<+yELpe2P;mP}@^9O~whqUH<9WwH zO8q*`T6q;cVv#GmhGX~DLFBalqA>aPBD&xd$uqbTM!gN9@1u6(V8a*aseBv`Y}f>S z-)8ZFe0lgfY$H4V>d(?L%A6Ip1Q&OIfxtKeh^tbil%gNB4%;B5;4y8PeiP1LzmD2l zH*$1#A{x$^z>53&W485R?loo!-_gw!9KL?74=T!FFYkEzIn4_{**=71xyQ8skvgaM zS3#xErs&akg@9p-;-AaGoHqLw9=)K=UyCJheV+>YRl?vCJPbE)bLZ)iQrNxXH|b6q zhj;T%(PxDRf|A}CR@JB!%O;xPiNh7*=Oa2eRy!FgEUod!tb@Wv{Tj+aMgCI#ktUvg zCU`XG(sB14bZloSJzhT-M;I*^4u?7+9kk|)3zkxW6V%&RRMN*4%elX+GoAY0&I|52 zqN)2Z;f=c+6)q|SZMFUO%2B1bZI~$zNXn#*%ja^Xq_(L3X%Ji~%LbJYIbQx!A0{+u zqy4>6xb2f9l&_nI73M``Q@E9G`r7jczdrmyAp;DbH2%0)?&Bsd#L)v1^AY=oKKEB z4kuL4a7W%pNC_;V;zd8e;LT-{?$E&K&r31?_GDUHFotr{(s}B${WxxAUzB&Wz~S4B zc*N9N`aWPY)IFO^t_Q;?-B6!LDIXIm;&sqz=mOB4;tr=AjJU+;ld$c9Km~qZMdg@p zbisNT{k!1D!7DY;V!t#j{jdb{-mRj<2`7{hAL`vJeH zizp|9KO1J_tF#D=wi$roLHS%%6v?Gu(nQUV^4Ksh7Y=_gi_%*^X( z&x0u`eP*z3={a(nFVS#GY7cxgP{P^jxp>|GCYUamPgBni#9d*bSQsvin)h>f;4)i& zrO`}*iRHp4C0#K;ub}St)m5k`yA;$+4RDs(5uUZzhIi&<&|Xx)w(mFLwDNATta=k3 z)&30Y?2^!HMj-B3ZU;ByKZ;tacc}G6e;#{jJeS*~lfwR6G-B}(p0Z#LoBi7aUknPs zdJp2sX)g5}Pw$2)=WJkqLoFPOZ5LOMa==DoecE_rDh%yfL0)}gg)_(JQGm>Ssy{ge z6O%GownCCKACKWwngJ(G+8jQA3!uysGqB_4T*%qf2zP$OpzDuz;q&pEbSz1dPcK^! ziV7cv(ydy2-b99*wq2o(<_Gx0P*WEFHG=s9r7CFzkHG#FF|gzNf0S3|!q1l~(9gFb-`yQ2T-J9%)tK?v>NEnM zs>yIMd*JkK^RaWF3V8221JoEy+Si|ngO)kM14B)Yn7)nbU%aE}`%d_2LXDsS(fq|M z8P*3m!^jIGQ8KAFn{)+2-1uLxQ}HYfzTkUE~&Ax?>2Ae4I<3V^XkwS`u^?S|B?Pg}9|4 zJp6Z`Y>x%-eajMBSvrvAO|pe}sc;VUosFs%rsBkwarob`x#G%y_rx8aF2YTRMZBR= zl{1IU$9D$DFyg-%Q2pMR4eV#Iz0yD&8skO^T5ssbq-eZSRVuy<=?zmheIWn5N0k09 zntpEY#ha`8;rAPB>jTG*LaqE${AOGpFBNAC?W4mWPbumvpMj99spO_G3Js6c zh@KA5#q1kSnAErdZZ8=Exxtn^?5Cu#^4VBuHytnT7+FJ(kJeH0nG5_UBo-@Ieuf=| zgYoEFX&!KA9J~D-fnQecr0@Ov;Fhr&JfT|+`-x_4^f2iq>;l6zsj`_U`#{*)JQ z(@3M61D4gdja$n{j!A;-@!f*ff>wC7xfo8hofY!h)X*-XjbQ&+T)bry)%mCL#M86* zd(vU?UWqa0JAtXTtQYF<@*@W$6@Ioc4Ey>;Z%GA%mvcu@H2G9-g`e}Eg6`)-q;>fqQLum+a{5?0JR4oJuF%JMlWFsWethwj zF=qdJOzT4?^T9d)(fsi>>=Lt`mp&%$XaQWJvlOK}9l%^^5}G&GiF)zjs5(N2&(u%C zK{L)ld}b?H-O?2{53itoR~+${(lB1~Opd-!ug0+b1K6x9l7g2T^1o(1EFYza-=8{i z#ZL+7ntzluYs~Q2@|)DJ%NWDwE@F?OUUcjJhx(L~R%&}O0zG^6<9jJmIH->`eo3B; zeLMEk*pUW2bdfXP@|I$QG97B%HH&iX&(iUzH8cU||;>+rt75EEvv!tnAU2ro#c<(W1p*AXww`x*p;{M7kR zFKzgAB9+1}KB1=MOi|loI&Aj2j{nRwApUUy+&CP?_qyJSuFe^7{GtZ??dn4zEd%*( z)?l7ttHV#8C7_*X4DQFQ&|1or^Hqo7^3PN0?Vl>jA9X`C>*?bM2h#cc!@Y1i-+{B! z46rV56CKU|BG^gyh@8w4u=dr#7kUl6Y;gy@th3-fg{Ck)RuRq(FR!=#7Ke^9Kj5y4 z8k;Wad5`a}9sc=G#LWGr6jEl++WQMd-_gU_`E)KV8+S-hcRj!gPbY(%TyHcS8Q|!> zy&D|cis}2dICQ!G3x?+PZ7?c$3Y+^(#<;m^IB<`QsGI4{D-XuumbFJ{sX?2gdT}mj z|0iJanni-&_E)0lBgqr_gxFO5hg7puNa@s4R6jfgr%Mlq)@n;O^|KdChqeoQhN+5W zdcApHc?^YD?8N@(`eLKsQ+8b&Dh#=<#GUgUaA=i1H!WBrJY4wyd#_G|v#})nzPbr@ z%XLY@?;upA4`sXM;q)fAoKlxoQ^c!G4pCW;d%NT&d7gH{>h)%9?U%^y(+|+T#FOxS zkQp1F+6%3JGWc(-60O^i2WbrnU{>=A3?9p}-{7sdr{xRX9`6oAKEH>Gfl>`h6~?6Z zRgPaDaK@d1q2lT3X|!fh9vXy~!_ft*cyUh{TYT-L^w>D+Svwt8CYqD`zBJHG zeJ33EI6LZhSZmsJcW8J}A&R^#S<2 z{Ro=e>C5WlO)0->1$$ps#BDDvS%&t|$*K9`rLPC@@PwVL7p_MU8)Yeb+7&RH^#){D zdGn;_hFE-ATIfB}k4WJ+i|cjq`Ma^yuTK`H+yA6E&1;Z9Pz_!F1VLM`GgP#-l;f4t zD12HGx!-byZ@r2@OQIE~hL6WXIUnl7qgu#(Lm|mL4dXsTlL4F0)w`~dLAk);=+^rR zOnLDZR6eLv=$;Y0ZG$cbYgRkvxwb&Wz5eXxqd97C|rW7dyR1D_hTS+WH~&^9|K`S zEy%9ThsS)KD^#mWLUmgYk4@i9uKDNeJGFX)e~3N^j)hd~RD$1*4WJ*%+PtN0C|j+# z?U+?Q25;WB;@3Lc$-&?>860~>uzE0-!7Opei5v-ctr2*uE5JF z+59GXDApZW3>|OIK?;P>jjOVJb^kwjqzJ;Q<%akoxswk|t8m4TE^&pt6KZ5Kyn6qR z7B_FkK<%BZ`7TE|J=zU@b`8Tv@i7oRyBGILL4<^oEeQaXjwuHuU(HMSmS*I5TQB z{qBs$S=N?VsX7;;UTc%-nn4_6oDMJl8^V5ir4(@FC*26>16~7^xJ&CcCYq`2jVw_53Z-arZ`+xBm}tp$fi@Z)fYFDl|H<505GIz;P2TSx#pRxP6|0{$}^^ z{o+tu9I%kT4a?!H1MblHA-8)RHAC1UbAtwcw8Q47Qk42&7IxJPW$Vr-g8r=&RN?Xm zCYRUOHEoL_O|@oWzE(2V|0_m2ufKFASQ9ltkz+&6a9Ds7E`I0A!#5fUX$zZ#c}Mr4 z*G;B{@r&%QB&u*o$(8z4t5~YKpu`*2`NHNa3Q#+L5m?Im;WLLch*PT-(p*N~%`t%cyT=hbDS2&{n<;fECIC4zbT$V{yJGVo! z(^X;Hm8q28l7O?;`ty*ZzvxtB3C#{0h8sSa;b9$DzR)UxBM)c^b;)tUxK;(sp<|*; zf-{+(I!ISD3+Ys+Ei9d&&2>RuJpa@pw&4w2!5i>n^jpYW^b@?t8c|642+)$-j*lv) zA*`8>`EGgkHnMx_52{P^j!B{Lx@|H)b00~`a`DvBV#&iTBY5=@Q=Bqe2IqemiDxTa z`MFJ_DF1UbCVK0@h(|ZkXG$qqp3?{Kk~q>_E(h{@@nrEQn%%Y}i>tT%a+Gbb>B+5? zVs?NPq+9%zRg>ZB)h^MmW64X>z&Wjrjahc(5 zlsQsT-_P_pbu~6nn^__@rn}Rz^Raxh{1QLAyO2U6ov_Z@8y7Vtz%i}OwE934^!1r9 z7XE0XGuFpZveK4Ya}((2Gj;ZzI29lDeMUZQ@_ci}L^vNH;QbxCIOaj0Ne&;2cw+5g zI+zj7DbArd<7f^Yy6D3Bhqus^4++>ZGXg)#h~lNtUYw{uP%Q9nre0m|$mRC}J{$hp zaq7hh_~T+RpI!Zj_qfNxf*1wVZ5vBV?zfX%_i4yokc9Ua-6N?Zo#N#QD_HMa9DGvq zq842Z{8cyy7N#Eu58o>g^xOj9&OQxiW>vGJtsQ?jxY9nhVmg|-z7#6|N%1Q63{YC& z31jAGu)bjwOK9(c*d_89=QIslvdsCbt09)8cMA_wZwR-qSYg91Pc*Uj6`uLnaBbpm z@;5G_4|6je%lDg#gMLt3}eYnv+gIBt`;D?66|1}@^!y|UOZ&q zIVNUdv(Gb2a|8;V!K945pQK4rtRa5X!pm zQZQD^#^Oi!Aj|*X#4-daGVx=s3cQ zR+k=z=e7#GdT9s@ou|T2-mhjynHo;h`iCQ?{HEFgwzwlngO{8&?#bnIaQ?tfmVE7u zo~y4>!@>Q$@Mjg3CZC{&(#cr4p&4fP)4?nEazS?S0NN7OOvasF{CkZhXZ8IKpZ+|8 z{b9zq@xml>aL~r=A3ucatIp%M)+qdabr8>5kj~mtr^Lk2WSC?1jZ%yKIsVrjIDE^N zi=5r@_^%kYUSm&s*Yv2yb1ZH$bHLD=F>I_R4-)_0k-l51uxR&6)Chf5zt%^IBmy+~ zQM@{ijO&?k{ajgY=XFY}TtriRO;OJOikKI9r9P&&97nvb5;}(KU>~o!>|6b~zB>IX zuGy!>>%Ym;>4$@O*tf;>Ufv&SuNkoHwldHkr-9*m^6=uBh4Ah2WG>jP2a76NY1yjl zlN>9IW9nSD|KLjZr8vj0o?QAw;gCa} z!j(Of;KBRZ7`JacKVKvXEgv5cy=sH7tI>RU-B>Ym!2o($;f|$;YT)LmR`KGVCg?Ix z#9EhWZ1>?f9G)c7n>Bj0)T*Pcw@-ps?K$}b{1B=BCD9100;!x?vtasBgBxU4aV z&)0^5(LOUl(R~*0vXF#vS$^cdM3XT}g%xYG{XO<}(^FAM@I48m7M_TAFrAFR*zVLt*snGX|K3=EStEDQRrB{Wf5K9T2tF=;l9r-R`zLbxHcwVKmm^4x zPOO))kidK0Dmd-UQ0&w#5DJ^#(AJ-QdwN?A-+#A974Pq4C?!Qc?uY6XrhgH$a|_8S z!hq#HIytFdDQ!J2i5Z3qaMuwH+J**&Ii`Yx2pf1KS?`wn3KmV>Bo_WR zfj5<1;3tRVD8n%n#`GJ7VKYRkO0S1ewG&Z7+YoC;_2bZ}gFSu~jNz^S!41bqQ1#Pc zpTQmCq{O@A8uy&$EsTQiPYq##BKI{|OmHa3A z=tM*BZ*zEYxq-OZc@R&H>rGwD1fj!zE5!Ekr1L{oi7S>V+RRH zZb~oC-O$Lj?a3JUtVTSxDHsiO1K5EQ$r$>fT-8&-q2v(EN=tzq%bc;Rmn=sdljfk= zWwidl7<_lCNDMBXK(Az$h_*Uu*lc*PE>!!Qc_|TYs>mcDp7~C$>Aj`|w9HfrV$6smB1ypeX z04^fWIZ+y zx|YAwOAeH5O5Z_Zk+Drn+* z5q>HbQ0c*MykAF3&)Rs{kZkCDIeK#8*}#d#|Mta*j`$| zzIXh@<~lPPJY}qSyrWQXj(Ja_&QXXwqK`SUW4Lo^Jl)>dOnvo^!#O7%T9!JG+&aI& zi4iqe?V3rBMccWgayNU2I)Scc0TdiMPc}ECFwWWuj|aqx){;qZVpa|w_1XdDw_j3u z=m2(K_?{HO3vM5AfkLfnV*ez&K94X+_$ zx)l`~F2hW#ubAblg8@^|ux~@LFx7Rbu&F^86W$!;3qJcvL0Sd3r)Gniax>}FCvn=d z0*8KYCyO%MeeeKAk(XjFeA+e!&Ra20m8%d&+_z!t!DrxmRXl4FG_&FgC|C5x3`s*Q3*vE>^ zZZwNa*UGYH@Kb7y5-9$8AkUL2#vL-6Eaj<-@Bhm2!F)S>Gt3uaXZnljgIop*>*iMYcAaXs(@xg&rn3+702MieX!SXZx}yIq_~s%{N(9B8g##oLWkvn zM8z=tE_{Lacpl=$xYzp|+!y}HY4CDYBMv(($DaomL#f|3Fo`XJkYhVxuU=KpcC-s` zY^`wO&S*-JiQwC%!E70w0xK`KgV8cm$Q}IxvQ&P7{0}9p`;$N_zlUR~)jQFmph1X; z=+AxIM)8M&W+AL!25rJzem-ajFUyJIj1Nbk+W0d38=HVro+e?s>~mN%zr#U)(n5}! z9S+%9r^zYa41M*_k#y^RXiHSaxZ2rpVfJVUZ1raK2O(Jb=o~D*x);tV&Se`tq(=jW zu2NfLwem+}2G!!TVs4gG&O zgJZQ9ho#AJT%#gJj<11`b(iS&$)22OILa@Nrt#LThoC6(n=rg+434^dtWGX;AO6j2 z1^H)j{P@gPu#1)B^Se~A#wCYZoJ?TS=Sett>=R+*qB4jR2+KFVpnt1O(DJp-Wp+$XJR!yPv` zt8*egZE-<$^F8>XczC_+3{_foWjjb0Okrii*R(T9w&CW&-E6a}nVP2hVE2wzD7Ka4 z*nUf}rBVZ@J|2Sp%T96S){$(`^HfaSfhBdKILj>&E+}pXX9okkac&2UP*oA^TeOkn z5^>tf(v_}As$^qhL8NnA^0+niH(FhHCgQL?TqTWid;Ek5YKy`j;1a} z&~pOfxZCT7 zRw==yq!fo81>dQ-*qfi&-lW*I$bGk@;GCD6*yFJ}RxdZ_c@?j~-)f#XRo;QVUbzch zlPuA%`k^@7ZwU|BsK~-heOgky+cEr64?{V90(pN$e4a%3a#JRZTjc-?Um9@PkMEA^ zrMGE8_;Owqm`>k)uANt_(MCb2K|F(*kO}d1I<;L7OGz$_=1Y<%&Z4|(U!D}rWB!!NFqW*qM;=f@_wC@wD=T7($JE2NV~p$|APBm_w~4* z=lS^IzORJT!kP{fcC-5;yzY_1gYx|0=g+|~Kg$=_E40#>N8iQhzwKc0{+fU{#-f6S zHcmFY%}?Cd)6-5%z9vpW!?~(Fs%IO#sMW;F%lbh4fP=UZ_wt*!m2h>M8#kO7fYnq_ z=h%UThcq(r-&!wcWUnKM42Gkx;r|LCIK#SdQr>7c*L=gJF8b^+q>D(ft z$11w{Fg9-zj`9xU4X18FubDT+?!E7l+LJk`X{nD6b`!yN^)~vjtAWzVOLF7t7+xEq zFZx7`lXhAUV(WpY;pydcA-?_r6nDO)(l=b$*bogL$Z-?c%ppnD_ z`|kb%(l}ilyT_c{4ofNJ*nA=MjuWlVA1F~A;K=2c??C&bH@<=YpkzsdSUFIgXZ`e` z=4NHy(<~u{2`ox}_Td`?6L7og4$dq&Ab6PeWLY&|d^bcJUzw`%&mkuCrfC#@Yn*wT-I)t+WOC?=e6SAN0Vmdv!^`=v#KNWudj0zgr0ozWu{{uS zuor_|H(vK76=HqU|Hlg?A>5WBAV<2J#HI_1nMt*i->&t2e8XNHmL2WS3xXe_Raa^_1X(qYOM zO;j)+j)s#4i~Z8Ac-e_XaC<`ludrB+pWe8O%BMaFg|?gM&ws1P>yi`ht6Iq=^|ztA zAQqh$yFmK|Dc!u}%N2_RYzPmBFykoE)_T9_QE-jp`pL0lPd{OQHwSFV`vMsa4ph>q ziiV!*v_EkxbV55hj;Y5?^KI}@emZKK4dLx6a$J@-Q_^xhmixRp#?Pb%)Gz5I+dNOe z%H5{Lmc=N_;5OcrI=(V$3T~A*-ZRY>#;1jDchS+5>X=dUw9K{t?Z=dV_w3a?F;$RjT1CKSewVkHNgSi1cQo3 z()(4exZ<5A9Q#iLFPxZ*Zfd3=ZEO^*lGIo;Zo6RJa#6?(h$cI$fiz?=NTNzDdE?BZ zbk?*JbQYZwemXb^rM|~#c>X^(?xBv0>*ZmVLp~^uYliDR_F?kq8$z*yvY>x{0qYF9 zL*IKD@`NcL$?NbAI=6o;Iqu8GXK#XN8p!!|Bkw-yeWcR-cDE^afn0Bvt&?$j{H^0W5L z1qov9adk>fQRHjOu3+HQapIu&YoJ$lDr>!T0-3%`VB5eiqI*v>hTAu>v`8MCJj;aq zl?mMU=5g?!nFWuNyYcEjy;<+D6BPOs;m!d9$M15b1%nc$WhPOua&DG*AT*4fqFg|y z5U}T+WY+x^Nm}mHSaGT>%C~sX(-V{6PmBgi+B#u^$ue%Ad0Vp2f1OZ!;wC5_nk;=5 zR7C4`RD=F`duYt@k!o8?Mc-$Yxf`;e* zARmx`Zx@hY+&rBYb#BIk=LU$2OCqVz-i32d>(Zhj+48&*zZkZFw_KN?*8(@VJo&fKWSS*vUfTdCy@uk^0XjH(`Y|@TtHrBYTxqoT zGMrV}A7}2nMYAk_f`0T85-o-S$M8?5LYkU= zT)Z@C$^YMEa?MRs{-Z62;~y&H{*~?U%#A_57;&ym3d#)b!D<~^^i{!-&AzDM`Qi5P zu*8Q;eYcWPrVV5TsgUb>kqmU3IDeuA^`E(qoLBt@vtIe7<@ar3epd(V0pR6P^NMP z-YRc^nC3w+F3ARi$7W!cjG5Fsegq`N+HzWBGJTuu$s3MjQ1X!r;J3vUXJivy&^bnS z2hF*2h>}pLpLpfO6eV_@X@#?<2Jvap1Dh9GNiqxnz_Qgpq>1Ur;PjoHP%G`m0ZrPp z*0ZOuXkfale{MEsHvSTZWCRI`b~7*_y?}(ktt7v)0hBe0`TNyih~1M(g%LjZX5nPv zUfw39>Sy3Z9|D z08yMMqHj&ISIb3rpAKU_VawGeKL;OKTtx^uZ62(@x)v&BO3;$+)ffUsX5NR1i zr_dA3?agr3go{|wc7!ht(}3X}-FQ}`E57bNm4A8Iu$@;N2s2es?Q|S!VhmE41-s?d ziMlmkDaEE!TzF0oC%}T^CWWHi%cXcF_8AC4p%gGO6;vKZ2sbZlbHv@f z95SpY<^=5JfNeeCxzq|iJ@^Zjr`>VQ#NJ#wGY}8wXK?N9vC)`yD5^tv<`MmY(Ay{@1DQTN#8cIzmHvG`ikegJ-V|;vFaU zi8~MYvHUtqNZHa`sEU3d^nLUeT$e8bsGW<4YUEkY8hcsc42u|;mih$pQmye#$r5&X)eX8vo@SrR-Lb{6mYVHf!_S)gG-vokxHM)q z{{EOqHb0ax`qydxkl#dEr(cQhodkTnSsu%Jc~P>|2v4MMB;ny|v{~ZAcrg;UN>5YV zXj9ad-f@*}v*HU$ONEn%^G&~{(Jvs~qubPGMb9F!t zmh?RSHO`H-z_X*YvA0YNA1b>E9oYg!DC%(HaBnVY^JfLWOHea1fEHYvkA3edazoHg zS{-&@SYFsARku;aT|LKO^wPJGLeNqVrI@`(g?Zh5$YzimT{rK? zC&!<^jDVkt+c8`_0tT+@^UsSP zNUWwWz~E1xg!i(e*t9hoK5FlTA8y4QZ2JmQl4N+-qy?xw_#$<9s0i7=4#Px;moP6W zmt-p5fzKl)Qr=|_LHAnd^q12#?U}u3T>oACuzaaF-n9t3%w;gUE+4My>u{LbN8!>4 z4_cw5&3(Nsd2WU&e{R?Z-MO#Wx=|B%Ei-3pKUwOz^go!X^;`J-XEyY59gWv-JF#|` z0?OKk5yd|Mqbr9=GqQ=oZ_kI>GmK%2_b{xV@XvXE)j~+f0M6g}SlYF|PUxx_Ee?F! zpY!sL(3b3ppcrU^Tj?}cPpYIpk%5%;ekP0#?7!LfWhEsuFmFm((`%0_W#t;*H%ul;DMq7UydJPf_pmcz=xKkz-|8lDZW5d$_a zf&R1QptN`uMhvY!C0i;L{ zNh?>~M`se#F8XV5@NY2TqdHkL2=1aa!%FLd3`l262L5^fjhL&L14{CvW3 zQd`|6jE=FuBU%>tqiTmZw5~r6e%wz`){h{ExG6mGc&DKG`z|cqKL{VBN`CTu-YiP9%3p!U^VD4iI{e|6kAby_q{^WMv01G3?U|5Up6dnrD!GDPS57h%Pw z7V>o%#_DS$>087Y)}PQz(ju1%%TA}`v)UWnvh)@e&$~w7Lzbib!_A=BZ5{jCuZ9iP zMQ}3iCf?Og#k9&7LaTcU59?<{Yx??=W#6&%ylXAno!f@N<%2O~U#J*zp_U}_J*m&k zb0FKM$nepQeXj4Ol002(aa{=3&u8<1?dCkP%>&wIG{f#cJ?TNmD;jz034GHJWk0v; z;)bh9*z{W#7n>S$tI`Lm?fVF-^#);pslYE^_Qh>iQ_w3Egs9{!*pL{>k2OC^kH{|J z#}$RS0?87fjv@B(K1y7AKS{oj?dco+VH9{5Ec38xd(X}nN*;%7vt0B z2%gHZklW?KO%qjEZ;Tgs_4`Se#+jrlS z*$;m>>}$evCx_%qQUq|+8b6$`;G;( ziCJ&_{UaXCE~LhCb$B@)>eAeV8rG zxZMF3UWbIFdPj^Koy7aN9wOJ?rhWqkVEZ|NqmpM*$*MtU5fCmtp&W@CvRh%zMjz7F z9>sGGzNFjBdSgV_0~%K`Pb_}Dl2V%0u+Qo&+WGJS>3%s&fqsVt_0}p#&b?3PbjCpQ zhoeHjlP7rW^aDI{#%OLCABP7{jls;xdnCE~b0Og8H?TkGgs&f}@%iA1T%A4^tof0! zcB6pr=f9*wTLfI2l?BQjBf;@kyl|^vG=@m*FxxFz*!;AU-c1Xp^kJ99%D%5?hwXV9 zd&(WY{>jAN<+|LwbQSzEQsraLW_U>N0iCZ4VGYgc;-Di^EIh2mUO(nia@KA>-ZBL& zvZg?UUo_QxHpMHJ{b^4hYYr3LF*fim)l9ezjamhw$>joY(~K0(p3vf>)`x^4{dUm2 zzNxTYIR%>*{}%uLHRKr%mVEwe1`OQZ9Us!kw>806{0gS&W`D5XWf-TzRGT0_^)o z!3(znYVRHgj!D~?F3m*ufj7mhhqA(}(swj}h5=|!LR^+{gG_(x^G=6H(5`lpWoB-@ z;yS_$_D;7(RgIgl&=1U7mlr9H=&9%+lQ? zeRBpQ9$$wA^M~;JFB1MVqYBjWa$voaHfyZc;f7mU_{t-uFy@`NTnx|aNfvH>6vR!$keriR4J2^d?O*)=Q6eK8;oD(K84f? z&G6XvE!lL46s$Lh*Tk8!`hYotmthW6hyKgm+v(sj`xtMk>dq}gyTRo}EAXDDEr&Iw z((A6JF!&!wN<0S3XZc~DCr8DL*QZc^l@5RK9*H&kYv^Q3F!dO`i8I|l(8f+(tU5Fe z`{=2`r@te4Z(SL5e7gv)7Jh)mg=`+}z`MWOfS;rTgeMGPbB|KFVF1eZs(`~)$xxju z;E37f{4-XThd7kc?qzAH7`h(fJ|Cs5->YGOj59jQ8Pe(BZ{gzHB<^~47OGw@fNj?L zSe_Xx{?zEnF@Y9%?At>avT-(sny=^5TPuYxZ~tYpZyuZy&rrHk3iX>Z47-)dv)!f< z*zhzG{cd}RpNnkSRQDVGx7rq6!<}3reD6`eVoPp3c>`87pTNG7HmUWR5V~-34CmZ7 zM){4G#0SE2I{z;VGnU+k#OJ4_v3`ePcFugVvI?i+Z+hTBUPO(PT_EqQKIY9;VMG1B z+$Tr?*OSE{nQa4Jt!7+m*c;ARIigGrR4%`8lq(y<$X;3wcMq;ZRrerBf7?VCGGuYw zqf{C->>>2FQ@i?etvTPhe2B*S&cpv4li}ryr{W(yKrn)~IMre{wlr?%QtK`7+Ex*ItrKDQKW7eC_={EJ7Es*F5Y*#! zta>UQs$Sicx&|JnZc8=MeTomRZdJt0&bxHW*p{36*^6pZ#tRR6-WTV7ct}PKexRC= zErgha;IGqmj9G+(KugHDi`1w5e@9Kg; z8*R2OdM2G8Hh@fCvQ|)-&7EOFn znnC{Ndr4zO9Q(HR;f%Nf;ncT!7%1b74mt&}(_s|KjK~vxryT-kjcj^Q{hMst)9|K5 z4m69ip<>BaUewbO-nCT=!rcf8ST}~--Wl?@DZjw{VqbL46@|x#V(I7sWjfvQ9Re*C zStsfU+FqYc=y#4=MjCOhoguegeF2{;o{=jBA{!cG{4RU;8GrjR#9CyMho5Z!Ibf?*%?M3qA- zV1IZ9%1`eD@2%#t#&a`{eXMx(Kci+*IWwLn7e`~_*B0wr7^R^zk@Q*rmrc(yJ) zPpJl}^y*O@$elO~-}0Z6-a}n%8gyP-Wj>5r=6~atW=H9H$1NCkBpjR8I*1DD#iU&o zg*S&@h3Lb7VCmsSIC1?te29+R)HhK&x5$ytMRZ6`{@udsYtx9MhV%KUsl4=T4_v-t zFvRMw!uyjnc!+ByY+f4xU#&Ih^}GUj=X{)BB|QMmsUulw{!APmodjnu9HqfKRWV6t z0#E%}3fH~gN=M9mj)N6+*a#cp%&KOx?W_{2jwXwvQ}%P*HGSAQX)d=n)#7%g0?_)o z02gmetw}DZ^YlXi${cv*7XpEkmiZ{M@=cQ@x{4sh9In{3jELQ^8 zUzR-b$QL10TZ6i9wPB43ODI4o32uB*#H=eMo(iaw7PWqdJx#HYS1N-Vw+`df^27Lc z%?HX%4-@rePDr0V`YHzdkKsDmb$mY~nXTP_xR(3tajQA}bCpUmDpv+eHb<9QfN49< zf=pf>Zmv$Ju*s!jtj!5}oNNb&W%kp)l@44idkfk#eSynw35z@npepYyRy?{*lclrB zPOk^g`nw+_t{Kv@KT15f!jBhiE#e3(f$Y{qOJ;nWj(Wi?)t)p2b#JSn-sci1NsQr| z9YdJQbZJzTEDT*85BE;Z7N#g^;?td9A>g<_97yao)?}2UP__Ornbex`l-(QPy@shc z@aIl0e`!N)L$l$*rXWuFyP2o=+6xm67&6B^g7VU1w12n;Zp$By$G01b)9j;pOZ*6w ziZZi;75 z+=E3Hs)FCX7?4lB&JObq0nVMuz8`KwT;3l#qqhQ{%g#sKr6?q2*|XsteY{+|7Oos? zg>9_D2hxmr`GrjAcVH-0WjuwPDHdopY83@^xbU*j%c7d}C9VBf0nfbvLqNR0r!eP! z1k-s=P`Q#p?#^NiKl>c!C!K?yCK~+CDorYm{y+hl3jEvd0(l2tr^_xAc-A+qtImsu z3A$2!G=KgRY_pHU=Y?m*k8%Il>K%x`&Glf>-*BpZTD?Z z@O&T!FJzg$uR+Nn4k}N!3*9pl(Bsc+lG)M(8y`1NR7AtYuch;DP(X3jM}1 zIgUNUn39cB;oz@M+DxTTqH5r1p^SK>BA%CbjGzQoa@o#`-COxz1aJ|*y1%L_hl_zoudblKaOt*r~m|EkMBR-5U-?;T_xlnQ|_2jZkQUviu|gBkzJaH(8+7l@XES$TyU=j9KTi2lf5@6B&U#ijBlgX=UV*D`v{ELwv0!= zE5ssIQ|f6n71qC4PV+ooh;mm<(JeRHhiRM@AJ!<(R;MA`g1He?OPa+e~=A z7dl%F_%SL5Fvjit+j#^R>~XGoH!!k(V) z;-k-pamLJ@;FDs&K_kt0WwEBPamN@jJ7Wk3%50(BH|qE$IFWBz?xx~~n?m8@XK?O; zGTJYd6&2)T@t&#|ZB~+j4|;7hURIfZSa-q(oAuD={4qh*Kv9TYe^|@eFe+^5(Y=b=JuFB-p?$_yi&+e$)TMJVXm1)wH0W3tW$KaA?_%-V`%xf$a z6&_sRaS@*-PabJeeNz(N^=zRp;rn3tHybF5iszpLr=WJAHf8F2!&CQ}Vyb5kD1NMk zKi^O0Q!9RoHe*wG_T?y0>t%$W^Ln6vLzYz0>WA23vj+n5wmh5-NtE(QqSNclrq|FG&R5RcYLGr5Oxg+!Rcb&qK{!B}%J}rPP$g z`1(*Ki4#+Vz`9Cs6Kn9PNj_bFw*#8x`f&8m9dM}Z6ZHvS#KSB%VN|m&?mv2$R6G^< z`sN1mGnK>SqwVy4LAAJfMGlGHKB!;X6OwzsM6Z2KRFmNXx!>)0dgDSEU~I!@Mi{Wm zpWR$NLJ#e}R`K=XQTTD)L9(3Q2fN!?f!pvx@_9BCLw2Q-%atYQm$`xib}RGku4$b9 zs|sk6431m1n?e^&!_7C#tmR^xrjHl7Gm7m zL^SMXhmV#@czW$;s{geG*3MGo`3E$4nMrrHQ_bcdDxI`V^&IuTG6FLf-xB}U>Y&NB z0@!6d6z4SrNzP^uz>yoAP;J;ENk)~FF1n5ruT1TaUqU)acS1jox}(5VCG~J&pC^7A z{De-{8}Ru>?zDa0G~wg1V#$e0b@oXa4+$5|*iU*+I-+MeZvAS4xlZb6ebJH&;>SrY z_&lVHRm-`cIhjA-n?c1N)?%&mKgJluf{sr@+$fulDW z(~yKY?pmly9 zJQ`vRx3U9JX`CI;b6iXggObDxwL|gGtD)l4UxngRKQ-R-SC)gy?m*D<%_MVf8w`B? zmanK!AywZV`2F|<3^+Cg+ZT?c{=SL-`o>6(>ED~|HB*62R`Fu*yI^KsBmN4%4jbyW z!+#qTX-?8z@KE|l8<&LeK7H%Tog?RRf~NvLj<{1)Sch??tZaXeyIBSiS`8XKe7kcxQh0{5>>3_o^-(+-zoTEYsLd_Wb~exJpoef$|OJECm4H7Q@UqIEsD@}19F zs2OowJp0EDly5I!MFS~-mkxe^uFQvnx1!nQcQkLYtx%~P!@0qFn5dRP_lGBPnUlSA z(9uMwUzCeC=JrP0H`es24lo0ExxUyZUJxu+cSHA(PKjUo zZt=sy6XM~)acESP1j^%f(HNyvifo$(iQm+4>j`@v9kmKq_Sl6r=Uu7dkTq-cwB?a= zW>dl9KQ#7q9rYimjn5-bf@Sep*ZT)Ip+b`lZSWT9&VPRV;8zbes{RI77mugegBP<; zLl(&RoTEdVPs7O7T3m8tGOYY-i#i)M;h=0Gd@ORr{Af*XzFmZAJFk=O=FxOOQH^H? zb>pvhoUp5hE6cQ!i_hFlO2q$AF?c@hC{xGyzrj4>UIDnb*V3qWqxgt)3_opH59&MH zS@F;b@c7XisV)NAjRlQGlvyd+3@JiuwBo^Y0^0_~w)sc)oUlBC9K;;nIzA@4bOJ zxw#bL(v$jG$d7e*uf)LX_vu^vG~T!7vEW&uhmYQG<4BC*@G?=FUQtQ=zywbRTH`Xa z?~ti)A$}M;n4bk_3Qnt^P>8NJ^{%tTGe-kZW1t&SpD`SmbC_QCm9SCbaM(9&GCz8r zNeiXFASkhb^J2`otkO+9c4IzT&YwHBiyiRzfSEWU&VUP+yYtp%z#TzJF!h=- z`WIA<8Rye z>pm4B%^?ayG_Hbbxh1V0dxF*uHO9l^rh!JTK5wbqizf;r*)?t^c7JEd&Iy&m=T{26 zcG+M0v~ePCc&V*MKxQdt?tV+x zDz$h?&q#2XAp?d{I@qD;gu4I#f7I};FmJFn>3L5QZq}%db@J4~lx}xP#&0Q$@|`p_ zCJBlrMey6in~<}62F_NP&nn%1(0#XB!LaTTqy<^iq2cp*-kl3@?p_;etv!p!KYS+r zUtg*J&tke0(+vBy`*QscJ9hMyiZ@M*xo2uBxP*_v7b^3m*DapWqSVQ}GGIAQ8r1rrd5=WN<75@yll+)o=r4gYi`KF7=E-8*wY_8} z%)-=f`OxtoQOs<=1^j6r+XPr+=(CliKn}Rs5;-(&5goj>2S!e`r?$zHaZRg~!WvXq zcD*{co2$Z@QR7g~AXqFNkpVMgy~uQ`29{M6(gVj zVQez>E0tJ2#%EW$Q%vp*P)^Mxt-w>_oQivpb$TOT>+cA`=he{l$RTXGJR0we>dS?Z z*J7nu zy%~-7)7H_)Kt8hyT1+-mMci3&`Ce1ki}z%4z`gUL#q6!(TB`x*;1uzdm}) z_> zuEa3CD$$bGN*&!)*wNTV%+)Uue=ZrwDJc_a#7h$%UunoS6`LfwO2a|iR}Vhpx5Cfz zyHJy|L}*o6j>n#D!EA*CoHFt(tqktR_W$m+ysDLi)p6u?)eMCCl|0{34>!NsFSaJB zJ81+Cx211fq# z1A60!(vwv2YbDzn3OI{%dA^}LI<_w2fLKfH+%yyZlP`oc)WSi#wsRLZfU2SqpOT#6 z(uhuR`sDrKdH*+LANS-tQ$7j3#&<`FQ(vsqo8w|^|B!FJ(898uCNXc44^}Q$u* zOZ+q`V5mO2>^Ml@GG@{^9~IUfYAx}qI4}JpIZd-hxnoVJ9wzjw;~J+vl<1+0HwRC_ zh?A`_!+ayvWXWTorj%r3E9lMkBmAtbmXh~J(SHlSgPL(D%x{_wf~y^xw}**OlC&Z3 zhXw05&cgQBaZtL*7UajwqgHDZxb$Hlu9$4XAI2(i4=*$5$e6~;VI^d;M^Exh_9ck9 z(c+@NneeTk90nckiQ82)cv0JU_BG9>OJSddOBH)zYIPpn7$1ZcJ=)+u2X9yPghRYB z*qtS3qan$(0^-}PacYJ+S*qyb=nXx=`%W+M+xnrL)a=V^W~!5QfG_;{myHLEjmfcx zF9sDj%_~_ z3URBcGk+MZ2u0!daOJIiP}Vn+KE3nj&WMT7d#whHO^ar8<&R{2tccfGoxw{^_Iz<+ z7M$DKo9Ul#rOc1U4^2*de7-1ns}*sdz!@0(?TF-=iZ_nv^yP6~X+pC0LugpzE2RH7 z9!7jwM%wP@Bn##};Kt)cuuAI}RXuUQ>Y6n|MgB=>88iy7=j7sB$tmtCI{}qte@W$X zZ%Aqj;nu~z{O0}wwA-8tw_S{&_GCJT1r6awv)PocI~)%bxTB5CKw+tNIoz5*PP9&n zMj>uDhSXo-*Vg?wVfY08wBs(kP;I59j|=E)L?TA3UgW$RQ?bJ?noo63M7?gJ;1nK+ zS(hrIeDPSGboV?tEs~+o`(Z2{(hqOsoT3+ndj-SA&V2d97ufmE2wi(eUQxghD*v~4 zwt0W%LN9Njh9bp#Ie94QXcHzDMA1j5V%XiQ36nBCIoaYdxvl<71}cV_XEp-EHmu;s zyFy@6Ym;cKFoI)Ny`}t24?OwkgSgjN5exq2Qc{^YwqCj=Dh+>6;l*J*VUsHEdfP;8 zV~ill@hz$6%c9mxH_UaIO6&W2!n2ZCEOr}?8E<=HYOgg^)Hayqm2XqTRbSQ~X-W%5 z9HQ`-3D_&Ii|iANMVrWlyz|mk@o3w5m@(uqRfU(suw*AOwAhyGwjSk7#a>w0w?yo3 z7m6P;I)t>9FX5s}2J|rN!?(It|v^$f|9Z$Mbag{ggMZ17bdcAmmxfLjMCgRl2 z=d{%QgZMo72_!T|z}$`@^ypG8`CL_p<mEE54ApgwO&b3Hn{?o8AG`iZ3>Q z7OA@|C@t;HZvu}~dT}vHcc!DCT9yzj9Rk_j625ri5!9AX2gS^j$`m~wb3&Nzk+=sF> zLJ!R^^yG2BCqm;CBlN1;F4{)OUNtmR;J$4tu17K>aKqg!i1@Kfs7*NyN&`NKqw=4y z*4=V=qhd%!{kCEK#sQFKlOv|p+kpN*cGCV{1-s;NT(~rcKPS9}0PBmw@Q*|B?F)65 zd8Lp2cGW>c=uCK^tjY%C^5Il;HjivK5{$GKld?-Rbfg>yhanll-vA%1`}{^w_??A4 zZk32~2ES?48AVQt8Y5~A`FF-cRz46m_;!6c87?yC0BKtaEz?x}dSKo5jAn$~A_6FQBOB>eajN$74VtClYeV7;O zg&}L|Y3k~Il;%?{q`G9`t4-Eib*+qhb)?X|J3TlgV;c5e-3M1BWkYf34TvquB#T9* z(%6e9sc=IK_IneDmEnW0Z0J)-Z#LQR-wA7AZIK!C;d`{Xp^4s~+QrvO+Q9gtpI|1V zgW+#7gf-JXLdlT^h~4JO=9h!{ZICY8*A|K%_y2?WC(K3bb;i=y4~L-H#ob`<(Iuo7 zuEJR!j+~@x$ad}HS+Jaf&1EG`UJBcLohKV( z5ANLP3qFs`(A4uN{JkWl#mR?7=NuQjpLR|N@08~|7i-Yr>R}xAzJw~b$Z_ARMfB#Y zF_s04=Fat=jFo4gc48n0EtKWl-P^^(!*bz#kO=G7bc)xfsG_UvPzd{Wk&ljxq=fCN zc+D>qr>x%Usy3{Qawb&3+s|Xc`_xyLVZR&D$-Xabs*0yam-leUzCt)N)q>p0?opSl zJngwM0%tEAjFp}JIYDtFM*Yi^q-JxpYQ9d&t8Ao2F~bFJ%BA`08~Ave8mi~?V?*tE zc$Pb;#4c8>8qyaxy9CjVmG|NG{m1m~+Z=qoBNN4_zF2WapZ}QF(z8EX#i=Xylio(; zD=BU~@9hUl=v1Y(N`>HHSp}|=lQ4LV7w&b=2bueNG-6UKj}F|$i>+6pqFV?C&Akfa z)AZp(z(|xd$f5nu#r)K}h>!p7$@hg%{NsK%%uVeETK{-*|7eX*=5B-c!6Jk`zAwsZ zOK{0fGfoU2h`nmexbgaJu=;zEh97CBoHyM-_3|Wc-aVb?EHg#J!#)^Z))z;8*u>kd zc1b6Nd7)*^BKY?5s-RYTmhIp68T4Pk2!cJ6@<`gTXHD{ac0gv-e=T zeIQ@Y34j7OOR?eR3|MBB3oC>~#ufwA*(k@)d+$fn&Z%7aayd+wI&kma(QxL341B+Q zg#uJH@$E`??p0kPj1iA9ZkPlwR*0hYJ8#_c$pQm2lmu(14UoO@G#)-J!@rxa;gP&( z{xZfBSCzW)jFJgFMy>}peILT}Hk5(<_hR-L9|}j7oq?-^qHvBRj~qN3DYvd2W=5Z+ zY8OpT58KPmE6%cZO&>g~tcRCRjY3Xqqvzi|G5(gTOxqX@n{`@hFHosF4cb4wv5Rb)h>+egU%xwa0-K$%s94G{16*eAgvOIzK+&dR81-$@zpnBQTtAP3^RsqB)u~~8{Hg|x zeApi=%bJCnK1rg(!L$7RVt0Ixo%a~>qapdrWT<#szBuCorm z4zt3nt?gn+`7Zu*G!#ZZ$RQ6q7nHwy2vmGzIbs0fysTRB(sabc>`{Dscsv_jjN|Ah z|D)hM!+QL`INsI{MHx}rLs1ze)%QN9L?RhQN+c^QBP%1?NoACjq>P40k*xH+&yf`+ zWQ7o-Bzyhv@Bi?=uKU6L`CR9`->=t`JD4txFveZCCFm;ahEHyG!-q?P!EOEozBuBQ znBp>@uWc=XOHJ8_^EE(u;3D#l8p>O9^e}kJXIl5WfU=(TVTJMq z=(H~Yoht(&E_n%!il`S3&C{Y)&S~slm?l0lf!MNuEE2iUt(t6L&_^tpu{Ad1NYWs7Ks^^YC z(;ZJiX?!>j^}bD_Zah75utt|9U4FI3LvnHCS(u%dM3=HYaeAaH^_32xhm%6^*((K9 zd3OVvjfdf)r&>H9Jrmk;KJpZ$5@@img>r`;Ag z>BAV7k-{3+b_>;uZqThPZ(1E7$J(ddcxCGroHo_5>v;_=Y?#mX0cWY8sZ^Yh+DWbR zd!qcRbD%b35w0?OPGctMvaN>;dvEWCYS%`fYyW>_*1Ap5-=+pPRz%^#U>8g+QRmi| zb@Y6Y60Pa+3TBy%;u}4uu@~_78k+G>9KosBm3ep2YlkHqCBV;FueS@TuiZs5ombN)I&%b3KcNZ|A?dxjHXq z{fr*i_scKd`sbzSpsmi(vKiy9%%NQ8B|yD;V#mB;c%a`bUf-htI)&`dS(B;M|53C>Jg-g~o!2zE%7*@IfB`4B&O@uw(4BA3E0~;XgXeC(e zHRNB4R`_wL1rJ+l1#t#3C?o8E-#*(&p;U>b-)iVWekFt#+c8)@6ArIXrL*%E)2)@8 z*zt%jjn*AQSvx#&+}PbhU#+Wf{%{;zyt_kuuMtagUq&LmdPEO?tBGg(y`zPrl3{G; zQQ_O{QS7uS9G&N7!s>BOu;7kOmm?3Nl95arfA5g(V=YPjy>H;`qlGS;{c-TnbX0PR zmK<(hPYZUbu~CXGXWzO<`{ZpoR%;S%s9($%n(cX=K|gS8@yAJd=i!>}Mz@%aa-O zfX?z(YWlerp6jTDOIDtEweY_3QW|$8f}?op9T93hU*0 za`##dUamg}wD-Rd6qmFM9|Pjuw!9sRKc-)W(GAI@JoU2hOy~yAcJg2C|;ho zaS4n)8HH<8V{pVkV4C8qsY;ab<4JcGep|&sO)NOYx zyxIPNq8BvLpXDk1C^-`MyA_GEYN8<`b_gx;&Z41iL3qc;l9$N+fucUgSXx$tzdoEp z*-5KmO3ELSwx#l{#Y<3Qb{u;*UZst#qq*^#zhLg8fpykaxO8m=$WKutlMDX|<(|o; z6;Vk~e_f&u>s@^0zLR({CIr%?CxIWy;!T(C&=jnWZKln1#%>mV&a=dRol?m96H2$< zq>-lec$ycoidWg4Ce!s-ggVy(Xp!A7F?Bx0y*9{m&~Xi%J^l-{3(v*Jy}nc5MZQ>X zR)n4_27^{p1UX%PNCswK#KK&8Y_sjdp5Z8URXRYGYh2j)-&h;YK~{U<7Qj^obr ziDKg?KnK4n(YU=GmPe1~uSYY*#_u_>?ZYFukU3boX+@{FOy?|I>$y^F^|?yk(>Gub z)n)AaW*vK$j9}ve6L_Joh1>5*$vkZuHn^7yy%Y8cWj~W)WYJBC|1}VkU?a&Is`2D6 zdqo?CUGUvSo7ZS2u=mSW9GVt`XY0q|WsgO?F4UMK21>|Rxi^ofN&*e<3c6USkGE^) zqHA6e<+`HZ&dNKO%7tZ|{syBCvxKUw!T-n&Riy_T{&ve?)lwab6=q_@4?sQal2 zG%Dph^jV}$sY$TP+qZ_Iuo zoZ%bLS3a6*PO4+ns8sP>c^uuY9nM<^`S1bPldODJ5t~P);CxqmShuh{4ls?Q2uMNe zY(IP*IukWh=14-;-xs%S*iM5_ekQHpdA#WSBl>Pz4QBQ3c-(qAZS(iS*g10K`@B0i zsb|upNj6-zf1Nn&-36NWehPaTkHTH`C0yc{C#-ElIJ#vp_V<{8iXL5FBN>ge+bY=P zr~_Zms^y82dAOp-b1<1Y2sc=IK>NmS;J+#W&-O}VkL8=m%-Ni)&lkZI-=z>adM`zK zkHNBEqp79Q8!bVOUC-`>Mn?^B`s@K}k2}S@S;gf4;3@R>zCsI9f}rz94gH=vlMQBA zqjByd_;=GD3r$Sm*!eM7nBoBSPJU!6KbN1L*Fo8H^+NLb4Cs;YTCA?PP1Zjj!~Ff{ z$mLZjbdDUt=E-GTXc31OZ5M&TlvUV2REZ7y|A51b%jkNQDev}mgR^(-uzbovT-t3T zm3?sGlfF0U{DP@sMX%+;swqi4*Z4RW`%Xk*f(w7MpNn6fT@z+^n4?bIIk@aMledNK zf|G0gVg9re6ux^JdTvmHA@44NWZ4(`)x4byH=Gr}#H&$d{4tJmkHZ>GANKRp#_73Q zyu@A~8_I%llm9QWxX04KCH^>MMiDIOCyTMO6L_O-Jk=;45-Wa%i~5=;1^J<`$n-*g z>1LTMzPz*>PCYb+PJS8(M(OVKSYelB+|v-8b@;S!DQyc6#2O(s5g-}~=7Ko~UbZ6# zT!X*XwZnz5`(jS_3*b3@31{8z#+U5o!w9EhSRvP!vP?t8Hox;=zG)I({T0K7tFxu) zZP#guM-lw~@&HD?eh6;EA47wfPXUkBKwd7Jzm5w5K7bleD8fYl^N^Pq4_?2Fh10hja6^=n!ctuh2*97?oL=akw%3pF|)VQAbxt}X1UU8)TRo&^;C8I*qUQtcqvPN8lef777a%kVAxsPvy%E>)Kv2d~S$G2{7kRM$SueLkE8 z<&E!XNRBmbZ>WK@_CrM7;9^i+Va(2F597o>b{z9m8;!0$r=!XGINEX^f4=F%zW2V0 zgZ1N~A$2g;dfkLMWQ~g~^Wf>doz!Q~J(9a-&aRcpbgtnk8CBT{Rrc+)$V^S#DR04J zg0DenuD`H6K_Yk=XT$5xePZ;SWc)g}AMM@}hi-*idB2k)9NVM8udEgk51uaAUDM?V z-A4?E)^JenDhzgAfM=V==gU0EZfYwnzFx_PcWFT1&X173{xw7m zkAwFC@#3cGCU~?~k7v3~;;BpTfEeh9X^R!GsOG77-D(1>ep43J^Y74N!%?*MpE3HC zju0NL?{~So^gbnc9-~c_=W&A9H&SX=Le27buw~C_nB$d!-ILN$F}#{=4En?Vfka0Q zw$rGFNG`eV$h|!q#o9r0ILq4|m$bytkrV1zuwxB%&q)J~MJ=%QnHsMOh{3R5dhoda zPBN#{Vs?c!r3aWJH!b1`0n0=TI3lLVZbNyU_u}cM6J6)04_C=S+}h*wtG@XeXF^f4k4pXF%t z*?^zFJCm`zWF1)fHnJ-JyhtXhR@8)k`1O2^^+89_99 z;}`nq*n|6*jOWIT6R_Anid15kb>;hQUTE|MheQeZv1W&`;z@tDKG{>6QWS$v%lh(2 zBWrq?+{0a6?1Sa*H^jyV>HLHfpntJ199A*pJ~Kvg>aC}uPih?4@5*A8m$K;XT_x@s zbO%P*<;g%EpnA!+!$pvmj+Qc!LT43fmc$q!?p@%AeyIirDjg}pg{ zj~vD9)xG>j-yFQW^To`EN749m9Mlh33iie`U^*NT&_WZO4;As}f(*JjU=1Hhdg!8@~_Kvw$`fZUGnJ68sl02g-jfId(%ZyH?w> zSK?=JRM|nXU)WFh^|(9640Xb-CDVoQ($~~9_6%p8jzPuxGjzU49nLA3F^zu?Ts$9j zULGbV&HmK9Cz(Bt=it)vL~8$22mb4~Fyudid)ODN-xyY(&$$7cvjuoK{v+;n+X^mQ z^2H5TcCdG#DO-;oNSoq^(Ei1>V14!!Z#DD4?Cd#Rt*b(f#8B{w>*0^~SzTGc$;NCi0Q=_3-ag0n8Ze zgN9%Bi4EV6K+;MXehhiShPD~JGtrb^s~xA&o2Jrwi!Icsvy02t?a424|^Nyu4m#XPiQ4;pgE|k$n!?&MOsZF*e1_S+W^Em9)?PYOO~kh+ok_!8 zo%~lUhMAjEIaB!* z>?t_x-Gdz}u80*ENc@p|2wFetaDe=FGWwk>R*nqe)7si%aa1bw)Y8V`Q8(zL_8j=y zLk&lvHn=O-(X!Bic=z8ixM;o%3$tgDcj7)F^xZI?vSdF^E9%83);p0Tp@nAEBx3J5 z6>w}&Ur7G*g+`p{&8w`siwSDT+xEFaNoE^ZeeJ^*Px^4PC(*4g2IS73v{{Q$4llMk*u8gl7{@5K%ce@!W~7?+}Yd@+ILlv(US-WnBORx^--YR zf&?dH0}M5~%Hh*pYiwYx*bOv?q}y}6Kk4voc@#uFIW#aP}CbNJa0pv|tCK<8%(21+xyxorT4 zkG2H=$k&uP=>v>ztQR_4T|{li0mzzN-<#h7^Q-njbJYdmN!Du~^Zt_%=jg)nef-c; zp&u7d(!~YuwJ>9mES{H*=JDruanr!5WcNr352U_^$&KeI`u$BIs#FX2k1r;dl>OX# z!$%r(B3!IX?}Vda+aM>rUD$d`4JVe@Q_ICbtj&($1htFsbL<2Ts=5H1?iJCr_n}Yqb@7@`vhhSpTvwg4J<0 zJ*z|UsTP=er4$NEmq=pvTk++LU_2uGK{#Bzj!3f>^I9BGVecAV@~J1!+aAnjZ}f22 zk0}g|n_={!lOXzirQ?6>>A}kF9Nm9EY|J@KitaABx}Yx%FCU9{w9dectOPtJznr7K z%dp*?KD;XHl(=c+Z3r6X&i+n%_;=}h;n+wM$&3_xKH4Lkug+Wt4c1d}(2q0VER#ik zPgg*pwKhKeexB`ui}>d94}zbPGG6Vr1jpfd@c%dqNBkEGx`F!qUTYQvN9=(;w~P4L zx*=TJ>P7eS5$mch!xxn~R8*>pJ7+)R^i3;;`V+I*Z~Ps2)u_uak~1WOS{I;_mk#dz zI2KoHHo+;GRQ~+$kF;IMfoC?K6*lCliz~YK2T{KOx6L~(Iu3ow-yS<*{X=87$qN>u zS9=C^dg}7G5az!1#!XHp`GWHwT4!_h)IrQibZ1IxtG=m1_-Y;oUyFBjb zV$X+(6Zy5vIk%k^m*KFZKW3O^L4fW<_;{#^8baK~)f?1l_t4EWVdpkDqM1P7TpnY- zRs&Vv%7;xhYMhcW9j%sa5)D(=@rV2~l(D^p##RQRXjn^aLuYcVoR4JH1_iu+&=9XY z`9=d~Zl>n1PlQOlOvHoMFu~u6!;Ze9vWg*$wadZe(`-J)SD~Sg6n2{Ig&$cp;)<== z_-?2ZotwU$s_q^p=c5^dnaLq2-fzgC-Yo;!L&Lzk?j0Xib`y0jZU@;D%aOvy(zEgI zY_6z^i;Q-$L5VV7l~m9zGiHPC19VOZm$_ z82Cz+hfl79NxSp#TdD&jYF8R2O^Ss-IgJBoJ zB0mAF(q!1TZZ1sNYJlIY=HiH($5<~y7Q=^);|G&fQSr+I$?4$;Z=={)E6N4jCRNKi@rOcr}((fP^@vE~ADY=kB!nN~^i7HeX5 znxXjMf&t&C9*9qduEsfPKZG}`VPdnqCZ}7^lV%P5NssjJQkBY1*zj-?j8dG)wwro# z<+&U#Ije!bS1g4ZJvs1*xDE5qeTT6#hM|emezGVJ!a-SQxO&EGS975k$CP@({#zm9 zgFVic=SJW>}y}lPX7XNM(tc4 z*E0m$`tB7+uMWn>us;y`VmwED-64z_`kpHl!laRk_N=hm4~u5_ko(Zv@Va~tG$|^g z!D4sNn|=s7kM!f#_I~`dw4IhsJp!3;`s2iv>caPlTcK8!A@89(9Fl)8oUt{d6}v8p zzGsw4eP}sNJ-wR>j``A$B~=$gvo3RQ1w($asFm#wmb-`q5s1z7#Vn*=fW_~_~^l{&o-b>Obis8 zhr^@l9YBi|u;RJ|YX|qfJab2%wQ{77e4N* zga7);z|(#w!Rw7VOdszIeWJW^hf6n(Ih8?r%c6vX5!JZ5<`R{^nJ3J8lu6q5F|hM{ z0$m)I&GQUW1)b1LJ`*O--%^}F_oEzM%2vbZrMoGc46sJ|hhS{66DD-H@qt0Z*(1!F zd(>#-h|TXoCMQcWzPSV5&7KNIzK;04Y#xuSO@jLm{5VI~R^0jiNcBDKw@|#u9a95x z>4vTvj*aifVOA^fPq8ePbfm%e|1?QaI8B?YUclPYUfiKDjaHRqvtjdOx;~@~`now{ zo>#c2rF&l7y-FXyE^)&4?6Y*i<~>ORdt!@E5q;Oa2Ic={Q+9_w`F~#qo_%y6vWKx- z{-0*n_vnuM*LrZ;sX#0^70k_*Q{b84j+J+-gy3uXSTK7Kd>XqL4eoW&#M8ReYCe}$ z{KKKLw+%YHxk?q0N8zLVX;N2D<9%?Jb6c;#<42qDTNfvLzFH~t=yeBnb>D=&ToUl} zlVo)FtLIJMS}E1L4npRc)^c^J~%UII_@91%*6#A7%KXEE z_Q)(6(dQvm`p-eO$&@VnG)L@n_zk(=wdTb^Qn=2-eD0V@OFL7ygNo{*A3^S@Wa)+z&7c4Pq? z%j~J%7u3QlXC0=&V1azg9fyYbO@YIs}e+r{cMbi4UuR$ zumaK}OHpsACg+WLR-G)nQyS?m$MU4eU!SG$U>wS27s{w{{&SMqrhuU{lred>4g@YJ z7gaB=rYh~vkmy{;bL_s6?fYtc_;WX|ozo}??#pjd1B%U zvWm!oZo)38zIzzx^kng`<#6m5oE zZP+UFD=F8oME6ENE_+ff%rMHQsc(~TZc99=-^dfcj4*~zg?WY z=o#J*4dS|l=5@IDlN z`bm|~=U{=JpRoM2Hm-S~eOdN%JZ|xKqWgpQVDP089BQHkA@(bAZoj88H|})$R|h{qtuI`vtAFUA2lPZ-!|+FYIyRbBTgzP#32g| zu_gZmRbH7X&RMg9t`0dsA0O=EZ5In@MSu$a8h#cd#+1PVTN6&$*N2l0s!8KNOSpYM zke|jH!IY@(*x8kVu_as3<$AEBZej(gB{*|&!ZbE|l}Z**4pQ}`LpWjlN_NxgP3fC- zg!1*(5Rv#7F1pX->Po<^vCU%Ibwyqd=5)8E6N2NF;FtGFsiof}ev@Lzf~FSMIMlfAXNxI!5Z*a<>#-&WDjsxJmzxJ`58 zb#c>Ucig*39;V4_@J|(4K6Pa$IH_1j7EUUokV&?}vN3Tyz{>^eA`FC~srz7ovy7jcU11*IQtJ@kg zDdIyLjA31|>T({h2=V8mPThpHnp^QI=D>v8A+*rRRLBZ6M*pr{%juoub~NKY1#j5~ zW5|+~*6){&Pws{kDuWLSE#UE{f&6}$JStEGt~)p#Pg%N3eb%&4&OmL^W99)Wp3_E> zdHb>GLIZ!>_fc%B^I)qL#*i|%l1jgK*u1ABRBA$C6p*tb&ZTWcWnH(Nsvx)bQ|woF{$ zr^p*mmh!u2&YZKe79ysEA^uoHb}|~&x9?i`@6~vm89tT2U#o_KsE5Zc zn<&=37oNB|mP@o%dE0*A1k}Y?mj~jr?q5MIyiWRU*ga61&>Jhp594*~7qfCr68{-= zkrbosQMYphzWA>d8a`wT2CodTGBW~%uEU29rim4uD*!;GFY@7RYH#-AX-KR~?*J8wG)ns0q7ESTSYtZ7)b$DYk zQLyPKq-pXA(m9S-g-;hB(NQ(RZ&$1a^OShL`Poc(?lFu$&+D4$f7x*4YabY# z+z%C3ABDo*Y3#ao2Ff=8Qb4W0T!J2p_Xz_!J@|Fc3aVN)8a=YkNf)lRN4E{XsqS(H zJIalw89Hi$zi}j9PPO6HU(_(JbSULtaN<>4v?zMeA^Lsp2HddH6@6_CFj%*zbpE8Z z&7o+%a;>7%}9?U|6oN ziEyx(&(GP3ha11r5m$TsGToY0lr8bT(Ok4Ex=-0vMwB*j57vIN!XutLc*93W&fl6$ znqfwmn^{4>hL=#u)rT-~c0ab5)g2FRyWQ2ZSzxg9F{Lg%0i)X+p{g{JY`&Qbot<`2 zYj>VP8*4E~)Z{^lDdLaeMy#r_2ZrB039G+`@W+Er{C@sJI&jlGU=zHb>Z z$irs&lftQ?xpaGEDJ^eQg2T!Kc~)4u@H5LsyrZ!crni@ZmV-B(I-`yY_wVG*%GxLy zxDofe55ddx>PR8Yiu#!nJf1y~mR+311C~7$-pK{=lBP>!;MgckzT=9X$0H+Fg4x!e=1+2A#wG(|&`k zt1TwIbmBf)>Tt^>R629(C|0cvTCZv=)Yso(XpD?VxqOHx)c+7lI2^AjG7V&W({59CqX| z&tHerG#UwXz43EDQ%*2ZN8PA!xayNhOO1P=`_^qfnJT!+YNlXN zZp|syPlXjfck=p8FNK!3fkL~`0kZ@JXgqeGd^avZ1;GGvHFrRCRR(|Byp|UEs?$-! z7x4bNF5EDQr7!swc-YdMR#ySS)JY|zP`(m=*)M`W&aD)G*N}1AbFN?Q%}tl5;t1ti z(Cbwtj4K!-+3!3a>z$v#n^{4y=<#K)c`*`<;`Axf>QleU!e4cEW|8GCXG5 zY%JUA!cX*d@Y6-vE;f}z6TQ>YA9+O-7`qh|>g~C0g&qD}mx{Jc@laCKmyewF;F>9= z!gilQWcH=Li$L~M+Nf(d#B4aP`SnkHy>2{%g$cN9P{aeX95~`_KU|yHLO2aIs@4OLbvctoFE)2V!x z9SaXqz)jtNt{Mca;YlG!`R#lZR- zmOrw<+nbYNtno@Vn>&VIe7z{;#VV|tYKY^C1NnNQCWh=%75QjPs7h*O<-^Y`vs$~s!IgR3)7wL5S#}ScC{P4>JUsjm1iO$!{qiDW@Tk7KY(J(8%e?vjY z->Qq&!7Bux*Iqa=QV$QFzJ$x0=HYH-;u(X(dGf%?T;{KgdKNFl(l_N|cKI}XIiZU! z-_IcfcPUJ-RKSuxYb32TA;L|w$>0VAyWK8OMR5n2d`v?=7 zC$h|_Il|JbBvDP*#IUGS6#M#uU>E!uu4}~Nk*-Wy;o!!-Om*qarV=PP*&Fw4^W|5i zgW=b=!!W7n8Vwy{#Y_GMvBA!dFhxlbbOL+836*D}T+Bll_P`K>@8nWzz*MXg#^BZU zebBpTFWF2zOLgNImjg&%}>o>SOO-vM*fC-BS9!{EJJ zfGBIHjsMN-fLrU@NWJ$#c>HEP{?<*TDYdO2EB!!`le?io>RY;9YsgD*5Vh(^Xd+dL z8*|=p!N{%T7i*7I!*uacQYV~o-bwG|(lKyK4IMePfVYKZVzf;r7ry!fP5MA}8>4XA z!i_LxW++FweH3TbcM4;*p0G|wocJzZg+|=jii>_`Q%}VWr2pvwJfa*>mx*T2hmk&uo^AS z(%r*aUAuS~-{Ix6PWWNgQQEw>iI&SA2fa(zA+=;KFX*w4U*sra$b3WAcHM$kYi~+U zG9Lens5Gpab9N!wmVZykEgPT%zI1{Wy4+^N@@l+2ezKI(VSd0V9Xq zq@4Mq#R1pa#4)`F!l}mo{3|nyp5C+qWzBmKSJ**s%#Og42_Gd31A5@G?a#%{^N-L= zgFI3H=^nCnIZEXn+r_hE4`Pg;0gg5j#KV4ptlQ4l*a;mGVTM|2LGjmY&0DP6xy$*J?p8$Ba!5 zr_p%Fb5e^1K|E6DAsn9ABF5S|gtp_SdJuxV6_I`uRy(oTmYXegR#3 zwF<|_{T2%k-^Ay6&#B#~Q8YfU$#K1#=|Q1ANUdCX(%!qAYWP|FZ+Eg_(YXpIIK@b! z&NoxH=I-eD(2a5wd*kt*H>h^;9&8_RToN>P96hbHW3{Yq;D2?c+mRi+upxR6r5Wv~a;?5t zWxEJ=?@_=>-tsW*f&2Kr%% zV1ysS%et7Vo+7!F<+cCP{GzikE^xP?I=oB_dQmC8+7yeIrt5H{*BNLG8cf+mC*W4K z8wIOefSq?$QSHt1exfGaU_D*>D)Er+w*&x0@9Yc5QMu1dU z&pS{RU(dXaTO~b^Ppsurozpla^N6V3*$#TzR@_jx4?>=pv;W{%lrG5@PpM3Y>B~P0 zpC&IB=RDp5`>vma9fC8?OiE#~?HGw$ztWt66VNkeclGMYQKVkx3~S@maj)uZzG0rp z>4yK&qaihd{-xDe|1bocKO&yHqmR?NntNz^5NF={4i`Rm0~~9DRmB>tFxZOLkI9B? zm91cM|CQwP#j$*&ZxQWtdh5m98P|T%khP)G>r3b2=|x*`(b;;kKCjCe+k5c%7n)cpq)|uWY;w@-&-<5Nz@BqQ z2)}wMiVCF}9H^2cC~b5{yXX0|R`Vg{7LBLO7=NB|(2|=2vILuW0hMQsgb1ZH$+_8` z!k?e!xFyjW-W%(qfodM!Syw8mC>4q?SI;7oojL&bPm`8pBkNgC5Jt~Q$M_N}Z1Qvv zvyYq+-?sMP6%vWC|6LIOZKxK_9{{d*8p|Kl5>Vx34CT-DM&o_Dl=n)76BRWCd3SHt z3ph=hK}J{`=}8Cdd&9=~CA?*|9S8=pn6YOsjZgd_q)%-Ig9aq31c_Q$x6@y!IXhM##hCO*e(ak{!_PSPVvH-iCt9 zz#Tn8xMjnc}g7g7bdPxW%-6j)W1$m z?A~}9=8XRZJFA}2ofk&9Vwk2_@OAdcl1@Xd)m8c$) zPgjDwTBUXuR z!g_%`){55#ejxRV8~Ac-8y~6PblV1cQmx00eLM?A^dY!9%VcPPlpzMUD^u={4!;kNp)ZVJ+WKQX^^^g19p#> z=V@B{V7=CkA8ePf*#}w7vuFd;uJ^B})rhY4LvTljIz)clOjRanc(+v(HEui+JB<}N zzqVRDUHqNq)wpqZ)N6WSCxT~Rz^zfE#EaXFc&G1YnmObhj5sw22O6eHoxVS(KTmD3 zcW%C*?YIw@7he#x`VW@gJ7CN4%OAsnQPbVrwBOV52wkpSzC&2j{D|+5zsxfq?VvN4 zmg2wZt{4zr0;Uzgklk}K=H`^J@Oc=%+%K?|>`crq(gTbiAW4pyk15w|IOIQT#PL2j z&{u?ip=qRZG?*0ZHMxG$b9zza0v12#^3m_n@K`g5D}9HuoP{%NI&ue^Hd^Dbs&LAm z(H|RIgN5d8{-WgGd^|REyRf$;M_gbyiZ$q22&? z_fy%hY#<$3eS@y%uY(1NZeaLbi&}RiVu8(HA;R`J$ks;T>uF7NX3r_nAlZcHho69X zk4<>#qnFefP)5ZzbFuVNAhxa5#MZIVbn?nmGMM5krkSVmwAgSmBVTS)o{l|Rwqy16 z`BXJnot=(1l7D~?+VCN2tC3^tgNf|+ z#qBam`lim0nm?B zr>W0|47OM5#qu9^!#>G4e2iDbKS{D2du%YCcyWxPuUx_zA6~$BpQ&KFVI0l=-A4Po zkHLULyLg9B5bX{K#75bfT%xGR(?)$DvHK@Mv+5HJR7fDDJ~QxIYdk2XU1Iq{Q`GaS zCXLh?7**&6(FgZ{`R^gHVe%55xS&`Fi8zbLckhQ^r70LGP3N<+HMDfrbdDV{Ll|*6 zj23tEX1n1x@UZD2+NXV7V)i|Z`;NT=V+U-8>sPi>m~tX1oHsm@aQ7?{if%dX&uDfg(^b`mDb zSn>SB8E|F#b{Zw;$ToxWK(3Dy_Hr7A3bR!C?&D|T!S^%xgJl=9X074@FM5$r-97j# zo5?kf$~b1{b6hnyMHr;2ia1e+b5h(f(y%ux+s5&w7Jrm`8if(|i>WPaGQ}GB^5BXn z`p}@ym$97gCI?`0btuI?4dKMczO2>}NS2+R@JY`O?|yy*+wC+!Lw2v&Z*vo@{2<3$ zUufX#LpuC*@i^h(cRkjLxM+@^UOdqo-^+G>R=%XU~Prpu+ zUP*)kLk|@D-bL9k3zT&EOy7J@Zhz&-+pa6|+p>Xdq+Sf;Y|5 zn#A7QW^iIlJk`YKk!>$2T#Cqry+3x-m*c^>)+GUw4#q>pwhL7AYz@iS$`aZHbET3S zIjX;*7R9fEyd)XpZ;i*uYpUYabB zltl;9b|-B-T(8d^CzZrL`(8ke#b3BS)sIK}J{C{syYiUg{QI#;HcLp zc0*U%3SUR{X$^j-@%pvzyY-EnnyM^fx_43kcjQFZHeGEzEDmFF%A zD-7H~Cv7bMY$}7f%f_Ljsxgh9}k3B7DI!LRFn-jA6{6W06Uscn-``>8UP z43J7>E)L{!g+wyzUIp)4ACc|xU~y=lgH*D;MYPJw;ij>zbf96RIH2%01UWh3C-b2Y z0h92@-bwUeVJ>d*OXR6?XQ6p{B7Lw|!(+cZc#SxZPeS>fX76*Q%{HN~}=k+za2J`5pxdg(6>%pcDyo?Am(H#PLw^q9iF zEP~Con+2UN#||H+MH&6_Y53qYkWXI*V>WbybCU<4*=kD~={=uaKHlN%$F{gwcLQYK zi^KdIePLz(EjU>pD!z;w&+4b`c{*-n({1utwDktGr(Y9RuS=vqJ4+zacp@sce;13_ zEAXC`+wfSnC#&|-Chv*1)Gde)2EGh1oyrT<`0jVznGTi|$u zWQz2->sDB-!vCY-Jlwf@-#9L$q7s>@P$?rNEotyM_pOA6h=`Vkv?NWEkr73M5J`!$ zB}tRdx$m?{X`rNCTKJY!QvLe<0q0!jT=#k2@7L?Pp69eC%Hyq=!8q%Y5{H*XQdesh z7iHPtf^%!B-Y|x~I#*Fb&TCK&&Zd5ET4`fW6Qx@GrMh3;v2xl@$*5~n;p+DuRKEQL z6=W^~4Cq1UXFGy>nHAP1&49h7uP`D_1rD#&fJNmYtXdMtm*t-bQO}+E$L?EnRqL;4 zZd=HAMxBLS8voeF*#eJ^e<%Ey_<#}{3=p@c!swSHaf!wdbegCLcdp-~LMJIj#VGP+ zs}5S?E5|3D6R_2>FJJ1?<#S_YIsFIVKpCdouJLUAMH!}APQncvrqdAbM#}X#!Ou?h z#g6U)P&Z}?4*YqCe4d^cFV9s%;{nHT#iv2A=zBcB9#czIvi6*%6)dbAH=HNhTozZY zi^ayBXL)vaImqi4F20*J0CHdD!|B@l6kQ&Lb@Ll&-$e^>do+!QE5r-Mz5a?jhA4u$ z(r>C-NW$7c9o+ipKS92!2-f8Eymp_4Vt!6{+*|P&G|L=#T1hWHD|-U{1C7b#Zi?7= z=_w7|x`w)U#`DDN@33yEnfUSO8mO#1CPt^eg(dMO_#OYF(o+k0*rGam{N|=mG1LKC zcN)W#!XaqiG77!ECPLj^H+1f-rVmabT)4x9PpixT-+|N6Y*!DSGU1`{r9)q!Z)L){ zGmp4##uwcE@TpX?wU`#I+szYKmCQSbSRvvtbc zHMktKQy&PPohmRtZ2<2=BdpN*1BrEKQSn+FcwL>w311_)W!hG;Z2M|>>!V2zz9~W8 zW-s(zJ(1L2Y=gz~Pq3|7f}me#XfMl zU=$9T=$8iG+#?PGuBXQ+#A}n zbq#OZ<4eK9M3lc!0fRFRN1FI*C7ZpFin18Ar2hq!?}$m zY^T&f^*YJ0K0X4^PrXWt3G>lt)?tV$za_rVOk$tPcG9Tt#&Uzb;oZKS&~JMN1i6kx z@J)l2?!TzcWhGVHC-S#1?ci2fLgT-j6)p|y5N`PN!pMDIShF+sw##@R<9{H*@Q=2)W!D4FG+J|FYJg(=9SA*xW+$Mw1038 zQUW6&?P!0#zFH4MTdu$cxgpr+l^MR+?1qY)Bvfp>Tw>{K#d_)cMcrr{P9E$`&qKCR zzgS&xdm4w^Ymaip{1)iAB5-`TA-?L+A?mcjPUs@6)w^hu=m;*!shQ;+{ZOdEc5M^6EToHw=ML>lX0ZIhf0L zse;Sg6tQ9M9HtM+)b-m)JYrZ52~`QCXns|a(sKbWx0(T2LG8k39?LqnV{viOKz@B_ z5Grb_aN^t=`1bj@*tW8ha-W0>Zbx@>Xv$u^@!AXW7Tkums#>a3Yp1cjT`@v=9NWk5 zfrr`Sd7$?g8dR{Cd&f+|Fz2VR*{TJOD~=--uTvIUbl+c3cAzO+c*0ETx4 z!yB7m>>>4l&iqOA$SsQefAnF8*ZZh7S>P3$?@8R0budbG3kiLelKP3>Jgl%20sdiQl0lC_8N`(<1gUPnCQm4>Nnt%;l?Tkq6M`>zaz0_*b5y&=IMBlU+-1O!Kxt^VgeIBI1a(x+_t{a0< zVXZaIIH1p-Q#3fc_Ba^q-OV3dw+q+D9)$?^wLJSr58kkM1G)S5!kVygXnJLl;B40y z|LBH@&I^m!_?fn7KXotH1}otbl}^dd;0@U1AYf32DhW*|A)LZ_=#5&Cu8`&D&n$6@ zRt@|u&lW9x)o|>og*3Ze7j?_>c%oex4!thJ*M&%gr@grOXpN|KObvfoxN+<2=TPdf z8Mnbu=dDg zlCJb6n+rCWpWj8wM`m*RcQbtcEgAHD>tIveXsUA$5uM)VL5H&)-)Jf1toi%IV}D;! zH(M?2dKyDXxlhHK4kz3>Ujfx`JOWAWVUQM{q*xy}4whI79yc=tze|td&X+=Jd^QPI zjqQc1+c!dfmTfGkj*#Cs*nt?pmIEh|uXcqS-so?2%*QNfWOli!5Kah9eC`jG=V?^6UL1xl2 z^m&-e-!k-huf}#Vca_Dp%NIb|`EHyTZjE;87tsIGZirrMPd>>mJn9FD`^MyvELidH z;;mxHAanfjD+PV?+Wx)EX_$Y|ky~C%#ga{_LTk`t>iN&(#=gHuie=0XwrFul)Iz8j zx(F{n%oARmdn3B)j6&ZH_E@sF%<4ea2yE|N%>B>bg5F7*{AIO1-hVI!WPWRk-yce0 zcEBNu+182?%N}6#)I-qa9>K;M`g~Q!)%t8v59--5ja%Lxhc8p|c*%*YbbY%krkWg= zI;X9Lv?g_qy>5lcF>~q8xkGeE=`1~7YRhwv{rg_6)1mJ!PeBP}vEot&H2TZps`D4% z%#y{p;9HBR7j^(k<;}R4&R3YdO^uUgH;Af5m+9UrLvHbm;mzyblCtN0QtrG9*Ov?x z_6;}0>WvQQ(DeXr{Jkc8Ei2)(LqqV*Rcn5ep$X=Dd$P>E_pseZf^DA$Qtg+M;N9{a z{vP*Y)9vTDkI4dV>l}dNog7iCz!;b4Izi3y?zpGdRdfye1TVTyz#y+P^n@Vb2=O(D&GCA95DGzLg&;jyS7B;{zM%)oMTzaJ)GS}~lG2`h`ZfNc_-apIeyP0xu9ft%8FHlnc7L*B@8Mzm+98bgej18H7B1tSr#3>T zZYWjdHp7$VZ%~>SfTdn>RDP<8N{-#5B+qm7PV2L<<nSJ8)oD<{LeCM)bn z_2nKz_TZDs0hpI$BTmw_^mGlzI8LP`c;e`b*pap4C5TYU5*}%qEAmtWtUWi+oZ0ksOY$pNZuY zo(gg&OmUc0A8y;~a{JjaX#TN+WA$utQ(iCbccT(4R&A7QJvo5WL`RgL6N+THx{?(KEbIi=Bnsm*jC<);aF&&ZR5KRHO})gEM{ zl0EFZtrxm|9*0Nm+`(>`I(sxPg1R$<@TRFYCjL2#F&|Q(`FR%Iyta>3JvHF@N_j4g zDXG}8KA&EXXoclnnb_lJ4uwuTN=;LH@LV@DTt+<8LSCQC%w>K0INyO#X%-E~M zN*Gi+mp$wH;Nyx$I&iZmH>G`o&BsEp-#(<0@8_uU*dX3^%9=vQ$WXnU4i}re5Z8Z{ z$KEnqz|-L%Iu_{gl9Tb`K9zJn@G%=Y#x{!XZ&uQ@Yz>^Zvt3NzvL5f1oxz-m$~fV7 zPp+6cllKnL;tgLzD7dZ%NBgpv{`4TuGv2`8Ivi+uh&4Yr;7GMm$HB7h5Bao+mhP9z-p`j7#7<|=U$*G;vI&w_jpeibq-^Uvp1vHl#vNZQ z#k|`2G(s3d_3z@b^1s_;arG8HO-U0M8i!K)RX6UNW1h_8pkExp;-MH?f|G5J(2!5{g4ydc?(662$&^RowDP_Bm6pw9~o zA|(C)YVoR+Q|vN56V5IifS=a2gYMvP>KPXzSR9;>&Tv$CBhw9oN&=;89HViST!yIs zD;cs4-jMN;{WNCs9t!Ab#jbA+uyogLcz$jS2AoTyy(p#2yKKex6>SuntVX={H^m0N z1nH;y_|;GZGtmeR{Ju;DXKvEQfNPRfS4+8juT1gO8C|X)kxavOiKu#78~^rofa0T5 zxX-BF;(zax!Q+TBH#+>J-bS&swK9wsw)_;vzdr$quWI1p-)cDW;guM^)jK;!O4zB6DsYGx0@uSdh+t&a{Jdsj%I!%|>^wk5mF6@+ec!?~&804vT4 zgUUL4oTnBk1h_vXpQcnOhD~^D=YOI_R6JB_?V(}olK8h<8Z>7b;of7(ux8*z+M6<* z!egf4cHcq#EU=AMUcE|nal2q-_Bj|e&T-a+jtUG`XXM=W0N#f~HWa9Ec$9kXtN zXPM)~{h{T;#F#M1*K=XBMGm;XAe9CVmF0uNN%D8K#DRg2gj3Hd{`LKR@mcvj@V&L1 zKRi3kSt(Cg-1Z7`&TYqjrz{}QGYpK4JH(kYBM^4pCHmO$)et9N*#n=A@_EKxwGYqnP?no zgm3-U;++u-g;xoQcvQ_qGE-$2C2z>WdX0tLt8gy$@8!xmAqU{w?e|nR(}oYM*1?^& zRd9b>Fh8bn+&69_ng-e8k7a3e+_->-yf_IS24ncdw>UbzX0!Bhgdyh-vBSclkHm(w zQ=nTifnFP^z|#2hV4A(0wf;;MhyK+Q?E+G8+p%46;&Bcb^qInXOIJ~r(>r>q-9VDZ zj_jc9hDq0^@}M&)-Eu~rg;~R}rBokvH2Rb3DJNL}Yz8MRI!7tDwDD!pAJ|bADsJx| zM<>^Rfgd;%+@3pfd}t@_yW))ghJ|=bE($XGx$)=~C#E$F#F3>v#nR`+525$e8faDyr;tb>Q`gj-ldW^7bf%H5e;y>`7~a+0hn*vn}x&a{H89J?tfFF zO*5UTc*tgU_fBHzEmd?;DZ|7W{;=#)hY)J8o%>YG#8nB-y#4ktR)~HJ7ZqbEwmF;= z<}1SLe?2pQt1jN$?#>>kL*bG4M~S=pLatHnOVPKrz^ix_UX&Vw<>Meya*cxa@y4{% zcPZ>1N)m@Rw>UAt7!HkiPN+TtkJ*jn`owTy={Q^5wxt3JhRdSYNC#fNU>ws4Lq5gn zuwb%3OxS)xm^xSyTP`Y~>*O4q@n;4GoQ>n{mBaYIIvoaETePhm&jy$Jiy3dPNTrSu zG-qZ43|4y#cfVe?8W#{MUOM`k(pN|YRj-NUUu;J@%0sZtHwT0zsrdDG6OD-~f`%V` z_)cLO*$SOhB8NO=WD1KWw>Wu>3p2*WM%5 zzw23k$9!@37-Q5b{t7$eZjy_(s<_#uFHSNH=XVF6ir(SF`CcCv-1uY`L_Q|8>8AX~hR8Z0mJtE1-l$fjOc zvB?WR*{-LPaxT2#&EG zLktV{`hlANU|d$W9>&*cqIF{o#Uu!HeENIzo}-ITzxh(0O(+khB9hVE4L>cW@vazm zwz7Q8M$_j&=-QW%Ry_enIYd)!vkp0GEWyT;zEJ126K5w*#boV!xDYZx>f=n^tR+0W zVFT|tc99NDaAP~&zIfTp62}ji##aATkx4=vy;2JS|6v6cLALklTfQ-drrMx&yFLC) zcm^Fay(xd9B9B=%N(}E-N5c9a^ggx+AaYY!piM-$?xR*3r)$ zT5K`t02Vr1zF8suFzmxM21x?ySk9*o!&N{gGv(Yew~kS9|vx?3hu zYT7OgyEKP;HeQ27|6jC2VG>rIKSHa0!vFbtv_$biq>xH|k$>7@^%XljAGuDLRCk>G zpXig3We@)S=mBMlHmvJ(6!2L$9AaL`JI5WSa{K=9XTBpwyaTb~kss@*X`@5#8KLk* zF@9)XC;oPb6)wfK(4*oOsPJu)7QYDR1vS3Zcd#QnUvOdPg^D&$Ka;Yc-!qE;x#(+sWZBOBXI0ce?!h;V{mTkKvH7 zpJ}?0A>KWxkFn|>;m^>^FyWu0w|j5Hz}chG#u*Wx_TwR@vV3f~4eyMMr#!8`aDDtw zdN=(#Oz<3qgJx&bf|3#{9W#i1dRt=n>_NPK@c?nFNxHbO=_7rZuS!3yEb;yP2Do%_ z2c+m+6SEE6#pUJGq;K52^OwIN9KHM~gcT2fl<^N?e!Uz&n}3Fq7j1=Pp9*1k|7GB> zGXu|D?*lQ9yxCIGn*Cq|T7Q zNuO&z$7B4i*OZZ=fY~$d(z$<*;&A*3YOXfqpz2|$^Ya;vez_Ds_a2C<%YRbwykxu= zUrdiKKZR@m`SAMP@nEMM3$m{NiR}+INotEmv5n>nob6a4ojqz5?^Jc-@O%F<``Ab< z`uKt(!)&biYP3{7@CrQJH5y+{Pv%}1?~q@~d5WqsMwQfeg2STyH0{-1$k}oqoSt;M z*7M$T;n$}jT>sYvw`h97ma<;xl(`BUe_f@?2ED+<^B0WzlZ3lI%oPru(12kMF|;7- z3mB?gpu$sOY@ip(-^wT+<<8-yKS3+~Eqt4D8J>ML!$GaV zWHCz#&#WHCmXj_?lBXZ!yAvkD-MT(}cbz+WRvm!2J=SpI;0Ap8crCw(UV_UrPSCpI z#UNfUp?5iom^1qe{JPLUWn~6b{zdLut*pJ+WBf>AOTi%=ns`AR_Vf{TR9fKM*3l3d zt$-I}Z?TaN;Lz@Uak)k?*1!Bg=Y|DQgQ^~yemW>LB~Ju-w_!Zueg-P+T8n9&A#lO< zAgdZ)5^nmM;_qua>C^uC+;?gizO|gr8l^hWq2801JFX>Xo9E(qdPJpnhvC?99)g3* zA=0df<+%FM_}RMzoV_Mv$rd+`nx}|s^Y(zO_X=pvl?D0pY2x{Tkr>|Z9o-o6l@ylF z;y$+hxng`ggw>B=Ly0Cn{=OP&uB76_V**>e=!KeF4QP;;8WM!1fBe3b>0!?fdYnHGbH3(Cw52x0rpTr3Z4wnA78Ubw)Pc{+J6nQ~P3W z*$jI0_B6E>o*>!LUTk`&g2&AZl&pyDiLweR_*S@Iv9V$R^nc`xdBbHY)W;0x2lHTily5p3CzM^|)(10D?n1X~=dV@MKF4V+4=-R^ zRT!?`l0h3bhG4ndCn`I771RPVSZ(+v+HIr5+rNm=_EZD4)pTL)$~ib@bQCV}{05l` zYdBZ+ylD4amY*sZqTNLw9#$|2hK`FAj=j<$b=@jFcrgH+3@wDyyUR#*`3<_ApdkwK zoA{>PzdY#aEBxo`O+Cg`(ZW9uCEJ?Jg+B5U_&!jFw#0eD=l2hUEY(UfIaEwb$KJ^wO3N^35MU_rM<;^CbnM&<4X$3yPumYj~mPOQPC4~AeEx=-}= z)#UBDeYl5SKmIMbND4Xe!tNi3vHsg#Sk^-w+WVUG;vV|aKF=4@>SP5j4Eac%=FaeJ zjV-T9Z5Hb%9R^>ymGHCl6dXzR5xZCS!PGiGO1W@A^5l#Wca6vn}A|*rVL^%pIQW|0>REvBo!>Ot@y?UYIhbhVJ^6OE%Uxi9e$P>BVtl-2O)m z{gmyo-`j<#U#Z4NGU93fi+!}Aah8zOUzINv{GwaeEV=FJZHdv64ytZH1nRZ&!L@&Z;0OL_en7w+Mx$-Y+qiL0J^@x%Zf zJohLBx6K`bFB4ag(T+kP$LKCJHxpTS+w+JE+wpW_Bky$_1WR+f!QNx0ILhD)_4Kl1 zd2eUbp1THA19Gs``8|yPJsHDmcac%=G2;0NGVEX4MMd+{=|t>C(BJQgbG^gxlILIH z!Du5c+dPLtRN~-9Y`&=WdI`U$T4BSF5Ul8X4y%L&c$hqybL+ePn{5o;vr*@15w7ef ztb?pqZuqV~7J_2W^YDlA9N6VWjsC&XKPs(@*)W}_-83H?3}f@P8s ze86l5&i zkCs^B$?k0wT=1G|E<{sL#k114KYEeE>LIM_R|GZnQ(3$8ATBc3;_iQy(Zaq)SgE~* zOjZm+>$Wv)IpGBV`C!WS^_Qh`2Fvk&?|g_-+9NiG*Fo2{Xs~}~3Io(sd7R5)$-C+b zoLUnFUq0<3d&P8~)piYz2q`eGPZ}weNpZl~?(DbMg%`W|a@&t9l2`No!VL!R~r$~_h=Ta(6)5Bl&<6tLnJ9v*5O~5B$zoXnU>7FNt=gMOOLwUfy!Pt zXy<>E&{1&&Odfj}@0MwEpGXbyO|cWt%HIzMN}I&uK^^q^iY;C|a*8z7nX_j}V7~4G za`|kDgMw_i@6a+>Jz+k^yeZ${o1RFI;sC9eFcf<=d%#lFi}V|pF@i6xu7bON-viU<%b`Yul?F#YNIS1g;}$`F>b8}7=DhX zufN^#uKfv~9P~@nx;+8P?+z!c{t2AASb>8^4}#o^R7m=~lb-$@4rW0P_$@gbA82dB zi~eaiaD%`}arU%cy-E79*F$k<HH_ zvgHdrJ|-`?%<9dV`{oOQ!-Bc$w4vB*2nqqv&W>SQ6#nhBa2Gbj2-kx1lIPlNB_bxVR-7w=Ig{@3sr@&cMF>!Cf8o7L5@DKWyW_pooK9=aH?= z6b^*FbC4!Mw?5dmZQHi{ZF8n=+qP|U+P3ZPx2e>}Ev8IayhG z5EYSCQFZcp5NG$Jms$5?1P^ZZC#`5cg}^1#g|U=)UB`qqe6615e~THPLi(yu{nn~Z zPduL@`VeqpP4zXPo7e|_FlnYOvh|0=FKB(_T|&=JrSdqrAoeZ@!&ElnCNH}Ws37-9 z6*ta$ZrKZE*yjvnXM?Z1|Esyve}ox5@+qXaL@J?W%OJ=DS_h0ZO&=I_*uP@FxHl!s zpSTa4-MBb9-*U8EmopIPdV<5_8?Og5FLLD@=AqxHjrSiTpEX{eUO*`MexC64&o7Lc zxZ};W+TywIye6fudW%^Xan7ddl6UiP&UT)M1gr=fhYjP}-j3&lnPLhQ)`u$r(G4Rn zJax-;NENwG$2=HvX$o(mS)AG!M=jl8Puhrz?UrEdU5qC--NIbY*S2fSU((7|m*Js~ zxJj;8U1L4#gCi`yQ#JcpCCj;+7}~Ydf1k&e%?EL3e*UTL&R>z(2xz_`{)-sV6`y2# zYmd-;DaBpp-TYM+@h~F|J|p-TRyZjYit@Rt>a_r-vAz=gXoP>cwi>dS-5*1^y~lB~ z?kf$KNzah4B|^T;s4TRupz5YMnXAzkm16o28Onj>>ANo&EyiWsw;J`$-B1&R3g*mAAj_f zuCk)X#t4kZ7S%|5?t^-{zak5vz=zcUX0yWfn^QSrqnjBYf$Q_1IL*}Y?uU{E9_Pk| z4-c-6e`*75s5z2ibdeqLH$rQgQpeJBO3pJjcuvJ5TUrlra-Qv}RD?Zr$ui=ze6E3s z{#cqno$`8QmtWNfl#y@+f}bNsVYW0*eu^A(+J1FF9y8}c(hG8Gy_ze1_3;H0bb)DR zdSD?fcg57#jSd~7BOccDW7_CspY97k2|8#=KO>z7I;tTBCm+2e4caa}?Len}AOG6X z%iT!9c=6j25}S#3bN$IuFfZt1sKQMt^u7m@AY3voOkR8Qw;P@0c?zvhj}A2gSugrG z_tPl&`Y@5s*uk$6y9ae2awe=Q%e#n1v~G#xA;@*H`D1m#k305**}G33Wq%0lM?sj@ zi|%`<9V1VVTXJbPqCq^bp#5Jjg}%%lZ0UQ3Hun**1&7axO$-@uUEBc!li)6=4-W{H zSvy3VcYi{*l%(LX1ahY$l*TsfaY^ibl$y!87Rs}AvpqYtPGK|-G%Si5Uz^za?cS04 z+87@`9yK(#*9-*ojmGbXxQef`Hs)0Er)FqvJiClp8NXUE4;dX`^p}~#GN?pP-6;sb z)kgQC-BcQx6yx8qGT{+rVfSHY5+3sZ$P3wjM-5@Yew?;74|L}(-1t%NtyS>dJgN*> z`Qy) z_?8_E18Wm;1aS2sC6a!gqt;Z;7R>OgcE0s?x+q45!2UnJtMHZY3GA zl8H{T-7oS}*y3E%DW&cKe_EU?bYbyu=H}dzpcHdkV(V4O(C-oP)O|a0Bg3-kaYg9H zRF%ddry2Q@%d0?695z8~m28DsXDVPA8>O|Tyg>OWLw)9Xc+&5^amA16`!A;+!m~pm zB7V)hMFQrBpin|PKwBsRSa^(I(Xkj?vM@#c)(vg$_=+&emkNbVu%jF`| zU>^^Zj|P`vx|+z*nNjEiR~F%E+(tyvwZqY^ZMLlX$N;O`ox3#u3M9{D7bpdE0R2L8;*} zQ8QPvPyW;FvE5vSZrTzPzJoX{?WJ0LX6;8Ds%wH#Et$tTWnr{@wM>(ACxN`}jTDVM z0R^gGVlS%WR*o#a5}-joR+raPiLXq_5hu{MHy%F9c7aItDO^#FJNyveU-~R>&d52% z9Qp4W@<%gl?ii}A(J|gqgXb%xp8vqdd^L?@HTId6PYSd&eO@pe2z_7-6lue9oQfTn zg1M4AttXLzl7n4=?>xJRCywDZ&pMq-~N<;n| z3s#1Lw_8MRHMbujJgv`SH1fJ3#fNgFe)-UUK7VcCOMpwSYs#wZ6Cb=Rs|71Ifvr5~ z$>8fdGi`ya7r;pbOqCm~U=)AhdV+j>;E=$T!1w+d#1`J#j>Cjg5?OD`#PSXxYo>lb zOPkTre&x={%Z)J{uTFZIAsk^hF9`~hZ+R)0Koq+A6*=glLb@r2)Jv>~(#rUI;W3L> zH$y{4l1{k5_qX|_+A0z~dhA5gHxW;&U$`LN+r9jwEfINj7+2KxsiOs#zJ5g{_TQz& zKnnH`ihMFY4Z8t#6ZUO)YL!d8!y$L#;=N=JDBpSxX&;Fv3E{AQln1ut81U?~s~laY z0XcDkWidnSzj7xzzXM+@@CJ9)a0A}YW8B>6c|=NyKgxSkl@yvnOeD8Ed}geZ^(x|v zR5&Xve?cUUgo0+Dn8Yzky;p0>J3(}V9ThlVXL-slhMcI@xG!U! ztVr_1S51N5?*e6XwCCtR5S z=(5GoQ1dyMe9~m=#h~n4@P_ghFW>t^{0k5Vxt%f8)jMhfqvk&ctZuN7r4Vmhp zby}NVk9K&vPReE`vJuAUr$>_Ba|R;)Zp1H)PLD~%yl;H(tX%d8h4rNcS5{zCY5)zo zH2^8%a^(##Y8r2R+s_q`^ZppdhS`#zcv-#pY&K9T8MiX07>~;QJ@^@n{l62I{AjFS zaWCj4MKvw?K*>LpVjN0|aCW`ZxXLSHR`sRl4|JR6+DF1lm15V*+~C@$IAObz89$_6 z>1k}2fHwVHyMv@up6e6{aS;e7{8*!|Jku#Ul4Cy)kBT2gIFqsPn1R~YmIV2DK&t)k z-^!5l?F`(T7_V9l`kjF%ZF*J8GjGz~$j?R(h5?cK!nnYQh`VK-J4dHGw~ig}n3eU2 zkEyWy{i#v>RGl9Rzvz&Ee(Y2m?+-9l2s%N)C9DRY;SjHxkHzh)W7Ke(ce1jtU|*G24vl>U>%e}Cs^rk8qz$^nfG(IC9gY)4oPGYyI$Ndy8i45 zs>0hLtq_V*2_=63$C}?3_xhO@>nYSQpiMAO6ogHjm-3=^dHnFVQC-p|B{Zc>Xzh_V z6j9e+S~mO&>MG<%&HQdcb2WKst4%G-?YVd%`+TJQ<%xJ_vT(*_C7Qs4P*Kno8IUuRU)5+E16$(wg7byfZzyKfJygwlv`efbaQa69rJRTf;|BLMj@Kw1k4p&}zBR#2 z8?I>4rj2*OsedlZQz~!!{ZWq^r2V-)R<;gqbqG4xZ`f?N+0n>61Tf^e-NhCYtU794 z(Y-W1@4qruhbP$gMZQlQP(mcmi<=M`#-0F-^qz^Xs$OfB2MBIGqcgVK5AG3ztGNh%WZG(6TA0IGKw1y{9-!- zR**P+^#F2x4s-$D<57i*S><*Yw34tc6%ACmO>dk(@+(;KmUm*?>QT5NWTk70Khft;j-ppZpE=AXss z8rb?Zr9BP1A51I2EiKP6t?PXK?$rjLY9{WJR2lK|y`Whfr9+1!&{JSj&>MQO+sk>E z0-J1KbUYfIe|TIJylZ_n&%N-Q|4sz!$=wHjITWAeSPo6LDKh*@16k(Qb+WLCG33!z zcvI+uK_V6k{VY=54dg)OT#;-zBJ|jFS`UQm1>-^U2XoI$HtMZVq|yI7%CE{uDr`>N z&e(eN6KG@@Mr@SaNq^{>J$GHM?%7~T*p;4X9J+#fDcBIDgtb#3O)NF*(MN(|z(V$& z;2~Wvggg_{7P#_vYED^)1SzVDGV9c5-zbZz(Wy6L>A_V{utOi>iv2UxC4ceOG&WU$ zY71pDul{(ZH$3pT73J=&%CZoc1;n2Db^HR2Hp&f@{HKLLC9qSDECdgK?f z1Yyvz0@6Q{h(H4PG|xa&LNy^+kg=4sIo-We^R%ru#VA8m@f^{lEtRnkn0|ff@+FoUl5>1a2 zMc?@Wc!g7%YuQ$qi-X_Vqhm+~s8XR+Gbq*9WxUf${{(vr2oko`U9F1@%hL(<%Hm|H z8y_vlMJ}}Y48lmp^47%V7NE!J0($bp&mnj385F=>Vmm|s@U9BRAuMwe8mo)5^qSmv zc}2^rLm%Yd7q;1FkD};*E)nw>dpj0|M|bK=MYT)QbAhSkjLX~6b%60(1b-Yc`tW2G z!WHir`D$N|b@h=vCvM5)Q=VNhjrOEr>S-?L20nXf%urMoo4~q*b|9hgl;w~fqOZ~dltQg@(+sAS>g_W?Cc@g_Yo$5{`8w*!QAo!Tz$FYl(`pHrqC z3Q?~^^iJdT{yY>H+;Pdo!GD7KPt&22y~?Scc~Te^*{%|rOpxWe=fyuB_ECh^u1C8j zr~w{Xm^tWQn6oNu%+*?eQAnXV9#dHAlHZaiy&9rl)ABHRCZb=McOU+tjP9X0_W_uK zVOiGUmeqZlHQUSIJ zm_+>`)L*gX=bwd3V;^*Y?Yt2Q{sd#Kv^KZJM=zcqYPrY{lgT}J{JFv9mbVwUXt#zt zRv32)j8ac?;Bpy)ET6^nN;e!4im&p8zw2?Tw!Lzy6w90sP)%f6Vhv@CgfFc&Qamnm z68gdZ4*gYxpPo<)3O)Mkd6NK8o-q{?)D3eH&J_8zNtIg1ve%L1C zx#iN>WP!`@;T!Ajy;%(B56$*FBhbB#E#Y&uU5`usAM+kA-JE@Jb%4cy&`AIhbpEc( zAW0schXf9zALvdnzI5tRV#vFD_LdFYKMFcjJRlt4*-=Z^+XYFp65%k+sJruQ8rI*@ zkHVXgDM;KtorkwDwT$+8Fcgd*+te0{x%>b^cUAcT*de#5cOU${i-zh3@lxUo z-A(w2**~IMvp@1&rh^TmMeuH~ZqAmqF8Z!>Pv4;AHq(%EengVTo zs)ve|iig2#>V~DYuf;!3Ljg0c2!Q@3Eb-3%UNPr#2|%oq=y2;ls%#$nbU@9YTHw>* z7m%`8VYs)%T)g)t5a{6fF_h`qEl#91GkhiT0}$%AC>|-_E^hH#9Jtd!3M8ZF2Y7An z0fPiP1`V+Q01c^M;`=MM;vJ`*xZknjZ?ty9STF|S8AM>i#nVCncdHqorYAW7e z{zDp20jCZ8nI<7#f%*>o@)ZJr@U4r7SsnuElCp=tVE6&|g|)4f z^^~|C5%O@p9Xvp_!3Ch=&pCY1nhO*(Q3NWU{p0c23j!kRfDRY8=mQ*?SpcgJal`ln z1jFC?gaCitP;r1*m3Yge_b|r3K0rJV1P~4yE}9(~2HdYa5w&DZ0r2-%h%*X9^-1Uh!OZ~bkMzMc#)Swjm5h#4QM z52G4Ri76ESZO9}})t@Q0ltlp|SXNoT!CW#BFun(&+B>*i1yTlyl(}v16(EyGn zUt-4Ry1;Crwr2^D|7ptqkzoIkS6FcY;1SwXt>-EIp(A{|Cswn@BIJS(oDVf0zO*>G1X7<>cRH~`2J%@ z@IUgOK>06~4k20`*s)s|m&aimSR~RRrld)tA}y*c@qb4G1_}!MpGn~Vk^duZg#R~4 z)Bl|J%-Jwmy&MRHcrx4r2QfB<1Up^S|7pU@+-BB^Wvx6txA}ITLD;$%`t8 z0Yp{)PpAKz`TxID6GKD8e?}odK>s((4}<^l_s_vYyN=k}iN++H2U_CYk655iBRmeOT{ur`s>jxRcvee8p47Lhra^&#Q zs}R5kbc!G(7t@;ijoZB!Y+ZG}@zk2?NVT6}X#ACdsv5{o$;7yS+#Q!i>+A5UKE3TlI zB~zsD#0cofgKBSzNYF6+<~!o5LL5MG)e0{43hDvW(p);aN89QpFBbE|8JbfdH%qrV zhhgr)DN<%2Pa#+y!jSwy^!$gK#e;$%Z-ZjR+QL=@O>(Df?)R_aU8`VrAv|6V!MXhd zf~)Wtry~$ejOXQrU30JQHWI9L%o*-WhV#CZWM zr^HN{@mepiaVn~7G7*K-)7TX_;QP3IHycKMgm6H9=8$0yo zm%$Hq6LZGHiR*mr5Km1uTA%W%^iNPH-*G=uz^)aP*|F{vZhiUt>bE zuXmobDhOpq(DVA{Q*leIL_`^uGYhV%t*-(5p?S`-imHNi*hC{oniZ3B7;h>9noFs& zzXFBbub(w&Ur4%zTREgXqA1o1g0Oy8>00iH!SprDjxXzlEQ4S=mV8~WYQFL^1qeDl zv0JS!|4QIVD@taCi{>aulcI7OE_ED;QZ+Fo0!WT+K*v4S8;8_TXHb)Inu67m{|32M z^FS!qEs?_p7$1G z_N6G37F#l=d2k@d(39+Y;$?>#V$BTeJNr8tN3(%2CJ{OO@~V;d@ye591ODibz+S{l z^Xgrv(n^EiTMS;s@fQ4XiG^O6s{Sv&HondU6iYqWGN<99;7xb3vA`Xs) zcs2hNrWSdIdyWuyCIKumD1kQ00<#tm+WiLXvq={?1hLB%u%#)RV}+Jsaeb#S&R)Es z5|UX;u~GsgCic)%x=!5T6}nQBcc}f6g1A*W(8ll+-TE9{wI*C1-_(YL1O#4xHS>=F z{gJI(MckD|Ja=QOB*_{KOAPEtkw#K)`aH!3eK;!3+IV~eY_X3`&e2G7>~+uSNbrv3 z)r{>f5-6(??Mju)7@=f_6Lye6o-9(&LEu3&Txf62oaDEgr5V8Sa6|o%V|M5ba8Bz2 z1T~L>+!P%xi?~I(3ZT3axVNe+fp(g$2%nb4kjxTm6mf3_-*h=`rChf0Z|QOTh(np- zYUh*(YmZDOuz^s6I-C^!*5_&ZC`16C0)zxy`xc#VlqKH4OfcGLZMC|`DTS(g^~qjc z)Kxl8tnmfh%^oO=pNEx8Myz?08Q+E!8(;mDd03u(hVl`Qx3mkslJE=6;j1isBBc_G zFq(s3Yz*|`vGGHSqh*j?JXp+Wlx;sk;sG5fvqOtjIjrB}oE1tlBNrLzx4r=rkmYh= zcw#Xx0xQ|mpD2AbG8ueoNgHUU z(HK?sJjE0z%6k1-W+~pjy3ogEeIY$xzT(0Px+)=+37mE;74q~f&sS4TK#v%l8_z|v zg#wv-A}196fVRl6kTcBNrJ&Is^}l8%q3HO{7jxFtIj%Ky5@ zV*q1IEnkZV+i`v|5jn70Or}oSYYp;rvG3y`t_Nw`jMe62+NES7r1Ch=>`10l3styS za(+l;NJPq^c1_@tjbdt4ut?Co$Z_L}{}>kx-Og4{6K_FPd%Gh*V{FOgHd}yXQm<05 za&&-7Zsp?(O2fa(_ya|Bg}{Rj(LMXG+QI0od_)`2lLMnsyHlcQhJkNZH!%pSYm`FO z%~uZ|`Yr?~Z#z>KaeLQD;|OntD{`v!W%ADV3!}t>Q05kAni@`!xyw~Id=k4|UO;&a zwk`CRZ<)_rMw^r?$opFGIv$dO!?09_EmuS1JoXR~5!o=>LvtNiECM#k$^>4jm?}?< z3;I6)!sgSHXx9uDz4@SlagK(Ag*idx014ef%jaNZfel>hS+E-@$Bi4UyUBR_M0c1^)S6*4PIwtATG~F%NY8TuCC;MpD78D&;w!i|EtkfNMfi}c-td@H64aLi)8brm_WA9L!`E2v%!S^0)Ojd818~DR{LO#ZP@F3+THj`w% z6SB;Kz{0ZBuS*>des9V7M1;&$77N7Pw! zMi|}xIKBP^M35H0nZ*vv$L~tKM3T)R>T)t82x}zbn_6SR16Pg%%fn9b!6+jQrM{e4 zp+;B2Y#Rr6jl$UDg5~RZH&A*rlPtprCH;&mV=AAD*PqzW)&2qqefaEPF(4#ZtHKgw zuXx&d-G4*}Y1ex|>@vOaktA=%q~t_-lB&uT(q7rnEufU-Ho(XW-NMs_MkYgQG?0wW zISj_b;SwgvnmFFVgtkUW+8R2&c%ptZ(`>-z1CRYhKB7I-!y&@yW72bbozsVVdDGgE zaB5Dis-ZwAgSzQww49>Mme!(emacdQOV2x4cnH}0MqrJ#B`dYSQ0NqmjYp>E2JX2=#hsK!da%X6XXx&w;$byiO=V=@;evHxKir{x8pJO{YB*%eyy1}1Pp zw_@aNx;KWmPSPSkhtZT(O5mWM1;k<6MjaHwyX5p`;e@5al1g^0aXGe{)spEit;01V zw#+7;o4>n+gb^YL>Ihgg+Me20xocC%M4Bl>4A0S0tDv=Co07tC z>QyP%6c!4L;52`p5oibl;v&^(AC-ACVZu9%!7(N-8Pvg<;~Fb~4n^cn#D#yDMo1gZ zqGP?G6doC|L^sb5MIs*;}?(JeCaW)CUMdxj8xdE=MsaD|}Q+|5ID?b7*e1eb>m znb2{W!mO_0wCw(*)SFqKIb|DdVyJ8&QAf=2z1-K%kIxwl)&+w~e4RF;enkg!|3idu zawNK-#K1Z@@P0xtlf{zeGl~p9Uf`pik0CEoR%?BnxXcg{yzX%pjKhRub3P*7&@eF7 z4Stwk86Y3tsD(Nl-7Z@roe!gg;SJG|@|PyUOcUxUOV9Im=+AM&GCIwtg{PibGrAgP zuVAy;!uRG}-J9zCg)x(1t)--UwHc@mih`+(X)bDDuroiX%@&w*PL!osX%7bXb3PhrKkhsu7&MqSY<2GS_LlYV44&~ARlOW!OtI{);8!Pr-{kqd4w8Z#TY zO2H1rk_hx9_h#-P*AtniMq>!B*glJFE$1&7f9OrTE)O=8dE3cL<8l2R)*7WGp4Gjm z+G!Fbf1hx=>pZZY4NHP@CS6PMVw;L0#|YF+4)q0b7bRv#7q4h@SrFpjrZONKq)||? za8i&!wM7^i>B0FIs7z^aK~av!#krY7r){qx z-6;zMBfYd>xZ6b3^BMOc`iuoi?HI5cjoGnIP)J6XS&@0=O9AeNI_!W*PnB+(SO)Ff z5E_w-HFs)ND4;^3bCR5M3PqCt%$>lM`7j^CJ+X?VQ5HEi?Komc(tBpL*iU%7HmW>q z$QpKaTtccUE+KkQ)z;i1 z!$2^rLWW+j?d(}v7#}f?Raw%CczPr7OiSeiX=W1bBMwuBdKDUi!3r0FX$%b#FjUcZ zOf&b;1JH~2(4PjJ>3#4vs)#6hCD#NYsp3|-B33e4&vunRkx@)-y~68l7ZL)c#)m_T zyW!|EhL%=L@k&&5`lPFV1L(aoi2C@F^2s!^3n=Sk6uQDcf9sZKL2x%$GGocd{g7lz zGMmaXg>vv)p&AD9(e+Q4k6JEBK@bHgJJ6D*Iw#rpm0bvnBSLSjCbj^@sz~;j?&dfW z=WB6RO3VcdsQI%5Dvt!G;o=~5Dng-C_@PXgNL@*0jR(Mnr)N0_x36?BK(HyHEYXw= z0PRXuAmTiqY=tGk*p&-;lY~c3h982c)~H#O;rE>DKTQb-&zCU_Y9lb}A^7_kU&Hi0 zd0(lmf<=Rg{pOS(naL)eN{w3Q(?qM&q|5;8t^{jkbJQ^1&?CDo^pHrRCo`li-O?@*BWHz`C%H~e&bXEIfz?+HzVu&wdd2W zv<249Qho3?`ya#I9Pe>{|6z)NH^bQUpSbms~gj59$(;&n9rj04bBW9 zgt_-@8hz~6QQgXIb$BkZ8$6KyjlXt!SF$vZhDf-@>gdHryo6fjwstOC6Og$5cJkK>FrtJy*|viIKX59o7>;2EU#BU5!K`kaD^t;lslRg| z(dpsbovKQ~Cpr{az%6xQ9vTRjj!=t*MaOlu4TIgvS)aeL^ z=K4P{upCiuiVpwb5~zQ({;)NEdxZBI(Sj|S%MWYl1FHVJr6sMckaOeppQOz=qW(cc6 zi77OZ=I>J_s?={DzCe6O)l3##8>Zk15~m>uxqULD<>hb~%wb|??V5R?m7_zf)@0rz ztWt>fo-i46kLHSZ!1_k_@10^3eRQFN`LLs(9JL8dL63gLiH*vN%WRvHex99$W=qky z+>1DWDRPH2XK8MRCinp!Y{zl#ieV0hiw~7HaWY7id{)2uj`rE4X#+(a05@c89R z^NhqP1N`7}a5}}Y0|Hf>q{O^3`w_5O)B?24l{}nzUc$XNwKhG8BQFi=yYH~aD?St*6oWnsdIxr*3LOSDKq35lgLDevPfXA9 zA_vrqmO`QLXUh}e&IT%(yN^#xwM(XXO2vET3*xZAOl3u#z2ULy*)jwtix?H%KTZX0 zzl2WH^h3Kol*pHcd!cvV#IH*53;ZdY)7{v5Cu?Vs84N`lRlAX#KZ~7bCSY|E1 zI9)Xy>M=B7f9`(7W41m&i+%RRB5y7>K*I>vqV-HKwTAQ%yLWV!AT)gyYzljI$5gYN~g#w#dqT%*|TD?^$gNT(sQ0 z^`cz~`IVpA1>=y&?FA%$jAU~YlB}~4&tr-`EMh9StHd>?zwUMrjxej`OpeOHi)%!b zy+x9a*vV~BX029&=KMvUWVatmy~T7{JX@>v2OFXQS=At114i`7P-!8cwZ>KO&kLD6 zG3YQnlhD_BmYm7-5a$w1zg*PU2OA}4v8+27R-Vh_QDeZmB@T+`(;#uF8tNhV;DPay z>CIldGBg#2D>WeU*YJ*`FuXe41eH$F8t#!=o2GhiVYHJnA9yyH_K$t6BX1k%t^pcV z1*IxyKX*$*|bW&kPdT)C^Xv=-&nYF=_)>}pN4hk z%f2osPDw##FbuxvCXn2WTqPDm9KePTF5>d(^*A$80s6~L5)b1evkp@=k?_X=Zwokw zTLNwtgB=APrgViSaVwLnz`y`<9hHSTVrKBaDG!5>6yTb|A({ z9}JR2qfC@qH#lmw`^kWAXsFj1Rw9+cB9KQPxawij5;6@{oAIjL}GG1$Sr@Zz9WYdVWuLziMWYY{x37N6g8(6 zy-+5@hqd>^>}Vyf2P||8thw@jucLAr^1ZE-TBf>6mWsmn)n;fcCwBuJsO}kw<`${~ z+>EiDmZU#ZShUHWm=>4YhKtycjG4P{E;{4C@ zFA1iWppCV3j9BEf#^c|DgvJio;c*L66OxkT|F$j==CamOqj8c=ZX^2u$Wlw!id1!< z4>@Mv6AU!xvxaMN^o5iHef8g`W$0yJ+%#*zq^jV|=}nkY7!bZ)>uCR>lb2pdF4qx@ zcXvHaWb>iQI$>WxR9C*@?L;My!{>Jh$Wk~nY1lM-;&Kne(#m>g%l1dZksja$d+IM| zWrD#EQ{G}FM{15*gwaY4o%NfAFi=LNYaiRj9BHo1$q`b-rNao+na@jOGre(#B`rqJqDyUJJ!K4P}Y2^aEK{aeRliVO`pd+GhJu_@ zebP5R%#4T9{xLWiM!v#?ElPPum$J*7$*BYatf!M3_j}A`=HC}*m#%WzLSro%qo8=B z&1q^@K`FfUZgO5N#quk;A^*fSxLs4%Y#Qp+4)O!Q{@0Zk+qs&tuB0 zqKfb?=qVJ~-^cYN>6fueQKZfX8@7O8VzOi5zsJYSGV)Cv77YcpiyfqCvg(kFL2?cs zc@>dVkPZv%lY51ahqUNb9s|x5*HdFmhW->V(CFrbw(e7l$j&zR?cr3ypCMICu9$4# zfqvWI>C93}t<2N#cVEthnMZ}W>?}@2cmocrX-GXERineRW!x!X#SZNij{`TnYA>J= zu-9e5lr^51Uzm_N-CZmOq?bQ=_8=T2>eP1lx%YjWe(m;XCEjrE>d#xLSY7B{<$B7R zv`=0(&%>W4&tG#5$W`JI>{@qW$y{7=O83<`gd1DNj4^XGR3%zG2=}u^KA<{Rw%W|k zuz~p?JCY)TX0Wo&_0}wTBVbOEcTM;?KM*mF>9-%eNb^v~M{*kTzh4FBpz8`a;{<(4 z-ecOf9&zlHTzDzbx)I%7BGXM_&u%Lfa*}~=d!~@(Ul7^r?s=+CRS>ceoG}Wqadg-QGBa<;u6OKC3V^ z2Yz(6ChF` zPLpcGHE*B;yn)7~vdK(Ko$NdbRlE~LKjsv8I!BzBJ@!EAQITU}rL+9fQ6U&PUF?Lk z>m?GAVRGKDgh@*x9URh+s>o|9G35nf-?LAWdmp!sX*=}yBRoV8| zg>$6)%UML2@OTi@i(TU5OQnwMPsK+w*PL_FAoPxU{rI8@1c5Wun^(#= zrog$zokt3Vs*C)&vAc}h#?VVChrCLfMMS1w>ecl;9%_SL*A+Vre8te*9~vcO*d>b? z-Ae=t9A7?vLmx6#JW*ARd)+q~!9tLEsgzr`#_MC#MGb?AfHDl8$-hpfxv ztm;%*^MaZDBm5TOfAa>diRGEWaNA3M$*dekaKsJtRLpnjqdG@Se~n&+l`IL^9IcVgzE`3kO)dy zcT3pgy<$Y+V{HNcxs)Lam|vL$G;)6GzX&rMAfCx)Aw_w@U>X2k}FB6c1lDmOD-NpW3NO zKi@$M$X=W;TT8oUjriI=!BW5W8>7#pIgI^(je zUsT8Pu9(*yy4jmaJ)euTmpu_%jj;hA+>_(~=v9q+eRw~LKvOiiT~Rxf zDt6={GjH6tJFh6*cH(rZ79v_xkip1Uz1?(r^ZHvmb!)0Mr{iTX#hi^X4Y5(*+!J|r zPY#=BlFB3yAnJ5d8KJrNRBt{a8+B7AuA(Kd z3lm|TsmtQ39j{K}AZR7mtbR~>fxPZOUMgK;;MO@SujY+ZP@wSBVGeRX&C5=G>9I`3 z^PaXQMep6m6^!#Q6v%Q5H+pd)MDsc7Hz<~JNq!BhQ=WlgSFLbO-~6i2`iegi4niM- z?yIdO8-c5QYji>p?blI!_D;ixEuDCzIoTrXEcqU%5MDH2ocI1QoIn1mR!3Vo^=y*q zCEd{BvJL%~P4DYkXFf)hyMb01KpK}t;6dzO66NF=U9)>HE_xspz^UysbXS`9S)Lbt z3fEPbn1d*QoIU{LkLeYK9=~M~%FyZqjDa}0GXRye}FL76(3=8y}01=UfZ<2$| z53ZM&$BRkZs#2}jL7hiKomp)T12f-|i}WOTKneI@q;j=>v}18 zF}Gyy^g^mEyGF=h%$EYweQ~>(WVg5IcQz5zElYQe)Hl zwL)@bY^`u=`8I4&3(20sn~Eg?S4tbGWE2`}f>Wtjhnc#ci9%%=imdQ({-n4zHVtnH zv3nrfi;p00eIMPDoQU`Bvs>2$a@KzZNYr=Q%=Ov@?pDQ|9iyzT1Nx?^Fgj{*U(YPH zYeH3{#qco-Qj*ne7czH5Uv8mBt9q#IJUmGqDzU$`%j(uIF{2OIXTp50UdJYbgIc)A z$d|Cgka4d0H{;IT9iu%B6R&Pj93P)mMpi{&Q;WkqTIn|PyIu^I=FO?Q%|DPbSwI|C0-$ z0jT;)`b~^?fJx%ny5loP!~Kus_l)Sk?qnR5`tTiful83r?H|a(@X4(jL9N$KrzIY& z43>6ih2uEqf8mnviQPWgB!b`>v^glZk@mDUXO4gE`Bt}p8dQr z0GvBysgy;_*P3|Yj7k-35YGVxh?aK@y6rqYI!KOFaAwyK%%7PG*u!_&w`X+^SjK4B zs4awCH8e=er%4Qd^4B4k(8i#RkzS#@ig9JcPZMcd<+t46J5%??#p0OSX^abo(0i`y zl91~oF-^L2h_+2cX#UYH*jZR+{J2${Q_Q;m@9qmrd#CJC@hWf+&G^r6WMo z4VKC(il5d2rjy-S-LZE_Sd&zuk1%4e8!MZ=KdEh6|D1p6^EP|EqnNxLm?VRqb)nGF zPaF=5%pbg>hR}41JtKlv=D9EIHlf45$W6Qgt8RhPj(f${&@5>Gdgjk#c-j4^^X>UP zK3%NYw@trBgtmok0O|23%Z2JoU~!Z~(sjOhwQN}Iy2EEjAl$i}MC0;Tv72Qavq#3X zbdRDmlzfnCF)1bdV;y`+IFBKkwYD09QU~B0Y4up1d8U>*hYN+qP}nwr$(C{f=$hwx?fD+keojoy*)MJ6Tzefrl|^mnpOn za19CAtup+#ggF<#x}gMn4GN5m&lHiglrYB6X|s~7*Q`^S80ZSpV-#JsoWOoBKX$PK zXQ6R9c1a<3;d*cN>8mtEkgd@=7D{`5M1iRlx-u(N^bN5VJWXx64I~@a5jX|SE+25% zC7LoM7={8E@s?Z(Wuq8}jI$2PiqnxtotROG4V#;PI$x4sBqUBvyZ$#BZs8Zf+C$?d zSL;EJKJ%=Zv$SV%*il7HdcqT>r9Ffz^xer?ZWftyYBb-#o>6XI>#B#TJrmI^3HEul zKTrA(o)?IvqQmnCb;ZQ>_(k#-9(RJ5oshh=h%Y{O3<&iUrK#k=D7|!e7e<`A9{O6V zdnyQFSom`y2xsjAq?NpL$Y{`FJC8kknVj%(gUrIJ5Skg#muyIu{PX*kI zU!HxpjT?;@zYI@wkx7LeSSk^Hsv99^yq$1aB)TLr@AqM!bc$``Qe3Vk_SG$pZa7vK z?%(NuN1NmWFK5}BgAD0EE1!e%17Q_ZtyCJ|5UNoL#`0a4T&ts##o*0{X1{&<>X2Z% zDMz&*#>Z*@COtQ}KLwn5BVmr)-R(d7DD```S-2yE3=Xk6TAO6ON+u2}s`|pgKs2xs zC~IqkkuL%!yN50yQENZ))6mpT!}to$+0Pn~SWJuYf>S|}Bz>`bkB<7Ue!MSXeUlG(2ug#_nR(D|I_+Ij53E)3hJsH2v5fxa zC7c4ocrBErM)50H%EI~BNWyL>M=YzOS+_`Hd$DPaDN8olJ^ zhC6l>Jk-Yh+pN>=x}ayclRquq z_)|eSlyD+2;rl|b72JC`dbeBMbi1W7JMlK%=4yMMI@tKDL5KWO?gMO`LuTHuWtuSh z0kyjl004cXIh&K;9C6&i3&dct&7xSG4lVw21~tR?dW53M*<2A-Gp2SSFz+CA%rQWs zYoV2z&djce7CC51KPX*(l(`d<+%Ea_qi@feS#quC=s_in1-1pio@4XD0re+I&0uJs_`j zbh0mT@A;6FI29`V&H)0f=&ETzU+uqlHpL5Yn3kJ*xc+*tf!dq-Fm@mE21Kjlo?zz7 z)A=j2Bd6#**t+ff+8B>7)FVLk1r;h$z${vSE%fpo&;_pt z)U8hVT}Bo4sfZ<^F1t$R7a`CZ)v7f!hwcz_&2YzF)U<3fwgmE!&IxBr)-PUB%UAce zZU-i3nr$$93#rLINnYIMkoW%fRbm$J(AJVpI?F6hDr&A)C|#_mzC-z^<)gg5T0cV% zSgJWzy2h7E_=@HuZ`|`9H2wMt`GOvHVy_=1ubOsmsaPv=S*-L9sxm6MyvBn*@%=pJBb}75_%j5E%IA=d>T)*6`|R`y!yJu)Bvs* z$kH|Q%UB;~4|!ZX1z5f8?OY9LvY7pXspeU68|e!z7shC?!t`kV@kPU(@D?#e_`~Oq z$jeUh?hJ-Uu~Og~69SDEP^iHl%Ml(zEO9BFEdM3&gkF>6K-bWEd74szz>(ii9I2|h zM8c1NDviPeLS+G;ef5JmkX0Nd0msafts~0j(R0_-e86C59tAZ5K%)qf75{LAW(aHW zSX>@D+w z9R+2A)uPv8eaJP#N*(G$OekJqWRcG&=WPi4_U$I`Op*0WDY%TUm;0kDb>BFC^7#dF zPJ0%nhhr9Nx6#pIlAn7%XZZ3^awWM`%c)jT=R{*TsX|pO7GV3>k%`ir3Mbk=kgQhv z5+%giwSyEe@=kaWdb@|u*`MKVE&=;I2BON7waK8c&D|7=i%@qoM%b(;)x_Rs2_5|@ z^ch^&Uc}reb^C6*jtIm3B)}nFf?;7uO`aE5WulGo6p@XVK?(Gh&;Y9g`abF&cYp$& zks(H1k2W-j@MbU*BCBTA+>73TjNmj`YAi4;JzrSOdmh4Nk@2N9+2)#JQf{4lebE|m z-h&1>>nx~sj_bz3Bv&aD{bPeQ?~@qukrAddr)I0Y8`d4s%i|2qAIe_-$@lhQt_TCs zRwe87BdJ64?-Tiphth1JI>_gE>eN`y#anW{8h#w#N3X0qzH{NM@TSbAMSXjHad#qX zi%R7Diw;jl&MqVg>{Kz>Fy+p*e!T}2fp@0&KfP9Zwl3($luE;vOKn=eT6^M%^oJL_ zMRXI9+dB6oHfH+d)24E%B1w_xQ>VFwU|~1{r&)viBcZr6agstEj*!aKnlNL_Maf~I zY0;mLN?oM4Bh5$a=exzE)Tgnc&A~o1#I14*vC3=ssui2;Td8DubZIM&DX^qkE%mF> zfr^$FOQ_MkvMS=i7FEY%13jD7P@afXxYWW7P%bBky4fckY?ax&7Mof6EvRxs(>p28 zIDH`l2FB&n6yI{Avi2Y@QgFl|aZ=p{`{TmEns#`%Q{9#kG)*Snhl^C$lb_1Huz7f? zc7zhLr?4oBN%+{kzOxT^>R^b%3G$=|RMBmjkx1Wl3+-mdFjU{|jNBwpdiQYu&x@z4 zrGe3zF`4eoOYied3b$RgOm(sFOG^b3XA^zcD5r`8g0iJ+>-IUV#ql_`E^J=%o<2Up`-x1@{O{Kj}$~$#kC|DES z%0VcFoC5njTE?Pa;mw*3=B##s~XLnhAtY^YhW1ByR@cC8`( zW_H+DB!RV7X+NyD+Q~_jb3Z73kKYuXekO9lL68loXa5&XUruNhS7&R4X9#M{atFBX5pW4v)33>nA^YBE_*p>z8J zx2bdvvQ4tx^i&F35xI-_xa*OmfIvgPb;GM-;wK5rK4N;Zbai9(xg&w`Y%{ zeFP48=ZT#SK<*K5*kQ=;Vk}dXrPI3&ZXln(>2qKQm0#CwU?hJEBQg zYEPs%XpOIU1iXE4Bn^N`BGeWHflj#-pJuqLrx~lnkJaN+o5u;Cp!)DvCJ7ddHj}Rw{>qq#|*R$ zUS?opx2Xm5-ppMkO?JuPNE26Mn+IdDhH&lyuV`D;A#(eBRN1bmh=X1R@}zE{9-Q<+ zT5Or54r4109fU5|ulpFN+6>iScj)Qd!eqsZ2oUwej~|CL_3KfMw?gO=H7CtP$r#SD z0{koqE{a)dX1-ppoHSZF5Z#TQB3-uD<#E!P$-|>nQ0bj9LD%hn+rQ;!kZGkG2S9kr zUVcnBQ|Cz2+%)#Bw0ly4@+mOkaz5$h$T6Fq>H%NAZZ#ks@({&DRTY>C|7ATD?>-QAU3XM9FD<{ZUC^FJ zfF&8bva2txFBQXl1PNdKy%Z3Z%^eLSSs$5UF7Tum2RFOD7PBPflb11G6W^0WN`%wK z@-hQYVth&PvTXWp@7Pg^V7I=zV2ve@4#=jFUD z?-1Z@)T%G*!T&d+N&(02)-hFP+%+oV^l4uJHAho@NjC$plWy+5iVxQj25h>KI2)|- zj309^r7{(gUXwea>@HBMrFaQ@la!1M%ekB28sH&rKJk-(G=!<2Xf64-YLo@HAW1r- z*~PnNLS{KV7TIL6ci3ye~Z#XxhRV22j zb;^!fQSf^A!kEkcRE?d~iyxdpJHOLb*OcUH(gG$(r$KSc-f_B#j%v>1H1DLYV3B7t z1@{(%e5^#}p~_Y8hDedai*d|iw9rD)y%#JUv;#(U+(GBe80+Aj4?`Kj@p(?t!cL`o z^o1f66rePEHS<6e9wsJI$PV;sn>A+%<;cAj&Zd`AQ(_wJ!iX0|;H&s~mvzuk^7~2y z-*J6$LdE6(iqb5Cas@gW!9Fa%^6{b-(~wP(;m%4(HZEXC7) z1%dRq{U!$3miAhf;w1u~O7X zD*}U#8y3*eWRx~8&u7`Q|>!maSz=DlUC`Q4turX~X~| zlUiOZTnffa?&$-onLf)r-PCS&x2&5WTVEE#_~zQ2D8&`DX^0zv(y5&Sz?d1cA7>AY zyWeRbyhSu_IwLrh_Djcw?&Jjt>%3TfWD{2G<B%NDWRU9h)0Lw*aSIn)#GU+^m#aNDBMDID2N5OZ875RxV4g(d3rO z+Sd@FRSE`GeAo*?Ui7=xGtd`&+HT3FYtnVyG7Yri_5&43cnl?`h;qZcTUo+4-t82l zSXEroqKiS_&vz=?7QmfX9ftv8r(&GB*k~u*ZqBawE1mK2+@S7>EbO?Sg7Fn=Ln`Ga zZ)PHo5lXviBdP)51b2V#PAm%jAirFVg+IX;goV2?T%b&{VwLLk6CVhSWW-IU&amo? z8973iw)CEhIWH{*%3?cP?*8efq_h?7#nl7Me8ue_Tr!e;0;AU( zf)i4@*FGHg@+t1%&SL-+kpt?GL}#EQtUW!9THZtrs)`T#Vl5;!*Zgi|K!yiVjbBAQ zAdjK{S98a>7u)=&w|%7B%cI20>DAAKD*fB2?u$O&A)shO@Q=sV7<{nM0>x z&~C~gg%%;){1>t38JqNBe(IzfwN8;pu3Ci~U*?#+gMRNgG)m}m%2I?G;EAx%grw7* z)3yFY+7~pA)kV46_OX7`n2#h!>U#Vi?Z4^jp%J>W`D-i!T)EAErX}@ ztAv1OL!MP)TxAhe*-g5U+%;@qk?s&dokvj)lrqQs@-WfbW6}l4eHM_m_Em!%f(`Sm)MD+1 zYThf~Vy#Hc4fS)q`ChZ(qnKSrkq_I$rcu%i&xl#`Mow|znP3sOccK|w6+>X;*7C)f z=2Q2t3M1TJj-$d^_)p*|>Zl%nyZy}U&MPu6%nL`mv798+4!iSi`g}JdSzjvmQTP|v z;F;$_wPt+d1qXm5fj_K7i^~m?={}Zt0B-2NbkF{(jr~MxHkBl&N9q(lKkiWLKaXWaFTF_a9I`)YL*rok9mK#RFx z-$r7;DThyw0`h?E$oSjzl61b&8b8t>ti80C;0h3r9Q#?f^)|^^bS**U;TUR4D#%is zsQvE}8GlC6=Iml>}f1|}#4afB0BtW+!y z)?K;J>P}SHjv<3nHp{xJ9qZsk-!|R>TT%bUL&NdHLIv?S8HyeY z(;VJ)`Cu~5=Ofy(fKEnJ$ zNAo!?K8Q67kkQ*kzcYfXsM36m70fUQwMH;Nsaa5;L31tImmRNe8I$4FcKLlfb_Odcr3s9g4b$pI^FZ8*eyJPC z8}FCxoF%~oTxwTqJfhkx{swTY`dh_nB9ku;gPK-8);r*1aLPm_1!<+mq7le_<>Nm# zX1Dd^imv4t(&=4p>Fry3@>Xg^VJvL5;PnYe5aRGIE1zHG**G#f!S8s&v$$oK7R>KI z;esO9{x&wlsJ^h-8h2hpahUN#}H7^U20c;%th<(EMo zM40oDQo@gy0Sk!3X)ZFv)R8KVw1jQJ%(FruI^{cv_2l_{HtwF_84xM;*|qFg8fhVo z4(5{hdKSKB?(d$yO~4yxf0Q1Ka*t1zo+r!y$XR(D_PX;`j~v|Mo3OIo{2L4rhu!0g z&qLf7^}EtrfDIqCYrY#;k%bjxufgW0)nN=ZSQ90|)QDmF@5gkE5ZuPR+>4>!()PQe zIJMpM+q~*iC?P0xyGY*tESy;t&lz#6m#AJ8Qq&#ygL)?499MBIP1e+yw1{Ysp=1+P z6+G9mf_t%5P$C^(BtU#m{C+ixS`u)^ZjxHq9!LWshObp=m`i3CXZr~Y@SIk^hH!Ej z89N?QG0T{SSv}=>X8zk7_B>(X;!7m>%LG;HgPI`1UWAXnHa*xI#ByMs4<(OzVH7~K z{s)Lm1On@+x0f2tRK2RYH)BMuz!X61JFejO{pL)jP+%PM8m?}hZi4w3u=c0WP8)wY za8yEjFxGVL2kUHABmtlZ3|dAA{*@fZ3IVw>DWSuGL_&^b;c4Q0VErd#9hK&|LvVW5 zo-D!2GEesLHaNWkx&EbLvN z+o_E4NKbU@qyIsgvOs3FekniI<{Kk}z8x|sc}Q1ueV50B5dUi(u&AC1gUa!2w%!8E zuidy|IkZ1rG=e%5ESk3UQ`o|zT4<%}qtccTe-yP@p6bC4oB3>NfLdhFv8`cvpE)#| zoCXNR=ORh~W8TCcy-?jyK*J$V(jx{<1uN~&OWN@$)~g!6`-0eXb(p8*wvRvljV?=h zfJI&kcqM1O&fsiDi<@bM z6jU=KW98Cv)4)$2@}*Emdy>Xo<q8*gYYKT14c5grpscBm|fWlbun z{KLi&EoriLT3F4T;Kg*R8e69?RI~Dwk!q5y!L(75DBnkKF9h0_+C6K|SRtD%$B;ym{u)qN z=_#B~%MoxG)Rk~vEt2+R&!DVvm$`BW`@Nc04P(`sY%srZ&uUv*qq*h1;BnASukf$kR(&6`$4T4--UW!?IBEm|JD; z&LPw~i_sQklh!4_o?P(>)>!_Zkxc2$WZheGV1HnjOst?dFKNle`Vtd5aEbG+e6*LP zA6?XNp%Jcarj!2jlHoryjaH!oOZLeHKb#WTrNT6_eF9ihIa{0K)z+1q{IcCTzp-Hs z+jBJDWqc}3K@Brh)1qUgoBp%UC#IwWwEUH1>OpP#z zJooQpi|m)|D@97l9qY2t*?Cyd<(^Bk9YZ(LVvj==RH^79r#iZTUS&}26RN=0svX`q zY!>n$Mv+O_5Oq$dgpIKS)rUW^Y4UlRjH(YJIuyjz1oC_FZ=$uQm&SYw95P)2Y)b6r zZx(CYun&Ewn6rG4w1z~jyPJGMB+#D9OF&Vg{L!i=-|q-^k)+M}m~k{bgWuG~h_$NS zdCTRGXkq{v$g(WhEMDB+@-n5LPt6`^Lx}7WTqMxA9Hp=0_sTXf1 zVew3C_jC{HQr(;FstTIr!i#Bb?66T_+*w~cNOlYrNF~W?*D=m2fd?4P(pOwPMlxGy zTBH@6;4;-zD}^>9S&%mQX4uJj6nhknhP5lX2{V@O5&}jjaQh9)BHEzGFiX^A8n{)~ zO*piH3LB)X@SkrMf?_1Yha@c(nxib1Q?!m(&Mc~4A$iRSBii&pAy`~O9-zZHY zLU#~_^5KuA)~H=Z5%S?R_{!aZbZbPW!%!b14Q-a3z*T0wri+h8K)WoT96qBHMDAkl zCg?8^nHh*&@zT61vt$`ARdDsD4tSX*@}!48-ilK!#k{%|AZ7Ch&oBe6YS>Ow>pD1@ zEO10BC*>ppDfWgIMa;@Fb79jyN}AO#>auVK3TEgT$w*nodRfK(@dfr)n)I8Z6bR8Rm0)iVut#U~Oy$ z3$b2+>cUCg(c>S~SQJM`aF%O!kx?dUhB$G<7{B?un1C~5y@(}NML#P-6z?G&!z$MD z5#3WiPIVA+Db*A!>%_%)5QDIlmS7L;iwycBoI`l8fj#E zWrT-Hz==W~Uw`ZkJ8c~@L=;Czkt1SHz5$MDp34(S9hvV9WTW=e;n|Xc9*+SJGO_B` zG=u1oF})#44?my*OU3am{SN1r51&Qjo`w&;!Z&lEmZ)YIJ3t9}rFwNC@Fly|(sh5FQ6n4w(cO`AlR5EH%%pE9mS$1B-_aJ@)UsMH z-mFGUtcid?bD=O~BK5|oAMzlX!Lp3%4S*+J{8vnr5v(>cu~u|O8IHW0(TuUMu+sUT zJ3q<`OJDhFLC0vV#o;$r@tI`-*>}9n?Cf2Q?$b|01^6;snJlwFt|IrCHp>l<#zjc_ zf5Hu`BPE$7d1iKLY(S@bbi#_Q_HDv)#8vunK{UxybaHC|Pb|m;_-^zEV91dW%LAUQm&RMEfl6%qZMh}1;Qyd4plQ;Y5oj} zLS?#fa)HbR38{4>+hjtWH_u07%C&T~u0` zO$;Ax`?$`*LKERj-62BOyPA8W;P*le6XQPc299t;)L0H#oR=K1I#P=mtC%(B+``{n z01+Q)lP)&DxBAI=qNQqA6F(0LQpjw*WEGUgCF@WZXAYWoN2A#JW!$}N>8;{rtdT&E zS3V0+cEpo}q=&h;OquF>Lir}yi%c?e1H5($Xhg=UZ=a^ZRwvoSWh}smE}B#l8o-s; z+bElVOtXdk0+pjViP+Fk=bcnPeHW)F@fW9gVh7`#ZL+)|5@N3&BS1@{k_`UHnQpFkOCO1S; zblB1Iypq3K!n=L3MztuT_BZI?|iG+61$wt+z;lmhH$^GN?2s zd?IOjsUzK$wxM!2cC{7+I+51&R91okyM$C3t@($>4!8jg$WWJ0d;YJRozzN2L^?hP*98;2@!>X1R-4=U7aTy;Vvdog5#I}>I)KS%1a`&5O>%=SW1qEo- zB@;8tg6{-DYo`Q<9AAlnpBf9%oC*=0(?^#sQ1r;?VO;!cE*jasM3*2BNBRxocBgX7 zK)ao zdtzjpp_gxI@9B&960MXYF!iMhg8KnftWkf^cH0_Lh88s8&31{ z(6X&Kvf@oVbEg;alWZ-|-^J)%)fK}4_B-yJ$hjo!Pbu;=^Ch4}{1bIAt;GGbn24jd zj_NK=HWwQp`AF|ybJ)t3YMUAe?st0Z1In~e0uqeAqR>6Bb^U}XtX?n<1aF5Ia&i;1 z)bg*1R*wT4~VIBSK19@4v zzPnKOQ3Z_6osO!1nGlIA2G$&GKPQK=@^zGuSv`<$qHgy@#Nm|DxpepNjZnTAD8OQ?`a9aS++#~$#N~*TP%k`8u!gi>0cdn zL@-NK(nh;|ZJplWi^+uXVhi))aEP?Lc8p}v6sU`rdi|sE%F@2cjpFlT$ZLYiB7DMy zw63VzG>MV_ zU56VFJAv{useRy0z+#`iX6K7u&eJ7Xt1Ao0$Zjp1?gtyA!PA1*=BHJCcMuG}($Qf| zg9DyEd543r&O-LuiHIKh#vJlpl-BEAe}DSixj|c$WTBYZH`< ztljjy%P_jkLgTLU?OduM{pVBZvu&@2GaC`hUunTiKyO8P>$FyQy&xivgnBkjvet1# z>qq2z0Hb6XLtQcBOwvSn$8JD81AobFMR+Nkx#dXQ*!*9OW|r(J$&S!&^qz^PT8UwA z=l54PQGWmVu_@Txb{))~q2kjg|GflqkKGk$|9-0tEhWUF9$hN$BVZ-1wt?0YEZSxU zkJhaRxtHJ|SeiC@5VnUwDQo-BlLM#guH{P>W=yR-RwJ02r={2~DN4w2&FyVAV_=U6 z1=xxGdT%hB0=0Xgc(XG^nFI*$hB2zEN#N6eNmbQ(q*nG@;x#CyR6LuS`7zAvM58>a zirKQ0RN}HAwLkE?9+aA|?>(RRo^GEBwbsOl3k1?{R7kKJD_l#P!Gpb-0=l%&^TfWP zIECEvkop~P7$3#(8Yh=q7jJvs_!=2iE?lmfH=6lHF=ITY$yh$X*(O#kl{Ic`WL;6f zMUWiQ{o!%OGdXm@piOLVaC7rMi)q@iCFW~c-!!gXg4o}!FXY(rCl0HjYbMKcia$x} zE&6*mIodZyyp;ecX`QysGA6BPeQJhopa%MNInGuu_ex@2gbK9gx;zxB`rkAkh0d}f zVfI2>p&O|sdHwStIqBkhKZUQtl~m&}w)#aS{C!MhWmoaVwlM;m;Rog8p({^WnO#&T zT4nZVBf5KkbH1LW64`{?a&N>xQ>Vk~hl4VF%vYMboRQCa!zKqzHd1;as_nklx zC%(%aiwYJW*2@Eex&P_uTu!LX1bv>bGB&uYnmy6BbBdkkDx74CdqX{F=7LQO4% zIQ@pa`4%8mh9@nrf zE{ZwNxZ4Oz-@(NJmtc}<0cGz{hv!q)4bYj*vPO98EEiPdnwS1jh} zS;8qV=C5k>o->wtWm%tqN=KWph1g!4^ZZ;h+D`JLGtg@%q{iI>boY0?0-`;NjuQ{l zDZ7udC8&%Az`ca>csLr@W|ZjJYMbF2boelN8ul`1>M;_eGoo3w4i>l@l408EQ2tqQ z=6L`C-AjDoH{!!}EIFwm@2j+wJ(8^L4Jg5arrdSH1D4+=wU3JY<@TD%iU*_x2yK*) zKe*!J$&SIEek~zwGSKU)JFH20()x)XLsH16PBp%fqFbsEL~|3=I>r9I$$FnV!am}@i$h{8*%e5KO5vmDsZDla?kHW3m3w1Il6 zt$OG^PF%;8hiu7}(7a;_-nCo;qhsbwpP0aPDy*$cFkdXt54jXp`AxTe6q$ln(tPQ4*wRnG4Ls{Lt<}FAYAl^W zLqpCXLfgIQq(DbW4mX)>EpJmkP$dQNOh`U{| z1^xlWGOjDVCBP3JtAAJfQoCXCZ`>Fp^_v8DLXsN(@e8}gWjw4f!ZihbTo`>ft4hXl zNU5F<6Yume=gKaP2mL!E+HIFT(tuj~RK0Xu`~!@nuEg?dsMLjI@_6;u$kHxOB}E&~ z*NlESpRkqt3mh~7uYRVY>+&h-L-r-9LLo3&+NUot1cC)&*S6CG?F>hW(VN9>4ib$u zxv;-m%vVk(I)LC4^|xKvyp63Xke?dwdGwIRH0A2V7oO-z6|&BJBCvI6m?+<|yY!+p zl=>S^UO|3mN#hJBNYO_2=&LPjSIK7r*&FTqrt4>Q`$w6&1xUS7zZ!;y=I%GTNx=xa z<^axBW^Cq8=$X2V#A^bhPSl3T?wS6Ff-@fMXHcG8%ze8=5Sx3%6Eo;hmfJ}J$seIY zUnsFNm>g$M`UOeN=0dqh3%v;dtd+@{hQ+fZT4#+f@7{~*uz@KD+ipJ%p(y^{Hd(Ru zgqzY0+g96KBX0T$3j{d)J)76FB6ZmP9XMdNUpd??@{_B|W2;w_VYe<+Gn+q)cu%3s!(NDx7c#Gc27WBHhSW-uiUmsplq~WNRQM zXG|}32@f#7JU&`T+T`ik0%Pd`P3$NPL#%7?PjH%@#df0W9Xc$V;Jdh&rW2jhsC+*Fwz~Bo+T1_Dfo9Tw34njbB~cHNZ4OE z5SWZw?L*c(d&yvo9E*v?@h!lbNLa|p+_~r3J>x}{h`y6)gOZc5WA=vDuU-4O>NDHA z8PO{+NtpEuY9feR5dn!sh}HR9jaIZN-TA7lAJ>R5Ul(;lG1{+A+0W=UBi0o(zgIEA4Dti3s;W72Qi(fk-HEK`r;NB&WOoD1TaxExY6r=wa^s6n zB`1OwWtfd?F2>!NX@TflJLHPEAVakG8U|o{1dyzVu0iSFX;VdrI#vK#VwZ}LbF|YG zq>Nb+g&6R5ACna;rmE!|-+zUGL^&vh^6U-Bh+LnB8bG*DXU{FEdv)*#W!@*wjYaxH z#kwCbAF}ALd=`M>rx+ThpB=?5*$)RoA^40VC=)B{fA_C!pB4SP4%ugkD=v|g5tV{&x$Zg&HI zAzRN0!E;^JajE}Z|n{b{7*E6&4=6qq#`1-dUdft&&pF{k1IM^s|*%slv7$;ef=wV zS(H2ulxGA0U5GaXcX?c$gt~Sozxs^lQZYm^*bwf64qB8Qr|8WCE|9@cv)czkf;D4hBp#E))&a0)%+Vgp=6yXgjUp z4<>iAIqHoj7o<^0KTWV{$c3z4SbItk0VFdr2{UNQf4g1<2Z3W;Qo))XoxpVkGuOh< z5i_bzr`;Mc6cSApcM;s`O=My1n3@;?%*&<6%AzRr-g`={ds)l4O9l#2XS4={=~$up zyqrK+L}Nx%%k78&gZdgFoq#VC)`Ebdmp2Jnc$BrXLBMzj9%tCX2)$x7p|%$804a%r zU)*vHXqpzL5K54(@fMUukD-jnza3r0w;{^LdDq{@nlM&)9#)Jp0%WJ@5lMasXptCb zeGp*8k?wJ2V5Nnm(DyPEP)MgZC2LK#e*=g#TnIS0qG%FJ<`2WlVns#r0eC_{?~+$r zU?NEeZxQM>jQp2qmKo29N#7B!KHXu`;@t56P7uA;JpDR6jEE{5XITontL=PH&dWni z3E2{m_7|RZip4u2x)j)T=_>=ml+5=f;>Feg>a!_S>#7^=7no5Tx$I7 z(^xYYKV-1Xm1v@Xy33Q$#~o6nfClWy@JR6nOsMzc~>&UKbaDW_wAX}-9 zUNag&AVB)A1}JC=`4ErfX{To^zIY(BLnx`-0#(w)RvHL5@kF~0r^eQgq7np6@}ZN+ ze-`~$T$oWaj&G#q#8x|oXoqiwCtAm}TkcnAB?lF7l=bJYB#6Cy6Om>8ej~4WQCU#4 z)A_Q&P+70 zJ9|$e8Lr?%8ZDTC{<1HT49Q!zdJ=GGQ$(R~NodFz+l%L-khw2`yAxXUs!5Nna?m3q zkfF#MkrP~6Ck6p;B6V}pnjMoXS>I~6Sb$4PdEwvFC~$IU;{Y^I z8CCkVM6)b}-FgYf*kzWI1u8*Bx{i$Oc=0I|0w&DVEp?&Zz?exH!o!q>X|e2Jb>qg6 zI~AqE=FQ=8-3S&6NQ$3UntXT+JWz}#i?WdU+XFgcVS^BR1MZZNaaUH2aFWuv1cDsF z|8EK8)!3+kK)^Ly1*w_L9U>H^9O1^VsG9FWpe7*phs^LN_*Ftgt;&XvWvHLBQ^e_; zhE6Zw9>YigJD*YU6hdoHe_b4^oLP84S^%vyyH`WOcb7&vir7nGGGF0Ql8kWhArJ{E z$R2>IQ8Y=qrKzuY+jlG~!^s;fT?*7wXj4=fRD-~c`V0Tt$+LI`C=UdJl|(a0oTa~b z(h*kz)g;6lJUj!&Qr$cFFAyb@U>m=w@sL2ZJ5R^)zG#UbtZdPE?G!ts;S&aE=4Tdy zuG|#X2Xncam@qbh$%W@+fi6kw05>inPRq`kV`1n=$)+h5y$0Hpo&J%GC`W(wlD5sa$W7GVK2{DOC z&w&{m#ueRTwGaSPM16InB-N;?4I1PXMN^@Km*7j6X9rlCUdmu4VRsj?ORS0+kflS& zX-(!Ij5L(MVJ9^e-!`jwoNVafeH_0HI{`&*+{PJKi3X`SVPOx!zfbZGevXZu$za)? zN1d3Wr)MoQv780A-&H_z{0^r2c%+N9Z7y#mdf zp2209AF!pLhfsW1g?LF9DCPSJ3C^Hh5lMPs?0zc-D@_APyA5Sy23#TQ5q-A}CmUK= z#2vKZNhsNXKHSr2X`I4`J+r9rJ~>K`rdESV{>Ub3;qzLi4Nv*6cdmq2V|WmG3o@kz zwSizMl+>!_o$AzaRRoZkvX%0cOeZvgHeqDds(_rq=PZcWh!7~EMgb4>H^|~!ymts= zW15Uc&0#O&^86~M<(-V;f*4+puz`QR5A zL!ai^?awj7VRkfsJNb&Dreq#0K*R+9VI|xL48;?KRUJKq-Za}3`xBA@ir`{WB7d39 zeG71)z;#h`7d-u-h#|cbJw%daj`oy<`?iLEY7|3a=Qjv-Z_r9OJ{3=;vsfBCWiz1s zv$x*(ak^XQL55W_kshMMNW~P-6aiz1t)@PyS7nOk1Pbw~W`hxk_VZ`rK%~X26+tE~ zXf!P#?QsST1FMl?Nq~w5`)3*XN^jLVSgxmm5!v~DD4M+^*)4dqn4IS#FckoKk(iWa zFDbc$z$^e(h@fkv<*g)gP5Y$s&Yo6YH-@nu{V zsR-)`QR}3d-tjYF_SsC8*bFA({I0r853Ah&3oSs>zbc+*>gIrw%T(E#nDkTvsrO7V zxILjgiKlq?LfRGc-K^Hn5R#7%Wazp4$PDopGh11`094YpTfrkPM@ul}0(ckU)mS@>CLT&*JWE)lw`p1Wv>w z6A}mmEFw2bagdjQ{SzYAD^@Z<+>#KfOh+JBes3lzYNUgOUC>mhdo49xSQY6Z*{7h0 z3E>NIt##)Q3JWfbXn3hyNQ5KLp_$J@O$gb+x4>u0y16c)e8~jHZK5oN>j- zAQ=q?s(=CDmjM&O0|gHmZxTs#M(}~eIlPROwYBq$Iwfoq11_g%v;sZ~WEw;Jqv81X zq1rP8G!p}39zCN9dJG0yMZvrJ5u!}WkrHn|Bv-Pba&J_cq5Zkf+cbh16`rn-NIR$u z(k!%GnHIkglGT5~iK>a_R(7dE!&;8H5Vye?-6o0O z&kSlSD;XESv%B=FkAe!cFNLed*E3I~?0|OwL|0`P4eQ(Cw?lkfkWN8>#57?(d#E9S zaucC-p<*hccjQTyI&Iz5SlrZ3+f?hn1XcrmQtPppYql7#d+w$C2GD$u0JKaplm@PNf?GR7x7_ zBM9;&23jh?_$Y*%n2j6WkOh0=eXa09Z{%_X5T~4e~+TgENbOSfzE)J&dz-vPMti+@{N|M3Mr@?L@J6f7SWIbLeYsyiA zI_*Ozq@PfBdyEcX8V<0dKxOra#abHH&=y67f^vb;DXArNamaV-y&|K)Dr_QZvstLr zCcU|1@Re1~3kE!8RYpA_c-3pOj6Mm3+wk96GO(ZTgjR!XgDb1YBMkWyS~!o8U(jhR z;e_FAQ^gC+wMPVVPcg!QGHs^_ggdbAh(XmO(;-=q)eDMPYHGz1_x^p>Z>V_#wuyqt zc^d0zk?*wmii)Yr%qCLW99G56yl-!r+(7}>j}@p(Co#cmP_4o#a|b(fo9YCzBS)+K+S?{Av)RH4GemG=W$;Wgz-p6WR-W zhC>AiHb|?md7#bR3j5j1C$Y*c4o|?d)9^?>sniB5;n-Dk==kQamS3D0o3Lyq4MRKK zS{jQ`<{+te)uSrM!BmUqHGtSsi!^Jw=2PMuh=yALwFY9xvD(F;fexm)K4~V1FJ&BK zfy~frj*bb2@!_aaMrdvqep5zCQdwi&5&C!^J6VD&*&N_4G5|)U6JS#T%`ZRTrAIV5-m9;0gl4 zQTjiv`a3LIQph?q&HqTcW8(Nmsg%Z?d|dj09yvj}!B90Xs&+oDY?|wQS&%Z=+Q9z; z%?Vt%dx)T+!eJvphag;YG4dGCk1YR#?-+U zQ8nH$A>iqUt7I|GQkeCQ=^u;wd?+kBDA6HS%i5Mz&#Yq^l;~GK#}mfhA26nu%I53_ zxB-I*^rW2<5?Z08#Rj7J0`I7(eRtsnu?fG2*odRXf@@FeD=j>j8xaB~2Yj1=yh{ zu^5~g!;6qCPJ6?=Ys?e~ivkkJ#~+{cP6-VJ{pQfwb%j5w`7D z5c#S01=?9buv>6%CE~LwKo6o~mV^VLu@*svgX^#i>#i0iQ}%?Bf)5QT@qNPB1K;B0 z@*_kkVN`RU_cr^7#nBC^!n8q%C4&*EtHM^z(?1wh^eRHfpyx|L_kfTQ`1hO-Y9hAdXT3hwTmVn1embv!WJ(NH_153VA zG42RSyCa1;V((7Ts5D4%dQx3JVk0UtX!2ybB9)TyP3yWMRDq0WSBs-l8`+4{;w_>y zci=SW497pODY2TNeP!h#CNjm#-I?dBiqZh0!y)d;>W~LbXf9z(A*e!eibI`t1^9=^ zYH0Na@Iw-u8U9ewcrL7iy>-@j)lOPFCflb zgBgko$IUeWXIg44n)^@~;as#%1G1jLqQX0dGEQKlA;$kJVsY08`5DPNonqZxdXf0A@Hq5vo0T~eYYsQ=ARlohvOmL{M5R5G| zZ@oXA$kH!O7SNjZCJMHsFq<1Go{)eTa(6vp4!X6@oiv9?$&bSAgiP;MU^Wzxi@Sjp zig=5Ht%`0+$$TU78%HOBSsjBMZSXr-h72o_@t8q6@Wlw3A-O6(Ko-qn;phaw5;B4+ zEk*1`!OucqCK;Z6l_W_NV8M0i#zYT_#B5L%@@|*jjJ6V<6j{}h251J9YK(|lB6cTQ zigmwi!GgvJqXdn&rNz@pFv4I*&14v>0ZIswFavxcbZ(%PHHsMSvgc4K6o(Bg_Gh6I zlAE$o`!-`?(EiiPsSKxrZt2LZDo5&$H203Ii8>UIeM2saG8-&dYl4o(S@G-! zFd&mZ7P8lvxjIv>TpTJlEdNFXCO5JY-kI=pxc&t&LX>Dz0ZE#E!Y`A9)d^E*4#M*2 zR%ABZIHNp=EVXTftQ#3c>lrEXqttTN6w(-xWDBBTBNez43DNFvSWpqI*aTp?7K;cP z49+cAEI4FyK~U<$^51aSvLR&)LQ+E}XG#E9mJADFM6|p=nk+j(&C@W&NHR^u@aQ<* z`dSiVjbEeD1ah~UEN^~7T}H7vigtLgjb;=m4(m&tHVjXZ1;8B$JKcyOLLP~tT-^{{ zSd`E>q%Xsd!i5kSA-^R?(K(eYtYga|3>OeZ?|%FAaNRAI;_2z6I>rT}#@HHk&Q=1f z)KeW52K6nREX$*%lLC<0{t{Wks^_*t@8xDHn)#R#8uy`a9ARvoUd{<7sQQIA4ZHb? zaL9WSr4WVIjQLx{L9my^e(|!@EDPIDfWE4_IiUO~jt4-Hv$h+b6)7Gt6F_w}itajR zfMlc82cgwerEZ>C=~yJEh8knaCW1Y}v$cwHg4nk~YXp-gBBZ6>H5>%P@q#e`p2Im9 z`Dk2$05#XZ+8{C^;s|v>DB&I4rPLJ7%(hnw0I})g%JO{#`TxDB z6`3YHJ~02)emn$N$iPz$u`o)k0IEb%5J;i!o+t?jcoThwr;KdyS)d@oUm+JvAm)e# zhT7qPcy_J&F>a?y)v~DxU)}61`{~TU_5=(8M$nK6&H8yB^k0q{*wSPI2?l1ed+REBX_G}XLdVdno2bSt zOedKmDi2vkh`r-)P|7nC5D@XJk6P-BU6d&R*FhRhBdHPz)~kjq<Q3nd1k&i1fp_lC|Ee+!WD?+e+P%J;m zuA_8fqzKzmgZOK%tjWeIk|SCyp@+>RVMl}@$kMHh$cB7lnU=NbDfU2EmPnGHhk~A2r;au>)GW9Bpyj*)-or!DjbLaq5a>ZS zz5mFLX+jI4M}olC1BgA>f{Tox8ws^2uS?i8_B`GaAiK&zbwU;mFiiaug3)A2wDgD< z4P6w`rthGqi!=;W75m0ZNKGR2z+x>>Rc2Uv?Uk;%m;PNNm`Z>=yduzH;FF{g*Q7Pg zDG{qkwwq$(L4l!+8>42Dx*Io<;u_6ppM){2{mH!E42h#E9k6bRT`eLtwX_aQMySt3 z6dWY0e;Gw$jVtuw%H%tMCi|fS1LD@DL6nyU`i&9FmkwTzNc!hcM9k07kP&ZM6*J(* zN<(SS==8TDEJMY9)o?yTwhUsiQL7JWu_vjDY?9Yo^s8FlCetF8>NJ-#PkQiT)X5oF zR78cKu>oxM>!7sU?klny-=nB$#X+|$;OrD7i6!Gy!9a(Hgj$ov0BIhMizv#X!|2G% z7LuLs8h+4z9nw<-{WiT8Bi#YHWf0zAv)paj-`=jO&OFU9YOQd^ON2mc7I0#OWSQqp z#s&ye6reKVrj0_0aGpkb1v0_xe|XVIJP88sF+-Ooa;ta8HIe9;3ZTJ8pQf(P;un3) zI+5qM-0}sCxGK|nrkO)*5qcKaW#N;eCPVxeRMU5iNp*Hkx|_Niph=2Vnq8S>cVE4w zco=rXliOc3Lkg`VlN8l`as7UpKB|kpUncr7zyZ=L^}pL3NYiPOz<#*ICMC8o+^cT+ zAd(%pTnDUvv%V02!VMH%EmV37{2i1+7Rnn~b3QvM#IdGy#c7jh6oO!0 zmDVoeCS}ml%Ct!j+8$nN_Gfa{losk|F{>4!MY*%V*gx$f2fGTAJ;3wa*{_hpB@h)O zC2~d9R3Tin5wjXoS%NOEqV;ijG9>0;zad6#EgQeQgDE@C<)tCi*_5>sWYVMs1PRMs z*AK9|qKNdvT|h#&STUuKFYdEkaP~r7Y zm6zy*WVgg!gF^00uLb#fed&HlaO^L=6!zxI#OG4f83OTaW-Lhq+5CtRF%M zg+)cAA|tG-+~rAM{YW^C0B;9^8^*5kW#@i}j46y=y-MH^SZ45|FqJ z^=!8RkW5XDAQe}oPm?W>wDvG-RGW|(>&7`>4GVIujBx2ncnbjN zBMH7RDN66OplTS0Y-$+~-w-)U@Y$H1*_&A-Om&0K$uY{9 z3ASyJtuD4A7~3SD2Y@;ET>Q6_#AV^s>A0` z0CNcP_HUbjZI5o`62t-{w>X`e2|z<0rdQ?n5ut->nCVSQp}cP14|Q^x$``~oE7^iG zA0!@92=gb=MOi^hL=o{HUa%Xh-hRh~T~zToop>rjIg=*ZxAwSAOwCyI>9R?r>)4D- z1#`=)$G;K95moILtjr@iuenmKLL|)rdlvR1w6ajq`a^Ts;3F3TrRaVr&Z*lhJGc~s z%OU*)k>sF|nCijy`t}HOo(C!8ErB~U=)VrpyK2dXNPs#duCaSck-|}<^GLyyXrMx8 zcHok4=5{qd>i~NEwk$-%Kon}L8U=h;&%`X69B>RHF072iqJXu)uO&rh;73oi{Ds7n z35kEdb*TZut}_fnnbsdzO|y=o#E<2Yl2P+1YK}YJufbve(6>{t#Z95 zyHfFBhk51r9F&dXEw<9KTpoc2jxl#_GJw2N=Swx8q*@B?MQX72MJ9PaLP$7t1qYd3 zW@NZ#JMybCYmydQ+4>KBtaXnGZmVi|iUdgtAr6yK`ufF5ZmdiPrf>^N2{BRpSTjC( z#z&tmv}m<4K&S1oRAB{FMBHkG3R*RfRHDbKTaB(cc z47XxKZzOP8$Y`x$^9MG98b(b$zs31eJONCBz`qhDVMgXV8l6FSi~{q@a465fVwMq1 z6C&^fersYI)?Cnz-TYz60k4L*FhE!`OiVFr(b$pdOe6F~O^;pt_#3BSV-XaA z4BKVVC;(p(D}$h(Vk`_ijk(lUU&fJAxJ{0lN(s0*ba z%?$Rm7`<0mEH~Bq&`EERsCF^<6GU~M$CUt^C~U9Vnl4wh^dN*yKwNgHPpnknp}aN4 zg)4SzizJog2yX@t;>-jb@VZAZ|6=~w#;TsRg2E)`Ln`&(<eTs7cX^db?rZFUpDB{a3wg1_p{xSbZtg50tUruE<0I_M(+4n)Rjx z+aBP*Ea=uzJWFBF5nV!=pV}xU5WOBw0nhqe+V|&@15&grU&+lMSBfmDXq|O)+EWEC z8l=n{C3@$QLx4t>&BLYYKO+1#H7m>DS+Fn08S(6b3w{(qE@FyxE3sY27R|6WPeB4T?twq&AB{k*~6)*Q6;E8YVPp0^C-Reyy)^|d(&*)X zB#yB4A}5_Jxspt02si}x=W=8$T*2l#kU>)`SVxY~h>}FSbV?Y; zAQ0w6n6qUisP++nZ-lHe9gwXei(nK!AdbX|2qO}dfy6Na)OJ&` z?9D`3`Q!7qZ8DTNqwQuOtAcyT-${TdbfRwdlZ|4kD|{M`WYh&}iI__U;b~=$P}QFV z)J&6VTm^QvGgb239-80|K3o&Cz0nB-`Ld?%UxtcI>PrfEmY~3)tQ&;uU$~Q^Nbr$o ziRIH-p{Vz>82;nOMYyc7kJlFln9{x6Bpz0~!h#Ly0O7)&IUG|xan~ncRDTBCgJ+0WBOe4=NWac0~M?-YKH^GB8({Q4 z{O~$Wfmqp%V)e}Dd+*m~=kW89$s!cr7}{c4Y2ip{Z9ZYLkorYvZfnw@VTe)kd!!22 zU=%8Iz5@$nw-ZTlVJsLegJHx2!-GwauD`Nn1SYauDB>edWsqV5tf7<*qisoYP>7F0 zAf|;ggO;eew+!ZJQg!rFfkssv@L*ZGJcVGIZ79 z_2+`KYLn_rLCL7K)DYBfI01!s7qd0BfgmFrEd7`P6^I}KFV^e$Z`Li?H%JL4+8TnH ztP@tfpoCW0<#Ld(wQ){$STWQAoN74Kr6R7Pih0~p!}JMhY5?3sQn(zY6tL06la~yUXCO9&oKh}%VY=^#V1iau$P{}uu%oz6|zKOGerD6ow z;c7-cnLrGL5HYB8z|x-!wgJ1Al2Y_IjW(^2fvnLo2{Khi3E-wsu(=6TCM8(YB%D`c zUxXN`p#?&$aeCvn=8O7G>{5^OX(Sr8=A~z{Fr?wKGTP z0SFQSt;R#{&&!+6ToS4w4Cdez25E`;3AX)R}gIn(C7#N zMaDz3n>IqQPZGs~o5ONx1UNy&K-^sXk5s|l!UExrr7B5CXaqO{>wQxyZ$bGAQosZ@ zzjK=fwZ=q!DRR(iKzNVDKE$xZ+cUlyA~c(p%d}j6KB0|vDDAho?_KAL`;A0YtY{B# zP2FeiKl)(eBRvc&ojJB2cQ*7D$tVN(=MkyfGK6Jh*izQRcUpW4O$&TvpIy)tH5EW4 z;^QF+I`t(H^fUne6J@SoX&nryshrV<2quIu`hq2BLWe8RY8^y69RQ?{VnJMm@QI8T z=9i9ul)Y@eW$K(qzK@PUVUwSbcvfx~a0N+Uw4GUre66%}1>C@-Lf9;Gk61b9Fp6w^ z>xHFAN)hUjU4Zv54Khk`2V{@m&9vFJS=2-gdSNWQtB5=zr1YSHDYTDdxQ{d5_Qu~%J{PSOmZ}}=?Hc;w}M8o>x?}Z>Tjf!>IvK3^#cpUG$sZY zLm5 znpPuSO*Z88hpruhV=5@tI1<3VfwC8O`42?CXx9_%-|TS(89d1tFre34rU_bHnH-#? zn?kh)lpfiPuRy|GjGA_VV3;Csq&)x-9eDzo@!!8-L`(14GyG_&osT49?8@6j867|- zbkP>&jXy(n(H%=f5(rpW4Ly7jzpU&(Gyql}N$R|uVx*65?NvmhgOP8aKX)eQN=aK< z0FEGh>$(fn@w@Ck#Y}W`qPmBW51EP+)R};ph^rT+8YNU^+EhV12QUySY2TCph&k2} zFGyO2CZ0hSG-vJtK8c;E3!9{~noRHBI#d|KK@O&#>k0BIG>Q}x1v%{eUHIML=4*DnN1hH|$)?q+k$u)_o49OGRl!obnp4R0W8)UygSDH?@P3bR6D1NDKOfFmGlY8aAkL0MCbh($t) zu0o9?4~jm`Q95PA!%~AXG^0ci+a-$z8HJWx9e;RHiS|XfX~jAv9GJP(3P6k$B87>U zyaFp0Se5WR9g1p_h5;~`L)NQ#Lc`Zk#KhCGMKW(mU|CBj3>`jS$%k(Szmf&QGR@&J zfQMZu`o01&Fw>l=91%u)6DTK?36T{eaqQ{zUUruYFe+6GEpDX<1*`LGSBQ*FP%|{6 z$Zv78lP_5PLu}ZaGIg;?*x|ot`O`R56n-qR`W7HZ+IFFmiow!dJlJ<9D*j$qS!TFk zo1o3XOh2Egjb_-n6jB;?Ggxwf@aJocwJSoPeKBXGK9(WUvjhq+s>Z(+oqiZPkggiy z+jvC+TXDi|1Ez>VMLcP6+cQTPcrm=)-dE_*s48-HhKQ4>omWi$5R@;JYg>VyvY2^M z@ytqdsoWxBSZ|zfMsIg)#g;nujLr|YqJCx1A*kZAbshHN*6>)?z*Bw>UIFF>ky>q< z-}DpxKl`>;{HQ%o)1pZyW)Yq9N;oii%NVUpFvzwBf*}nclSvMZFn_F2$yto2B5d#W zH$@a31^5X<(PM%HOGBW#e+0pRBLvs2$cOC3W5G0KP;nq=z{(mb6tbXYfRwITxilP7 zJO@L5KGl0pfLp1kK@+*C8hlxqnD=hzJd-t=6={7=yGu_DYTw7lh!(ppUw75ZF`ab_z^ z0-30hhSP(ihq~^3;JyKc+OS;x6Gmyufcw>`;Rz87XC;2Zr^>&Jty=x{6efejUQHlJ5w=;LxZnL86qQ*iXogBUMuE91wd?)iAMuAgMXOi?Wi_%M5X3 z1MaMYBsPF6p>ul)EyIJP`m1s*B|R%Zwn~>^K^!Kpn8i*`1c9-x10V!Ytvd06L&cD` zz=9-cFIz>6G{!z+LoXIp8}ts_5R`5z1)|-f`v5ceSht#Yx%_3F>>CnBI_eNlgg| zOuAl&0AvA)MFLPZW@ta5271-u>7G6k3U}kg=dIO6h*E#asr%v{hnt`sSe|W$(wkaD z9TFxL_XopPrRrq zX+Jr=gyYrCVBKjKF&T}#la`FdtyombN@>r>HvJWXtq6YwQ5DHm;s3Ro+2GKQ#)XMP zo{%$<{3dY|RHrT@I>>>|1tV0&c8S0C0c-GM(y6nsO*3 z7z_Q<%YGff1$Gp$XvCn=yX zzM90l4BAyegOcnzVqP$eg8NJW1qx-<3MXVgFf6XD`Lk1ctVoF;{sZ1%a>}(GP zqYit+c&*(uAVL6HVfefqr&6P4(hRu0&7rk|<<+WN4pxN%gPU7Eg3k1v_nLZ;z?bb2 z0y}hZtvM>lV(#1>au8;gQ?)#V0lgrk zY5kv&7>+&i<>7atb^<3#R@J41qHx;i_ZnV3Q<_0OCswl_3yft+V?aDdf$%P39SI{4 zL<2VhH-VJH#cMJhX^|w$hZ&NJesLw4^X4dN;-pG~Z_XZ`&#biOG`@ z0Ia_Rr0-S~mAH=JqB5UUXrqX+NI(hH;9@J$L!AP*8LLF4G#KuMvh8n?)OYWw+YX3r zSYi|zj;2PzIJerrDQy$T2SihYVxF0ywE%N_6e>kGJ6(k^jTovX7M^eFmZEQ94FvYH zSk5HrJtxb=S@E>P0<#99)DgAPHN6-E$R@v=dy$$OPtL3dkM?-qByfQuS0{}%Q7xhz zpqPFt=nGp9F^#Ge(qEtP@jOaymo79~=Dns)%1bJ2R z_=ys3c*S)blAVID1-s8QT+gMK8T=NfX%Pc+`V8TM1L^B7WaA*Vfu1(GQhDQjVxWgM-YmG@j87DU{*9e^$c4nvAKuIZXm*O&dNO`G#K1i$50z-%r9&N zV5og)qo>&&!H~vQ;7s`~V=562*x#rnp%D$%W8uh*HEqgA(5!|c)*^#SQ$(?BX45M6 zG9P%HmQg1{#hcW!2xQVr09VG8k<<1_uJ83ewE-xx|aTu)#Eoe>_Eawma|vH-j} z^gYsocT^Ax0h2@qf6IJf2mbURbU)IIDnCMlr2=6>*&Pkaj$+Lxl|&LLOJVk~hX7IL zaW|7ssQ};-R|422!4>)pS)PzTZak6qkktV6H~uoGvXW$oL6QayKjy;j#wrWhE;Rr= zCO9rgGU$(HdJmJ#=4cj-dPzokdhSIwgf=dRO|>L`>`SgYuo>cA+e9`z>iWKE@szKl@8`Y?W0;S9-9<#Tpn&7Ta>Q^azQ9q-8fNqXzMpnxLRlJsw^cFC1nAdkP@7Wz zeltW}84=}}Nah4`P-1pGDR*aWgi}caemi;Q%c4{)iTYzz1G6a(a604|tnr?vF|tvH zV#9g^Hascj6ddd^gKy;ui42rZ{`%q_VdPLqsBGLi#9 z^ajyps0hYop8|4~|FLQ0$uNE!w4}cclIrOoF)hl50ND-DdjpNuh=9WbCg%o@4($zT5C@ncyk+7PmmuOGF{~7h#Z24q%ynpLkjpaoT{A2l7I99x^nru{ zDS$=U#5MdCMkPrE(taQ$jiv@u0yY)e%eE0yO7_E=CDAJlaWGC&JQn==olrY0O1q=l z^d{Y~^$VsJ8ToG!C*9${j?s%UT!tW(s9&y(63Ej~agMBtTIM~Sg`-xb3hb`0!rzUg zpC!hLTHXa>7%!fhOcV9&`R^i38UAqFuf!E;RxbLFoB;19(xiFa{Ey`3c)_O*96<+UT{HpJczpnflSj< zl(JEv{JXxOQ0lt~AYPS8#`(C}V@ENQ1=;N!Fnm=!hx<8Y01#Q`Qw~ zy`|3vpvP)_r>nBgg!!h43j016f(?wG9O!IYZXZ%Yf$D@nwbVdKb0B#$Sy1u2PS^2l zsGQ!0SY3&o;As}i%UTRSB7Bmo9wy2;Yk1hB?4c+!zHKjI=Q}w`Etqg6vLn$Un8v4r zDVX{xlmu+RdL~L%2*(gdERF}1Y%-q=zC#x4u`-cdQ5Pegu>vL@ju)YTVk`>6xabLB z2Ihn3VOzAoig9uAP<9j23WE;CZlMHn01mD&KA;DZMJ~wdqYuzqn&v2LPh?ow8BP%z z#URSorMF54n3;KDZNtZXO|Oz^t2eV3W_F;+g#Yqw z5L^aZMAag+g$BI5BjSRj{cevcEQIiJv4SNU9k3CpO(4w{AR!Qg5Oypk^gjNUK*3+E ztr)D~5J;?<-*9tX?qkyqXW1KRo#Dn-u+}n*A1HSYa)5tH zm#e`=h9J5|2!tTO;&nz+!yO5e>p4Cqd)Mq);HFd)*5V<9%%mZ{u#rpL$&T}^YsX~S zwMlbvK9Z{Xo~HPyu^9`~0^|zxz62g7r?e@-S36a)t2RP3uQ@mT!~B%ry!`h?Q1jPMS%vbmdk$SYLWL$XK2gIO@kPx9Uh?azU_V`3O# zMZuyiFf-Bh7E0ILq?3eyVzS|gGNHL|Icn){l7!j-gh22Xkdp`@deyu+p)mN+(Sr7w z`6t@%fk+|F+8#u1AR~#1ZFWg?BV>~r=6WjE8#VS&it7Lb?X-0bi=cx|zagzD0QqLJ z0a%ZvM9qE|t=Ei;4w{9IJ6#wv=*B2AD{RdV4&`!Ua%Deh^`h*;V`TKMjFU0UQuz*D z1ECK(vCPnJ1B4F)ZUAQ69}OV(Z6cCZLmOAI+MsNI6Uj-@0wW@BSqO*Z8DTJrD|jr& ziMfCtuV6fiPV&K79H5jfkcqo>*1~RB>ZB*K=-GizQ*zr;OgA;bE*WQ9JQ{OCB4w?S zZ4NB>rXb+6e$`fmWXsXes+G{f$bH&bKtql|01EC0;RUtYeL~5zrXgB1Kx3+!Nno}= zcHa}^wp3EH5;FkWo@ zcAj}v?-8=D1QEJ;Gz5LKDEKfqo(JeIduy@btFF@5FknRh=t-gbFH`*-bPWwOCB__a z?1tFfffA2uaXqvj4!fO?i(Tg=WwX{Fn3PB-ZookYx~(a27}Q_`j7Po`+6W=P#s76l z&YhGEQzA}XYf*{<`Ved$j~OZ(#*pv2A?0nM5|aqPU1vlvw0VL_?vGfHyyH#kX?@sX z)u{pS@+G;B$gy)0OA9p;AiR=-ViCEIAU29lJ@|Ym;mM+A8Ryq`#9|chMC>|n7{$xG z1LX~heI^99CagnEOHs)H<)s1+{mDr4;2X&ps#G$9WfoM( zU>)@5yo8nQM=afXJFjz*g zdBX4oiGIdN!7l0_Yy}3esI>_Ok|RPcx`M5+Py8u_p~Q_ynw@y7h`u@cZ{l~C1axka zx;;LwVjgo1e-3Tr(Mt$RmJ_k6NvNZh@$CAVC<2==KF*U1Rh$*e14nr~7$FiiehAs> z43I_554=FRe1+!VEO{85M8`WCw;98UlLT@2t;nweOxKUY3@E7jV44<^5x3)%rj8(o zs*cgmA_e%a9YpPEDai6d_jNG|09RG(P&pYPBnO7uHW#&7WwwX7We8=Bv{_y-$S4BD zxR$uU8ztk!STa+tSHAjotcJZwa!HWw8dh*9^bT>?Qu_Fz3cn0j<47=C@GG1ftUl+W zZiVFgMN#y2#hh#54Hw12%^k5GMN`D08GK|omAfIUdT9VbJZxM@sEZO~ZxM`{R{ntB zh+zgLe0>y)nU1{}4L2lAI#!9eMfi}JsaHrtRzM=;CmggD|2zUD!}3D!ly|7O&nnZD zhDdy+MdgV=d1BNl4~JyMn$&-kjl;s1g}4ypMP#{obg3;ug9>pfIwtQQ>oRFRoWCOC z=L{7PRh=(l>P6p4x(qe;npEau5ro<2nj&v7 zGhv2406+Ypa1GD{86{I=4+@T-#ghZ>wvyZAIvo?5TsvL#6w4BW`|WrGi>Qx zOaz#{>?2ANA#TGtEKsdU5|}sOBkehRV<1X6l+ya2UjS>ZK#Rz8%m6--4&+Z&1~!DO z?+tKEQ8*OIJ~42-W8s2aza4~XDQ#(UM;;0d{78dH=)o>f5Z_6Mj#}XWsR2OEK0VU!jZj!lS-mHT<6lY?Vk;Z@K|oG|*CkdX3DKZ5e>g zJTdBxJVn}Y!)q6YqjK^JEqV!FkI|uAU`8c$#*&w__!K7E5||B7UHJ_jNj$jnZEvfl zkuF(r1mz{;w!_mYd8I`~Y|#hUm<4d^#QypM&{#|8mv>H)rhybKBC5<* zU0n_B8(l zwvJ(msRvs!Nf~hnB(JDAP8zYUDiBE6M6{eE@?1Zd#Gae~fIMrw0;(Vcqov}sA6pn+ ziz}U2q;r@`@5Yo&^LD5q$?v%*AfvS!rovdHQ6*$L0gA?E0Vj19N#f!rWg`h;5|II1 zu{v)+2sE)QheH)(=%HCaJ$#;u5v*x-u17@pXj5TwwFbymcwLin23Sm1YAeM-go{)= zA%o?N;%=CFzQWlWs)K3<0+f%JYs@R99Y)1(5s6VO>XGEZ_e(|~G`z(={@U50=klgR zvmS=%*cish%%FZVx8S9-;ca>Kz)k9_iU?5w#At5)6@q4QN1oFGk3p4B3r37m!6FqU zGLZ|MgiE4qpfHA1Ae|%@jLM@8I|YkTxl?G>2$0ofR0XihRD}i@(6=bl zs}?1(Y&RQ#Op_Cth$U6w$8aXjpddUTbP5H}eM4e_hM8FdFc0f7%rSIUe*#DhvsgK2 z%{Zo9g5nA;77%=8pmN>{HfTDSU#P@u0zBT-nj(nH{I>#DyqW`h zp-v;P@lrqlg$A6M5SKNo86U|YNA~ZMRv9ZB^xKkc*dshS0AZ{b!qfSG<>1FV%fcUG z#f5KdV+{Uh`=Z6jWebr0ll@3+lc;kD&?FGTjaWPpQ-XG@)V=^b^p{*Jd1J$);vN`s z%#f=)B`OwCiynmZS^*dg=D}P4qN$5x<^kCv&&Ah6icIo8^vbT$;Rs!WskrQ1eA zlP9KN&~^YTs}aY#hJdg4o5&Bu2n`>51?S2Y8IqK=HE|o+f^mq3P6`!D#=^Y>28~M7z|DtU!$?{S1zr)5z6nTUBH5!Ron!b#3@-|T~F$sCJHJQyf!gALiZI<>uvd6dtid>+ zMmhZ9QzKFnF<4KXRUhzeE9~L1#*OWzXlpa;dzIZ}ExQhvPOO=ob0!2D8AU5ZO%J|M zTE%5vfN<3Y2i3gJE6OVfIzOOTP*GL5(@R>6P8xK2?GS__+iC#*BFse^6_{6}aD|p( z`i5+$DVppJR9}Qs38SBw3J-N_r8s7jYgt&!@<0$TELZM_ zafTuV!S_kqvg8B2id#6#3;f@Y-$rp&3^cgLzcFaz3Le=2+4_^7`zcH$puGHxF{GAM zwFfs~1k@U^xQMf892+XIg@Kr@*Rtu5ik5V*C&?~~md{`mrv>sqAZT#EyRAW{g^lcf z22&6L_YRiBM12_n4w%IkBQcea$gR*{qy$8;ti}jhoMxAVo;!>{3Rx=puwKZ}Z-lG_ z8CXM{zfK_S)(VBrJTYRlM+ziZ{1JytGZ%~MP^~S@-d<*2t{WM}t+*2daAX8PNK}Mz zqG~U_Zd|OH+Jv7f1(+%1v?;rz3JrKgCS^d+i@p>e(NKd6+Y>tg!@WtIa+(H9^pp}9 zd1AD%r~NRwzyFaiXoPZP))+PsPS#24gnFA=q#XQiw%WeFh8XY z!io?)({%jGWD{WzT)`nv)0h^{w7q_ZtM}NNEqD<2El=gWU9=ol&H&l2$cq|1v`1*^ zhCDa5`I|^ICBle4cihXR*-!?UTjF#Bv5FMwE1V;VKaRsRfHfpMI4H-1y$E4(;fAWu zNZ9I`w5H4pYFN5K4%U;(F92)GtiN%jMv-Tj)Fgb$6e3_|5s6Kfjss{#O^TZIymPQD zKC$+bD}eC+{^r~agbL`=GZEPe2{1b}D)Uh(Z1Fn56;PJ@-jx7NPn`iU-$g`{<3=4?bmc#aD(H?Pit9{CIjhzK z&TqLE-+)d$_8VCmN>T?g)wQU>m0N1?}`fu1^hJuB02r3YXzhYjRG$|rdcM&Pu)AF4%hX7+>C4{8VfI+UF6=#y<#z?@3 zJ)q<2mz<>3$hoEDaKTo)3DICbR`g>)rt$v6+xqdX?l4W zEJHjE_U?$CZWW%Ta_oYb^20*YVX7XS%e;3(nL&PO8%Tkjpb#REpaCzDEtM@5xfqC7 zCN^}16Z#m%S(0i3dW7XDa*U9`XB{CoOiH9$4u4lPg&2%IKUwG~yVpd#Mopa# zHKwwiqaS#RfjNaMB1$P1*=AzB^3`|Ma9_b?qeKNzD66EAN&RJ&1`AA8Lni?28bS-w zM6>F|c)+oCjnFRr_`aw29V5`Lpi#~OEC4HJR?jK_#1brP>{~&C2_bia`7(_LVBSf| z?NO6m0U3C2j2S<=hgmy2O#SKu8-pwrI=rkKKP`nE`J{$2{8P{pN=EuBpPTNIu2NGK zT|cK+UQS&}@v776s;w2M)L? zlW(b9j)DRFDKMb04it+O3_#*TINff+Y{xrR_SVXXhmT|F9#VX@tS?5AW-CZ}N`hrU z{!mp5H@Gnz)}Ai8QY~y>SEhg{9?{`*ZNaFr3^+>f0&MmZPJ01_T(w*?_8)UhMKrVN z^++#1gxN-P;wT_V>biv2svybM2 zdkV&26pYTc?9UnWUX&#hc9S69l&B&^E|!4EmM<|x+!`iKBp2yiPK+xi$>AlcdZP?( zg?NZE1e!>Yr*}Hrc`X91a(k>B0%GQJ#}S@cUV^F?hVr&R}OTh-+_sypFDR^5A=7{RE7uH6$)u#}Aq#L+KR>jNRD zCje#&uON44!;O*aT_2Jlq7ZOva&v7#~%jKcL4 zp&Gv!NChl-Poiw!YSJ>(#uL;I0BDn1I6`O$iTc<}t1Z@UxR?Eh>hLb2+(tp4q3i7o zBe_T6441&M0rHM8WaDIrza#;qiBD zouh3Au#iGH<}yqyhv-Fx`YfALQmN4rR@ou|Y!Ihh_C)9e0+E5`I5}ynoR6h*$L!VPB(&U&-j%2-{ zP&7cJ)ux?b#XDLw8rOXCh7glF!bJ!pWbyVu>k?)?a9$(246T*mL?lFxQ-McmON4o; zVYY8R8#WOH6=JwgqFQM#0&BC-N_4=77Bk&ht>c%l>^92B;XJ{FkKmv~K^0sk3r4>l zcu6!aHbMpn;#n@_7G|w*76M1~0Du39F;6{kBF6lyOAmxTq%zRUo5pmc!s@~D=vNE@Ia+)x8>f4?J;3VGlC{9Lu*&iT>|T= zTKXs?n0^axEH%n=L705-wKK?FH{cF{DbGk>ol%n0CW)kBX15@t=M8}!mU7V!gRmRN z)=Yr}<_a1`zbOo}JbOlFh-%47D7el;WDd`RxOGE0Qo$5xwh@6Ca^y@h5eb8>HyBo& zbi#1sF`^nuBAfO3_{Lr_RTqRz(0yXA33~o?ri18DmO}eakAP}6=4^`uo0{seVPyQA zCdWy46QV{C3BGcgw3VE!RWm{z62hm>i;Ht-O#}|e`FYThf8fjB zZBXcm@1~J7a6?rEiu)+FF(D!j5afu*VIE|AZN3C^>&G%CR5HYQ7tKXVAPzUW9LVKj zTgYU$YuMJ1-lVdY(DB%lY(Nu0jA%xM>6pFvIHmanL6!8zXfRYY2nHtRAiq%GV7Lhm z%Rv{xs_I*T%yt27j#{y0#T#n{z;3t^fb}_V{Y`rmDW}nEvie!ATqUI)#sx#VR>RCN zNa#M)iqWe3KGrD zhDlaidT@}G4dc4CO)r{jhA-H8FCF2PLW1-OcP}WoU^m$>81zu>5U^MP{!um1BCxdu z4HiYj@skQ8=aj&>TI%lxR`RqI4wq{in}@2n!zCI;L2+0$nH{}xg9Wa_Ss=<3bHBsN ztU}Tp&{@K@Prx<N)MM zM3bN+l^pOI!OeLJxxA`a4ty*n*DCIa8^L(-@Eh#Ux~VYnns^HSt{B2@{xIe1YOi()Un} zVv*PnXc-=1Vt|dXQ1FRftzZN4b5t{i3SX5b&;~5B(NuXirt1+$yQcyo3K|=*kY;7X zoO_zJ4j>InVA#c@Smq5Ag}q+xb;~2NkT2UyTOQjwfx(v#6H(jxABg?shU69&F;jGN zfVrj$@GPEVotOlHMk6v>r$!p|O&CvFbW%l)*yA`>iF6lPo)R(>+?Gi6gpS&w9|#;v zw9TY-;R^?YINu3u)wFzb&9q7TX5rUsPScweFq$#gL zuq;t0lJ3s6Sv0yMoR2m#4Qp-zx6vC^^?SNaQ`6`)v%Hl-sJpTuV2tQ8gd6&(P@Us* z>phsY=9VQZ6@7I)_O^M!K@3G9%VCW$!OK+33o(4qD>!b50+0`YEtKk=NEPOZylP~S z^kV9v@zrRGa>zN`Z+g@iPEkI{W*B;d8;!$?hSfqdQV_BP8Xh%J$kl2};yV>Zyi*=t zYJUS`nXYBYErppw2TEL4Jb!YwUu_~EVGd9@fJ>ez(h`Nl8G8^3CcWmB5N(HYoaho5 zq*40X8UrBrZaf@F#D&1APb_VQYHL}sx(Z8eOW}FcjDvp+3Jl}1CzL{gK&Pi1OnlU7 zRa9EX%{)B%(gwr+B+PPt#?CGg@>y_jm=T?mo1SECnS zu!!{BOa308wQ_K5GW5Vg1#U)`5s<=r8n1rd^S6<*G)AUi#2-pBShWUwQWBHv<3Lqc zpy>>BBIF~ChE;z^WmnpC7C1h7U}DBl#~=IE3xMpO*GF}nmi%Z5Iq{1N zSop4jK_VMbLwnrXz@xXCB??eAQx%M4|MEITf(?R$xo(X(h*ElD)ZKO~F(>J1-iG*L z!TRlck8CMumXK7$4MPVh_)N(G5h^zfjImCgI)1&&5kl=_1R1DRZQKyT<0lA6jFAc> zVJ6;Do#mWNw+of_5hO6TU&5jt)&Qa!q78xi8xJ!C5{n2906u4f|I!(8|C6K)!6>5^ zf+`Im%x!WoY6|K`CdblaR|Wqs;|z9NLF$&I z08l^>n`~B+ZCnn4NRpzjoUG1Rq?iVDD2FaDfeB;D>tf9idr>Sqh5)tXLngS@{^ApH zKaoiaIXz}}a#xq*@2w}QJ$PZp2e9M;d7LS*id9@%tCX-t`gGP^XraM|WaSmUTi~P@ zs?~jy37TyRWOunum}&cQ57aA5uv$RCv5O+3u9Il>juMjMC^z6IAlgeTK^FM&$Ox57 zIk(3N1wn6hhQcvEEF)Svw=!Pw`09X0A=Ded*_GV3=AQ=|IS(LxrQ z%u~S07a?Pw{Pjh5Gek)N+i+}}M@CbooGhfk<1;4EmIynhfMA|OH=0bDgVnNO0060` z4GP)Pc-JK?opU2u4j?F{7!yzsOOY<9anLdMZ92mO)Lc_l2<9vCl2(8bWX$KqvD`GY9~wEM7md1e|YGvbGs znshU5iEni9&drb7aK^J7yQ@Uo0{fobviFECS|JLJ#`GiY43a!TEk?o-pYaiXqj}+0 zG7v8*8sdT-Xv6A2w5lDki0&ER#Wi2>*NEkp40Ya;4357({3bBzg@V=I zVw>{BLatV4>8hV2M|mRiEMOc*I- zBN#tI;Tsf2*s5q>u(K5qgt{-%Zd%x%R5>nyTiAzmuW@lgAz35B0HFLKh_DRz;rrbz zOe{GtX$4btvL#v!s<0BOMe{6v%C`N=u4AEqP8c`H#JJ&QLzFK+sGWf2qHiyOp-IYU zb;u}~b}PtC;W4Ya<8+4jhx&u&H0PHOQ6?PWPbzi|*-@tzoEbxd(RFg5`$9mN*)Zo4 zq`}nO8P*#*sX!4m(#z-GxTHwNFd(NG<#lSpF~xAcRGCu^psiS#;*A%qo<14+Lq@tG z2>Qe*`QHxQBwC$s%{E(og;g)o7fqC48VR0Yokl|~?T!;z=X8bO(-R{6ZG%UJ6J1qe z7^*{u5j_k8-3~Xb*#lM-2{<_>Bgc4WVFAftCeNKoPxX{SICEDsP3 z;=NFUidxq3Qnj2xJsFI&hp*VF2O#-#PxrbY`W^(RH{iiHAciiOF9@M?4iA8u%&BoJ?e~rPMK@oW zUAKx>5t9hZnD;7ga5g0D3Au%Y4I+iL-Bs<+m@UARQt~+~4WzygxoJRZ!~j6yj!z>O z-8R7DBOBw?zX&OQCbBggcjOtl2eYLHvec0tn?dbmGE0S?OiM?gN^+eXiZV)y<`$L) zx9%y`SY)uK<2V^Ia4;T=XEx9UP=T7`3~wMu?zTsT+!rv`T@q`K(ze6A++=ewMngd+ z`(@q`Iz!^p+X8phEF!w#AfXLjD2Du-lth{^0Cd*aY7HUYyb0QxATgooH5h|ZE{*n^ z(>)Y@QMfh1&InM0o#H(TWMQDyW>t@)fG~EO;nbLPnWaSdAMM2844Q4?(3!n5U?r`DLND#< zwtm#rm~_`e2^&NeBk;b&#pECBcP0~hTqJ#t1dAykL9^ya@Kifc2h!xcra7Xo={7jRnFeVoB26R|R6^C5O&znY9C^O zU6uNURA{ht3<(Pbz^MwEc92W8jIdMi36+T>ne$wFX!d+RN^e9=h7m?4s+k0W{N50u z6{UR&GfojYmmDlK#kb#vH3m@Ys_sh292#;!&X!7TQn#rMEiN>zKP#_*4;`%2TAgaVB5Ss{U4#-X`cAM}MO4z#+QQ(T- zc%TA4Vu8A#6Ck6riDV@5Rks}Gfo!0rgs>wUXiHX-h20JzeMaLHb(%!(H>e6ouqJLp zjhzQ@>j`J3)I@+_K(9XDp9GHfWf@CC92-atGNK_-J3|>Sn^60J&nl7R*lKO`v|J!Q z-Ql{PA{+(lpVWzgd?wr*VeMX?WlBh8&8f>C;KQ3 zLq60>(=oxy(z33Cs`N;Kna!X=Gw~m~dEsmVB$Kavjv&pL$o0jn04*vZojuvOK{nQY zWiBX-*av5>>5oFgbyE-MN3wkRpbludNq zChOdYoT^GJ+~Q$p0)bQl8FbW4bT6n!*;%P6v+wm$oJh=G6GEpSG;D5(JcyId6GR4@ zS#n>NzbaZ8cxOU~%0KJyRTaeoD;0$Yvy#RVo{FZ;vqcW9P-jMdEKqigE8F%t^BCM^ z7XS$5$3zNrNjCr~VNL>Z);h3iU{j~kU{(`cKRVZvsfsUt<|UYg{YRl1gtY3vVWP{E z1`Sr4%r2^O z^ox8Wp`|8tEiwR;0#(z-M7XE|%gS2Jd_l!fxysWyMHQv3hS(;znvlR(1H+T7F!68< z_^ILrDBlRg_i_lMF6N>Mp{KK-h#dF%3??F7C>Exd$YdnR?Eqdb(h+xP0P+0oNpn91 zbHPZRaB!6~pP_gL&+21fRVKbo-h$|_1dOm&voflPVYs6)InU!t7y~vkqYQBd@Gtas z0q_8@DXjS$5r8U1_)9vaTgD^0?W0iCOBhLohLQs&$v1!i7v=*dp&CnQhbx{VkCW+r zBp_Kp$!+M|jxzw{JiW9qHzndS?vz_LHTcZsNi}@!6IhroWPMx85`7lbM4KfTMre}= z>=Nrrol)vyFeqTDE6ql(j8yKzV0je7%D_#mgjN|JLQ#7uNJK;uC;Ji{*TgHj@j;wS zPNc{RB%kK;t~#y=SYuCC4r5nq-D{5u+g5!qr&iG5oGtDsCLsa^ zBlN6Ah)6`A#wkSQvQ1qPKRqVI3dfTJHE#hQpBQd{H@ZFxFQ{lt{&tEiri^k|0JKW< z+8gWHHGWKF$9}@{*5v_@LxU^gsUzGw8q{140vQZtHkC_9*hM0w^<6;^JgB(aOm;EY z9!1vieTc+yrF9b;1rtoHZ1p`10FXIDwX%hcf;%a33wLQNp+!gZfq-U(AcMs+hK0O6 z&Y<-g=%5Edhu6@+KGtkvECi`kj)C+_NHl|N*h$7XG+@nxNBkr5C}r+%3qUOKU~d#! zOY)c=YlxTG7^nHfIpV$B9B4G9yKv1SX1X09SzC%HObkT1A>@ z1PxI+HXhMzi^M0M5_W->&w#KbPZu{P3UH(J%(WvFbX;0K z!>>>}peA7oT1!=v9?y)pI8q_rru9|X6~d1^)|=Z*gKjd2h$=>kF_Hl=p2Ye~WF?T8 z&x3=+YAYv36z0uI5A`|sjUBzLyUPX&G(=0=7L8ev^e>M4l|kd05IBQAL>e$-GMAj2 z22tB+7h=}X_ZNiTaXXqZS4pE%acq7f=;3si&{At^+{d#$klibTWQE+N@T~jLoE$%m zj84b6B}04NSFUE-35Ur;2#Gz{YaQ2c+hJj#b2NcVR&&^Jvt-tRN`ODu-_JeD$=iK} zV}RTrIF+cmh~eOO80 zx~QO1NII<%dykhzABOIAh?Sm*R9wpLFLJ4Lp|MRPB~5UV5I0fccZ{D^CE#^hG5ZCM zQO_y9;bLve2%AK^l!p}t+Wbo|EsNLOqA$(B(muTr-+LFl$hlV8a04zns7O4E-ZBk$_O|x0n0`hdE+v2VpUEau;c08!mj+{`*?PSu2x7&|1Lp)4nO5k zo>Y2NW_3l#CY&z197)OCu$pXyeL~>Ygeaz@OQHm*@&H1f_D37r{irz51}HX+j3>C^ z+|fE@*>VXV&Mxqbh!NJgEvBrVQGY|_T(u6Lz^GGnN))ly%X3fNTR)w%37p}rchPh! z7!;x8^)#8&_CQgF^Sm0tW-&RNI4=d=2sSo{MsLBeiV_iHIKmDNxTCZI9IFZ-l$`7U zZMP`Zc%^9m2?_)tMvU5&pXmeyLRuq%QF!ZGIopEJ&R8%VPe&jx+;yxQYqt^w2v}JI zNtuphkboZoCg2t zV@2(T9+3$KoxU-#9-tJjBcXb|OG=HZ5yNK-;#j#99gG)ErE5Z~b(JN6gwFB_#&Pz} z)N<=&_EF;%v2eW^L6sWwlNN?uCByWBJ{nQbl}2T5Nrlj<6%0;M4rtP8sNy~t^|ze% zVgTSyw2e=PY>UuZ5sc<+Ny!FH`EXMxr7v%Bz)HfsH%#FZgR)ZFHx68>X1SH-#xx}R zwO6@AdIq6L?}g5r@yt8p5+s^+;>rHdcVz{PK~O3*1ReQ{h_f-Dkp(TOy0 zmf)CO4BCtv`39_#$`PqxkS?rJXwUuJ-RUvrwpdKj&Xp-@pa(NAQ2^Z(D5C6W8p^ye z%4)GG@#*QsCf+tzLxL+6bEasdi?ihq?e83wK_K~0Bpol8Ya^BYreg$NNDftVs)yyP zz$?Z3jx15It1QyK{NX%-fs?ZMhZ;Dt_PI-9tQxS}(enV67U8tq>`;C}1@n+%bd}j- z+T&zwP{T%%g-mtC#}zlNY4&2rAMTl``dJ`3G5SIe?xZ|L=!NKQZSHIPHf{IuOf$1HOU6+B`-w`5m0W_SnmI+9tp91aq7 zIY8l{RHb4j&g1DW!Xy;Rk^1_1(O?0J24YPDNcG2oOh)Q+~LEGOb5Nj1hM;w6zz(A_bR!#(EAt0 zP?Qp{J&;U^#*R&OWF)h6>wZAge(<>>gTVtrnD?oM%0| z=CStD^9>PW;m5IXtcR8k5L?k|@f%dTDdg)X zIA7#(90o1wwHYz_*I?v0peL!=bBjCucBR*WiJXR!n0fA`smlKjAyPzLXu^840S&rW z3096rE4cU~4IoT0lX6vt21FAOahRtiTO?%D#Jnw#98v|+TSz1%q^D3g%GOVOrHHx225qpik_ z&VXc~aclcnu!K>7P(HRU@Nx)1WHk`TfibXplp&}Q+GMAam_Lctx?|<{Dt)x8tTasY z!Azii1h8<@Hj%k=1ih_w1a50l(GS_^LkXcXDLZ?*stC+Mwj;-qT$o6^BkztQIaZP1~X+zQgpOPD>f5eH>1F~LHwY+UWYtoQdUZ<7 zJRN4c5sbOS6YzvYMqlKB>gn~5nb8tI2TIXW457!SskMa%1EC}5aae-kMSu~e9@PV# zQH_=)(I&u@%G(!)CWgv!NKFFv@o?FsJ-R@3FNJ|%?xUJG13KlnU!!O#GED)QnTj4j z`gL#(k}k7UPzQkjR)7El9VUo_&xRy^cCUt{fubIDSb^3S1ppZh(RNwgRY<_j;Ekc1 zlPrkLRYYuKIXH#q8Q>*6jYFH3vtogA<}epCe-*%yd8!rfN}sVbmX?!H`?8c@(`1VwcX(CI8x z0Y)`U}N$|stanEx&z^eDu z4`!bn-9T;IN-jJbNpCe=Ap=M=fnc9#O7Dj|lqT9%`{WDL-=6K_h$ zMsF5~mqjir)Z%Sq8{NXBk;oBhT@m)50AW{5G&Pq(exnf929vs~8;37XT>*%L&mf+;hzn10S_~<$YMag45YV*p-oUHa4(Rw+HpNl!mR@S z*yR8%;Ak_*hn*fdC{=ug-v6xNkk>U;%6NKILUpfS6pv`Kn?)zoTlL6iYZ#)(4akK! z#*OJ`)>aMbDlFu*0%K4V7@>9|3xI($WqAx5=Yb!uMjb1ZxMh_gE>|H9G2gf-#Sv(D z^P~t~giDq-Df>Mjgn7kXrpxk_WTiIoMFlG_U5sS-ts1i~Z;CDj7$p{6;g$EjH=e|f z%~Bb%q2A)5JQ3tNmb9AElqeJsq)kqtjecbBK`Ano`+%k6qE!{ozEW%n+^@ht*K8{k zOnr6KAcYeg)ko0FkuZLX&D6`CdSnF31U{Lt0g2H{qH4$0tkct+cIbL&s5u%%Hns_b zmL~I{wM#>#we1sDo^v(@_?#x}+AB|coc;{&sK8d=(BQbVLYAatI0(v}XpB;#G8jhPepYDdrNDO-sUo z$C{)Uqx*ro17UDl4;(ng*P_t;u+k+*Yym0otBU^rjKz%=na@c2Sp36IG?oPtJL}>? zldev|9tV;ah{2YUYb6BD99ZI}s>y}iAc9=V@MN`<>GC`46(BH4ytIRhBL)_`R-Fb> zirtGUlZZH+7Ky3oo8F~a(R^;^4TM26Au4VobM@EzN+XfVf0*C$PRU#ue4+em#6=L~1 z%0kC%L>S5dERvOx^}&RoUzaEausLXOE+`Qz44Y^5e9E;~-+nB$5Jo2sA>^XcYkHS&Bz5xHVi@Lm#a?`t&oPi-=a^2#!uRk+Jt%Dny9?aP9Z58C1%PWnnx2B z5q;r}B-Ajz&S*goV(fSuhyaaGr%Vax0SmmuBPwaSTSmK92Mt}BYHx-E&7pIzr+zTi zekQdp9aq5)x$$sgeX#*0WyYc*hJw(n2S!OsD8w`8_ z1Q9vbDhd?u&oS#N*+<3dYIIOY@V$s3l>^P;n#1LsR>C-V?=ul9GeZn*lQAS`DN83p zsC$>HU9FfG5R7Pr5KEzqf1MF5>rBX_J+c72e+ASwM=Zgn*7#92ii!tI4wQPX{SE*| zovFW}%a=s7bOX4VqBRur14dezs6+(gJ!L#Jc!UZMrcw$tCMd!7Mw1putEm1|A>ipU zzz;Hmhzg(rbrhXmZpFOz1_rGwox$407TAxPl1ZR#k?Bx{t24vQqjqRtQE6En5H@7n zAcau0uIW~@pO#M86O#kra##9S7s*0}!gPFy_I+og+evAPoMGdpCh%#Dl3OkHuuF+c zjOw>!1D;n+)Sv~*#-~{e2eTr1kSxUrKdd|(gNl8@Yq&=(bDwfFX?j}bE7#F!6LI8i zDwQ`IYGA`x7A>w~x(|0GNnydNq(Ho;cvpr(wZNXJ1BD^NV2F>R5KTN@5MoPD@HYSe z000000A?)#0000000RI35C8xG07#{ydCW;B-vy-WLLCB%*G5lLLq$^n2mk;800000 z0s{d900000000030000000000000000PsH$CjbBd0001F00000000000000000009 z8vp2XHMdB`K+t$SR~LC8>VjbCL*=l`<-XY@RfXmb8h4mQ=Dw zX^>RE?>UvdC9;KNgc729`~mm%y7!)Y&-uLdk0(0*Y#WMwV)xO2ukLVXmInNOGGAO* zdt35M2Q=|Jlsl8?oSX8POFq8 zxX!~nX}93SllSC3?SycHO+>S_F42D4ZU{Dy!?I34T(mG-=pKNqZ!?n8a&*~ZU;?LP z?7{*5X&AM>Lm0Rr7TgXTXP4^(`R&C!_;mhV+N5w$+9S6Y+4PmdiZ539GEc55W#oM! z$n%fTq!J;zZ#ynDZB6Co#)Kc$8cufZXy4% z28L}96dYVl$a}0l?)HC1iQZ4?Z-X)KN;E*f4R>JMlbyKOY#g{0{(_g*w$kjfvGi!- z5cb_8Qoo%E(0<8?-BNI}z7QvN^v4;y@?c5%J$OFE3p$4{NsDz z2lFQH#UaygP>0VI8aYl!Y|j$FMXQo*r<>7-7-bmH`-m{s(4a!jES!7-jthBT<>?x~ zlK!^OfCuya9p}Sxtg~=H4MPQSmTd%&i!PJcuDlNTF^-(75;!R3u(;HFCp{<&q^Mv+ z@zjwjIAX7hBh+sTFKiTruBc2BP7I<$Z+kHOQL0M#mct94luEa4mWA)y5{br$2aw%a zBbE)-5w4XV5wi3X`M38qbf{|+Y4LKW;_6KCjByW&k^Mmv9GI%l^>QjZ_)NSMa0KT( z`Yy2>kWCu4+r)|i-Kq?#%em3ZlUL-apn^sNDksKZw_`&=PwAnk=<`qnV;Sz&vx>al z59jRJkuY%meL*4Osc)u+&wuFBb)k6}`C0j_&@0p`MRp`VQoU0QKc%y?A52g+*c{O=IVo~Z`eb|xID z{7b~MDU{{5@3P|veN*4vm=3x}{`wYsj z*u|@oO~7N8BK1u77A8;7gTL|u>o)iac_o#i|E>_6J1&BY9AdZ}19+6RGB?CTf=PER z+;Luomib2tW{wHMwXihUCbLV>oqH8s-zq6w&gK!0Dq729@vN!xPG3 z&Y3-sRGA>2^>Bs@JAR8>tBVEYvs=i#u8lIkDpt*Huf#o}s@&OW2gf$$!QPvTX@>f9 zY~GU0&zyZRt8%Br=~e(}cSVaUzN2U^XTb%X*%VPKL)jZHlGOx1sMA_W-Swsj z6J#pU?^9p?-5}?bv3nZZ_KbwQrc5?7uVSg?PWDz`&v#B=5pCzJ#v=>WXnA`n*r&u{ zT-F-;oZ(6OrQ6_4!c6e7lEL5>3rHy13jH=0f^FJvcqLy#gXdVoga1^8ktWs@v2ciZ zDa(VtYb6M^T}!CLJ)S!Hy%&eoE}^|!3q+?j14>dJguc<;F>S6Y@PBf=?A8UE;WG_d z?aWZ6!v(folmWZpseI~FgLM4xS*++EOS9klk=n*FG_)Z@Flfya1Aj$}A-9`goaQo~ z_$`DL^!ABLE3eXpP2KRdgQ-<)uxLSeYA1 z(!Vp%%)wdUU!kJzbE#N6`y87GR0+jDtg+C=1tTB+5!=`1^7Kzr(e%hg$&UNy==x7( z_R&tn(Q_Y(nnwfqZj}~U?;0ejh!#M}CS6Q!PNY?FIpF-XiQgJAnr6CS!`l8>YFk7h zhH*3UEr5?$rti!E+j^OQv5LVVH5}kL)!>SQ7;-5E*s^kt_AT{Uz zuVqUQun8qP&qi08bTGTHr;9y{kj|A zxY4U&fM|sBUVX^YAO}`V`c6CB=3!%b7|oGRromM?bSXFm=AIuwZwzjt_O@txd#I3> z`Lv5=a;oG%)&}oSX@PDDCYXJ?Hw1Ks3b&+jbh&yjn>_@~6uY6Yu}oB*TtL2C9|^s4 zwcz%f_f+zmXn)i}@p)lysl~P&k<$0Aj^yCwo_W3_LxBlNAKUK5a z-Km_{eFd#LE{AmfL)nB&@gng@O5K<%60eQ{$*#uUoD%@jk_#; z(Rqa-Exy}%* zSIwmi15++;y;ynjQ=ItL_Z%Gx7$6$-tr6zDsSy+;dnhL)lhaQWislCsAd$Fwk+i4y}89U^n}bjl)^E zkR67jwX-3{%}}aU;V147u!0C*6@EQ2MGXBM1O0|2NiJ1yAfF{__`y014;@_2kf$rX z{?LmG{M51H_eL62TSe=CCepaR^02$FJWg7-o&1vblZ?L>UG$0rtBLhg-7*jEZ@dh0 z#}>f72{T}z%4_lG#4X@l_L`<1Os7AZp;&djFTM}{ByR5N%dbk8h?n_>+)dw$$E5pF z`BMxgc}>TGb9R$ubsFi6+bOMxa^XVXWOB6D8LTeCa#^?7cOhD6mkXto{b-Qa0em@#8tGSd%q&jg%I+ zwZmtBOCiELS$v=(kLP1eaF>c7cy*i4-=}X94lAt2T{#;-SC@smlOK?#wjNF#T0vi) z?4XXeQ|uZrjB9Scrv+?*8uKF2V?sZ;dpQ&*#6^oAvRuVhA9Z?frp?KYIsfu;8+Z+0 zB7D9wh0_fbIl!+FjOLV6vByJU&(ghI@ai3^W#mG1=3F{-CZEEquS)+LunIGrV)?3N zZwhEB!Zmt|*sww${~o_X%WHm6RAVl6b6>$So3_!I3FXp+^T`lzw}M}5M8oX8r|6rr z9zGql4Gh&11+xbqz*)9NS~$9n3}>&Sa~&oid{DuNUN@v=&2gfpO+H8hcfx!ZAAC}G zLEN3uQ@YJ)B(3tl23w+KAY3$O%hew%JayA)$lUj^&1f zVZaIg5pe556d0QBB=Zwe9`9cRWyNJe;rUzOUD^X0mOPd$KjVvKl2JS$Z!k)--ovx2 zyM;-n7fBxenW29K?R5Fv5iti%nzV403WS6p?;&TwM z$Y3wcc;Ft!Y%*4k|1<4?TQ!Q1{zXk#Blm`%Kb#FcYr^ou{8-Gf=*~q8w7FND3Qo+C z!)XI;c|cA!y4`ufcK7#i-_u?^M{X)+KXt>!?^3D6xG!3K&!!9|FFY|Nm4E-T=e%S? zHt)S1k7Xo+$>fK$q-hS=z04586%$$VU@z1g#WAP$#4+tRVb<^;kgzx$3f$*#-MPD< z)~3y&8R>lBekhhqS_rNRci`xp5qxBz3<@2ZIKs!1B9;80y>kvHU2TNMjaH0FLuJ}{au9GW5lglN?aTr#M`w}aoG8X@IK&+=&ZMaQ%(j@i)s=| zzK^Bbms=aloUBkB~Zs0S&!>O_BHEgY(3AZL2(1P)i=<`RO6@tg0*5?VBUfL*} zH=M|21627~mm!|ksg?R03n_FUF z_8U>>R$uh*oz8;C3eX#5Pg>eb&~ogf%7g{VY`dfnu9`gof7fIo&)r3ag{^|ch}mrZ z#6;peXdutHsKYH?(eQeyh8X8;j!h>rKzaEfg!-qVk@5?A_}_9eJ~xT;#Ou^!o%z>$mKxBXS_uD*?q$iAlZ)4HfR^ADV^%!6?|CZq2TT`ItG^mnyH)9~NIiLPk= zeIkYyTfY$1ZSPV-k6iK+9m)2|L!7bbB}lgTvh0&x{PX)M(8w8ubuo&3-C!=K{2eO} zSz1c}&AUhWRy(nu%q1bgG+azuHJ*EW%Hr5}gE9VhA+38do)_PUgX;Tl*iqtu{>my` z^C=9wuR2RZ`fUaOCQDSAaR?3V`r(bzRFu~n&bh0~!M5*W&g-elYi$L-zgv;E`t9H< z7h_y_A)Ph*tVBs2>jiiLT z^U(fP5~K@AmzC^z$xk;N@bUp{9lc(#j@^fgt|dcRtQ6M7TWZ?;Zd>bdN)^UNZF6iI?TO7?i7|2f_4igmi7m22xpTN8EEcgU=`?uye zr6**N^T6w3>yIo7ldhtO>d9zvTpc6J_o3I-iQF;Bi03&^V%2`J5F3(AExz*HX7vM{ zHqPQ_OSfiM2pje#{upr~f3^gQqD_`nyWg5NxIMA$K_wJs5yZTxXmYpdu_C~_9NU-{{fB9{ptIe zdFYqcjr_L9lGf`fsBkrewXQnBy4(r$INK5rNp67VLnBVzatusfH_@Bcd`=E9#I^M| z!P(*~nEcBC7T0!&!Ltmpebx=|-1-tHTQA0ws+~fomM>$$Zjifq5fYOHZYT-iiP9Rf zbIj%o?!mM$B?{#~j>gF^_tK<*RvHoFg^lU0V7#n?#s!_^+!7tUP*z24mcDp3;4v*v z*-HtA4Pcx3oL*auN3Z4^+~@CC@M_&5u~b+HIVoeg&ueQs{CfjFC^`p%+)csr{TOyQ zbPOL6aPMfyBc;F~8x;An^hcev=W+MpO3W1I}{d=_AR*T1)5xLt7aQsLQmZ;N`} zwo-fcPDb{AacflWhTh`k|y+VBff3^L&3i&}V|6op0pQ*o`+N06W4 z1|t_G5N-S@bB^Ax@KO{+F9sXs%;H)UYf-CTBaH{iANx@h7Achu9i#gCt5VdB`k zQ1RD{>OM4cR#JCRmGyw^VK(UJqRnnUvtjt$6?il8D10iB;|C*Vpo)h&cr1y+4=RH> zI;?|Sde+nESEEV&`DysD;1WfTG#A(X^VfGuW&Fq0o)vSLhT1NIul5d-H8b9ldD~xzHr>xXA9(S-D{&mLej$2JOcpyvPsb0H z9#GUW8s(N=f>Ud?`SbHK3T(GW)9WkYww41v?a_l=CY_M1y15LVeA~sf*+!7&mCyII z^+XTrUSnT~q)0uGk2@oO<)vdV5~^GKD9`zoYrLrt+h% ziI7ub27i`~$AXv;bQ>&{9FP_1+MfX!<^Pa|%sPtpdk4Vj?f}!bPvr|1y*YVLia30p zI@_!&z=cj@XvaXQ;I(%uFIcWBx*qBeZ?zZl>2)We&xzyGMLW$=-u(tfdKbdgMXAEB zZd*C!n?FgO2HE?;=SQ%;rKfc_A#4{bxO>n~#>o1~d%|g%|KZ%;x#q&+8VZ3C9A9()#KzzGa>bv6{ zFI#VbWjBY@=a|WuzH}N_O?)PtIcqsgcc=R4jArDwJ?*YSPSN?lc!hj z_X)j^Yhmx^S5P)O7B}9zL67BoF!obm$-zgU7*s3tSGM3N4q_@>DH!t)Uu!1_)d<7vxjhnR^XxmvC9&=?d zt^aVscBfSz8rdy0((BVfw#J!!Df{LVUy)#S`^^P zb|=#uYcGdzu~rL>I9n(*Jc`7P;hmJB(Gz!!dr1TDorfc0H;TW~pI23_7m6+A*&-)` z6wL$pUSt*3-I^$Ziz1%NekG=ES@0^y1y+A(_2^m})_(+Q?$f~MQ_u6CMN$|wJ_36uJ`l=GMzeeez)PEbD46TQ&l~S) z$kYoU-cUrVHIBSbX&FRMMOyEC3$%2k6m#5$tk%B($B?7AY}O8{PfEp`FUC+>d^BCG zb>+s#Q&>EH71S^J(Uu-soYcFgFlT6-1ULHwHirwZe)fVUGh=wxPnE{6n?s8SX0YA2 z5I8Jj?)0JOa$IrxFn#TlCrYgrf_2Ii+Ij5~U%GCGb$8zj=eN%kwv}d)?}t`$J)r@E z<_2(Ft})(A7zVq4gwf1i*YL~bW!Nzx8>+sCvTEiPT4Pc|EgfCrtP@?-^45^|mo&i1 zIZ8Ze+Y^`~tt00@HzCfj1}uJeiEn$21Ls|_B%Z4m=0)Ac+lIGcv-<+Us`EZohhC&B zf$zm>i`Mem*mSOvhVlA?>RkRs9Xl^wkj_7AgygjkhW&BH12)z|`s4w)p?o<%dg;i< zF+kbVhG1%j3JSw+k<#sE!R=g1g{Ep1S%mfA^~rmEV%3d#JlWzTTrIDpE6SeO7JrR`ZGAZOgBwNE?}sPlokF*MSFtj2BIV4t zN5g;KTKm12suy=-og{lc*;T`5T4wR{VfAE!>8M(J9@I2z;efgdZW(`A)ZLy>xyiEd zr*#YlzeK@gbuf*Hixzi#>Z0RK6P7vuijptBpey?ipw5Axuv|eNzN^G=;ihu2__3FizN2yO(13k@HPT7+_gTbGVf|u_v>Y2QXeAc<+o7=D8 zly85~jw_;N)^lmo{Y&KaYdv}T+l!lvPJ>zRb)0``IA(o7%rT8ZbIW|n3w$qqp41QO zRer`Qx#9!Y?YDbRBw?=VMg!YRvUF;#bF?QP!3Q(Wme))%|qgp5^^{fX-t4 z?J5%q*s;RH4{4xR9|Hjm{jj0h1t$&vi_u$Vh!KTz zxOmxE(r|Ib+GbCrZh<_@P@n&{L<`$%;!&m5fv@NH=4+P+@SyyILf`eqV)kq@M!>Ypb$F7*2HCgiZ zzf#ikBRk8o+IyCDZGz6>7?^I?N+Z+`t<8CTpJ!VXOeRo@MbP`>(+u!HyDU6=I~dvplK zu9$?oXZz7D$GQ9})R`4u=cBHhzF^(^g>dz}3%`iDM4<}}QM@vPZMH$o%MDfqFP$X7lV}Wz=xOOpK)gBThtp!P6Z!ryDJ=2&E%wERT$PS0(_3@ ziq{k)`EGxSkUusVy`$yn@~3#()>Ol35L|F6kNxifxm@ggARLEoA%mdTZToNrW z!!g5Va*$+_Q`uNN1*!0&K?b*$r63&nNDU#ENK)E^PshvR%TH5W05u zfRiSTWTUOhVS3@v7^{NY738_*bT47g0e#G9ttR&|L&T=iY~hxVE^7XpH*q5^`NYpq z@V{&2aMS7NuZ z%@n?51icyD0%w0HfwHa=dN|v1OrNRz{?-}%=r{~V{Q?|he}fwCo5JNAQ(@PZwJiJL z9=7W5Cm~OOafv?M&u;@Xwanv9x|6w4U#rq-?*P2u^8{gzBF@g80R^X`I92+Vg1Wm= zTf`sw`1OLIch>e_uD^&wj*f=$!({P|pCxb4nF5El*V3PBnyfqO65VJn6%qr!P;To) zPWqn2N1sN(tALkq*=RSmZu|}EEk1aD?n8;z{Li9v)hPUU`2sK0*MmncyXdjfMObUr zi`*RN(#GkL_+gMfC-jJ6wO_x5&5au%aEumiKC1~nbvs~Xu_Zq2Q%_qW0&#!MbgVz$ zibF@eBE^^MX!ed{Jo}0tH(j18Hg4)Ay=-2NwQtX3=%)@EZl%j<)rP#|dtcwN+fagEZ>MPX;Q3N8%V zEo@f4OJ6h{Mb)j%pjk1UKldsjzw*&ot0fg>kFVvq`2vSI+yc{Y`luDuPh3;uNLETW zLFGRMezbZvdf(p1gN00}uIkUF7b2i|T#4X5X*a!VT#BJhkErR#C_dtN1zRSVqPN!# zhzxOO7YkX=HVg&NI9(o?XNON65;N=9FUE;Qp5^u3w;mpOv{w=^d$!&LqlJ!=$|B80YX={BARx zo5$Uy@7A5LW>62jGAobTuY9J77Uy8X(kzVLXAU2C&gVC?jLE*&2hs~p1Km*zImp8u zVs{imk z*Y3s|#joI-(Iat0+c8R0iWg@mm-6wo*?grSg$;A|pk7KRJdnRd(HWf}ICX(#T^26X z3&Zr0G5EDLl+RpVDmdR!F$*)){bEwmLzZ#BaGe!XyRV3ZK| zd_85$9fKyPSb9A%lT6CHBNn;y%fZJm^;0K(Jn|9h6({n1k5b3-?Hl2PeJ3TG%kUiU zgS=oJE;_|{*BNq-kA7?*%;pDQH!c!xeM87~yr?v;v%$MKB% z4!Rn805*2!K&xLBZq;|-&h(iazt@8^>^))MQDr>rYs_cw?1zh2>fljvEREffK__nS z6sgn?=SBA=t)CBRS>O;1wYeZ>&0Na|qq|rA*Eok0m#%^TCc0s2NQAf`={0QiNXH^I z3!G%!7mk{{;9avtI8$Dk_J;N2$V)lm(^6ky$I|}%++jAq_>%)QWiPN~i8%&WXu(qT zcT^FAtT@MlFN_P|m&;UzX^%@_knQEb51U;TJ(@5?aTu8~oyP@HEb-X`Q6N+@KvEo)L zrMNr8!bKyXM_4QBUq1>h&N66S7)7GCAx!G8&F|jju-ET2y8355-8*mA3r})~KCols3UEw@5CoDHC-5OGMw^zaT787JrQu=|`nJk$xq)9-G74N?y>|Q-Sa) zzX}^C9TN(wYK7SPBo5FirJTYq;@?HpboTgRXm6h-Y4%LSgIksO!i?RhQ{~2ELK6h> zOEDED81m*`|9WHR67E%?j61db@bwcDKD_d%Xz=Uhw{8-JH*pN<3aOgfAK`Otu$?Wt7xTLfiIVPqO+nRMrkf$kDUWJ z^@|Lfha~c~!@0uw`l0NSeGalE#TeZ293o$7@J3aEH@D}(uUL8P_T7M=zb)sI&ZB&- z|1LbWISu1)c;FkmAJk|4C-K0S^K}2rR|+Tz=fVNKICB2W%5%B%ar~jN)a&>Yq5MRm zu=S4`Mwhxfj@XjLT1pn8dgl`SHgzV-1lU9J`CYVnShX-|??AFD(c&EUlk9A_iJwNc zi`!BOlxF;b(4)Q4-N6MXu6hFIlUGRX{9<5FK@RKL#`E40CqYqfC0<@|P;yCo96$0i z#d+!hIQnuN)s&`@Y*iN>-ZBUR^tZs`hgNWI%05VLE`|;ogmHh);_6|hVDvs2Ha5IH#Zrv z82XdGR41^ik}N8Pw@Veyo(666IH6+cD%dbr8*gUarmCDN+^cC1%eN=elX0W5$g}{w zLJy0N!+uK!=P$&g^P{1(X#)mrE9B$j)ZuuyD1Hhj;qRhHmAQGkVtla<4v=|IZ(L&d zlIC7qcqD^A-06-6a?>FAiVGTS{S2bbLRLHU2vXRGH10c~|HNW88WJk^f}-*iM* z@4qmkX$QSBwS(Uy`(U7(R5EL67+d;nA&V8$V5&+KyfPX}cK^MX*34Ld7r*VoVN=Y6 zK?jv+W#$Cd4)P-dwE}U;=}M}$DiMyT{|9=99>e3d1R?og8N@bB;jAIPRCyp!2<)0A znm&6VwxbsNTu_F?RZp?JE)u-_=7G~ODRFaog?h4qB;9`zXWg7dX|p2e(Y`3G{-P|r z4d?+~yFZa;TQ<3MyW#L(&3yK>u!U#7c^sHK2KLM`=HFd+A@J`bxKutD)@4k<{x#3& z{Az~blTLF*`5qJks^QJJ&+u^G82%c47amNsNA-SBsHJWQw`92UMg4)8;9(`~PY8fI z<6v=X%5AY?Xek7G_26Saf?!P22s|>(44+9-@u#$bR(L)T3>wV15A6CUHBGKv|DNtC z_2Jy(yWr&cvAD`t4O3q3g8FPN4h!BR{GQmC14?!1-rY-dWn~Y(pJEPrjgP?I!dPtd zxa6>=YmlJX=L*EW`Qp4H@p7a}wH1`r+$0W#W?V)5w3;GdQL`0Tt#i#Z4>s@;&1XkbE?a)-N^2 zkJi>)si?s=7GGi7uW{HT?l9|&`ezC2Ra}%k5!;k2;l;*NLhb7u2uf4HD`io5@XS6u zuck?E?Lm|>YzE7`X_cNXTEo(_T@-QFTUhdCEZe*4ar<3m4DacTYs*u?bWoOX|FsVE zy%Ykk&RwC@=qlmy2~$>nBE>h4T18i3A~sts;J3GTiw|-))0CjaJfOgdgDZW7IH zTRnrn+YGt-<1`+=U^k3z(!&)7vsgt~h8CBPQ%Z#|lxj>BcRneBlqxULrq6UfY8pnp2(6SZnG(=$)KN+M5eUCLljonm!Tjq-fq(_QJCgH9Td+DHR zwAAGMK9GMX&x=m5@LsncU2FQpdfzT#{C{1vI&ciChRU*R;2@K+jHM@4`}Yi z7#uY1i||i&l^;I2^4mW9VO;zSVOhmJa-Z^rUQTYU9Gq*1dsa7qRgesi{`Wsm%`T(# z2m&`%3vTu)r{_%@DBtNZy)fJf*Jj&5PDdl`{#+_-Kd~HU8|;&q4h*A@&s_M|*B_L3 zYY#VU`wp|uEruP|W?*o{7GGxcMQi0vSnqS2e=N_Spu|kPHOdEzjw#^XjWc-5{ zCh@m!gebqp<0g8BW^}%LUpmz()QnI4oa| zo|E>{$|5&zTQ>%y==@ zo^fy|)(y6lDi;R%gz-a(VcMdIxaq`%&#l8A+)*{xI+eG=-R zE^kz&ZEiSkcls)Qxv!D>%2~nz_ch|W_??iqJOD>{JQIV)#lugRB>vB24CEy{u*%R= zf}WWj#YM|vaLf=)RPYw+CfCBWxuuZ(&58E}ByfDyNNK-8W;ip+5L@;p(VBEq@$R$$ z*cp8gYNr2yn_sq*LtHT}y4XW>?Qv6(8KXj{A4ZbA=3m$r^%K@gOL2f{6={6fR@u2f zkGHh11?{r#JS%-O-5ofHhekc3z4MRro=X*cTt7k*wSF-=tFIQ)W+M2uq{AYQK$LgN zWSK!;`1HsxiP!6mxWPr9T=Jd^<%U;4Y0`TBG~~3ns%18|m27}+fd`;zaBrTp#ZK_d zdM$3~d?WUmQzM2wzetiH#+X~*i+9XDgsZQqaAd_eQKj*cxaNLON{lnWwX4Iqe02nk zyfl?9&m4lZE-&!v9SI$4ZjeqyFG0EI1(2=PAT7;TFtkhoizcb?+aq6v`O`B=zI;A~ z4bb6rA1Y{1$Pdvbyn~*Obp;vE7!DY`S=jJsIynaq2K8aTK$0K}{Q^c}K)DyiZ26Zt z?^*GP>aXJ7@%Q1*#SSPrp9vWkhTt~eg-|<7j>P%VDEIk2(2$FQ&cG%L-877P$c?1b zN8xmO_#Mh}wZV1$y^up4dHaveY@zYbfQ@S)cjRgCpW2giHjKh4&UPHOCIQS_yukB^ zBHkQ(oTknDD)vw-gl@4V!e^XHEf2e>@%2>fT9pQG@d(tKdvWI4^|X9{B4oaf7YlMt z{yA+2Jiq#iA6WI|fe8y}bJ8x1GEO5sO*0DB7>U;1{Lx~dDd*S8uyo8NR*5|Wm-`xH zOj|7OaSn%ZNwY{9ydgf)mW+$C@YL%r2pnX>pBxr*bpgnP!vYu+^31S?)n*t zp~WT+SM(#jdx;eHS&fcQwBRyb#K;?2FgVbQ(|-EY#m$B_bG}ZNaKqr#*S!0eI`n`NF-Ws-mH+T+|{91Jwf6hIKwif#Z>qYgV->RWp zEQzMItG4hF^|AcPUljss?g%=`O6cEo8Pma6qEg%)92#e{o5K)EW6&7B+0aN!eur~T z*+cr~upj-Jw4iIeI~1N-#r?0i;)>)85OQZQT`-aZ*CB>+r!~GdY`jmKPc+!m$lsl?)w>>M%*^3^ zg_H2kMQ`EID|J-vKNNbU2T)#IfAr|?%V{oeDKh^nue04N23V?#O1n)kIHwQ$y?raZ zdEWus-u1#5LtW1K=bt~?(TLybz&oQiey~@gZz)|uVp#&s8#;xjoZQDX3y&766ivd-#Zf4LLnRZ~SuPqmzqN{*AyR7(_goTdn^ zK)7sgNB3qOVbj0naBz4b^f>B;pXB$z{l3}ai=tV4L8b&uzh0-k!4jC!EQAfrGd@sT-=ToBGebZD1+(<46Z72px|Tzcf7Pvea1IQyU`3<#v&yd-jyW;&HU*Ol9#XLOyg7Dz#CHSsTOBDk#MkYh~py zD=|-!dE*gW3q8mU`7Ly)?iwvU?Tis>>7r5RVZm^H7hG}eg#Fql;JMXKzMxP{N!Gb+ z4`)EfR~4NVs^GV+CT_nyo~=3$LTG(ByGrNql&8Cd*K@aH=0q(x`qY;d3cAQ*aJu04 zY%5>Um?X8dEk%!U$8gE#T)1MZ$9iwqv0G&}eL5J)FMW?w|Kd=de$t+{TUuaHm@~dG zii5QN@#0eZtKc_XjiNWz(y17mfNINW zFnnkPU-$QhO!w*d-E|y%s_CHrhW#bo2n%`==7bIzMm%l!W7t_GkB+r5f`+*_9Qy{S zb^aDu6xj67 zDY7u$^a|Ph&v1FibNNMaT#~Gim6c>ADsX7nLHL>J#cCB## zSB0=WFc))QKBKAkj0BaMZzTL`5dEKB6L&wH%O8ARLBteatbJa`uikXQ6uqN@*7a~a zGd5SEbJl}5ZXbZEy*AN1tuS_2Y=wDW2BXeScsPz!q#g})0e;d z;ftj|sx0)uh{jgBm|8$KuG$IyBYyFnjcjpW@qHC#L)oBF=f$3RUt)N^;E zOVd&WAEOcIx55qA{&L4aElaMSe;G9{T&7nOCxMzxGK(!eV2*|}N_8BkUgy_h@r*XH zwA(|hrkL=kHY*yX|Ces$DDv5Z10i8b7X6Ye;K*}PqAUL;S=d3_n5$dN`v zr+4)6TDu^{9JL36rVFfEYu1V?XOSo}PCYA8kwmZ>1@?wuF_42m^lkV$9xAnGZP*$eF`Q@OQF)iVE&=% zz?0@blT;7V5KE#~3-d~fDWZJ=YDL>n=lcREpLCeBFQvo1t^a|hx)i!adW;U~H;~6Z z_d?ZS&d|HhczpL%R*>uC!pWmb=*+E8;2TgxG7jOq@V|Cy7`7J0AQvIry@f6Nt&sFS z`kIEnoQ%%JKHRnRx1esg6g#q9IqkR#o0iq``_+!Z{QE}OVBn3XzO2LBQ>Vf9H&&Q- zt0(Ji&Eoev+_=_8g|cqHhW1rw0h4NBn4=?ZpQVPQb-tJO8v1V! zht8=+pfyMp=kZ>nKL(`LsdfYNu9n$9_a!L|Q-S)0Mv%HAL zn+Kv)*(K=tV%E#mW~DNh%s@W!;bOhSJO)EE(!itdNL+Ye1~1!a zMJE*>2uJOni@62L;4pPAD>!AcAg_(LZk1u!{loCMaUwhKmSGdGbbOe(fuxOQvh)~f zdK2KrJtvGnso!Tth02uF@7GGCtNVTl6YnBgxYkmsswKCl8S?$fn*8qXI?4K^dEGqp z9@dV~!qW>i&~ZpP^!8D1u-apXp&vfuzo&sT@!K6yYStjG%8x|zHIK+g^yVQK!&%JU z407)OV3?*01{quz7SEO`fy{737ZF>1QBn5ew+zEP#TVlbuN%j^--wyI_+j8AAwV=x_vnQIUS8$ zMt1#*aN&{|+%m6_+75cM+eroXYk4Q8>;4w+gjZ3)=>) zNqM#=5?sZ4wSuiSDFyLYBuaEu*>nPNIRUEYHmP3bFx{dEn<} zsHu4)uHW{T2Je=qK(h^aCiE|ioOy+wD;818n5mMmt*^k-_$+On*3ITh2gJ8MZ18mY zRnl{xk3Xh%(90WxaQ|Cr9=oSq>;;SH{fs!O)%L>kBXe=Qwo@>WZn`>c-c^*&L*{@G=aP71}cf|WdEKr?%u*#*@u zf50&O56rV2#eOEw;pn5``1zMTzl-=v^B&dHHk}4=yQK#!ow^wo3ZUpw3%uSx5u_Zh zh;3UeVN=m+^fZkXgN7DU>$0=-V9GNn{CP(#d}P6c_T{5u+I*C|QvzCrT< zEKW3Az_lL_iiI~GP)2DS%-C>|L#=&T(Z~=Ncn!yS6Me~R%^3c)EXnvAtl<5i@^njvP{t$b(PK4suEzp1C zTp{i5R3Ufs0Q~0L>edvZkH+D$RVv48zD#$&6E5`mvu=w!n9% zqx~{Hu|q7S>bv^o9&ey~ny3uJ#&lBEAJVU2C4#O4ZlcX#!< zbkI^2tPgbeyR{?nWkmq#)+h4(?ME^0LK&aGKMRguNaCh+3Cz7Mhpj8a>EXvjT+*Y0 zCNFo!yntAKZs!O;sxmlxVI71u{1#>xXT!HuBQYgmEp5!d$PG?o+5bo;3SSoE%)hD_ zlCQ#_pYDbuE|-KA8S%8h`z=3^^5vsbIz)Yy5IkubjExgsfLVKQ9MN+QZQ68943X5vjcqE$& zlN1J{$4y@v{PexhGufB2zOUh)VF}QBB?fO>IoCHd&g7QWGuc1lg?PQH5te;zrfEUz z;A1}nTy;8iSoD*<3LJ#Ncu7bBmRPoQP^ALO46c@cQ<2h|ZFz|K^ zRXSgQ!`g#s=Z|_)>E<-8Sr6#VjS9T$Tty?|`f*-aAzA52iQYARu~}*{hcB;&WS=$> z!fMcRQz_J?32grJEY0kk0*dcHLWs{w_VU<48KNItv)+YLO6Tgj&a2|#$QW9ocn{iV z@1)Qx!3@dw$!z*D>a+Zpppl`AraV+!2<#jN>Wm>jZ@m zXO7t_MVd$Lz*Kh^oPVs(K?8K~-LOImgj^x6mnt_##??10eE_2ZT6 z{pi;)$6bzm!#c^fBSeH?t!|T9)}4DY*nOBHJqN;#aTj6Z)oNZVY;%igKTW4kjKIsi z%;8Pycnlv=Lw_7Woc7I)OV-UIX;P)?ZPL_Jb_!T~rf|=e$2f3qtS~-gE8LVl!sagi zJZNO5sM+v?G+m$3oFg^-?)m{3IQKcwvUSM1G30Wis6JMF4V#8qm` zM%QYgO2Z7;Y&x3^v_C?@Dns#y!X23AxeJSKCE!F)hSRfl(&DBTI%4nyF3mOL{XU&! z-19o!^IORM7w@2wf;Id&EeD#Ttw~4K8vVcO;XPGTz8rpEqEz99`xCl9!9a?i>@wk} zc}L+?e>XUJX^^;YY$;qGvIwf(#|SPp_PjJK9Ge&HqK8lIae{sqO?3PqL?quej z#H0w9$S)$B?e5sNZ!{l|jIM8-+?$I`dUM9^8b~m^U6;D`D4dub!FPL9Qt7I0uL=JF z_X_3NBxN)|u^oXo6Ng}O-yHZA|DU8&>j4(+x&=703vw4OTGl-C!UujB(i^C+}O4ql!gOrxVqpw`fdoX(A) zY8?+c_^BrkJL3;JUbEnBKowTz%t3Wl6<5m{vTJiRM|;N6zCEw0SS}ER8M8smx0)5CEvVQjF_d^42>&p692SyK4VbO!t68{vU}lQ}i13br_m?e_AMZVT=A zL#9V0el%3Tx#O2`T}m5Ge3>e|{gw?*s%G33)JZv~H1NUrTAtaUL3wK5L>Bcyi(Z&d|F{eid7A!`(#Mt#u3ZL#k$eqGPm33Sxn2{Cm#FZAmJK{Jwpv^f9Kw1{{qXdOpLR?@wrkgTNs}ttLM95tF#F&Rp~7W{OB(x*i=Bp)EnTiK$?68=#q1U3U-}v z;ETc8w5gW@v}~w`SfhG4-ba(~EuW2&xcNLjM;3iMf55ocFCa_TpE}ZI$*=EBXmih@ zlQH{g`muX3{Zkyzn%@Pp-|2JZz8^5)mOxEyM}@5?`e4}7)ig|MBa9r8jq7*)Cf96R zp5{K3H|82qseezvrHaDOXTj*HkjOnz8q<4TfdE@Tq`xh{C!$)25@kpI6RxQygSBoT zO}cl8LdV_2@<3Y+_`<`xU{)N+HlQ`t=kNWz{&9q2bf|>^{QPcJZX)O2v zm0wTLhAj=WB_|%69%$mQ+%e*j?Tz$jP=zofu>h{GlW?C>XEc$K2n~sGIA;7f`ewF` z#Lx&nA8yB;IR_#7c31sZ9UDAsWsh!pX(;DEly@wzrFByRgswA{k|httx~rL{98%hV zljcvyu!noNVZj7GZ$e2$TX9AW(3J=Ia7yVpv`o!Md(oV8tPJVsVzioE*nK4{~+NjR4sk8BaZ6oec) zP!Bb{?!ld?yI3*x4Cy@4?8eh6yya$hZa;0Ms5?IV_NxU{9Z2A&xuKl%GM3BZd*R;P zbog<9HVWN7Avd!QI&YPO-;Ez2zoLO=NK&w5d4y!(=RWmAeoSOdjoWmwn;|`3{i3Ul zJJ56c6+E=K0&bp{W7WU@^kl~gvDo!D1vnpIt$*Xl+_gu;_*puvqUD4W*2kgD)dtB= znRptrw*j7~8(~-YEK%*lQ{iF8cdB((;EcO#>a)#4CD|uZVb_O#)VM$j3(ndJB_VC~ zKUE?zMt2|^->?SVnR)fA!VJ(WDvO-_w0S(`iX|IH@!I-yOquhm-fEK*ge{BZFPY`y z)*G*&Noomg6K!F^gd?Q0W1_HqSQ3v2CgJtvaEkjp6!VM=1gU^t!W!!;c-Om?W-8vr zfEELm-uV>Vc1N+}zdYz0Yfgcy{v%;kIcx~}4A;w}siJ&1$4M`zd2<$tcVsp|#D@D+ zej^gjrFMbu-H$lp&jvVIv72q$+URahBJ3U>gjZdh_{0Pmo}M*VjF20S))nj7>*O8k zwSENeo;eTBmiK_WbBBqQjkb8~bTm8`zS0!4cnadR=<;T{a7c5ea9c&0Z9eov`y3lM z^`e$4ax>BEj1j(h&@8$0wT}9Zy-J&;;~}Ny7cE9vs$Q*5(HnMvWmN*fhDx4t_m<$Z zUm7GUmSINjAzIWLMDMf8z@?uHs~vtOXl!_a2luyv*}XHu{y2f9zb%Ej)m0=Z8p8MH zL<^6~(@=B9b(%2xDiqvU%H~5d#kBXC^q_PAFYY0W*LIHuy%4YCkah`ih{nw3L1R=57`}+qvF0nu;KTR z?wowUUW$7tq{ITdd>7))-9sSlfGi*K5wPsWAin?96~D%=!B<}x7O$)kecP6?)hQLw zjnd_^7t!6lJD$r+roo?iCUisbrJ%5;nbI9gAmG3{jCo@r$PIcbe)b%S^BxWp%Aan7 z$4{1$N@)=_D4wJI*G4Sch+t{Kf?7W8f#EK;9Qv^@dJp+b{j^(z366_M*;)?H zDzt;(W`Ki(kK?yn{kbx*2ikA(r_Nig!jSumc-a9lV|F^83AUrg zLSuArAI%4M&f;$huOPSiu^2J1nYZjMLjRhF5bm%7S2(5dz6?zsqa(plZ6@$(f+>_- z3PkzCb9vp|yYTj#G+fwR3bNz1c!se)2dkcgWIZ#{D#(>FT?Vr&i)rf>Z46B9BYgg8 z34JTB!>EdjlEI$#)cW?H! zRP1Dgol`9^OX@Am*Bk~Lj#^^fjrHRBC=*s1q|a)v&Iy?rC$VhpV=B41ga*3Ea_KK~ zwD2v0Pt&bfdr>TAp&5K_SE14C{&nAH3i(-Wq2Wcjw6I17Y8}_WZRfe{?63=#Pg22w zKfl7gDL2Vx?MD%c2`j zZOba~OgYGgr%cf}%YsfC^@G8d2HexKH&))+gDcMli~U>Vp!v)KywE;|#@erg4CC{( zY-A1f`xzm|cF1#_qB82GcGUk$`iIUimd;79r=ZDaX=K`dsQ%NxPWX9}FJHJN(bv?6 zrv8&r0Z!xU`5Cw^$dZ2#GiSvyu`p31f)=-~;E(TIc-`Al{P2l~PDlO5u+`i)e*dm!aBjbAg%bPFYk-ms~ z_$6b#?*(cedYt4JRzt=rXMFO(9-U>Mx;4KsR)8Or3DX@Xawu=q&P)>?9{@3 zKACt?PKp0JA;GRW*3?|$gYM%jQ2U|`k2S-I2sXId!^n54&rBg{~#){dr4m#UKqVoH7Yqp|8QZsX#&Qg|OxL5pQUBoL^BH7##19|rl!&hi zc0%#$Op0>fMY7r-#qrjj92T<$vLo84@mnSOXS(91;;k_1)pTB?r~^-yo`UGor_?LR ziJzE93x)TVbKez;?5F2LTAd0QlcPp|FCP&;95Y6nIe>oWNAY00ojCE!EaqkQxP9~> z&ib_oCha^)?+z)kywzYFcSwT`dW^+K1rK22rz)X*?}Eof@X=6Kmqro0TtI!vBD(+Y z4^=;S2N7Kjqqp?C4(6NsvS#`O_}2bK5T=GoP9^T6_q((3d1eufbGSfC@6=dk#7JSe z-VRt_uEOUk_d~M7T`W8~RZ?~)0~1>n$uYSR-d#Q=u5{nUKC(~6FZ*qI;L1K&@cTGh zozH`$UHw@uTawWD7&QJorP(h(Qjwh@kClA|hX)6+ zB(O$sjFzWM(sGFHBk{%iFq-i9B3#X0%J)3?azXepxITU;dY(K0dzZ(;+cA4#N~11% zsi^bixyF=Pl?yk1C$ex%BI;l3&vKtu;Kv^MaB0IIp=!1s2Bd$hKe#^wn-f;?6?bQR zo|;F)I`q-QN}64UrE%Td;}AS>ClDsx81_9!{`wg@!mW?*Sb?mMpfO zNr1uuKgnQpswA`Bm?lk_%_cfi`SSEA7^83ua&!amg<~E(&KZb~TbIJC{}g!t>{#j? zTv7icK^<-Hqza!sFA6(tN@#k4JDA!&Cfj9}Y_&oawTngQG8l+MNkTxy`{q_Cu$GhG*s7RLIoigT8xdtp7nM6jv%jm^z3rLU7KfCpYY|p@r^etYwRF9%Sb_S+w;Tf>jx^ zTv%obJrnmp$jJbHd1*hJcW+tKjuTOL>!Kz96;luUHy;7tV;!s7LiVm^8^3%@3#w zvuA{g4K>^G$fYSbKY9W7i&(||P24DWkt18^E)yTD|Bs3|P6#ONhrN$n!+MDgjyX18 z41ctPXKb&bygB}yCa=v4zI+p39XQ0hl0CWD)saIN>_YVopM{4QO_S7q34@LF(EHI8 zG}{As(B>j4*$l!O9R)lz&5c*)OcdW~&*B%U8C+#14IOLUaptU2;j_s`erJvlA>Sg= zX;^_{6)pHq?I@c2U>g`(zvO9_ez+)pyEuFAdTi+EE$UAA1t&L|;?Ir9Qj|b;{{nHH zdL1sG6_2m?*mBSfS=Ka)XX95h>f0+b8Kpl9^H-hW!kBaPX7dwazOyeDO?Rj8qYDL1 zb0^$WBa7N=9@bBBjzqa1$r$FH1L}(Etd``%=5-6fENd@qsJ|j^G5A6&Mi^n9vOZq> zY{kcoAJMR3$7p4y0&J?*B`x#s;^0(yRM~R~!WO^8`)hmQqg9h=_*yHzaYu(6gRAJw z+|{i9yc#TbHM7gv7+i1=c$LW*>}`@twPtQuGRFiLOqs)qe^P1v`Bn5bKao{?zr;Du zEUCqFHqM&bn?sf;;r_)DAbWHUZ-}43;{CIA4sK}}Uq1k~lrBsDOqxo6Vq;;(O(jgp zmgly_Sm9&-3!IxP!^zXbCEjIu{Kpd^vNf38dM8uFv}>SSZA|&L!?<#05Ts;Zk-Vw> z4tqXG;MkT05H(8+CzL!S=b?r8>&i}4>$paO{$+{R9eX~R^+_~;kGxe$mHXXQz%k{K zROjZ0ssYFO@f`=$l~rRt{|d$$CsD6Asp3AJ z;g?IopLbVay{tU%(~;)nCAGNMKoO6bFNc$ru{_i5o_H@Z6OJ5lrpIxPoYs3J$7S!J zL9%I*H9vIGgY3z#A`SAg{(#l-9^(77OO#?Du)_K?;@ z4ismfcceW@y>as!eV$(|&qg#=T%;CAamjT! z82Xhw{JjBtsj}0ZSkkwUg2NTNV0OnZp>q3aDtRuCL)07KQj<1^RXNfG`zky!Pk@5; zH$i{fUaB6D2c5zjar41BY;>?&Bc8uN?!jQRl8Po5r5Iu8qkg>Ok~y`UXridgv&2lr z2Fj2h29>iMdF_lM*d`^?LxWck*mV_VIA}qJ-CcMtH-rIHB-Kkj$#ZB4%zu0cGCrD; zl13>MW~kFWtyrkBDdi;9Fx1LghJvsJF6c~S+MvbmvMce|(}U2txsnPLv}y3Oo^*4T z8aAGu3~jIx&g&PER?mer>T$IA!ecxidj$A$nj_kOUWvNP3TSuyKyE&5049=4H1^pB z()NhrCu1k`r)i&1d4(rB*IJ3KD`U7`-<*m{<8ZC24bM3^gr7&ugQ&H+=X$J7wrM$~B$dIdzJsVlX9yKXwDFnc*U9C`G@2L?gva{#fGU|bTH$DeGp#xWFH-|d zHvl@QLvT{Zq|zhnTMOe!|y%a&Gbd5(C1KYUXHaxE#ds&7?}6Zg2OKMllB7-@y+gE4~-7uGVPD&!SV%mV8Q3UcV6RBm3~K+&J_rPo}E4??UsZNgQ!@5Bz%> z%dfi5!S;_*xHfJ%hNb_4^c-t0seBCeEh=E<7LQq;BXE*uJ~jFNrO=6w=-ZaF!j$x7 z{KbAFN#rVda78vW>FvRQ;9O`G^~tdLwjh!5M~~+T^-h*M_)_v7h+o{pz3;TOsP<+w zgkN!_u)!(hur^SVv1bi?^p;_*l)FOA$(!Q(j!Jyt9(oD}cSiCe-BI}W{BC~o&kxhg@eiWbLxNNd4j_?(e_3ts+13d6G!gRiFMN0+;uyl+bPo2{VBl_MJ8~4q|G0weMu)9iecMGXnIhq#E zHpI6)i%(?w;LZOsG49h4RD5+?beiJK*B>_tO((yQbKWQVmaEAQ>eoQXT!UdDKk2dO zH(F_$Pd}{Qz@z5DwDsI<&buHF`|@uI%hM!^_*?BHl=~{9 zZG9n0O&SdYcQ3(!gICCI^i8(21-RkgQUAcr2elTYh+T$Kd^~(2MjYD)@E{G$59|k} zuuHgb*Ku)c=q@s{$YGa4EkUC(PniDPj{lCiB>cB|JFnU5!9BkuQMt}Q43Z0nGnR*F z=kj;pVBH5>G_>*l$VQ%#VhK49!a3zYjKEemNcrVGc$zO@R@fb3@ONWeu;wX!_?Lt; zZO%zTQ@VuDy&EXU1gN;f6s=ay=M6cT5b(JUKdT2(^&?|^=Gv2!J<@1?ha5i?JXo(m z12gcpINLiHkNo-#zpuB@=u=DhOOXKu4$6R-wF&gv@EjGitO7TmZl-(@iwedEM3-Yb z@M4A>Z&Ij+PTxsjHPneUz8Le1=%FmT!9{pq^O;S`W$ChvJ=>|zK>0uUFlb*4O!qs0 zzusE1&%1kK52bB<)_)wV)~SY*Wmc#)O&&MO6w;C)d6b(r5`P|R294soyvUeoV|g4I z&d^4g_JbrNQ$(dl60uLiOxAyvh!&O-Q2c3z#jTsU(WekJoKK5tV^b*q$0J(eYl`!J zJMy+OuVCx+I&tn*2P}=30kSvc@OXQ0*4RnrJ%5NpM;(UikK8$+Y$UmCSxBb7Poena zObDx=P8L3qu>ZH3DCfQduWQA_qjitr_ZSua-thz~J~mO(M&Pm*b>4MUg24%M@blpY zq3@ax)T3xO9FT2?&o$5MbHgIJ>GO8d?zs&o1(wts8O&t`w`?+cH;CT!zY0UA59hsy z=Lwxx^s(Sv2KI?i!hv%;;Z&yx2!v}cMLo2xSSe7*IGrW#C0ezSJ7OuOk!g4czeE2Gx1N>h>K>uTuvCA9x z73;H${S|TC+FhVnz8szf#*_c0R4lu=iKM@K;iDRLo^&=7c6wZ*$d$dh;($EGY4_sx zwl}zIzy$Y-m5)Y$4O+luz1KkQ%ww>(ehWWX-NfHF=HrTm))?i-OvG-+9!iU{ts|-Siqy+MAE~|^J1up3GUt53eMNfsH=1(XwA!nAmd!z zubRMGY$0AV%Mz>0{z6r!GbO$bEi?VeBMqA9)rVo&bt(W=MjBJfhh*}% zNx`$tR=DwH5q{TAME@Dv*t@MKCmkKZ_g=OgWfsfBr^(c+}pS7`0PMSNtt4X*v^hZAaS@b76I zzID``o>fi~XG;ePn~MAL%5CZF5dH!d502&2-TdVeIiJErB^leU-BiXp+<8_Kk$q|+3Xwz@YQEWIa2MkSni8Tk0 z@X`w!;5+{y2?q|t%S-KK*n1Tm=}N#qTMonYMSJl?SS4hydLk~&*WgQ5wRB^#H=SG{ z;X{))i(y}LM5l=(L3{ihc3gUia+X~aR{77wMeCNsxqI8l_pmg$Ec}Yk)ra7wNdXkm zJCP6AmqOdXuY&T0Qxs7*l4qpe6kGb~vD+bE`Vq7QkI0V3(eq-d=2IV*KK(;vDSdHX zxg9rf5>Ne7K=ms=VbMknam^zgRC?vfYa}!A#^gBq(yeXbwl}W|iQ(tBmT-c!FFo(G z3pRdn#h%|h(D0i8E?yNN^{E7PnPeg{ z-$D23n21n0%-iy6IA+a6HWgd#t*VF!t&`AFh6KLkDyBN z92Bc4edYGzZME>jgK{JA^+^cd$=TIy~>K3%6qD z;*MC*t9MCUj-ZUfTY| zmoHy`L5_2asjdGIc27GB{{|I4S~zYd$HS`IvAoU&DCFf z@a=G&hWW{rSbQ%A2e$;^)$Jvchu%9$0pc-qelmC7`5_6O6N<%h2Zhl_{!}_niaGO> z`1ba0Pn?9e(`tEkiym zGz~lA3LsE*G$(JA6TW9VQkShF7cTZ;_1XklcQGHGkDjhS+|!P$*o?I|U9Vr5vQ4*7rNKcpysc5aNIu58od`o%=|&~qXE1dqQYvyd*GUW3Vt41 zOBMcV+^m|8E5l!r(SJ8cI(RH^di)(4H$>9-1+OUEYhT^w;NS4 zM%t-;m_OSofX2A#e6>xM!dGo!pZ(_Wbww0=j9ibQm2D7Wu@@%PB!T;>1$^P>2aqY> z&Wl3^LQ~LHEC`N=n1oNT;ln0=+|wRa|2s>rrR9`4E}kRTSHPqEJl?g-oPwN6s9r4} z3}RQ~lVyGB@~R1_5oOAkw)KP(EkpEK*9rGlzNG=9By3g6%P}x9uggl{FI&nyG=jtuY^#IZbQQZ@9HQHRa5$V_-qNz}5du@QKGI zG+v5$(cud{l(J`1=s}&EET}Npj<+0E=XIVZ@aUvuoLW>s^FH=tukClJ^|n7Q?4CtW z$G-e#Q!KS&jKrX92PO}AEu4(3qxby{*vs`5>^+_ctrvXxi)83XIuPFBaFV6&7i!}uMl)0 zh7(+);9J4~&P&k53zJi!?O%#`=S2V>Yx_=Vn*lYo_u$lyS74BCP4;zee6^c}l7hnM zNoyumyXI5Szi$vSW(~=35I$Tp5Peo375~;+(7FO$?&yCQ4#`^c^_Xv>;_*5f|9%=) zTK8xOnKlm_c1DqRr#YT!yCPoS7{forw_vcp2Rk3=g<#ku%ujG^stK3r&xd1o&y$j)0}pjD#rO}dJl`*sBk#Mzod@nv8u1CHdXM7a^Y22U zqdnTFCE$bmedy`X;dtWVYHqNxt5=+PpDstZQ>^N5DC(0*FV8xleM2O4Myv$i7a`nN zD;>f!D}@w)X+E$rpHvo4A;Yr=1RujhyzrodM#g0bhg&i^a84zCi+(_t&-|tP(#rU0 z!EbnScpFR@uoJ7l58xR*o>Z>);&H3Oz{EdUENtw<>&pfUBQ2g&&!`Rj>~tvkY3ae_ zTq_Jn`68I#dMIr6NQUbS3*g9=Lx?Ms^Ou zIwunA+x&Tz&s-WRiJ?_4isauXfQw2}!Rpp$8oDk6y*CYFufS&5cvFWxZq&o%`x%0c ztU7zGO=Wq%YwT@t1!`AZhMQ$cSerG47VVsc>jtU|r^b&Lx*EoD$JurG-&Y^OEMg$K zf0W|ryQf97ZJrQ)SC17Mi)oF*0-SYJ3)i((i>f9D(EQq!L#FDnFnv9jdJYs#tcxVY zW81}P_tJ3L+T*y&Aq%u#RfvD=7IEyAL`h%6c-9Y6VA1ubL*lEo{ z+mwaU6>G=cH2TK+U#4afevN~srOVS&Z~*1I1etlcvd^IYr2)GQxZy7LU( z-Wn=KD{ey>zitn@c~?A_Ie-Vd4inzJIw$-bWx``iSCMbqX8uUosHt!X&ObNA%MlUu zZAg;jyhRt-SIF`hc?%w~>OM(dOTi-V8=&}14Tsdo^7BVe>W}}vBc6W|O?N_e(>t9* zTpXx`Jw2@`d7}(^8XEH2{-?mVOc#%gKPXz}*z?#wJH>6G)m)IJDj6cz3llEJ;I6Gk zICjblia+5E?XJ_Y?%oCL2&tsW6%%=9T7RK^QB3`nf+jI^Loy$jz5@DsmcW!PUYP2b z#zp2g!BhPb72dQ*l|=%7SE(imYhc$AHVU_a7rql#LWtQ&l}{&f`Os|7g}gwq}O%0b6_exEICh&GJ)`NeiMAEQRT5`4f6kg}fo6wt#OkIkVDn+LWasZj;ls%y2vjy__YubK&wbWnpwB8v+`@P^d-Ig6 zr}g5z@Hm#;y`3~2`lGMU1J+w#1`dXoXw#Zx__589+*a%nYmT_%y7Gg<>ThFzAVXyA=l2*jOGO4c7Zv!w)W+I z%2WB<;gb-P(jPm9jl|rLEUr6SDn;YX0{0%>YJfWZIjr%P=TfT)z!V( zri!Im2S6oe1j}OvX1-1rZEssk^dn8V-fkO=(;A3d%1+au1sgE$ZUntt_7je}*m0}Y zL*dq&jpC8hJz2WtkKmy!&tv8l;l9+dcy;nZWQ72Fa&jV>8_UyzK6BW3SsOKabWpF9 zXqHRp1h-!EBpuh?(EsomQRP@)SXcW&7^7g#HBYwFpn{2bVf+zHv{HdTo2)obTbXCg zFsC)=8|pu}&gM0}r^5dXmxn)=eH6wiLZoOQQHo@=j6%Y5pOZpKX=o~qx3m;dO3DZs z*@=iGq9i0~@Z9HUY0%KpP7`fu(A$4-e%J4OzUO->MfJni8V-#8;_-*tHB#yUsGwd< zGj|7*@88kF{>*n%t16kU1)0+EPO=g`S zb8&8H8?3)H4J`ld*6~}>q_SERqH2B#u0NZ}{OEo# z2Q##B?1vPgYuI)=TXLQH6{lg(6HmowTU0?ldKi0Ym6FGZCP~DKkt|y;i!q&*3o17H74kTje8q5eN2_;p>Puq@d@2p!iU zZh8|a99HU$Dz<8qvS9+o_1n#7t#|PVzs-`$G-tebJ(?e$)MZO)y=eAmi%@f_22QLs zz=kvh+EaUyK7S6U33N)j(|3{dzGEG|l=#z~9xC+Tl{FANARY1-wnz^QI!c?2!|0sv z7Z_=qL!ZW3@d}w^EY&d;dmTrdAzdj1MD~GhT5_*&{6xKcDf&bm7U{4cH_&Fc*S7wQpRp(*8WD@2` zZwa2G?D)q1G&*}Vh0_d1qEAVLIL62Vb>Ci>B+qS!p-po5R&zDJm3Rt~e)CB4x~X{B z^R19EzXSA?$8&+}7jcdHE3v5N5U*)3lPuM_Nm0vHvFEZDYJL0%QV%)dJDoF7dw#Qc z`O5~}KB$>`9=Qac4)x}P=GP#(JVc_lF@el>?i6+ovEibT=kYJwfbcMy>sGc=`|n|# zKIF5sws;AjT6qWFFZ94(mH>kr+&FjH0~nKEOiHnG822QP5)U{)dDU2OIO-_XOx*^X zJ8L;0@ej;pwuc5RYK;VU_5>TODyy^@RrCSlBRRebKy zn-c1O`*L;AV8aJTaKbup3PY|W8-PlTV1CHpvj;6gc z6T)q*VR^eYYAv*f11m)~UGa!|>X_j#=VDkqcM5lX7|xQiB`7zc=cKUutF+H`5D$|! zQ`wolF!k?$HI*Uhtlhgis0```>N6v$TYUf*UQ4BCM%vVnWrXF@({Lf|0hoMgfdQ8q z0Sh~+-w;zh{b+pCD{^uy&&R6KT9Lmo}mQuaLZrm|N3C+v~*S9 z8ZG-Qhko4}`TBQJ;ywKVNGHv~_>*Sfe0vigN*<2(Q|fu;*J#!|^ap|-o&c$g(m&>x z!J#j^(Z1hQ%q;88K3jdUG=2;}JaU$LAO1vE3qqmZ-iDOFz9p422H5?4D`;=LPOsya z;$HnhEU1kK(#6y85xwM8p;RU(jY)Aqo>o)kk|bwqTgXR_!&A1 zw@RYO)oQiGZL2v4yqpV~8Rs0{>bxZ`)kNp7jzUVsB9t+ZW9?V(;k3$fQK*X-#`hS( z8L=u{H(e8JR4&3u_Q822g+g+~Jz8S+g2Waz?&G%GVRQ3vzCXf*E45_MP%4LZPwe>0)?KPTK8Dkw5Y%?01;(YTa7au-ky6BENFXyeDwE{TZ#v zj1~7AQAtvqF&VwgMuym#i&KsW&Su<>LSkofz^R5R5yVSskYvDrH-b{|& z_Kcc8>u{JALCv_4_+hmkoORlRhB6Pt)}0wbd{qNhEzcswiOC?dxR$1flQ2U&mtr>` zW8I+WfAgFpXCG%#^pHnS^K!QB{{}Yw38TW%zWBS_AfEBBx5!+v!JB=pxWgtBtj-^k zxO=^Y#-#^n?uECcd*dj0=WV8?T6timB#VP9@6ozdBXI1>-L&-X0Cb&oo-F?L`k{|b z(%;^>iW=>m}X!XQL($?J)w}rkSA62YWW}bmEIcl;B-w3|>0s!;9WJQ*xIv zzma@_#?x}V{b(r_=3ax!-Gi~$+9b*Np-1?e`DHQ1`!MKM55!}$R8iSj7UHv9aF$sf zo%6XTCU2k23nnD<_G%Mh+YC)mxNC;?+g1v;&*ahhSucDam(P7Y%c#A}Q+(a)B3Py> zp|P?Ig6RxQT%$(!V}aVYT5^Z{H7tEU3af^iqsPotHn^B4iPC>dDGq-~W${&-^k5BF z4Qr-HGLEd4xe9Bao}i9}5m2Nh70uoaN9)OT;A6E8@|Ei_&LEA_YBadp?$xX=x{;Nl zRC@gDbS@b73lx0U;iK8z*ginYvo|aAwKtpK_r@LQ6Z(hNg+75FC&EE}&;jvs{XDF6 zzQ#&BpFy;D33Yqd3n!iH&35~)iJ#Z(#DeFKNhcx|FI?_Xd$lbYl4q%Kug?isdhL}^ zuWQ5urWrx{^h_LT6b1Fgd&JdJW%ga!i+GVCUOMFWMpXDt#0^RYbs_` zXMt{NBY$k!f^#*OaM`2#aI=4=SQlcA!OBapBEXW!bcTh6;9WK8nTCbXdAg ziR(OPabedPYC3dSXbMv0szVNV%XKW4PFCTcPcG8VQ$zW%ivn(~{YLUh?zCU#0!$VI zVI_rNi$fxH3^^A841e*uca5AlMK^Q7FzjBWc&gKKU9;_n`hs8`f{+!)KytZ|gqHzdR3 zyRQ80W|ZVwH$R$e^$P0BhC=bR6{25pI_&RK<2ikQ!PS&-?4CUp9i)e8Lwh?dd_10J zM(M)VxUoERfg#TA<<4#u3-QXL8?@}3IljD;M&&+7si*!<3TZRrUyh5h$vnm(e!w_> zAL7j7s=GBCV)~Q!Jp+2LS}lyVo`Ld9p7Z#z%SC(Z78skFhqHd)hB2NB@Jc%rPEH%h zyT;n{l8*&EWXv+G?qTY}ny8Ec(i+he_7V3yI-G2&aCxk<4 zyaK*V)RXr4(*vuQBudgx$AaUXD#}SRIsoIBcqEA*=%c7*bz zt{a2U*TMv{bi&vc_EY^>xa89Y&=$H-OE7hqV9h0CxPLF5O?y1jgPr*t|hox*)g%!j|Roz%DQJ z`ECjdE0*E>$CJd~8pVQKfF5|uxv^r|RgxH7hV;uB|GYSz_5Zli(8Ync+ATrYHvX09 zBHvG_whPDQfA?^~c3b{EXa(0v5o7+_D&A^uf##Ki(Yo0Ydk%O9oV07yXak{D#RGD}~n!`+L z99v4-hu83lKuwI+m7COTe+c?aek3aGKgmXo`WWzd43Co^K^KQwvEWn5N8>KywK>D6 zM1L==nHS66N7kd+%=NfC(?fiutIlTCJ#e3YIMlih!goHdwEkp~u-AVUblmU9MXl4w zd&MH0^Wi5xT^EDJy0{OvC~H>2MJ~oLvjUKktVp$9yp&`GC;v>3l(E(Pa|yRq6GyB=R%)LXNUS z+3eJEGEO`yJpHc?)SRb+>AOu3__hRYEXftV>qgPg);P{>+l7fABOr3_Fc?{9#(#qy zd5f?R-#(r!nhuvk%ZWdD+TL99+N}yb>|!u$ZoOF26+oX0LNMQGBsPxgE%s@%qa~** z*?`Buled5)#+5-?&;-_!bEK#n`*Gz$S&aTL2%}p+lV|t^klW=eCazfshJ|~G$7%C` zS;b(t^|v^_#0)u&CF)4s$y+&c> zBsE&5pMV*)ao9B{3X)v>DZ1Asy6bv|MfYWJf2a=L{;h=NE+zC}mMNVmn1!OwF3B9; zMgOfn#PLtssq5t26RyUfd#{(U7*|it9_nHk}`@&G)^`Fx}J4>0b7g`+j877PhB!)e(1lQlI0P< zbjYf^4K5m0E|q9J;;Ax0^zL^h^|)4mCGVd>!P^D@-p}y2XA~91-h}CS9_*1WE6LWB zO8OV~!^L+tk!;8TP}h3{bEYi?w~JNO)7Vq8A*Gn&Y&Y^cmjq$;VF!4(crOGeo}%S) zr)tja(L#kQ!F=vn6h4V9hXWVnF!}9L4vLPaKjBM-y2Q&g+A0dX?FPaKz2P{TO0Z)| z3&_evQA@XM+GMzx(w8al+=BVsa7;p`Y1L3LFPB%CDbSZgc09;?0yZ@b6PCAnIw)AW z4|swPr%7%Rv5Kv`I{_-AJ4Bw)3bbOF*(z z7d?wRpvTqMBw00*z8)Bd8#i9YG{5yUdr%<%zScy}Wqmj~^BwFik7A|Nhj8u3GAOUs z#qK7FlydtTrxvdeR`-~TyH`43%S%;GomWQ^CoLQk)rZ2?%JRa*eB2+a4v+O>#q0Vr zcwOUKX)pa+NPOR$&o?UIFols=y+xMp>y=Ucs#FTm9WPn(EKR)Nu0{bCAEYwd6NG}M zC3yQs1&*E37e3b-aDH|yWo%zh!9^Fucn=Rwy;Xr*PsZZ(*Y9azqCUTESSPCX>n(WQ zp23qkm#}xY25_4)oNceqq}EjheB__AH{C=*{A-1Jnwny-;CEu$(UGXJ-kYlrt-x!? zW}{2s3>+?F8^rjBn|&XR2$*XF~h&X)0I2v_=x_jap^d>pPJ3$ zwv({8XBdtct%rw|d!a?Ajqv`uy;u>_9bc)f!*NmFK~g8r7NdIbm%pdMF8a1~%hGF< zD0~!id!7Nq>ZiDCz;rH^QQ?ZyL9Fwm5?<{8?C`?yB^g~>fE#{1hn`<{k(JvJTszK^ zPR^JiZn4p2uPPE;g3`dTxj)yB2*V-zn*8%~6LlVxu+6UH(CbB!XuJA}*uUZ~1i8Ei zw5a19=c>zL*Uq&n5V9X+G?jnuWvr z)Ns&)L8xHYOnrwX;FkLjC?vj2EH|7AWq-Ewi;WN9&3;$zwAjtE&$q#j^ChtQ^a}LL z2R45G7>c}QD0KM++W!0Bo);P82E`)yxO6LA-hZ6FO3R?GdLsYy?V_IRZt>&Pp~CHs zwYbCAz{$98%qkR~9VSCRV3XIg zQLe6B81qS=HZ}v6{ar*KTZR#?`qzO^IFjb`GMani2$lVrfXmE0xngq`e|#RsqhE}| zfR`?K$n2Kzy0k*blRGGx8{mcE7R8vAvYtPD8_2p9_T2P4hlV}L63q*4lUjp-4?MoY zk^{%tX}~4W>fFt*O?@z|<|e6~Q9*T+tCH2GMRei8O!Nv^O~Wr;#)>8tymwMk(@@$^>M^51fit$)o?ZKCJj=}sh4{5OXR9Nt?RVX;A&!V*ss;Le| z|CCBBPKboNZFcM_KZu=%E5Z-&K0>zNO#Zy7iMH-F5!$4cV0+n7qWXl$JIPPnI;IvB zlx@N1@f~`TaDmQkJBf4V>hnr{PYR#WpI3ddq+im5bnBT3Kdmvu#gGUs;k&WpFO zs<}MS>0eJjnkRPYmScyd+@vq_sv!ML7@Kysiidu)u;QSqxWKEFKh0lH|J~TYzkb`( zsN6L;Gk7!(F*Cx392K^h9u4}5!}vjoH6Ixxi@IU|fz%@#6AhF&yS+woYjhMZ%`Fj5 z-%$__4ymNbQ+r_FiMw3l@C|Z`yP)i7D*#VGu)qAV>(3egG8F3F@x$|K@%Y_MU=sQV z>=j>-?uvS;|K^j__aC>~;!hKo|B|kJd_dR}y@H=wM{~uZqi8(o2ymz!uF6=)d$Y_j zM43p<;{yGVw%ov7(8P#R4VRfecLC{-c*F=Gh}hO zc?~@~KZ3npK7n)nt@uEL37g)X#XUE);?vjXInVemJioJ>=ALxM?bi&^{$2!M_^FB= zdYT+`qYvGgv=KE*s`2eC6?i{Kn=&)Q_@Rn3$gCT}r@pDv0XFAF--FrrwJg8Pp9f_* z#h|n1pg41?J#IZd6^A)#V5-MrL0$bfCj={TXKo5Ks|TUsvs3i-T1oRTKpLo zjLIY8#S@hV=yYZ~N2dOVi5|+r$LseXcgu15wCo%NJ*WqZ0Xg(vjU4BXl;_&5`_Sm} zEh@P`M~rCvLCIGKVq5kAJTz#+zx?+LVe+n*%$Jqg*l^Ks15I=C07 zhVFBeY6kCmBv`%)r0>UG;D*a_bfQ%WTlY-m;`j5xYm^={1AP93@=QTgQ_=jphT<(Z~gV|M~bdnDN4cRc=j!lK+;0nff`gV1^NA z*pGwR))km#b(sfj??z_|#{K!uyKG9~ z%+j5lS^Wj%v=5WHTQ8J3*Y|uyULx75_QkpxYTWk8fZ^#xWEmSee`zBmUfL$E3%Cy6 zwR(7e)^Ls~|T6Dlf25ngCi>eIX=!4?9_i5Ml6{Tt+90 z9U0w#mK`8Q8q<77eH~5kCYPv(iTu?ynd^@prcI zEQ<(^yO~UPyncx0W`=k!zb`Eu=ZN!VZb0ax3|OqPLX7@39{&6Em<`4dDO9fJ@+&Ur z;=2nbpH;wV+0P+zQUUDrzQ@&rufv<2N1&;{G9I>RBCF@GXx;rloH#oYPC3oOVX0cY zdxHyavTUR;WwB7`;)ZLK?vm!lT8P)F5_9GnqUM?`-qZIH$%U?>MJhJ9e55LRj5$kp zZ#O_eOSx!#Itbfy)L_xrC|;6d$PRi%P_lX`x@%me&w9UUQ*Cc_*NuX-=ZUCOnE>H! zSB2hxy*OZ#1)cq6z`LiOqz|};&fT34ey{iO*;i%YpBe*?7NmpWnXlw3X{TM$j<~F$ zQ+Vee2PG*V*nFZIgk*N3eKLozZu@shU~50&`i(L{eQBU5UQGnAnj2tkW5z~5{sr{r z9?ku!hqI@=5=@2BFubq>_Kbf5Z71sSS6R7ucx4~zr9+fV~gGUc5iF=ePUw70(`02#K$E#_mqat5l9?$vbBY4uJ#c*!+eAJxc zg4IVGg!F+6gmI@Vpt)fbDx4Mhk$N=f#0-M;`bcb)DWsk!>^LXt6TC045NbN#O8{&}yNcNTzX-VeO_!IHWP;7Ze12&hMOh#9$!vZ(#JP_^ z`*shq>oi551atO#87Tf~&Ew|YTj;RyIbngG8M+HS@R@^-`mr9#^5cCs_`V#@#%?4gna!-CGj>lJ-y^CcM!HIu@H zBhSfG%@qv%9?|k`yLtXVKe0nRLqg$Ac$##y#$cN(K6$+!clgPG>6p2!?vc+M<r?%QCD@pADPx;YaPe@*2jl^Ikp%L>B>rwdO^z1X-z zg_DiLLEC5??wh|8PVEnc(OU!A{WfBpg<3i@XZW8vUm+MjICE(=ddADx}VzqK{^rS$}KyX#bQ;Mo|iesKu9 zhP!}ZXN_{R-cictX3=>em?C? z*~z=Q_hG4P9#(ZG?X_F_t03|W62z;dl2ED0XYy%M$2?u0kAdS(d|W-SpzXZ_1`Q-9o7 zZG@5g<7$#Uj?=!*qtxeYs%TtSDKt&$#gc-{^e{XI2L9N_aVN{^g@UG-UpE4+rdw0^ zt5UF^t&DG9UxbWx*Cmy^X23@W1N`8w&Hg7F1i9@~=;Y4J@a@41$|z5zUqes8xuqX5 zWwkojxLdH(_4TZGGJ#yQ|3KO!FOEzZgcDB;tnpSXK=s$B{@uqCyUJ0kxYs2EVUb!2 zsT$T%X4_(37M%-AW<0b%a;BVHL~As^HI>F*?StFZL&TlqB*+g zqPVD?Y>z~7@q_EIL!$zFRGi>PpL+|u@EVmxufT6^cWHh3GFC~u3?9#V6Si;U+OH90 zG+7%Iy~g8)y#Dxboi(LvUxBsq>EwQ(hWB1b604o_sOxDIR@cRVeeNn)7}o@4CQqoj z;2HdIs{*5$@9EdFRK6O>4sVm!LE3C@>@QxT7yf0C5SIZzu9UNIBodGQy$cNnX*g#_ zZ*HG3LYySXLEj{04*K?2G<~uR4VLE7$M%){reHcHJy<~x>YZ@f=iYqdniRfV=@8U> z58-*;AS~+Zf-`^Z;Wf)gah$dsr!23a!#!9uaQBrm|C%hT`1cNU0<;}xnF{@)C-)WvegUvNK$9oN5Egp$eD?dmNWu{V1Ni5!# z*TJ}dtd!9Tk^Ve=hGy??5YKILVPWA8`qKR}Z>ve=`j|X2*wzFN6Q=Q zOg0B*VcW7EVyvbPMrIh|`u$lD(KLt4Kf6(*w+r0Y-j0!t4RE<936G*CfWOXgp?*#x zjX63PhrZl`N-E2R-IMo`b%i{qm~JEkD^;HQ?@o-q_!1VCeHQjDlSM7ta4rrg7MJ<{ zb7sXrEUwBE9?Rbro-SJh>9%*s(`-97H&)U6CBwkcU?f{K>0`BtF?6K&WrO(#snyPn z?Z4N8!kuB5I^G!~3S!A;aWLg>Uy6-J$A!C7%;@zZ4X!(Q2xLADK<{&w=rVRN7Z z#-x|h9i1Bm|2J|R+f%l7^N&Mt`0E4;y0INSjSac+${j($ZZ6L8Gs9@pQJ~mX#J9qr6S;fKOBk6~a09Nmopl<#$aDDH` z$p=#~yXd^c;nOFv;NU3EJ3kBa5|l{W{w~y)HPi3@I^bNq2L>!`p~wU|>Ye9_Q*##a z^NHCMY^KTzlQqyjSPn~%Cy1pZPeIx?Ckm52jngCg;g*t0;e)v^`qTvRuLMW_>>A3~VICw# z4Z)kGYtY=q1{)2>P(X_@)Wj-qe!(KNbMu8G=lvvcF4~;^Lq-@EJPw9d9wGn21GF}4 zEzhsHfc{t2xVXp+olQn^pLZJI_2M#Ve?3iB)EA?FRY8YsKD?`RV8!)cCCARJr+^@B z5F2voU}>eWcKLJI>0garyjk2um0sO@1Zf*(adM3z#=1vQ?uKOAocR>` zx(pWPmfRQJ^i@Txi0LS+H=QqSWg2^t#C2;!;9i;>Ce+!p{re0kY<2{3$ux{?P~~Cj z>f+@QLs|8blQgILz4&Ng80|hb3$M4P!h}g@>5=k2j<4uPS-sxFwi&H(%G_P7DKHju zw*LgfOHK^;lGtt1A;{f#4(fkJ!giZ|aAveQejfM--l)p6N85j3UwnjHj>ogmwvQBa ztkB`ddi8K3X<|S7yvX`$?Mk!g{$-8Wtx;Olg5l=l#)r zK|K2Z^Y;^`^6V35O6OK*k*Spl3>efx>3$aY`@TM?O%LGo(~-FSYAFv}YzFW8gu~;a zA=ob^47?76a9N56ew%4eL###%M*4o}{#OvQGEKyJ@naa|_QUX@qoC#{Lc|I#Hd`ic!L_!`C z^Q3U)(Znj}!AQjvehw@kJ-=Ucyia$on|J`{ zKTCXh+{#;`SaBK-RR5%J z8G|t_^AE@w$e_=>Se&LmndS42k@Gu6)?DKQ=lg$<4*D>j4BD z7L&L(Yci2<9EOC&Lj2w1)Po^)ZWT^ZyxO#&aLrct)}Nt#}u$wz`c z@$Tgg=zBn&`_^Pqr)4L&G-tt$!;k2jhaLMTorgc;CqrC%CmcGF2RCMIr(U6EY#OE` zW@XsYieBdQ_?IfrF7FHV9g|45wtH>8#Z~ycy@m9~t;72o)A;J=Zm8?)f{RY*p;pc= zzVO)yA6;2R^OA3aa;XEmtDGbgizT?~?FER8-^BxD>Phy~Ta1a_3p)c2!=AiOI=l8U zB)raqhl6AIza)Rm-R{JvVz!X)x@J0MRwSGerjeD~H5zel4x;NjFn_p}?=0;@5i
h7I2znjR|^@_(MNQOf&vKE(a!Z?$ju1Ihjja|IVY} zNkbr`mp3-6Y{Nz3VqCe)n3ueKDRnzzOcQS1A!$?qpLM)K17410?@@hl-+~ZyeK8Be z9&6Iykw)AQmP%XCc4O7XSd#fY2OKV(5XaiLNoQE)QkSg{?CQRhi#`kilLA#7(SISm zTf7>^YuRvGgCo1=bqI#LFTfe^0a!6;J=xz91>=x$kYDkGW0p-qt#5b1vgHe04j;yt z&`c}CL$Tal6!&eB!0Btd@u**y=(p=FZaA@yQD(tl&{x}F0k4~~Vffx0M6je$POPJCET9Tca& z#C{zH`1@QkomwTO-VK>BTQ@_resPR@c^<}7LF>TVSA`c>F}Zj&kjH7XqF#4p3Ux6(e$UYFnM`T?6Uq$>q6DAPenA@ zmuB%d7m5)*Ef(3V5asIat|>W27=WyKHSe(MHm`TCA~ z?yLcutzFb!&<79pDWcUA3m~M&2Gp=mr?SZlIbm-Mg)gaq?`@jUwt9m&!0rcWkuDCU zc`$VEdLeSCE+07V=3rZ=Nt1@S;FZOjA+X+FH0zrNR?jYrvuq^d;otH2p!gCL$fn{8 zwKt?Q$c&uAk=M-ZM+OhhQ;BnT+CI&Y?Y{REh+o!+c;G6;!TtAXYP6Ey(v;S z)%zZNyI{ckN_4Q_Xn#Dfk|zE-ZqHSl8p#6P&}efH(Quk3{WgKlE2Th@k^Dc;?D2!f(qnX$h8gr?-y7;E(fwq|)yU&4}%W=Vl*(&=pFwC8k11oiR<&T<*iCXcOwb2;jv^Bf;~RgpF;zs9SsE zzeamqTzonaBO=3iR_Jc76iX#L+QQ*dzj@g2N)SC%o`@ZNR|%hUj!8>3-_xWKUU1}-*sC+!j&C?gpPjBSqS3F?EJQe(-HVgMS=R&KE z0gL6f_&!x1dxlE+k9&W#$@ZYWYBO=%g(?9qMv)0l!R0?6QGMqoem55R<5e%-@?Z_t z#ALvyuW6vZOil9UpcWo8>5Ug#wo&Ke4ZJ1psyJ+O3`y_z#IHqRg6}?ATxoBCia(vj z>{pf0d-)+g_Hi_bOHT@gyB6ZZn_76!?zO0;9fq9``*PsN-dw)LpTkP_^WSZsq)vtR zAa7h4EV9+ZwZF`9wxb;`nthWqjWgh?+C>a7bi#QB0bnt3BUcqDVe!~bnqv5gnwJ&u z(yJe6@bF$d;C=@b>vqQtf0uyGM;pAmx>_2zYZmDG)JWdvl;NqkVZ!anPbqP-FWc~b z$Xk0#+Bm6%a)%o5k=n&nW}VFSJzv6k8&{H6-2-?x1Ma=4f$Ixwk*D9MgAqSrN^S*a zj+%o{*4K#Fw!3mSaRl2oPNng>I=oVhfNAd9u%vVZPv3KkD|F(?;n6?#W-q|h^Y>ux zt!d%|OGo_EWrZ_^jcAtYPFr_sbI|>-^xb|WEK>-Dt1)A!et$Ylo!!WVVJq-B{*gSY z_r^`rw}GWs2=w3j2mw#2LcZ6~$#KRi*Dta3* z5}#;&5%9hV&$GOWJp-r1N}Z`tS-hU_9ehNad;A8~qH(O5FoETFt-zW<`P!`3JZk&$ zk~}9I#ir8<7}pX;!LOQOSbzpcrmy2t@a4BHt&m)F3KsYd#-J?*(gDwhqQUGCh`IQh zC*+I-i4e{_bb(gq(pj|-fbCU6>$9SNZqoy=X?MW^ zS6OtuE<=*9J=o~&7g1^8ZF0LZSe$BZz+CGF3kMFUwfQy|?j3IupJuvX_gU&3@TwmtNtl4hxoF{#2SjSX}F4tT{&l^#nHhy7#C#jUuj?jW5RX34H; z7SObA3R;+-=7Wt#aPetPUUIuP8hx&yv{f1ongiEZ%#p@mlIr^56x=|Y;;UU1lZ7%R@7hEF#?i#JSnv)}Lx zvGi{+UAIu?jF7i9E#tb-<{OGRi;{W&+}AWm*kBWiSGQau>Ii`^Kg_^W zQb0zB=Lz#8uJFKsa7=d>$)q?3GcVOp$mWgUa#daMfj7$v))X-1{nx>Uil!rli~A*A>70C z4R|W-!^}N#?>XpOn8Si& z<1pDIOT0IJ7L&5HtD-%`ciu@sWqb9VRC1 z^V*tjjdtYRnDwyrk|TVw&4$3Vi*!F?p|I&~GE6<&Bt1t*VOmxdE>izZW5VTYj>Ktm z$a{V4^R|qpf3f8CVY8_7@I%^p?;ZICM&i#uC|SNJ2jZv3@{9w2;h`+mJW*AkS2?Nd zI@XAfk5Pmnks!R%~pA!irhq5l0KydgC^HJvmsi zEPoHy<@X1bWj^rvlm#!{?#LB4Txtv=EV;g9HWtn5&r?oVvj6LG-0NftXcm`4Lv8^j zVHJG2mm}3a6vjX1Z{t%kVRU7<6i%KF$J&Qm=|L|qJeV8=g#ktwtTX^O#59A)of-_v zlc#vAQS97-Y$jtve*@~kcW*ZiX^+L(Wl?OGTo1vu+B`vH4yH_=49T`Ke9fviHDA0< zA*byqcStDDT4VypOtYbSr8Slu?WBPH>5@g|P7wBS5lm6q$W4~+yvNiS*ZJDPvC~?3 zIsPUsaLa*(4Y#FYry?y%JpgeFj7@va1yUybDEa2dNbwUhMbPS_ydpAwqRKq`{p)MUoFljjJRzHWrJQHOca zx#2i4yMBV64ho3|}nE%|Xj?Z&(BVi5<@wQ}*zx;}aQ^Pe4T4E+{IS z%7b681^;ocguubaxr24l2d>WbJj5<3Qtro!Sfdb}@Nu>^==9r za$l8Z{EcI+o|fFcrbSe%w8ANQi0S(Z>An0oRLz=A8TCQ<@>{kzNLB~ar#vC)w@z9` zcgQ8DC;R$+fqwo(Av2!SF|B3_s@sR3ZW=3wNX@aa?=2dW5`nKKg|f_vL$Gp>Ghg5T6AsP0 zEIgZ_M(wJ1;d{&=JaR#n+f{OT=0C=CPfQV#|Ab@Z6LVT0@eWpx{UoeATtnG!@6g$) zSK+}RE&Tq*81lJ*!dzYoZ|yYk&EqpP>QE|&`snic=wv)DHw>eO%Y((J`Mfc&6G~^u z*1(J#!nXbb zn)wgp+Aj}j$*48$UILdh_ z%idf{BebT%=KUEsW$q&=nph`JzMn~o6^5juBug{xRb24#|x_}1n<=y6S*zsG9Aq?j%2 zw>ps^(+zc^hH};OEGnBB&WVC4>%2cJt$(Y5&*Z~FVeBoa`8WuyM_0pI-!Bm8se~#U z6nLEcbHO|NBQ4Fl3a)pVV!Q1ngEu2!^NV|2+VGoh^vEX_l@#)sFTH_umzF@kvAcBgs;vrW4DeN}v5Fbv9=g0LAg$B(5 z6mPA8p1*1-Br^ieF7m)F-=q?U`Ih*rLltkTC3EG2f&6Ax3l*#)XpGLJz(;y?MdLjL zgzd!Yc6Bry1Y*Q*b+)~?3rbTz3Zq^u;OduJY+16NGSe5J`IU4`IaJJQ&uvK2HJaWY zNWgt&?)>{@5GNOgLEzI%`2Ok-T7AfrEBj7Fb< zo_ySA80&6Lpz$3de4p?c!u=NVmzhzZ=rK%KcUG1Mjyud>OKTxeY!ENS4aV11XW>%V zPZ+P>4f{;7;P=J*P zYs~xIR57Vo2d7&MX6NGJ_)6acZ!VsJgP+8~st;b!5wxG1W)6kwK3#M^dm&!&xJ7AC zZ;5a3cwnD-5$KYsjoL4hq4BDrWYO13y1&(wBDy@eCefNEUiYVpqC-3|KUesA@dmHh z+$BWoYP0_DC>$VJf(HLRg2m^QG48A_FPBZgV@G9i{vjRk9{o#vR-8!py!OC%>v3$n zSeteP72<*@O*~Z|iDlk_{Qj>ZM-FSD3*+`t<*|!3zVmzYvuifIFRVAUC5!y6@B(zN zwFA=$RZtmQ4iiV@isRfvG4itt)Xa{ipsqxAd+AM+MxKPK?b^6D=7VJYnrty^P%`vA zwFmk=n}^3f3?Q4)Zgl#8iq143$FGUQQAw*7B@soX6eUFq>bYl%WUW+4qKISiahCxjT*Hehr_!A1zEtL14(e7<#lL3NWNX^GNvZ@NP}w3SmRVrYEXzq*}y9Jc>g?A_UX=TR~|w1c`G#1 zJwkd1w(-c_aa7hA$ChvBz|0{V#Swnpv1Gah${m%*)J27`B`^gH=YPWD=G(&AH&>{s z@iD!2sDv1qSlHmOj?DuN+3$BW{`aev2ODq3a-o#eY}|3%Zg>7vr9ZK-0t~IiaI^nNg;~k&4;2eR2yHroraMTSzd8n8-7dNP>6BkjzQZw zIoXmoe)EEw*L{$-%A@|22JrsY38&xo1NWjhOtXCkUE{Lx%-X?x{eTDSevG72#oLrH zzzYo1WETzcTazqx$<_$=0U z)rU12W3l&T0c~oAv*L9Zw3wy}F5}}l=|%v&{*gtRqX%Nnjkgk?dy(M(<303RI*aZ< zY!l7>2J?ag52)<*19nff!JyTbV1btf&Ya#r?O`(T^y_GRgHv(dm_*EyOJWawTQ&>x zVynn44!Fg=8amEMV;;y*!S-4Is#=nwlwoQKq{eR^Y;qAuJ*XR)P&wWFaDSB%lOmMk%Cuq5?%~> z3+irX1&@8_g|tBy*t0l}=ZqN2-{2>7#BIbAt*WrMCRL2A8U}gw%6R7A{G4q(9s;Ik z;dYyPJmFCVhnw|j)+{YpZS{a{}J?@W;FBhr(3Ha}@VRgZ&kYrDvRz zq}w_hY1EbeFu3Oh@$=QgxZ-sq94a40J=JA7F1<^5(MphKK80(~zN5u+JfX8{Kf?8) zTv>A+!ae2Lesc?KxSB?$*Ijw(guGYxU?7;$;<>dj zZ_Fn2?R$g#*Q=0Dh9e)Ja71)CSq0a2?-$OrU6Dkb*(6;fS@Vyp37?b;{Bx!owLBR? zXGb0u&L^0WZbJwUmU{!=-LJy5Q~o^WRgv^fkUMmh%b|@rg8R9i9Iz!rm{T}V{OM3D z=zNL7|G&Yy>v+1T^!}aL+j<0AX@9CtHlD-LXC%<1z8tt(14HzSsPNAWkXw37sAndL)wO12m!3TF-Xd)MY6{;DM3B`H;LXaad|z)le4l)jR(Z%lRdf|7ZkKbh*jFru zUPDOwWy{Y7j=}%t7Slw-sXTE;AO33)1)d>93v$(A`1K^VD_4Sii(=aIK^}u_-hkT2 z|DbHN8G4=h1~FFFxObodhMieXkJk)fot3kMVSkHh$@U|nL^Nls?hin1oGo^J}YlknN6FGN&6Wy9R9ZI&Y#vy90qPMy$N4P!&9i3)S{PTgIn?>T76)L!@e`N94x-G(V!3ZaJ5^iDLoncAJ1=&5ERRg!q{)OA@8In znGE|NwzMH;d`ZR`U;1;z&SR)?UW4s@ql8{p$8+BvC#Y?@9C}}$P94;P5}jU%jqU!Z zllNTQd+Dn9#(WYxWi`R(*VBaGeQuL)^d+*h^5u&YjQHNJ2zcggg;!QP;uRZpiPMWc zls3r{k0j_(-rU>d|LXz&*>D?b-(=C;6U(uORG_;7ZBY6%1HJmagrohlxY=7577P1f zwtEBYvUVW<(bn9!_Zh@YyXb5)@PstC-jppKp2bo7)2VG>fq1&vo;N5Qfxh#nVoJjY z8t$FPT^3q!XUl9JykQV}U#ftkSr)jrPYpcUrN&L$dxKefG;3&O@YM}5AckL%ENNbk z4dYLWT}oc~ZryBLFz_FuPx&{`=A}DtH@Ii2u>klf^WJ zj6uuy7O2SCa-;DX4*9Sa{MWnjx0mJ6WH^$&)GhI4Ni<5V-wA_b9Km6+EPLDx!|^SE z28%zzy1t`%9aNCg)HIr)`B+q4s!!W~&EP+?gVAKfLza=tsa`bbni%zQ3;rr}!ksn> zY>pM6aY`T4tFN$=+I!wqdxSD8c4CgN2Fe}YE`89qlw935VXBi3uWEh_T3tK1UbyphdAAQDe%)nyjo=md{Ilg;YM5B)M!K*b^?2w)#>fRl~GG&`Mb##{0=-U

_zPG^fA4m{E#lTK?MfD*M`qFTQsIIzSBt8#a9(uW;< z(9xM6=8qCo|4zVZce~^I5nJ)V*E!T0cR-kO;U3*uoXnjz`9k}j6{KqBfbOSDsN=Re z_AOrvW!?wCbE!4ToJzw%E{Lymz1dn~$KsI_!s#*@(NSLDk+-X9uCRxdF4f|BmtL6g z;DS*6$b-NBl)$)0kDz|_7}l9Ti=zkc#mu4x*87;pjX!kwOnavw{;`0%5IN2r7=zC} z7o*iwkqTawak1__!TXadYJRrE8Kb4riUm{XoG=_4lMV^GtsBJp?09U@kEh~o_2R|O zd9>>7H?eBVVyOS^%Pv*lp-;UXE|*=vIR=TGaU(%&bzO(~I1=B@KSsFvnOL@=0UCZ5 zL9aYNyysKKeJ2n7$Jz#hblN!Vw#SaA`FQaH)uG^|H5g}H8p}#0(?q|(?!2$t3#fh^ zC)UjH5Qlt|!>DD^l)rT-ZmJE%OUe1d(e_8AYH!cCax0xj#zU`K?F)C#kLf11y@8|o(A6g1xy{3uye4HmgIeG^sri61^H$|-bY|hfn!SLtgQR;TL z4wRnt!l_Sds8acqaOL1;922O`S;hA#P{m)o<}C-2I1vt!$#u~#Jo?=s>6vek&s7Qps{Gaz`>SbpSZhqq33fv2)P zKYg%~3(CeZW=w~!K?Beu`UdpzZWOy4JQDq*@{I;#`iATA zqyK7!JHG$c9&Um}do*fJ_Ji$vJ-KYceO`RroY#HUqwG_C(aL}hk zG@RC(?*BIn21;jr$fjkF7vK)-IQ;VB79^=zqfW2`Hl@e&c#YL)mvmNiaoh`8q7@td zC&M8-+F-BOR+?1yp5$K-#*dvj==aJGhsM1llkOMD>GVTN8MRhin>&$XO&18y=e|bG z;{Whadj##d8Os4CV`#+E69ES znx5X!W2JA_yt&6I)Hth;GyeHr(t1N)`qH1Le;dkjAgd@39_4I;PS zM)-NEp=i-=MPK5}p!=RoI_QxPa(6c4)$IQGN&5(ndwoJY=G_fik3@099#zg$P2fv# zTP#n}M>&}iny5OSdnYRMo?{2;)sh>q@kU>A-))RT-JU}7qhbt8=+6gkjNzpQ5&w;4HR#&o{1(_o z|8bQ#+1mpz{#nA|F+(u_UKVS|CrT=*k#@|Qhd%g-^1Gd)uTR@RPcaDo9$11a9Yf#{ zWTXAkuQcng8`xf-$+MSNidn^)+$Ygdtlu>TGylxtPv=(fkKH=_W4R34Ib4A70X<;# zY$aSDdJYz>-4Czan2eqlY=FLvwzN9p z7?sbK#p8o!qRV|{m;EP|S^Z5C4Rq7ydPz^VinM2Gej(rA-WScJBK_=9L&e4~$T?=I zBy;0(*jqG!=7ep78*>u`zqvc1!`E0$>@Tw6;9M}(Qe&k}$~f=KEyChs;68K=227YL z_Sk=ne)ue9WxFTf4W+UX_8Nqu-m^A}q9#DJ~W*ukJx=eWG<4ru@L=Ec>q znE3Xz%ietVU7ZVJV zF|7`8`@=r``fU>Q)oh}>8wX%{<9^r>P(T-o4vNitCb47dXf)LuDSTda6Q+!OMWzlN zg7b7m{`RRCbzV)NH_NUFBX(bg@CG#+et0`>F+N9owYE`qx(YuO-wKL4p76q5gNqdo zRDUUvXEm8*4*JT}qs2^!8?^=HdcK17XXG%^{~9cR(Z!qJdg7&tz1U~SChR4Q=fY=p zl8UjD@Rs3zP*~Uj!|&R%r^ht*JX0&&Em1~AHA||RGE2DAD-HJAtU{&b@`AySBK)dw znnL6!kXOVOl9@LZHuro^8`@T|P_!J&A0+Uh%va*U4S&h+qY@7>x`d&*rBER+ zLiUmZS{AaLG@E=xp&^QAFOq>@!QHrK*n6lRKNo5zzo7`f!&JPs2p%7+ghd}yXnN3D z>ePxAd>gw!m@o|cJK6Bn+4Ja6ODWZx$bwS!c~UxRLFqpn@xPnJG;VMJSBAXcVBs6g zQgTDPP=EYVZ_M8P9I4>QFm!EOfX0>aT$x}_^|xDS_CH3uOrbO&^$x97ivYOM4Hv*x z7?|&jHhm&kE`9`FpP?q;0X9WPGrqj-T8&~EM7f5LGt5?9;z$N zz_t;Wp|baL_%Um{P}X(;m&xCTxvQST3`uYHv9RKog_fe^_-K|@i-*?k4`_X&9Y^Fi zpkhW9Ddk@T@N#79KXt;zqYq(bf}J?Q!wddC)pR+(#|Rs4??Cw{=Ok?&0&Pw8;J&&! zyj3-W+#fg5GZ}Y$F*B9xmPB&IWJ4Zo8-=cy-#|mmZsGOOU(&FDjz3|^I^J+Jl(w`U zhYtpW@aK0W)SLU1VqbK@c1L^qRw+xH=k}oeVHYK`zee$=0hwZ+!Y*lX_FDMq^B;J= zPZv)QOM^4&&)~?(EVO*Sjt!Sq!M%NQeDA^#F)gl*_H1{r+ z>i)RudJtUByZ{~M4p@^spC7;JO)-zxQ_8F;($PyrajPnv3BLgc_O;L*C3DiedV#*@ zy0V{fcPa?bM9V6FmYaUJI_cyo={#8nD2_M_YSxYPV)Pl<)a^7BCGUg5mp|dM?>f?` zTz4qzFk_j)Il{Q_!^nL~1V4;+#c%pjL0)zs1ifF%imywl=|X>4H{}@>=AVPE?gu12 zCPm

T4kBJ((3cF4D4qQt@_`BAy zh<8K4p~aHllsmGGraP)9OabE#JN_?Dz*S?vhz~RR;xVyW7<;QuoN3Sm)vLzxMe_{Q z%5deI?^U>G#s_Jyn`3c}pAAm+j^~%!M_|t;Ie_mvc?OR3--aP)j?(rhbJh{JEhMD(X|td`DGWP=1YERi5b7t?LI3!Vq+}7x9}E}rB&}s|YUCPp@Ad`)Z-$V` zG)u6W@f>h+D_yF~L+8P@c-6uH=l#3;#&N@W&F?mv?W@iwMk?~Ot_f^n9*7qM5AuS+ zh)KrHH0alFxX|OWB=@@=S3g$8bG5hNPka*`>N8Hdj^JI8l@Cz(eL@-^sp1w{Qfp5bb==!F; znAYPpPIWB;Hz!N>Ul`1@+iR)0(}zAJoAKxf6$B*(RCtxgu?e4Oyw-JkG;IjpJ^U3s zFRc>_4II&S`$O@VMjw>+|K|-}574feNKO3{-SV8rrI$;o#IgpStQ^g+YkkPd`XP@o z^+DS@caSXFh6*MIWE$t}?0jbjY>hJG?g6W@&(Pbv^2Am+UNnu>*Z+pUePlW7r!w5H z@W5f|6JTEMHrjedo+p(&!ZG{%OJ6VOgLmuS(|g+rm^R_Qc<$jGeik*V`oH1J(X&kt zWmX=Ak%hK=BHM(Yhi;>9)8CQf?{!qz%Yn@tlzFJB8mgKdgBLZk$>7xt+W%A;`#b94 zkAt36cTJUUpZzZ68prZPw-T{!8Vj+b8o~L{X?X5qMYmhc(A#neba)%%OSAQ?7<&$4 ztZZq3elPqpv=@(U(&ED=+W0{CJRAIY1GT?>cv-tCbf5f^-UWXFlOIV~I8_BYZ@hry z;_LXj-;ky$4V z8Xhk?ed&vR8l17py(deJqQGB08|UR6C%5G_!u-;WTw{Mzs$Jfnv-cZv%J3Hu{-d2u zr`|$UJqe$G9DtQO-jLS7(KxiP7b=%@lH6E5_O4e#@!oLQaah2=!|jRhZ-Nycd>F5M zpj3~cprw&UcduW??VYRe_qwfIp1+cBo!LNJ?{7p0BN={CKbQB97%M4^&}8`&yZCVE zNRIv%3HfVI!a}zq&|RJiCr)~z$PQV>&J#hZa4%n!ElZyXq zfPTp`xNg~0{(JKv+pSSUPF{?jcg%6j(f;H-EuZFqBQB^pPP1NB!NLV!VbI0rtZBK6 zyl!2gq$v}@Vs5nX>7*Wc&zXv$7Gv4^R;Va9O&3F|I>7D5Sb7`h#Jw*2nx9+}UJvNVxLo+8V0GO#ae9r@_$iGMY$P@|><_Iy#p#=QA>S_8c7Q%}3^)Kb{HnbhhNi83GV(mEL%{5-mm?zG6_;`!4lVW9;Zp3a0GhIMGy zX^FK>dojOHJ>5P(fSc!y;Fc><>^`qSoZFmD>o08M)K6ht(DE0{{NnNLLVt35t;w+) z^x&txfU=d_xyEt}R~_txhujzMj2eSKa&D2*4K?o3!w|>CY13Z6Zg4+$4*Ny^>l-aq zu(3Q2zcy{)pwZ7@;(=*kTo%C&!#b$uQh$Erx`g8nPNqi9v#|TS2zG_*V7Ku~KspT? zs@inUa3*G!ZQ%^xPtZ$}M8A!rVRKqO1>9~Xr7^PD{alx`s`mkY72YD;GVCLr((Z~L zAs3;Su>mv<(*RCDvA@CHtrlE=R3Ey1&WE!a`*B#@NY?+kk6u(*lUIr=oJcw?v;>Cp zpvm7rbwwz~+x(@9d%ww=hH-n=199R3bsW3qhWL2=8TkFV4jio9!y zanfJHgsVp=Jy#h`k9EVqU&AqG%@cn2U;tdco{B~f0|ZcbMZ=TK*y&CJJ_y_exlR3e z=*k4K$4)tP9iGJ{BagsxmoYTbWD`c)9w%#)CW3K|aKKqW`;InnTe4G}GS-ECDs_lP zJJLlReV%l%m1Om%L;D;*bk%p}h=x}ZEAtVo8NE;1Z(EKq$EZe}HPsW1%O{Cfd%Z)u zBf2ik$O+d zpe;N0(^q+Yc-Y{_r!v=}_4(sab21#p+FT+sw4=4&V=*Fc19v{V4~llaG$*!(ou5g_ zAiWeE$9{xZ; zp$DCsBabTc|H2^CpWrd-hG1W~jhxrYNrrp7vQmK+&n~DF5C15^lDH1?f7KrXY;!1V zi6S0a`;AQM=J2n{-JRcB zr*ZPcBwF}47wk7(gh%6CY33nilm>o;M+s5j17LjW z5m?iR*rSITuE}`7m9$N~{eB13mucd{^ETj?QVmyQBCz@SW;$`nniE${##w_ZA^wjD zFINXrNclR!b$t;T-nvYm)7$9!^&(+Jf(d`IImm4_eQ}iH7`V7z8&3=xf^M@a;Z(;8 zJio}CFY0}V#E~`}9lDHlJkL|+M00$)KOE%utrbt{ts+fR<9}T2#CG;Yyu$hdRO^|* z(#+|2zGxCzrO9G&SR#ZLGzwn|)zN$K03NaC|9@;Z2}L*L(RWJ^R8lV|W2q0=)i;O^ z?)ogQD&b=x_I!4AH>~rSjscdk(8qBXMg1gj9oQ!9oV$v4o;psc-Q(Ff&sY2yoB-ji z-O*=L5!keRk@`0GL`NA-ez{qRJBFzV36p!Hd3vBYQE@3fZ0#k^sdB`f5452|ZWokn z@x=8yvH0i0Ey|6{r_0fnJm}Uzn3dI!x5$j(t24B@vdEbq8pUAOiAg9m*1%=n19^2$ z0@>x}fOh6*nw_u)6Z(y1*I}kuV(G-@Zhzr>Rt2Sp&8BN@H=)l+U7k>XQRwej#cvhP zz=isoG*(#|LshR(L2`dQXN~yy(E#GBFF~ZswcrnGdNW^V5Abr;< zqz`BnZDwlno8okgzqo`tdJVvLJe7Z3I|1|e6o@x=mQZ$l9Dn{OivcDr!frDsjJ$L~ zxK#Rt=9ep>$tp9x5;q(C-rnY#MprbPHy-;+tnoYKlT~gI=L}hkx@S(1-h|VTZZi?@ zuV(nVzKXxyQ|8U5CUKFQ4_q|*L8b4);YdI1VNX*G{+-^9m#?!H9(d*Av+`F$a&U>z&p8zr z$E?R=-M7MK`%hw3XATWsr^(Sruj|abi7lYW6fP2_-nHZVo85xN^hQ^{>Te592|`GJbu^VM{;+Py>E z?HC62v0p@wt*)@F!Vx+<8);fpKOuYcSyCHj%QNUEN1b^jj6RqJRso49v*R9kYZgMc z;5w+xJ;0@f?XY5EIy-NZ!C~`~AuLD^%c?$u|3WLi?@$Y4?li>sic@{vxf= zH*nN{IGsFu9L|P0(99eso@P}kTD;7G;yn2p)zeMXQvFm|zH|X@_N#<~JadY+-G!wW z>S=k#LwH(L!PzsGNixlTQrZkBT=B6dS`D~(@$?UUoc}qWVxr@5r`vs=RJal39$54B z&=%29TYyW;hmeNJcI-DVhhG(WiMkgSkkXE7_^Q&AH+vZhbDIX>=3{zTTsRe0Cq#qm zks(aunfE{K%T}|aVA6*1*zR@`yh?UK))6z5Ro)Bs=XT)pM^7ZpmljA@zO~`m`T>-5 z_yWClKTdi{%3xZ0U93<_qSt-Dg5rl_p&+~qd@mxKM>fC&#VlgEY4o&QhvhQLXwA(% zJZGvAW-j>)LvmHYe{ie#YF4UHQ~w{%zc&>>1driA^_}cDFG!RtL412L8s9$)P7 zX~2f>LS5cb3d!~0(d9cSt-+4Rx5skkj}!Q?PY@c!X`)TlBK|N=iQk`>qps20#Nh$Y zC^BOh%3S;nM-w8k;Phe^^J}EayKj?mslE7o@(a;R#fpQT3n05k1F~D)aX?A|<^7yR z(iQ9Jb!CpAqZS47VQuvOKVRP9b_{!FZRQ|#7aFX%fi0BNfx!jWtC?`g%>kHj)`kNz z!dX7v6OYCfz~)(cXdb_fKgVvDS|s~m?L0FGsCT@$_FOOatvUirc7GK{2h_rW;3?7# z=QL@4sRD}m$0%-n3|xCV!sWrU{kTD8Fy1hY;Od`!x$B`DpZv3z_xTvot&lsUzFZX# zmKum9-p3%|vInh<{pVrt55n{OE24k&MJRia!S^N0Fg0d9>)*Nnr@y@uH{JUShiB_! zd&wZq8=)fHn=z8h-%P_!Wqm5lx538`eo}$&6^PRM3mS{_X>*i1AmMF zl@>F695{+xeudFfWho3j{SJD3G!U+=T8^X2I$?E`F-{m9$)C3Cap0ADdZC&HHwNl) z!(?Z^p3wl`>%zF!w}L916G^vlC=S{87Tldr(9i557*f58-e)i4+^*@oXo4sIU3>)I z6;Ab9@1D!y z!-Hs;QWs-lx%c6z(0=WlsQY;c zJ}l+MLO`@3@tMJUrLf*4IhkRpPc;xJGym#WP z=(qehIoSJwQF~9EF>@de{g;RRChlS5KyzN)6-HWz-7&=5SfV@-srUY))bYDPe7S`a8dBh8V|Pf(xkkn3_3+CqV{AHlfs(|R zqJ7vUTIzluf>%wW!bPQ2Km3hU-TDaxmF?kqKeW*JPo^~H&t{AdsH~1jQsymN4?-U$ z7rxW?5l70)ptjEhv}lRKSY8B|yJ=K^dUQt`X7q-FGMdPLi#((zcwkb2E(FzF6qDLz z*}D7;Xishg&Ei8e=ln4`^z=7<@~nf9CwZ9gpjqs*Y%l4&6nNH&Zs_cCee6-c?mV$) z8Vm~kCVf424KMFCkX_5uh5afA;F?Z0WG+7;4*uH%wNny7VZAo5Xt3bRw7|f-QBN8i6gtp3u`1vfR+KmS~9y zKKuCzmX?1LTDMoxDhDEq;d1!rOA##<22soET%7E&pGws>Vx;a8_8OlI!;ePN@!sFX z1#?pAV6Ts~T&lv3=g;!^&`;vwV`JdfZkc~xq=Cn4G_Xz60>^C4qZEZ;Rt{cBuRRR; zKm7`LwQ{!@`L8yr+UFtR(J7cWx*J{Ul7XqeMQ**6E}GjEQ&q3+Xd!p1I;I^Z(^I11 z;kJJ>!@z-CZcf4wdmXkfo`JMYO6ms5uurN)^XflPFV99u(|JjWo>6G#SWoKt$`EHJ z%VpPp3nMn@p^_@oFbftPFXnOPu?PxRjl+gl$#|~6B5A*uWy_c|LdNe-IJf&9S=x+a zGo=ciJVg`JH6!192GizN z11x**Dw*S33gX{qB(CX0r?X7y)$hIHElh-plI!Bvv;#2lTz^W@9W4Y_*HKex0V=9pKB0WOQ&=-W-0muLq6nxt*VcE90f##lr4SKj8ZEsW9SN z0_@N4gIWjvLGlC-+B>Ny{#AP@+mAEtQ1lZ{fp-Yw{Xx-h>I5z1wJzk&8Ik9J;epI_Kqn{xfxQyfn_qyPB_nzo= z*A8wT&H=l&dbmDa&n4#1MH=!URLmZ9klTBu!9)*(sS|ADon zs|$JayTRB#y#$sW>&xn?u5{u`F!$_cO9ARxbobtHGz(k>OZ+-udj4zJcwvWF=ygRL zTv^GsN4N3XMIkh6%qnbqZjHvl>SWFP|BKC%O!&+m8>>Io+PuhwcUI=QR*se1i^oUZrsBq0*$v?Hn*2 z&{xis7FgVe2`_e_#pJ#$w%7${-e?%TnOt9)u7>E8lpKpfsg4rMqY)F~~y@$@> zv|Z6)-qVs7MU7_7H4QASq=kC)xWcV?BqRHGu8 z9gu`Ale?rv;}dZEOarmof6K*7<`%GW>|)+AvlKJ)hT@LZ%|hNpOX|>-;d_53qH$9o zcN<~G4n8N~V9rF2vjZ&etdMHE)IrXZ$3n}$th@gw7_9pa*6xfdjFB;57^CS zbt+gCbb>~2xdM-pbUDSa85&fk;w=A4@Vy*NVV;Y4#UC9mth<2wwp@U$E`3~A6iz)x zeueGZkBKV7w(}g_7W$HYgRb2$VtyY1ZEcSr$|gxtp*9?Ty_*7AC%d6-Q!Lvygj0@f zCCiPLLwSemqV~~qFyZb+Xn)`cwtd}EUs=JWcB2w{y8HnP^J$zhX%u%nOQ3!=iM*ry zAAi#l*m>*KFwLWPsI)lQ4c~1d2|(SR!*){Bvy_2l>Rq z9sMWZ7uzUm-}A%lIZ2eK`Hcm~-WV@2VLz)9*pOsIJ+sX4G^And?@Y3*Ef<=C5+G=x zgy$^1O3M>p2oZ1-%1)a}cP-gX{kMkVCEuUmcXkR7ogO3Ix^e<*p9}yW%gw^&%wFj8 zwGVc${3tfexDQJcmtwyvEsk0>9%d1e)29c>r9M|{n?y{x2 zf}Enu;oud4CxuVLgE3|pz0HTs`jv{0-_%J~B-|9+$A8A%SN2heVzby?HI8S@O@eJl zw?eUZ8m$=TLDgG!aQ#;We%fu2P$PRDCjBwR_+f{g7wV0}_Jiis)oU~M_Ho7A-;1G3 zI3u1KQAji1W=o`z%lM;WIc@m)ohrvxvWn0y+4-s#U#u{|#phKx4AiMjXDH^)j|0(a zDZ3xj;SuBfNtjxM56{WNtqVH%YCsCBj{OE>e-=Q3`4&NHxryhwb&{V6!LZp1sD5$+ z(T6A0x7`P4Ouh@Ws5{L~ng9-oebF-i0S=fS_0R45kZec{WAiFuL4G3L_%VoYm~JES z>OQt}Pv-0)@;ttGPkjA!5;$ecJICW9_d&^r2GTxW0u#M+pqI%aKJ$Az=3LL9Q5A=Ip3Xwj znx@WE24=#$#q+_-DiAi->fx66vuW>_BIx_x1Y-)^I5&J8rpXWBZ40ts)0z|F(a1_l zW-XLeaAxP+9=vJE1l(6Og164H5;r_^;O$9uP`%L+b*|hX?Y6fNINKJB6UXx91Qib4 zkxw3p=Y$>#>mj7~7s_1y7Zx?2g^1(@>^=o?^xI^bzr`EZ)^v#zA7_d8SC_$qPwMP4 zVh{Y-cN{U}ExmKsMUAJwsPlpwWJL;mNG+W&Pn!pkTNc8y#v%Nq?w^}v{uN|!5!CF` z#QSz((kII!VR@()46S}Z=HIW=row~pRQO0n^9sfFX36C1{1%#y>te&~5^Afh1*L}x zJZXTdxT5X@#jLi%_lmz^LtHXc;07of@Kx+^Nv~E&UIyv5iQK5S5cdwfL)+XJ;*8BI z8R~`?v-A%sa?|z1zi%T3cc5=tN<+UnELSyrQ=EN60RsANyUuUfrtlPCRvM zE|uXau%RVr^`r$<9g4uQ_9cy2V8}_U9!pe$Rr!`A5LUOH7oHg30MG9hc-4Cn&Oda9 zW*E<;i6Jhm@-&<5KU(pmxxN%!T_70D@5cu6L412si=eS-FSth!goNk_a_HR%gOrD0 zWw$h5?K}sJl^#-c+!3Mm7Si(Caya~A22R(?fl;p&aiQ`a?hLyL9qWzw$iNS9ttE** zK3xKHjcrlqd!~3OJPpR_D06MQo8+hOQ8bzN6e4RS*nUEbCth-d8^x`3e?K)c@2=uDRRYWp02vOJxJ_#Z^Nd z7a zlD-%1Kb(d|^Dhfum9<#Y)SbS$&F3evn!L#;o-Y)p-DH3*uFCwv$)o(aQD0RI6in^|c)KUL40i zvd)pgqG6m|>WJaJXYo|u{UE-52bY#xVd2Yp5(QkG5ot$GRU5xMj71 zIMliX>I}Eiiy#*`r??cKEI-F71M`&%3@Kuay+@XZ%3Kht>Vs4K6p#F zP1vQ{jZY^la+3Nzp=8us_%X5BlMFy&F`Y zT@00lcPRY&ZNbE_MqJ?)i%%B~6w0FZ!j#mtob2&KxVXiFZUolQyg~aZyS9$QWBl2F z!%ryI(?*Y+Mu_bZ%#TK{#UpEnW7o7DkngYuLtL^*&+Ik46Q9!UoyxSLxKWtQ*4#2o z4lkPMaQlG1{ATbE(vu&6FXc7yjkh8yT8-tOhaGUC;#8q`*m+@S)F&FJ7(q2>BYDZr zGhqF%)ceU520k}|jD5Q#Gd$MgJpE#J)>OsUttt?lTMAttoOn;@Vj8CZ0gQ{XA*|N` z=i_UQz~gg&uwJQD^QbEmo&~D%nWNsg`+c;yUaS{-pU%YRI~HPO-C_KwXbY|@W^?{E zAF2&oDZS(Wn-=|9!L_E*w4-?`4vPrJW%bQasydxZ$0=~8-XTFLWCWpkH|~-7j1*@3 z{r^o$crz~=7e~#+lDuNdQE8%Shjhi|0fy8Z(T#UD=Hsm|Ry?DhC3Kl<^C^&}_l*r= z<`Hi`)}W2zKpDzS`j;i1m5|qHfeV-3pmPl$$+p*MPH@PwQjFTr`A-@^4( z7wDvJI3HRof#4qTSb3v}COFqp-M%Q6wuYU5YoKl2 zT>jnqlp=a%(C;N}6uD9r@25ob%yvxfe|(Wwv z3o;kQi$|8!P(iReMqa(c`fY}ksQ!>PZM_QNzKgJEWP`Zm;sV@n*n=_jG!DNsj{W|# zpn>+&IBd~sO8(spl{>Wf^^|dVcTJqo|Ee-<*t!GOl`X|bdb`CT7UTIr)JU#=mgStP z@D?^k-=^DM0G!z!S4=^WXnhk7#LpztJ@crmLY_ajT&E{-DO9!S6={E|6cnDEW#1i# zguw0nDP++xygo$>*Iv6VYC2@W`KmNLZNyCnN`k)xf51 zUZj0>Gc@e9#=vnKSa+YPIL1MngKD3{+4FOponxQS{&f*>*G-ocJT9Te@=UnyJsq`Y z=yA#K72@XuHDu!TjC?os=Hfl0(Ef`Y^?sX<|3zx?o~orrAyuicED-XYEFOL zMU`7Z;Ki}csN39KXr~BTRhlLZ^4Q~`Qq!Fq6K)s zyQINfpp!;&~~IBA8m}m^NlNE zRU zzUj|XoMy13Ob7MKz6qN9(}e*p52<`t51ev86hB+86`ei@Vr%zkeBJY}^ue$m?E2W8 z=V)t^eZLD7e&8JaI=v7ILgK|8k-K1JL@(_9ZM@XG*GBUG_CadWD-L1~H;eb=dvnL8 z0l4DSP5}d(sK?bIEdIVsYis)mk1BKMk=hUlUaE;XrH^Rx&N!Z1*9gJc=Y&x=r=pJC z1G=!~0mXH7!}GJgNxP*!gL7^ZvAN$wuBcMsVgI$0{f9`py-@|Od4+RPS|tp=beOMb z^}+FNBcb!6Ccf=dX*7>aIqm?H;!PRNoU9;yqKK-48h&d zL}FC5IH)cKE+mFvhvRTu^YOGWOTm-JYHxvC9;OkZg>#-I(#4y0@mWQCoYxqH(+9-ET*aQ8BAT=I6H`=3Ttup? z)<|1M#N*!XdOUfgAyzdevP--HlxsCmMWGY%gHA7`%Miq;Tm&l9NW!zjV{rPz0ID9Y&Hg903zna2#lXp<_(I8B zJZbQX6uO?_1J$8C``cGYFmd7>rN!L;sXA9j?IZoHQgWIx2i-R&)1-}g(0Sn?4Our7 z!zMo!zs+*s_(d|}%{o)aZ8`iuhRZvg%QlMRW+A(fN+=mANl0Y;o^yDktsSMLNTn@l zk&#td6%9%vDGh{_c+SyIOG|qpN;It2+h6Cu`#RUT?(g{Uu6yMik?+mda^flfw=`ba zDvLV;+;E58IjHcB#o#bY{Il4Pu1Q+Rez+W4?vci)C5F8I!2wzn;7UttHuA3wDdI`P zMMsM@7#4jMUS7`-pXy9U^*;If5Z~hAxg#V!L;UIY9r^RW%JLpPC3d(dDOO^)@<~w2|tiwaJ-v5W-x9_#E z>0&MHJnjweQmg4(ntzlU!&e?+dHIj@xMVxKJ(>)Y{$@kBO00Nh z$rK#)awE0X55+KxbpCCz1ZA{jP%oqho|u1}MwvZ=ArLOjl~Zmfc*xrU_W^oCijuUq5)2v=uk%13H^DCi8AHvSOn&d!Dw7v1nbIok0R@S*$RqgH)!sdc{nv|H;kLT7c52< zQ`h7qF()KI@G6mJO|1u_s`P2<& zY>iZetY`Bech4krC{M5Yq!>jn7B1qqks3l=k8Z)&@)j9h)6)jnm=ix8_UeT27H2gG2(#t|4_{R!2unEH;E|YZoCMJyPQt_sjyP0rrh%}smYwJ&t(d&F5~z`-wbrk+{-hLd7`GmG7Wl~|@e1YRkBAb!~*iz7xnByA~@$W0FvycfI> zbEbrYbFMmH@sLp6h)f>UZp8LZnLy*E(Z3ea*fSQU)(t?-_YUHOmOOG)*vb?2p9xbe z{Di!@agg!f6&jKsFE}V}$C}S2;^}HdT)H-#EpjdhhW~ov5XUt5p{ok&r_3l@u^gOI zUeSM*a-y@vCm4Gy8GB8wq~^!zH1h0j%9Xt$3|f4VWcMfV?yuLmb=Pj#GS8mN&)Z;g zn-=ew*B8I*E=8%u58zeXWLQu)izk-s#%(v$MZfb&u(g*BSH4?Gn)mwSy0H12%CBKt zyczED%cpxrTD)IwBxhO2g858+ygzOwg*=OgSqM-fWrg4Ln?ZOs5yM9hCNGC1TCaRs z>|Q6&AG}VBwfC&KrAY?sPc&1ERtxK%Su8+sF%5i_h&8djc(b7u%JDWlvVAyB${Nh= zvsU9i`V0wkZop3!AC@^8N=N?P!FNimB(ay9%ay;IA$8*|&O9N2q23*GekPB9iyn$G zvY9Y;)-p8lDC1idITZ9c87i-h$LnWT2<3m9AS8bRmhQ-d8S=fkN1ZPoRaRm@Ndz8x zm?lw3&_~^r=k#*JTz)vLFFf~ma2J=n5lqQ(rRJfXcIKt8;+&r_h|WMWxio-#Qn{s z(W>mE&^fjrJNJmB`=$HH?qz>|bt(#9mV6Xqvb)6`!+|W>IZ4=19*H^q8!2UT53cyR z1cNg3c=jkgye6f{`wi|wN@^aBeIGzA<|FW0)k;j5FoiGoIgBH-kHUentKgtMoaJWt z@V2%qaO+_yeZTUUH_W&Ko?b>|Ic_>yrQfHxNsq|b(HXaFaE38~_IP*j4nZZVx_cz5x8 z%BUcad09d6Z}ywAPrcnok`{^Hr*F_mZ>`xUm8!Q2* zr904M;!#fhYL3P=i`h2my)byZ6t9`KPCVf_1NYB2hn4o~;{FZsH1AX<-&YhVCq7k7 z&s~MVX^UX%7I~C*s|5?2i`-!2gMMd3df9mhJWrdmP<9*kmoGzZ(<0SJr$k*(kqbPI zVeXs+n)7EYCI-#qEPWNp6E8Qkaf>IvKPB+oR3K}rqch`g^X||xIJZ25;{N%!c~AoDw?R$Hm^K=gfM0!Y99IC4@NqJp*R7$Q%}=Y=1+L{{kIB65{lAW3 z?1oP-orB-=`*LGa2(+!MhBh@Lq42~N2>#Gc9aV#Qtlcjf`oIz9r6dZsJpY6UaIqfV{^v^z);i#r6HR-HjC@lO?N#m1_gak*$3m;ndxo&(RfuKd+fgT;bBVr29Vj#0M}HY7W8aQG2k z@Y@(JUUx?KG153lszPiC)&VOoKMXBcNAfaS*fo3;yM{-x``Q{h{mKI7_F95BFG|y$ zf(~$7b`rAs?}C@rIb4ySQZ;ULFZgn1I)2;wL3k&tz@2(3*m-Ric?WDjRI7o%IhpL6 zbBG4UMZ(jC^KjN83HO@!l5WQRWBcRx$=l)wmJS|Ezfx||nC_8$KEa4IhN|MCBXikN z+8u7b&14?B4`wLlSN&%@6jT4~qeDeEL1$hUEQwQt^08Uex-d=jJ5UKbw||8zYX{=2 z8QW>|&*|dHzk#Bj_g?B=XUt!U|Ls!P1czIvqw_sSUF_tTsQ&o6`I`z)4> zy)N{4@BmuICZltiGQ6Hx?ffTmIFERlLMxi=S*<;X25d0JT-}E-pfZ+ErVixyQ+?@L zjwim`U_;{hG-#Ne2kBAfyr!cOYDPb$;CVG-iN0};k5IIJNl)ilk>!1@NR<(>u;P5hJ`)(=Z$al z>E%7~cUcc?$V}oBt*%`3T@g1Ox&Q(1r-{?9?c%JqP8eGujma@XK{qTHU+JA<>BzS* z(q$kISj8}S-z~_^?4|<`BJrl!O?Pf5hLOfer>*T7xMJW{x>Kf&>c%5@nA!}|`udWTKG<`RMLejy(S(;PR#MT;gEY0T2KcmH zhtj#v1VvV+(1le{;wMvWv9gFfbbR64$S$z1Z-M#eVri+*KJ0O3oiKC$KA|;k4lcjE zjE&wrhWoV>`0D&@Vd|aTH0aALGU+u9b6axA#@Y+#M@$zhAN~@X`&;s_M^W@~SSCEQ zaiq}QHfpF=ojb1OaB zHiz{?{Gimh4D|k}(uyuEym+BTJnA2fRwXIedEc`7;Y4+=T^7ob?JK}y`B2h5X9Z;k zF5$Je)!;DW3)kexpz%Co9JHWOs8*2Xh8ve@OZr|Muzem`iFe5;PL`jZc){Du(<$hV z9!8}4;D#5y@!?D>al`He9N)v0)|V9E_+TR*F=rtRG6?0W&;NnVWNlGrwK$X^1N&JN|O}!0C01MXY;5 z8vc6xv%WxhUHV=~%^69@^%Ai@xdsasEkw(YK`iriEzQ<%qkg@m=u-S_e$lm<=9eDj z&yMk8)2AF(lb(kGNeQ$s$P@o;EQT^Uf?3wl;Bw1|Z@GAbnDS8=Vw?|;M|cP(H&da? zQXcER_JWk$C~}$HkI$cv5d&n>xyQ>RAiux>KAV~2Ah8%erSBoX=Zeti&>#Aw>Y-PC zDtbsI(^V;HQqEt(^UGwQ$5lg)3?3}#-~T~Rv^6kEK7#jW%VB}L0)168!M;sTs+xM( zbB|}w;i1?JW-&VKQKHJRE7w!>rhF)n{V7c9JVCQehCz#?H0BseutDV}lx>s2Tbn{T zUUxUiDOb>`VLBjF7DA_8-G8d!n-IHu=ynwDI9p;yMVOUdfNvxeC zgOb92lH!aMa8gHHKWiIHjS45#7z0?A)fe?V+-a`yWqOeK5!S}3;c~+PU?h>lMG9;1 zlImFYy}z5Z!pyi-p&neqz3JXM7jel_RUBoSfJRLd_~Fo8l(*Z+eQ$q(w*6*&Ch4>= z*((A14N~Ew^D`-++)tQnCtd9m|CY8KyFeA!H{jCe26%7t7g#eg3j3U!&8pj@!S+xt zzFx8k{r&1`rqduEH@Ss^r-x8tk^`>~P2*qJm9fBXB=>tT0FQr|Lyap>3YXOta7WiK zv58GFYq2Je9N8`eZGFjMef02e>}qm~dWeUL7<&Vpl4_XsMnd+9=05biSfrb!8lAh1{qDswmS$oC%wOqc@0m5s5V zF#o~W0qER3G zZ+SIsotzK$`_H0ybr_m@Y!y=*blLU4qhz#uJ^6IZV!K&K#V2=P2s3O(@tvv7!t&BD zlHqg8Vc5*$5{sQDDDZ6q_%qzeikufqW`i{YBd zD@ZwSgkM(c3485w=|ox-EnYAjwv7v*&XoSVWxTm?QhiU=m~XG>&g<)ZSaXzEzHN%w z(W?{}oX->O*9rJ>au|FVSBPCMEBVeGL%yoAhtnR{!J>n&Vff@ox)o`S_FV>ou0-HZ z@~#|^*#LX*9D$q9^w1%xFNs$VK*byzh7Vsj7TBlS#_>ML!fe*cjY7lsiB(Nf z55S|-1%LPaO!{8Cu`IeDzHi7S&9#%+ML&~9JI2z&#~q?MSI{O^8Eh-u$_)a9g!&4R+Obj50!@3`!uIqeEauC_qY zq))=^@-uX2STZ=v=1Qcd=|V(|GvDfV<_mYn@qcPBL2cD2usl2sM;C{~=L-$cK2#a# z;}LLe3&JeD33zecGwSm%o0Iz3(b$K5==$nKl(C|dJk5MbdO#!G_4CJ%C1zOb^@={} z{G<&BuTk5oLdoTNdp@fn;;^1tFjU`wYp)2reR&DE-`9tSdOf&#pAnCLZiwoAe1w#} z`RE8M{qWZHc5z^H zHW`K-qeH4g=+^2e@!A5B?b{-GdCx5lprhI!f&)V9-s8B34RAfIsYm%k?%dn$8of0^pZL(K5N=xMCFA__yss_?^JgHf#Z zMWf}>aA;Vy=A_)sJ3Yj zOj-5>Rs>FSUb#etb(A;za_^XxnWXqzya zuPcv6*f$5}HZ0^d)>`7Yj56wyDdRQ6#^aj_!D3qQJal#I!TYT~LAl2W^w|(2*sHWs z`_ycHx={}=AASTy?R%kMpc1NDz7VE;*pA=s&!@4M4LRkN22{LJgI3eIXySJU%57hf z^A0VRXx0i39Fsh@vbd6y_v=4 zntMc>AG5`s1C02{?;4USVH|o^nX>j9;x;?ym z*del)DFka*OFZeUh4&-x!Vb|9%FBGjq{s{`tes59CtaX)hcG_Be>)h=*nQbp{Qzy4 zmd$6ZS79G5E^KL;w(?1t+6LhMB$V?x^C_KA9W z9G(g7$5JIX+p>g=5#_wTJ00B*?}XZlDfr^|LN*yOm@Y4E0OSJI$f}Qr3=r)qapBF5+}$W#d}YUxZsB@M&`v)&gnCvW#3TARYZ+rTY{#`IA?uM?1XK0;c1Ug7bV^XO- z&RlL!!%SyjMB@xj|8YS))4#6DcXBIfYyE~8RVSXgXbDe#^_EgxRB3_3R2Q?s5;Q$E z*k#g#^*H@%y|8NY7D1+g@0PhU#J@*zfuYiG|cnT4ALG zd22J^v_%xeAK8hw>q@JvYQ_rPQ@mLW)TL^p&!pL`%C+AX!Pb9sM(jSpcD8GEVT>zI z)mP+DtzgXgqQKumRWYr07upzauEf#tB$%PUif;>IpJo~Np7t-;XSLASZZA? zP+B4RjlN&?b#Wfrr#?C}L0)pbeg=4w=reNSg)JE3|{Ho&2Ms8#Wt@1^aKtiQUPr|t;A@MW*5 zRVh^bwsIb}yWfGg`lnbXsIQPWrn~CV;c)!&=8530*iGqqZ^26pqb;`tmOM~o7xf>4 z>tbVk7IF>h*7tyKqs`&A?l?GJ)Sq8WOyQc^Fu%&M=d3;&1La{o|tMq79Y8t1F4Et@J>FO?&qz? z==;v}(_=H#EKXxZ+xxKAyNY!COu>=}stS+r64HjAg2wuI;qbW6uzJ!_Jo8(Yi(Oxl zY!3}CGI}Kpx;{)Wm7T)nI*t6QWtTADB!KkU1HZfW$=As--pN)d1S`wV15I_chnNVKtE0&3pckb3VP z!~}IyQPm%?N&6;ZqRHCh z&=Ty;OHBW(s=nE~YT&PIG2nBGi>8e-85Jx*O9NfriV-ZoWEI4cJIowzfqs4Cc+uVU z;G*G*lHg6;^Bxa#r^YMXOH zIA60?viLwxuGpH4^{C2;Dd!-3>wR(X+V?on^s%7$B$vAGda~f)$|2>EFw&?uQ$PfU zy}nhUbZIH~-*#DyRTIf6YBsL1OW;QNPhe}k5e~|XXN^N6AmQS5wl}*5KJG2#fA=Kr z)AGc&H47nNgakB0hOoG+Kj&QA$91dAVEP6VEZt;?p*^;ON0*v-XFv(uf0qt{vXK~f zZ53Z=yDe&&exYd@%J{@&I0dir5@(xk5v!$l@uH=BNK>f~H2jjqr^}u~hE*s$kKTwD z2P`VLnW=Hu-q&IjS>wh}hWKPa4YW-3WT%*Hs#BBU_(kVvRq8Yj+|ZvF&r$>JVb7R5 zG_hboE}R&phEkndo%$F0Q`gZIXk%1LtxuXcaJmsEzaBwt?I8H`v@0?YJo(vs1nuDgaw}Pv?+4WC`dwGU`JZ8K(^5+rQ0$k6TFVfB}{Ncqe^?+p` zxv7l;(r7mns_kEw=-eu%i!UPoiIicM`vfh}!E&UeP9n$7*NQd%UetQOlChKcbokO5EDVcu7}lrc2XU=r3(qn1H!>B-WbM-VYW6mY`+KX|+s4sz zyt462J$$~5?--Rv_ow12)Fh@VLk*7)jue@tez^(Ghpr=+>3EtEh}a1e&pxO}m;9xy zJMnV!A^gf@8H1?;cL!n$?F4ySfq26a6#ai^@G3yYqls zD!6rCy-BD!UW@pS$hYoSU@M~h6wkxH33k3(o_%7l(A_J7XIH`r)|?ZK$jAevVwp2E z_QDCS2@zS11$?8pBURk%5-*_i^vNej+476_E12)qchK_@5TntROd0IFA{zB10DJlj zrya~C4Mn%v7EhZf)=MptrzrKK>B>Uy9d9lNn@X$jA0mW=jO%xI?uK!8!5+6?GJ4*s zaKX0}MgB&xwz2slOLpjuW3?Jd_6)@tb$16V744OY{Ivu3@Vy)rdcrs+zZhw@9OLlP zTojMH_*o4H`D{kf1}_P$^VT_}e&3xaX{x`*%r!R}b#8HEFI#7iYF+eo)7s&0Iavm` zNgLfVqUsDgTHMFNsf`NplZpjm0?v!#XcNf zA_W0Ul{_M*G3U2vAkZdojdDk9llb)sx>?|k8k*r#B1b6etJW~7eAvRcRm+YJ0eF7A zY7nKXA2fMBfpslU6h_gMqpl$jt%pYKyZ&%!eHSy6xK$UEk%G@x#*A5VDMO@1c>R-g zX4kB}F}3)RWmCG!A5%LT4Pn#mOb-M_;VB-xm3V3z9mZStVpi-JkfHRZ3ud`guNj|M zys2SNDU=I7Mx}IPd^^yJSjy*mx(Ic=e!wRFw8B5qKkqlwSQ^hSygf}5C|SMlQkF58++D@-Rcte)?#E0Ef_ch03tGAusdd1#_>LXrkNKUuEI zMueRQYeSbjRbJ>${eV7oXyUPPZr3O*A{_peVb?M#9L{zu)M!@0P8}?K6~CbNMo$hi z!!A+@iD~Da)yM8dYm0Q!tiQjCS#!DTv>z#th;+5@g0~~7gKU<{^=lG=K}O&jJbG#B zeEGqv1EQ^!41P;>%a?QDnct@SKlivL^=tU^a=SvY zvj#(9n;s|1uhdpbdXx*a*OK^XW=x}x@~ffP1AeE1tdq~}f*x0Qf( zijk*N+4}+y!d%L`zH#|bFz26Ty$mMi_Lp7NJMl0ibuuHX*lGVr+mmuEc%Z0ba7T1$ zq>9UU3se|48OjC=97!Kv?B3knvz&nbc@}K{D;ldZrG6hOihllH8;bJe0UN1^E0lFf zC?nYw=lU0;rH3^WsBX*&w;Q=Nj?FAJxsT#Egvw~UtrD3Kl#bRJLg$2(AkR&Fi#cH zWb3uR?i-n~0PR{S&R@Fj5IuZyhJ@O4uHPE?%kX{e=$a>4a}8R^C_^M_IQzZ^10(c^J3%X*@i{4t0*WoO&~){PVx3Ct-xlH_s-{~@uDp8L!{@#jYbi{ zADozhb9Iepwq?tLK>NGHdEO^P1u4(F^#wc?%S8*zg*EuB0YB=S2|e6EF8h$=#@%#5 zE1zjORy-j-yI{r|I;|kI+VR=9JE`-uUXj>TXA5uUHfhfMFyyF5iTksR=GmioX2>*Y zV5m{u=0EP7WSStW=k$ogYC2VKID!21xy(=KSF&`>IrL(219_Qe@4Koa=PkXXi}kJn zwfQQxH?g6cTgZkAez<*ieWBa#7Ku`h=_wDJ$@2LakjH=QOnVW>McMgpHyA2|r(nA; z2AD?%eT2xUJaoV?%cvKC8~7pxN$Ww^=&y}MBE z?@R-KxRZoV(JYJtMAA;H`b(sBA+jISa%MTLe&?Tw4sY)MR>|jeo&0`W3UcU5MM(0^ zD#NWKtISV+*rtto?Y10zfhMF`1M((SBG{f2qHhvEcm$Q}@H(pdZn6XUL&oU@4qvJ~ zL)mQf2T*L8Bp_9?OW~se8cuFg4i?+4pxKd9J}T+#hHJ|sEEe|?oi6l|uGkO!>`1-i zXK+CUvB3jZ?;=fT&Rtfei6Kee43|J(J1{s-x8^b;#dJz@;c$F|opV$#GERU@2DTI0 z@c?qa$B6I*KR@`vv@C>D%fCEdmirz5>+SBz%lIvWA8D-+E~8mTm}h@gZZ$qAG!*fG z-O+UfC z)qHiYayB4(ZM*UxKUNEIu*A7}WYr5=)pd`}w#EGq(@ITejNn_k!j3k!NMIAQ2BE;f z^NS_?HR{-sQu1sM-ALx%n8h&}Vdm~HHUK}c5J9Va6AlEvJoW51lb2rh5Pf0vL0Mh* zm{%{-*6HYqMtwyQH^r*Z2$9lO^Skr?sFinfQ!YEaa!A5Eu!qMbukRz1$op@>r1RYk zN!(huXDc@lFSXGp+MPlhGSiWwq2q#+F9;jUtI|F8X@~uK<7GZlk>zLleo}N?k994y zLDxT=UW#!E>fgf6uhoU1AH0lC3N{axhX%EI9w+3CyKVNhhvju2bog( zcw2n{zPGshYFmocYu|d`dIr&xo8|}o37#~6EBRa7xsLY2*aT_##V2~;4F2d+(A2U6 zo=t-vmnH~6;@?3u=u!E6OQ6bYA}d&`S_dY_aP?y#pF6{=<5jie3%?c*ZUG=C((WmY zWIlZtIwy$)I=mss#UC(T!#&{|rv4P^jMRj6FjbSK7<9es#MqZ6Sp|QaB`w>%V))R{#-o^+b|ZX#OcT6jHz?`ehBGf z+Duf2@kWCMxU}Jv@$y0XPqj33AH^Z?hzFNhNEz0+5W3oD!cg|5Xi`c`Za-1r#@WlE zXjM1u%l~z8L3$<7#0|Z9?doV@&bK%LxiwCq<8;#6XQm@%aO*(_Gx7U#nL<%We2qmb zj}t7qK-R3Y79wxLmC*V1?myiNZHmLc@K|~C&7qL({7bbIf$4|Ad547?l@}#RUE;8O zl)KF%ksM_GHzMnaexNZfZ@uF@^WWvROxMoCF*s_L!HZS4hvU(bhixyj7C3FfI*5mG z7wBnHUqfG^xqNy?5K?Nd(Sh%tP4BeJ77R{o zAAEw5%KoBD#{D8X+>bH6A2mgtt>u<>8nTD9m!0Iev_P)HWJf4F68ZgofF9LiiMq>| z8=5Cw^4NdPb{Xab_pbgc8@?)e-#nwi_HG>Zy(F;x;s79>DXO=MdGT-4GK#`kHLR}% zZ$y59*W*f)l|ch_xI-0vV%7?26_o0!b_*P%%`fCD&cDBX67_G2FHqqHn~gkfRKqA9 z%^O2_CmOwpD{lIvEbEtJ#T3i5pE4m#?D83V%a>@0gr2sofm4Lbt{#ZzEZ(vR}_!68}SUTr!dcZ zi;#@PRMEHI-`!6a&^EZtA@;^cj;}W}H=C6a@m0z9hhp5!l^D^c1c$=>DBOH&xIy@T z|D98+aLFfVnCo7PS-TzO2ZM;g9Tp!peorgt#NTcSPvIQbzGC}8!G8D81`sk_sgl;@ zya++|8IGgu)OJ3Nq7rk^`%j{p`_2S$HlG&z>UBo#*!(#vr*w!gQJ)Qe1CBVl#j(*_ zVT0>t#!IMy94F*;pLdbuk!jZiTkq7vYI%(&UdmKFh~Q|m?jVx{y(Qf~LAHH3YA;nk z0DROtkx=*XBvEt4SEma9_QH)~%3XH%x}db7{S|lL=Ax7r3oRKArI6c+4|dfP$ZEpD z*Up7Tr<}tOCqwg6xik*E0=o{>>oRK; zjjSl(R1SQQhtKK#rQ@CSp>NN^3ATqj+E;Ujg3B`l+_A@-CtevlZYB<{guf{GS?Kk7 ze^kvV#FCEB8Ekj*f(-Hh23aHyH*8HM^0Z$F4hFX$R4cP|DV59ezgiKlP-i+(=N*ib zW-m{dMUP!ca5$4=Eu8CRzCWEHqKjY%u~o;vPZ%w_pR#7p&3w}0Xfh$F;-pMstrq_p zX-P5+NA_Ge^V~lDLYvfGTRbT4b69fW?@xn$9rgd94R8oD4ATO1 z*)nN}a%H{$$8#FXh+ml*{e(s1Fj_Us;GxYN zwiMo9(h!CDo=--9?w)p!f>%zQp?jD>!|cY*6i_E~mzbtfX8hBGNCo#9N!=vdu=`R~ z?-@x?j><>6)kCrFqcqqo3A*fNfK8j;L-p*rmOkY*rBc<=(ex*^tNld_i;i6v#Fs8! z(9sppC$}(?P78Zs;s=j}9!s2(Y*j^PDZe`%E`%LV_nDR;#gAm7zo8G&VlhwRmfN-d z!jZgYYO*+`75unDRYL0St^Z>m14=(>>PPH$UvEy%`1UI}gU27^7lS8Hx4SD;+-dSq z-J3Y?_;f<4Au|CtA0$-u)3G#;{*=IDb@`bW}x~~Z)kA(v(H&<@ZE%~|wRYfrD z>U{v7!QdvYUgYDknbKdq7ex=LBygVJpmd=cLO)X2+xgx>WNj?UebC;7Uay$VfBi}t zPojZnF}rffW##{L0XI|8+8|AIkI}8O*Rq?CZl6V)f$y8yHt*-MfVQn&HU-wBPe!L3 z>@R{5@|vcuTmPlYYn4exw{<9`?{g1$28Ufv?12lOA!3~9Qfue)r@&l?(5SYOLl<9> z#M=>&@@`LGWsyf69pf+Z6Z~9vFy^YkeZtdXPY*IvC_zYbY_saS5m)R`EDqoexA+7! zrSe6feATiHm2y4hU?hVl^P+H&_4->Gd}W_};=+p6bAbivov(@;jVXX#QnbG2MH`Rz zE&DjW1uHDxJebJ~#c-Y*<*?2Nrc@QX?i1_P^031ibg|mE|M`|taOMw^WiqwjpHlSh z=h>OTJU8#UYz6A)c|g9cpEv?uye(KF3%aErzfap1OJL;A@?}0l@-vQV@xqMV$&*$2 zC!6cyc@6E-T@|yk)WUJ(E%|Wz1S3XvIjm=&tDwki+vW<`GwxWb(1jeLF?wh+8%m>@{{qTI^ zP`@khy)BbNKoV%e&~GsClQm<}0-E1z^S&NGJ>Ysy`SDdZi7%h{VWbVWzE3N*s0Tl} z@yp}DV}TZ9Z#_Lcg|Pd|JAxJl%3>LWcoDAyR2BMFKyuOY{E88zwByof@D@;K-Dr~j z$fsWPw|SoYGw|MYpXHZLwm;5s?qI=Q_mLuIw6||GI3jzq=7ze5Y`k9VJBl^y8qU6ly_!v z7#rstCr5_QAg$nm8w=J)^u4+()FnEsUOPgTvZICdaG`UKF->R<`~WR*@NMOd5eT&Ww7NHd&t8V@~@>4FbpTI=#UxQ5yH|^Gr=9d!fn2E z;#N$^xom^ZlTxz$4L5C^KNfi9$>n*Y8LDrBW=tR>u;3D<#5un;3&?TU(7BQ{UnNH@ zRvO39Gm0Uq=cIu2;=)7C+edCK~mBElz{52ANS=|V3mvE!PMsE&hn-Y#g%VnP^4 zIxw)3NIIwM@tY}S=qjYc$*Q1E{U^Kj%*xparFh7&Cw4=p4P4f++%Y1c_JX20?N1|5 zh<6x9;Y^p1;}{e)UmY$CwpZ(ds3~Z#t=%|ZwwLi5XNmtVGnRcHpJ*>W35A|Q0kyW? z09Gi5ho2h)HmdZ3!dCuacm?-?-WJ*FtVCI0Hl5Om4r)q|61e=V=)iYqn8i0+_KMx> zANVe1kUj5!*g5Bk(@y@5@0u{()bxYmLCW=KTYyWPMzN1Qw~WLRdB}m$?&XotpA%FK zrp2tRRbZPgr1-#m^+E&IB;}e!a^K3*^Osi*zd z8ykq?XgaIvZ4D`R@$HbxWBj0hFrnp?c8GGQ8TdJT81{A`*jYawi;w0kb@$*Bx4lI#hEW-0RkK-VVFT&B!WAt#>CKN&`z?w9JGZ+q zP^fenN_AtJn!LlvZ@v?YFI3NVd=jMLDIatEecpZ!cyP&FVaRr3_fny9SU$d#x!cU> zOH)J?7H$~m@(3f$-eCipM^!1ecf-A|j zFpjalAsFtQnC5jKK*aRNiEBLcvsa(mEshO196g=F9e00?XTUt$O{v1EUMVVRWrX9a z_fVdgb$GfRIOF{`^Wk?=kY%IhBAAT$!fkwjPayfRvWCW*@s~9Mj0Z7HG zhpi2NK3ul(95<|tTP?aI2g@mO+#cax$B`^&z>sb>F@D0^7)DgItHa z1B?r~)!y1pe3$3~lFLxqu3ki?bxkjMD*6i_41;P93Fz{@5)_09N-%*t==ODm9fkzcngpO5_9j*Tb zvP+NH_~E6%fn7s%8yU<}UZWr@$7rp-0+IAU6#gQ#`#BEGaxv#A$_%7-{+rOf2D{WX z!hm!KJ*Hql0!cUPs$n)S%o3If;stJ2~ixoO1g@($`g;@TF zZ#@y&T=u{euD>-gbE*`D>>4Z_tkco(%yA3`CjhE9`a))1D3lt8xHILEK4bZKA6fja zfas5D1vcem-n*1EEM9rdAbTcsP~*)&s31?IUs2Di0d+T4Q{t>Qq2MM1#%eBSwCI2e z%gVG<>sUw&8citH21~-^kGH*Cny~tEw4xu7IYUX{-yYleW0s_0OOhXm-R!rU&Gf$aih#(L7|=(Q~cAsu$H9BK80 zP1t|NN{@sR$ny?_O_zaMzZ7Ku>Jmy&?=Qr1U&*(+wk&m?xRXji*FCQ^3>yA31GN@> zDw^E!<)6^+`Cy-N<`C!#0IY~0-VD_9e9hAoz-OqF4 zr}31+koMYT^1lG>RcEH60RK}I{zHNOL)XdO<}sUu;{MzjXr3Fpjj1RJN{I@q$SY|Q zh$#umiV`S`ssKRz=j9Bp|6u_CQzw)CpPqR(kpFJ^`+q48(AXFFe*L_tYG-+Mz=u5l z5eLBgA9?=>!hf;Y=vgoeeYjC;{=>Lzte=`2t%SQL*gNjDF`OjXRS82IW zBL#V7Nfk+Xx&K2UFyQ|x`rq&M-y#I!1^)kD{*Pz?07&fr;Z)?r75ji#2HCsv8L!_(c6ka_p?l zrY59XEocdM=$eh9vOs9I2^L|Bl`9m9NU4C13S>|yL&-ywZV^xgDNdu$^HbpED*Z49o#~W$5N@Et zFxnWKB4K_(&rEEK;XH$J93iq;(Co-@d;kRLD-{$=?bdu5=!a)E0Emjd zUfGj@m0a9&^_ZiF(w65QtX}(XMr)}kO@B4B;(^ZxhcPFD*8~>PZU$(%%q3^B18i}M z36jM~A#^qYQd!Lq3SyVMVRY)O>LII@tM^Noqc-=!$hK(E71BnqO2?WVUC`J`RikWo z#MF7b>b-jJKvb+wp}#zp(rf!*`{mS`$Mmk+&Bb!@;q+|!Naq4t?eWn| z2cVKF$Qhf*ftX+Z9^aD@SBS<<)~7-*NR^+trzw?PN$0< zX45am8l-y1bMQtLdusym(%L!q!;pwriW)jiv$*q#twxEAOR%XXT@L|lR0bp#Z*IqX zCBYhr6n_SyOa5e+3Tr3tcy-`=%_Jo#87t5?NTj0-@)n5KH>4W`jcHkIZ!rBrK~-6= z>a2@)&~A)aP?JMyqchqzSjSf(pnoL_EKLOq{DIp3h~hMA0;Uj(R4MFX{AsOkPowlb z&=YsRzzY;@0NM}Xqvz0arX?-Vogu40vZTlgCu>(&E}jKm2WhI zfO^4sM(^$%;;AUe-dKA_q*Dhto=3GQ^9b{YlvU8?X{cH;K>OJT;Q<0QSr!abQo?bc;IHc0EQ!b@=L+8g{B_-cTUWF!_aiN zLm-P#q2@XdsdIvGq{}G0Jo+uhiu-tXXj7unJp<-wL8k$}3!B&9h)SjRO3rH)VhloY zQ!dT@R00Kzua89FsX89i|ebn(hNfz?wmdWN$sMt4ROwjxIyJ$ruR zP<^#bVwr!e+xzcM*eD3pC=`8m>%mNI0%HhZPkYMUfI>BYpw6qXw}NZ$!0SoW2~<1} zi8dPfI-xcTpMT-FE(_qD(VgmK1BPk^^gT&Veut_AoH_d}pKOm8O`_^h2k@8EFtpqa@nbc&TN96x9dL55?2_ z7|tics5jJblp0tR=((c75&VYg+H)47hX!sZO@k^~0_(BIR$+rcI{+0ApA;3#yTZ6a zswx}Z+T)SIoEYgSwwTN(R8ZP4ceHQ63mpJfi>paEh&T?n!Vmc1Ky`6b_9Q_I=Ncj6 z{vwWD5(l#pU4co8f$k%}ATb)}DoRP){U+N4S4uQ+PC&!%I}LN_Jbuh0k+}8sp@yr9U!`qNURuLHz z!CT)~$g6Ho8~q{NB<~s%^zMyDq?5i6w-=7_x<(id zZ$VInBaV0s({MVCu-xKQ;TNJBaNqDiI9%c8shP>Qf?J@4BsQ!PmWEqGh=8FHY2S42 zd1?#bT^@SzeXqa&%uWtk{4%AF+ik=wED2l&rnL*4SnPVj z1$n}mCUVIL?1bEBbdg>bx5>lVrq3vCGbpInq1VdmHcPOK3JnFk{ym4eiGis;5FRIi z)YVNz0o9u;q0kwiRHx;3pww!nDmRoYeyra)9vdhJiB3KOCR1p;+?deskEXSen8!Cd zliqP#E}g24i^5LA4yg@+%nXBY-Mn-kL-j^8x(H_f3Lu>@0ylGyq?g`6Gv#-@6UoAd z9x*`CW5t8zVo{4Ik}R|nc8#h?$OdhrD4WJrecC7Ds>Y0=ixU)LYl%LLWO%B50Nt zkM<(T1E|cfblsVZvM0?ld;L^4Bf&cUR;fhtw8#n6fjxcDFlsMu=V9?FOs%8p3Y*7( zF=5nWBfdc*dOq|-vnukNqCxmtl9)3(;GGa ze$Inr$Z;;MGNvO@CK;;b1mGqhg33*lA$h`<1Xj08@q?V0JJyp~p?*)>;}&J?M;(Nv z4`5os%V5G2J&5AZ5#vR&Y6W6oiS8T4V=UcVAT+4XTcH9MyNnd zB5fj_YUUvv^l93LW7wNb|G5Q9I2LdIOotO<1fA8Y}L(JX#hX zSJGKol;h?8V7r$?l@+?>$THz>l^B0SCQvUw65wcM*GNjFN-Rc_=_$!%FrQXfqCGkn zuQaYvQ?W2HaEU%~h*7by7()y42wsWt+_)-23PYhylP-k3w|OaXp%#GVH&BJJ6oUXg z=($2Lq!;PT@2$`+~6;4+OEoz@}VMQzk>!2T;hcuXqQ`ji+kg3jUowxKe35oG`V$1mdbV7k=JKZhwKr3U4~ zM$CTZ`GF6B9rq`PpjKw@5FNF4;7f3(O9_La@KocZ9hp)31G_H5aNQRm7)_=y5qOLO zSgad9*?VqSn+G8)moHYQe#ebx0}U%Ng3^)dHGY5ldxIrmykSpW@Nr2u6q_b+_5f*; z<|~g{VOR@%F%u14qBHgy1UaAme|m&?qX;9UklQd^%KwxUxY#(zAK+C-Ar;3j)tr2_ zNP{{bBm&Y7cAOt4z|d7+AWXt*$~Sg59lyF zF{rndWZee$qkK-0;f= zi+uIN(6QUfu8E5QyvSu-bwdqT2!F!du<&66OJ53Yk_v3~TGf z_OrBwi6(rMi7-_JYOU1-n_E{{*yv;$?THBA1+m>GNU~v$K+}xtxu(2a1sJ1`HP8@@ zi)K#p0jM+F($)&(=zHkt%}9deab_ubftqnZ*kLnfeF$@q1{t+)cBcb1*DMlAWc69M zojaEYbck_=$UYZ8e$cc>|7a3}kO;D1yn;jxk*%#%7n_j+<>*z7wZ3*m-#$VnAQ~mu zk8A^^!~V;}ux+PPRy=J_8J3kutx&|HssLiG9c2VjH#-gTN&<6GXDrZOZFG_N@7Bzg0s@;XQw zxJ9W$0kl>vq&JN~n`n_>s>{5+o6E#h?V`cf2RH(8W9tAawx;k{)ZIv^odKV4AiLM8 zBt<13%rhGtb?HUhG6)#}I1B2zUCn7N=E`t(?@HwekHXT+4OOwJRKcQ#Z-G-u1{vS7 z;IE!)4G?ik(8>tJq48pUY`p$wHH!#X5Pe{@bfL<-ZD7(`<3n2& zhX1A(K~Vf3BAl=bBjXF32vhSkX169&iGC1k1ig(&b`ZQz^^7w>j?tG0t6Sisdl{i2 z#~&^du&^fDo<7KpinG@4x0q{NMp8J&$o#?*O;Bc4r^K4-&aB;@yqAQjWEp zGRSgmmzIvU0l4*HV}Ug?yx#69>7yc6fiu#1sblGup_!z}SB{{IC$`xfE`bKwM8kep zFC4qecv6T<#$Fka{w!Oj(0@2ps&|g%F>~~YHG7Z6B4X(A0EdU2zkRD%6S^FF7x_h} zKBEj0m4&+DmV(PG;MYs{4dOaYSUy7i<7lE`VvBG&gy9JO5OgD&tbhsQ1XZ!HP8)pD z=VW34F)bt+BpYvCO*lHq1pJ*1FX=r)F;#3WY7P~Q^pCkU2b4?8M!b*mO6~B-f6~Rk zoq2+QOgEyd#WMwdLgp!QVWw9-w%BV05b8xEoHlkUdRM@kFO+7e0@N;=0I*<9C%N;K z*9PibGemy{Rtf)-&<0sp>C5YPu)=9H0MDBl;{`|ca{*8cGB%KOnAXB0^ zVsrw#J0n$hi#_d04$In?BWCu+!viEaz1{F4aYr7W87uEOxJgp1d-eRuXr%}T#27;3 zpU0{u+=T{XP}|;=)rR%MFdCg8ls4(vBIwD=3eg^uzh1YdaTP%`r24si1>~U4TB)a& znVo;PWwg-=Ax*%YY${DqeHSd^I`#)30>xSnJRXW;QR4<2ZvZ#M>`s!oXlnLGBn2=r z8&H(Q$n{mQSf#G^(&-3Yk0hpYO!bEzAm0f$g@@vW}1Ns!!{ zF1b()!{+tvC%IZlKLb!zn#|n*C)Yt99kwyOHQkRkv0??K6n)Xn;enE2gb{Ij4MY`{ zDtJwBDoAkr9?F&$h~@-T9HXb}$!7~&gp31hlCsZGprhEdm| zT}TBzP)=>KZ_@h-)72|RpiD$H{qza2<4~derVXPf?fw^CXQ_o7llqZh5EdmTu3uH)EI`3TzCRjKL?0SK9X%Z zl5x%Jo6DNysQEzkdA==%bp*P&G`-p5J4sC@qBos?d_IgPkGJ-~S`P?-RtE50c z@a1Jn942mTH0|tx!K-(QT=5_>Ic}wXRd2~m+yfxyxdOVB(g``zG)t<#CC}AP>-*2@ zBp8C?mmC}qdOV9tuMCpb_FqRGB3Ex*7-eavmTfvfNUxPZoQBT66++}WIpU}71i2QY zL<7_oFqK)JvXD`9o$&~I*PFr_DwwK@7c0fv#gj=#HS_TPVT_F=Q|*>^2xSgs(2an7 z+bD9TcUQTl{eO$a@GwG1kaa57r>!AdDTTm$QNjW&hVo1gP<*+Tbi3hr%$yRmo=Dwf zqcmhz)iY!^E)MPmYA!tSlL;HNH-J0l0mSfF-)O#tzk7|rVkDEomay92rhh1)oi@OW zCj`2A%{9#fGRCSbmZsr_up=YuI3?Hf=8;Z0TNIV1nk{;3_mWVeUAP7=6f8m(RA{1_ zK!k{1hrFFaZH#N7wPtBB$N_Q5O6e4PWpfU-8FmaeRz&P(Q5QH>Ekzzhf%6UO2PLhr zi)~7XlVj!=zy!7cxbURdMzR@$uoVSO*K^al&9`s+;>3*(E^}WGgGw#2@Y;V)0jZwm zDR#vCrnvL6MHZt4aS=r;ZMB%E!;!ZMNsbOm9a~dZM}E z#1q63Vo;;H>(!&&jM68iOhPU^nkO`J%Of!ju{q$p#)1tNF^hFZI_*bSCp&#}HGek8 zcFYQRU+h@aMf>fu{kM}I zQy$?i2kP$Vpwoy_w{q{s1$PifI-E9QseQ+dsBmt?ZPedR-qgm_SDeYV@`Zf>{heLE zKvI3>CJt7mV3PIr0=g9~(Z14Ax|}Vb@FNLqvLzb_QF+*^qFJ!+x&>Iq`}Wj-7%_nr zm`q?mjBr1!DA))9kQ(Rn`;E0XE%Cx_@k6twb#c!8L7GzGcXB-jxt^p8T$SQzutkZ&#gvGJ1kUZjQbf>5Dj2jARqEw5)>}R>rSv` zwYDOOb)f9UUHI;cA@?#AsRd)|J7-7Ru0gHqWX(DxUQ zC|OfytzFLe;hmHo8Fk&R)Mlbw`ig{-q=|C)U#DAW?j{bgfnMvFqI2o$P#JBT&n>A}dx!$;lmQ3c-KF#OD z+}2K3^Kf!YYoL3Tj@4$nKef^z5S6bM-dd$=bx-0}ux0*SGE{Moj*Cr^g9+t5^2oBGHMWQu}c$a?gm68%+ke^LW~zcQwi9Z}Jx6o(3`F(TGi56+s!_4y=X3 zwx&;H)4W~N$XoqzlCN59R^IuEB=n#3_WTY?LwcAXQTKdwqCHmO zsCB|^Z9p-MLn5o?$}Dk1w%Q68HX4*Ht}*&Gejm3G2;P9I$J*1Og^D7cw{>{dyPJ#@ zE|S3Pf^+xvo$j|YyDq!sZg?ofdxl8~>~dpVA#dB#{DXmipFnd@YAu)N4d#nS9qlzm zTonAfLH-Q>Fcegl5iZFH{ApJh!EyP$PrVLcRH(!X*!1WXBtz$9{FLt2QXJdZf((!oKp}4S--XZ7N zgzGeMhEFXrX|i~TnWjLoh#D+zQpXxWBFDN&X4hb&T~E`5Ht-{}YcezOxB?29eLMD| zztNf+-m~*iz6nYqnGu|8@D9vc3N_Y0aT$~7g8n%)QN^Udan0`=ZI*7P%TD~gxezM; zM~R6o0)v@oJ^Eb#k0f9{S%DLdF=#zn+Il&nP?GnX>*j^~DeKKZHpRI@l$nW!WfpcA8i8lgeG$$>L zWUJ*SEE_#m~fbhKMCD6U{z z82Quw)UQh~FUc*Aom*bSfd}IrjqMe{qIH58+7(Rc2Y}0@aFz73y-Bc&?Ofk?P;;X4EX|5j9#t{z3WJIP66KR}y_EJ-_cVCTq$Adv(K< zO|hr5SX&2I+}jbKIWq!Z!J;u!nubaGvto7$sW)96QJ=CgOt?Zay;Dzdp&tdGYA4ra zRAwX-2eEaJEpu1jFAnsYk)vxDyDBYt@vM5MmjTeH|JG>^@=Kol?cAgWehTu-)Eg&oz@{{zWA0O%9?C z9*#*Z9_y(fZ`Z?U`q6+qP}n zwr$(CZQHhO+uV1*-Teo9mE5JPQk8Vl)#vmlid*$P6{eS|h|RT-#R6fmxblHTor&r% z1n?^5PIktyh#G^iUN3YUh_Nf))$Hb(6qI?Ap3>?Zc9mxk<1NphHN?WFR8i1TKYO`a*T`77~Q{#1uuUsa^R#Bm@!U6-l~}VGi=5Z-%qK1 zym!s7+}UOR2HH(-YolG&ycwA$u4ryd1s414 z*b%~zA5I&`Ra95$x=R$e)MwzNZNnoAG93E!0t^@#dB3!b$fRGn_L+N%Ga4_2O?d{e z7Znp&IS>zlNhVEEZ{trSv{K-d(o`8b=@N>k0%6z8OwdrtWsZLZn}0wW7a4&aIYjtE zh}W8h1s6svfGAa2w2a2i=j#lUWl~$yV4FEr;hP1lfX*gFN*9_C=A0bQ%tU`3qkR)O z1_0fsZmU@i=qflJRpe(OM<%;_P)s2C&ngRIr)U?A)An{$0{&cEwx3w}ZoEugGd>4< zp3d8c;nQj^^MU%mjY|~f{+wp9KR6w`rt({4=fYl30tEKDBPP#Du8M;v`tsBbXXVkk6@5oE$2mIYtw6f_wAZ= z-Cq@@WHg4NY94Z1>&7`M9(4o-_#qXPq*?evv=}-g4kZzy2=|>LF*K;=PwZF;iUXW3cK2ibvGOTP53w#e;$= z#?TI8JwwHFZovC|BCp`q=jch|zFfh1dXhKMF#@&imARqp9cR!o8Hhsmiqb#)##er@ zxwZg^fB$Bm0zr&bAT~i)A(@T=kT5H_**h9%j$u34fsNtEMugWgRc3~f6djpwqTU8K zbn~)-o!1g*s!j6P0L|XMtDd(lEwRue$-EM7?+{iv7tr2~9i^$Ih$go4C@s|kGm4M5 zUutnq+D@l8{*@b^c~r7Hu6y^fVRl)b!nNU58`ip&VMKadO)6dxYiy>Eb92iLU?Gqd z6@$ghCPwBr)6Bp|rZZ`cimD(5r>^O~0cx`bBkJUd&*Or-7OvnR6G;qn?c0Cw*N zh3#*5x>F@JkqIXrU+=etO_I0u(B^N zBZr0xE|I3v4@wmWR54nSL$Q|Wt?8`-Ib{W$>wHBqZ{Hj+7zKnSrE?}Vsdi8#$i_E2 zox=;AdU|vqC1RDS|b`pY;>TlVt$l0yCDCA>w zgkuf$P_31`+QKjg`3mL%uxC|{@s-*xx4AHWgmm3I!&5*5x=9l?$@fbWkpZeI24l?X zk*jmCZ%sVW0ovr1-R>g{Tu~Oczv0hsikcz@IGdmMOxVd!l)Es!b1y6{&4_TM`eK4K zvtKB(v`VJvZv*b4AP+SH7x{%HIMC%?&7ZaQ*HVMdx;o>D7(#*4l`^iP7V^n%q66|G z`x9BknjMqBgwgTpT2eG51Ee=y zSbnnL8Eoio^$#@0&4{Bx{pysA-BPrfTaHQGNT#-Hz_8D2i4cc%ew&loKgtb_{~)%> z0T-qte5{I%K=odU2K9-B7^;1QBiJ6Xp6{5|vCmU4|E#x55tZwIO;w}7Mk{V2xQ&M7 zIsIC;^ zwTQt(FT6%c6y3V97@&Xz(}NEq3f2vn)L)WC{6HOtm3~LnN0czR7bpt3zI4-Ao|dpy z(!><=rI$Zj-!cw6{BUu^>FLVAUE8woP<70-PRA9uoIGm{0Jl@;T6IF92Xy$@QQ?TS0{$YM*K4MMxyfm(&usqDezqj&!SnD8pZ1?| zxk|=3Yem%DB3*)(yF|DRWbB!hHR95aqx=9Lvu3kWzi{Yhitm2vMJ?BJD&Vz9T0x8vGtLdv6`VPjct7+` z>a&B%9omWO1T+u@2X~91EFHQib5|COSO(TyN^XSd(B#(kaMv4^5e;+eVK4ZTb(Z4i!U@}QtN2GCWIo2Ljk)6 zUUv z%2+kjMVcvlhOw}fR6Av6x8P;1V$T@CYqfD?V7H9NVAT-M8(3vJX&!pN@~b$$;#$0F zQ=7cFiCx0Cru1#kE|%8BKU@BmXaGN*`NB&8Z2`!6dK$S%fZQHoK~!fAnNk@97Vpi{ zUZ*@E7C@CKp|RcSn|oZ$x!J$a46~wOx%jnpP>F419gRM?Ng+#wrp8Htt=SLk$%~kb z>;9tE#*HG7*&E8XwIU?~?{%^z@5&_PP~3PXfsl03-7#VbE<8(Gv2{^f4-{zIptmy@ z9j|!RMYDeqAmofc)nwggU2WA^ZIzWr2%S8o%-h7U3uv>QIHn%jFcgR2s1|n27TQXl z^RPpXogg&lnF>HE&q0yuy1`r4%MZA}a-HxT^aTNt3AH0#?uDX&>20cJTw9_c+8p}YWeT?w^w4mRtr@CUgSP%pv02xaN;xl3jNrCvQKeg&)P)yiI}3F)A;vL+P-}9_I7rHAC;omq zW2C{ss&z*v*Rb#f9UC zt-Zilj=Wm`0wv84?OiBCd; zBut4sv%WKzkVExb4u-(JkLXBOM76wMHs?xI5i>+LOW&g0^f_cdVgmf|H&<$gtM{N! zPZFqacQ2u~S}O)WqYZcOTiyx0ZS6)NO1~p=)V)NZy>RNkLU8Dz6IgSivb(#{C#%Q$ zk^~^_!jgp7EA>PC3p8q`7VPcH*NRC9Ns3St4;$50ZJTga%83~+;@po` z8Zb;cubB8;6WceCbBI}eg*aSpXa`65_jY7=^L9Q1X81R^^Fwk69ZF4h^JpG#Dv@_x zzD%7G{aW0t{I{*|LNB(c)A(gNX=^IM*kQV2oZek@uq4#61`P1(Zj}lOFl1SOrE*tbuiw_-9kjF_trflBAyy!Zu zKv!elh4bNtijl3+vy@X5BZaY0T((CUbDUx5Fw3dXq$;{G&W-MnQ#B_a6iBQI=nSwZ zOTiOj?H*~mQj-~|PH0b%_>HWmnLgFPf^h2MC+s4WKxefqkpdEZ)ZOjMx-+OFy4@R! z^6-<@4K^o)0ps{dM@MAT8tQ~Su4X=-+19}SOlZyg*}6N;*v^bW6%8=;UuOo!$jCRx z^~Z4t>NM2%H{f9-J;ZzUYOqXmmM=BF-Cy4 z0c>*)WSpaP!g&OR5@oz80vd_%K12rbO)z-Ys;d1Da*C?&!wX!ro$|V*S={99?_ns( z<7g$6oAK5$!k)r_MAbgx>MfI6yhy|omTy-*gMRc>8o~0dAFMZwYZ$Bv+yAvyreTxY zRUZD8an7=vyR2qc^T7a#p7maGBp(VJHg)i1nA~%}m5?@(HaC#*4v8Ff+YDH*#$hI! zE^+60z^mnn6jpIry}qw94YxGF0>DP!UkDAyyr7+RabcbMwOT*YMSl=zNIwnAm#ESq zGzq!?ONF%S0H z-`N>cW}GBh3x+yw?1E)cZytG{@K*@F82R`@R~aXiGA zJj2V}_*+mq=0!IyuMcD=M@6vqX01!%N%74s7EVVfh;Biw;eanzY1(b1w5EZHXu|a! zkQvE2HQhRxbFl8;(TG1n^9jga{t4RQLb8m8aUT`Moi)~(fEx9*(3q;tXnjy+`QEW1QA#I~@@k8^SgtCa9z4C1%xgp;DJjx@QxJ>UC2`72LADFY zy5}O}Kd#ZEtetZR+KlCztU~%hp#us6x!6pZcU&46kU<11F9(%UO(dcTmuhP}&+?*$ zhYpP}UH7xu?rddyR)n*bu)MN+XA{<5wFfqBBlLS`5AMn)>eSTGx7A*{u3&@j_X0T{ zBm3jH8rI1ye5u}_N3N&j{hL}I-`N1AjfwR%_hUBa_c~afnBxa*FfYD`RSz0)aS|tw z+9!W&;-CxG%v!~QVCvf(nrC4uhYUQJjxYo|*K4*j2^5MMc|3NGLMHT_7(Hs${AAHP zy?&{y?p`2zRj%#I7q@F|=U>9V8=M=#fV?SgbQbuHki!?fH}+xeXFgS;!OUdz7>>b; zD=%aa+|wfkDHc{kIfiz}aoTrU-K;+>T}g>pa#gI%zs=#&x>k^xjuT$Xd4x%im>Du2 z-kty!$$f)8F`o3d;@=F8RR6m;5CzSJcE_?`31kl3M^$4+{p#5vWR~#C^|P1skQk9s z0X>CJ#W~?DFrfH(C|=J6v!U;XVmn)%z|_PMmKmI99_cXaQ| z6z>^q;Oc6l_9Jtw%tS=kr)NE=eA_l;V$O_W)95R`LPXQBG6UW^ppX^+ftc(`tGe*% zDVu?Q+a<9o%?97)>AN6x11Jl~2uT>kS#)PR$5~N;=43a{EE)8=>LyxHG@&zEPkRq( z29#t$w2M{#W2xXVVWP8szM1kZf$%%{jZ&b`sKXinh9^}iogiVG&k^SoFLS^NUH7;4 z8guOdjeDnYE>(on`0>HP-KFjv6rTtL5J54mfi7DvChPb~t<>oK_20?*aqS2BS0gs7 z<*nB6(dO!3)`1@vlkB6lCz>6!&XpRD36aRa8cNX216j1Ew7NOH-zi{#%brWiFV^w* z3zJj(WI;bod^R@HA8=krLTudI##CZVtEal`8!Rn_`190?DqdJhSHC7DVn9eNfF+`tKO=Pbeo@;E1LXLrWjG{045AOs061oq-@AkmB)wrE0c}vf%AALxk!)de-uz54+T?=8BkQKs1(nkN!6%(# zJ_gRcIOIf~Y-6e4n`;=O+MNAXjc#5`CQpDENJok(bGL;{q+(+)R<=WTC_enNqV>{J zki`1c2vuE862Ukbg-G3Ssq26UwQ~fDMKr2kVZ9jO$CTUxk^LW^Hp;`dhS+JF(G381 z869@0mm*kFt59~B1Fb{!5)GQ0Y>51Xsk0A&p91*UA@}Rz8K(HXZJJ*S3Myh*ef2IO zo@RKoxuH&Y1#b28#fw}1ud(jCk-M%gy)HZI+3^Oj>A2&M>w8e*sfkpbhx(&}9m&pD z`_mi_4wI?T=MW|;f0ycqS{Xs(L%kl6f8H&e-A%>QXEj|%NsvpoI?boWH|rDEw9QWw z+3|PPOMyad$Z4+r3>Pune>b>RF0oYXdOSD#+7YTIn41qI+PtJzU$D}*N41hk)o0@E z!Ng2XH#pxStUf4ge9rJ_En1Rn?7TeLgIn4Rd2UDcLJZfpowLqP3u>|Diru5oG?)8a zgLZkf&kMKeUsD9HTQ1da)D@ps+JOO^qfb7m6-)={p3low3EwrfZ6anz1@Y4Rl`3dp zkag6c-Ma4YoG-&v%153FjG4gQK>`5v>n60}+ZP1Ta0^ztiB8l(V#)vl##L#g6ppMo2Rl z_9smA|D?A9fBYJ7@U`uN&vGEm{X+_k8@Yt?3If39+x;UeVrFUjKD!DJK_aN9Wuc0d zp4_Hk@!zt-rhzt5pjSU*xnP=>sy*rVPy2UDk6~`c+yB+b{5!1|dT6%e<9WqJbVep0 z76|v5+3;(qKI{Q0R%>b|1W@|6j1I>lA)BM2ez99*;%u4vn~_7eQMdJq)nOPxk09__ zpv@H;9K*}x1)!GgMNqC-Ot%4eZ3f)A&c_%TE&0?0&L|m0u*#-PGEVP31FAhqX2}@N zD_@BvtUTe<80z=G9`!Jxl2nm6gS81nuK-g}+FS?9!d7_dbTSivZ@4g}!J)nt!E8!5 zJJ5L;>)t6J!+WqBTuU(2x16}(Co2#sb<7cH#ReDCeS<1 z_X*~tgAP9vp_^}$YT=Gp`cEaI&qh#YbSb>r; zjj}(|amWJ5F_3(+&N6=fAHHG5cb}XiCF9c!4R4H>A|o>mD!ysX**BdVkvD&v(8q4o z6c@{d$z2dI!KsLrdX2KBv32sZPdwLy`tvPrju}m}mYe^OAY?N?`s#+u3V8m!j%EY)?QF_BU z$}7j*H~cX{h5!}}P5Zro=U_&Hk>uo%%N(3UKbIn1NsSB5(z`&!T>nR|9JVxXAPuBB zfHw{Ab&y#*dxpfsN>rb^QznQFZY?M;eOeUQGuVYIeJPfq?-BY{WwRk5sN+)}jbaMO=+*F$Ei#L)}}qv5-y zUwSx^_>y&;8O1i5QxlP^gJf}0&MKEN3V@Qhq2t6Rjt1QjKN428WVPEfdIyc6$bUY$ z4dS!k5-17}3~}jC=<5$=3jSQ)`wMJv*Ype(i2puAPY8-pxyVaPw0ut<@m<%;$mTJ1eUQER2VS1rK zniWb!9#FR*_KRF8a@v80G*uz{g{Z>>y6rF#{k$4XSr=3xiEZ%qt0&3lSg?d`i{aRx zRp`s{T4m)rOsx~I<9ld`HtiS)>{n=cqwLG-n8l-3g<I>-*bRTOU%g-$$`9LJyB5-sb30b8J zD4VM@zqcDphi!Cj!Vke7E@=?5_3}=fX1xX7UNuG9#PW62qTT7;EQ*gtN&^rulzt%ieoI#L{IuODWEAdijTn=IoNJ+aUT z?Sq{l{(C1p;}*{t1kCH*5keL@9G4YEDcy0L&d@Y}&tIY!=J@)nubcy2R% zVJLB6y_t5Wkf(8_ic(XJl4bu;Xm26?M=s9~K^+icGj>@|>Xr8L8%u>EUzDsrt=uS9 zFfWE;!@& zEkU=e@+=@Y?gB4q?rok&^7Q0)RR8^Mq|(=N^~hvrm>*T*O%E>H26eQ@hgpuk3&;sO zeei1tfyS1g6xI;%l&w*az}4pN{wuz^OIGXE4t<-q7 z&UwNoxmvh*7#PE(gR$)QT>5wY+b0Cik@08aS=J%>tGfnt86y*CX*uhY7^5p`RQaBB z23_7gyb!eE4zBRniIQ%F+aaCMMzqUdpLH2QMztrcN%G(GMWrD0VSe76QQ1;oK7Ip| zN{-=&vlfp~tO)*cdH8$YrpDz4gF&i%Yx6GkeD+wz`(6s0&_hbHcAfxcf5{s$Fh}u< zCdCJi7Y*#4ha4YxkPP{SU4;@Z^{YceX~#56TUCpFa)ertu3!beN~A$A$0{cA|h8H35R3tuo=JhTXR zr-wZH>oQ6(c2GD2?&WIQUTw(-K17ypTgc4*LsFw&I!Z1FhU4iz$^;nU!ZCD!Iz!bkW*ED^r0>CQEoK8?&+PaiCDVQ8jJMU(s*O^lCM9^fRM@V z-16MYG3O04tom$?PUJMh_KI8Xv-gnG0#J$FGDp`tG3gL8pb9gp-jOjwT1NjOyQ^0gISDfL~?ja@!k$vY)iPieMLa-Kwi$15)8u58(R;yoXX)$5l9~siXdtpzFk2dk8OanTq@NjJDz{s-&Kr@T^O! zh55>?;aCnJOq3SpN#LS*{s1(G#72g9y3sp8kO=aQGm@GcDS;dCgX1c2O+rm(aR%6f zQ^wUIrRha!<R+I_#BUncBDMgYvUFuM@D?maNb(|3InEVe2$=oEC z0U_R&$g{A`S-lgM$xF7OoV3>z@3K%mF`aThT&IP^N4#RH#4|?00q98~kV;Zpt%Lup z2qF^X(nLm|-KszaQIPkB1PP}g2JFb9QA86g`Hq@>5*W3cWHACzL9PD@)*}Of+$g7G zErD1zETavGqt7OdPCN0lpTXkF*klkByCO0GBhc9W^

Pty3F_@ZZ^J%l5>(! zJgtj>+7-R&GF8S?0gUBO5nB!sn25mOa-xNy4^~H$Ply>O)uamm4Lk?%{nqCoI9_1K zvle-=osBVBz{@rk6H}hfFpSp47o9QicS|rm0aQxT^um2W5Cby_lLXo(ZD#^xqp?Yb zZ>+f&u4-R}Mo($IB3(mcy04uOk^#C|AjTH*k%ieg#EEVvXA1BMRkAwakqL?OCK z|F3+=U5P3`i88fk?@ed2TiuDHB;WN=iS{{3Kx*TnH~B z5W)@jShNERFV9m}F#_1Yu#Q9vm~qzyZ~~;;bCXvc|osmSpp5oq;7G z46xQ2^1$*Rr>Q96xmXzL1j|L9&{S_vN&1BO3RR*`*AGREV=y+8+uM9jXW%?zB`<%8c0sa&?M{TWYOcbHzA0b)GY1gO8UmkpcQq4KC&Jo2-K;0hT{Z%N+D(m4&6PFLr0%@kjWXMB$01(I(p;jaP3v>1KX|_ z$%oVo$>}{cfF|gX5h$4wC`qqkrz*HZ#9z}ffnmtSgmG4moP(t;EYe~CxR9eFoKbk!6sOT16Hzt zxIoGq@D}?r7#SR=eG-PdjmWDZKSK#yI9k#Q>Q1RRhz&?_XM=MjZD-6{o3 zfgtVBf1R{q+P5g$lOux-0-tQ z9CLeM2wQ0!g7hNdsN}ffT%1pcIS6Rzfe99*2Z_zGtnX`@G{zPX`c_&qy|ADMKt4&h zO%}Lf-tSaw`y359lAsX@B`+byyJ^E-vveiwfk2xR+S6P719Vi-^j9&71h)KK@ zq{)EXQ)K^+2h~&;BnPAI?aYG#8HGR)uvyLgBMUsp=0x}-RYo0v#2^(kn1eT7J{;-^ z)46rb2c*6hxE^CXzfoxckft19wkSEKCoKSHbBzw%)wiW7lbuqN3pFngKZ`!s3GJqg z{Grz}fF_q>RdGz%Z|jase918u&>luwsi4&l#qqFo07rCuA$sB#+UXMx2z&GkN_{4v zb4RD@+b136aIM>ru|NkNMj<>q+ZX3~GvEbpKRXE+a5}R+H4f0KfMHreJFQE)$*hgO z5)HLf*|f=OGKlNxv^XA)Ia7BL3OWhHWFuhKLV#Q_4V1Ddl1Pa`P?S#^=p#)!e-}G3 z?_c^B`Wr;lMgRa(Nt$=Bj}d~dBE40G5Qv%)K~oWkyTBzA?tnM8NUMi_$f(;f3$hU= zrMQUPg0oZ+1fb>=)@F&sc0r$lr--uvav*c&L#5crcYJfCYOSKIH_-ib`t7net%WOf_uXAg8oIn%tlkl%nbD1J*{xNf)I*9*L}O?X&r4 zksT3D;S(9RNQnNkerZh~4zEn=lXCG-lSn2V*@_0dVl}V}?ZNpL2^$4FS|fVC?Hy4v z1<=Y0EuikCq2tw$E`WXHV1jAD^>K0i;I%b* z0U<2sGr{|UgGThECUjiRK6AvG{Ui)dyC%sr=;O)rs~beZ5#pG}hMSW^^F@R&0%w!| zlY^9n(qTXn@ojN>nPHu;Ooi6)m!a4mQWq(6b6SHc6^Brs@#)!JCOsc9^|Y}f8_rr8 z7HH_$LPd;TktqhFqS5V+PzW~6S7_}GkN{}4irwr~a zr$%-ju5h+LS#(FMf|V6tt4&}`AI-3wv?Z2|Am&gG z%xMm8#{e>!Lx@>Cg;^2r^-#~i*B0Z~gm__UvULT~;LW0ng+F`T@Q?>6AfX^~9}FPY zu5Sl`W|YKoJ!2PWq6e6uUdTasaWW{nD0F@zV2)YL-Uw(5m2{wXg-V+dw76>lOOADu z<~5j9`$<*Q8^qh@fJaK;>!Q-b3DCbmBc(>~xJ)n%FKr7kkp|E>>6dc5v>wCXBE=w> zxUk$HJix(&?B=i!VI3rwo3_DjHA{ZTrJsmEbjdC?;DCsag->kXiXVXL=tL(V8|@OW zVhIdWkLvc+g{x;cq6Z#n1^aL#Y3Ln;&!YqflX(V$awKVnkZur#Sm{8m2ch;_De$z;73PDH!2_69YIqQKTPW!xP@}MBMbdWR zEv+w9jsZ+${u9s|Z0n}c0G4@P7=lZjnM}hq?iNxP{pzEyBVZ?=M2z_jXp$Q!rk9bQ z3f2mh9s`y-*sbiiEnweeShK=RNrRf)iM+LC9>XaoaNFCw8n8!I0f>ACV*C$oHl8tb zCy)upZQvx_6cfev=s=etc2;IQ20#sJ73T(FdqDanSaok+B`+x$ImeF+>_D%u`b9d;w5};g*%S`emw#aPUyYnT^Y&OZz&V<%fgWBP{Kn9! z5lCiEWcA_!)wu^9hZibl0NfYmVBbY#Sc=*{A(*YFEbxwxIEywgx43%>(R2#Ykh6&f-bIvtYn$9 zn}OSxbUmympoYbHH1*-J(7qyQ#xqX(wc*uvpH)RPl#NggQtELl)v1+dCtP`j16 zUy-CMSmgjoAa5{k8abj5D1?ieZ!`hV@E%2LpmI^@$|hPf4g$KRMnxOT-rAs?=W_+X zggr_$6PYeG)Z6UQfwtZSOuZ{d463Tp`+h``hb~*pIy7(snk6lD2l9s53@WI1d*=^E zj4jNg_C%FYCJE>vLhVZy2>0SvuLO5fqP)jmg zCfRBoAlj+Qy9FGUac0mQ#pqXXlSN;nyiT>54`*bhit*(GEL5%16f2a`d`IQE1)FIh zym9DH6;?LlqIrPuHF4bf1JO)rg-Hm~L{mRS4S<|8*Fy|OYk^sajEWXmZ$-M`tOg7z z3=_g9jbwW+&08^T8Qfb( zeP2>o2G%6E?1VVcxIbV74hYXOY6j79-4hp3_3c?)_Vf{yA&apvkKJ(*Lab(2XLlX0> zuGNw${X`%@JGu=wsx?I(&Zu(t9M__qKP9CO&< zMyVTYJ1D?67FK78Em_C6`e~V&4X`g%VWT1HOQX}HHlQeuj=5^VH*91bN!hJRXEAo4 zac_Fbfl@Cg16p$_qLuPCzK3yIZYgFk^onSzk^p#(9n+{JrtTp2X!L!w?gRi1r^2G1 z&Y@KW$h?JshEo1O+Ly!?mfdVVJnWqDG2Ov!aynh`)4oNdqa^SXz(dCPTr|U7<>IG zj5AsgWKg{$!9MUTs$?^<4p1ONQd?ALz6pwg%FV;oTo}$`L9G;A1P7wp zCKVb$lh_j>Ji|~I>&6ObdwW=5_{bvk(uHL*Q0o(M5}r3*kmcw~s>i`iD_IN`qgoX! zZJWWvT~`UV07o3Nn|ctzfQI2iA!7t^Fb5}=OJaItOtEkNzuUlug&j)F4l)hUt>-^T71-~<%tZXph$%jk8AYz#6*XX0c`sgNi5iC*CB|!#x|0a zW^a~2+ZNVdvZWzZqOL-+^r(|zcf0-!L(HN&3p|vW zkOYf4(&s(vl`f6yuD5sVi9;e#0N1=%05F?o$E{!;D_84CaA4p<5nr2$_)Y>Vo@`Fb ztVvi$Sw3qayM-~oSlnnHSlDjP<+BUgvVWW*3+x`S#F7JWloA(skJlqd#89zK2o=xo z7e0Dmbr2&)8ly!6t)WjtK}>3kw$*RvRx7hbD8BU^lgsK&#KWI5j3yyv8b!8=?8R8( zJ6Hr&BLQTlUMu%8W9UYQFasfAzpNC@77AqCd_{_c&F-oc8Aq1ZkZRRZ`P;GuHc|Tp zOco~cHRLN|RI9XHc)<$0D!K^QvB4EXFp&|1`VGsOK?C@wMrCP9B33rrB)}zoXzEyI z;x0kwSUN23rHhl^=0S)IMH)jB35@_T8LDt&0CGr8RcSI}V;_tPiRnbaRD&*6HB?Q{z2AWNMtV#1{a&YXyv4bFv&36{a`V) zltNe&l8&}8;ld=uRER#20|EsE(pOgcSOYKHY+?|Jka17j>`Ab2ji{!pZ`g2uB2gQ; z6$GL9GQ=o)tENk$N#SWH5)ZAtqqUk!CPJd!q~H=xwECXyO0aQi%HL=?7Zg5$XH}rK z6h)bhv+WO+c}CYpkk(;bZu@YiBM(n;0uCwg9!1xAzv1Yzg9@m~i}Q0ZfHOjryFV12 zOrP9e$!bbAg*Dd5R?n~Kna72elL$kjxNLx00Lg5HHF?SlGXPSKNG*oj{WEik4z{D9 z>f=19&fv+4YPTQdWm@I6G#B@`EfP;NDw9Z@d?OKEgCWUeQ64RON6cvf3>WCpi z4fL@;Xk{Ze$S|?MomPD0giym_aV$BN@#`^Gd(5ODLy6LRO1mm4d!o6RhTve480taA z77Tg|im?ik;Aqw^=qgi8;<+>Ox+@Y^&mjSYLpqEldUy<0iH>N2R!0jUOh4;x%94Wm z76GP-yO8G3utO|LPOxGAOw@u3rg;L0eygwPPYs+yB{xNAn{2jI589HI8(^maofJ|_ z56vwY6Or0r@;D432L&b+;_;TPE26Gq`2kT`hteRO@??*gjg<)}xY{f^RK<&p67eDF zvZH`Qp72xm+Fp=A8eFf{`14Y;MCHE#`7QvL}OH%z`jAQ9X*OE^1IO0Szu8F_ejv7EtX)|k$4h_2;v_&o+x52eu@bRs7wj; zIC0j>qm?~nXfN6M({`%AQ|9y4gT5R9_&spGj%9v*oY3S_EknFH-3!OI1!# zONNPc8(SRxO_2uPTL)Ikv(wx(na(~M#d$lRw0Qjmp{8K}fwYa|5pxR$!h}c|I1#|8 z!_48th(P150>;Et-#ql&NGL8K7^|E+H?J+|HEh%b3mgb*2_nZ|#894QtU)M}zlCna zBLtFn_0tnfjio?ggd1u~D*3g>!7dAt#+`ri`xxOO;)oH8A_W*RB$$Mb#4C_j)ANvkzG| z9!LG1b3bl2B<=v01jSm8pQ&5aw!DT?H@&!q)1*cxzzCXgB!ZK^BygLbGd4`PjG0nU zQm$2n%l8nu7odyuyg~vB+_{Ig(Rdg3cEAs(v0gpAe5;-)p!gr{iAK|P^C1lD)QS_< zFpJUw*$Mc>wQfI=X7!&mr{I}hfaWPjL5Mv)K$vh9YZvG7!gF*c+0+HA$i1Lasf!c< zYZP*h?4Ah(LagTWRYFV(Mb-wvcZL!tQP>~#>yK27A~u^qkWtQElRCu=kRM7YdS6Uf zbgK1Pz&wjC011Vd$e|5ny%W0Q;dmFK?tQwzIfKg^S#{iP^z4m;`_tCcSOa&cgf~|K zsAO#D&y+@iTlvtAMKo$&0#q)2Rss)00Wq;@RMy+jkspys>>>6MtgSkPbIc6O-cmS6 zFeO>b7%}&c3gP9p>4_~N;p8#6trv&8NXo=l=VF$Z*Z4mwbj8i*OmM#@4r@w+k!gNP z_yyW2yV01z3YEq%0<`&GadL!@j+m;IIAhWQgH}~389GE0v>$pX)X>iXuDzEn0Hq_K z`Xa=2m1vVnO?v`gLJq6}!ZehikuZXN3ZLe(gJ7c`=|BdEX%tua`a9^Eq!9Ry-R|M= zVLA^j{=EWuBdrzl?5|}XV>{(8(}*DHzJhCWbk2NG zGmUVm@PJ^J>jqsOiGyD{1>yUTWDK34!9KSQiu~_16r@axJOt2yCG3{5l2SwPfn3R@ z|B}y$rfP!t8gk0S#ER&FnDkh-B8suXCnemR0ofEsn>wqGB`Jl*@-tUE>G+uFtNjh! zXjAOd&_YX(@^Y3fJ}__#WoDahlk-vW&kA**7ZnSvO*WkfAfIy^<;-tQ^H_IDkuqN6 zcIE5PQK6W_ig=2Mfs5qKf$LPH_`?#R*_0!Yx~GesY2-BXyTdkGVBUbbT6vv8>03$A zrzQpl3(il;NGCa`Rf85f@(Biay$6~KrKpNus$^Uc`epTw0mi|Q0;I1uny_dOEDy}} z0;Wk7QWV|TNG*<@NU!qtpSDR%)3pV3Dh+i;3>Gi0! zb^HPdp^1^$wP~t(^^KsciDR@*x7Qep@TPp`43vD2YH_CsEnu9C8Pe2yPcPQ4v5lzA zB8(1GjT)TVK`@qTA=eR_fM6G0qF6Li<%_C$ItyLWHED=yA?tQp|8M zn3Cw8=!{xe6hU<%fNa90He0I(=8t!xk1g8dOIX_ls&`a6dulPHAi_E~Iz?lOim2xc zmq`I)i=d=f2<4UQo6Ta$mXa+oEyMF=rW|SjSPbemg7e&gR)j3h1)0^)JJTi4_qoI~q z{0MORx`NKB_Pi&`(kxs`E9#KB7y>%f^Q zt29i^nsqA>Bf~V1+NoYTApM}Y_1y$#(>B7@EG|8ao6$*8(kw#d@=6ow%=c;?8-##3 z3?xSnLD&U(80Ctv3CsXhCp&yZwz@&tF+6@Po!t;nhQto9Y zF%?|8=Cc8{F}i%Gl3m@97l`^01YX*&C2!(t15wl1q@vF9c^%M%!UZ2S_%y?+FuN|l zR;HSyW-bOH6?w2p{UFqo@sR_tN6{l^>JLA

ug7svdNY=22Bm&7-Sue9D_wkpM_G z7*L*E`c%zMB9a+ij$Hm_LlR|%)AcebPTw%l11P(%NxN;2?YN2B8I^*n3SyE-ivo5N z+ehu6g-8KxRc&U^K{QpdIYo=)+DgHsK~-R{0hjbzG6pYgAqr|K?L;>~RuOW1o28op z-OxIQ;xIcvHfHKpx>Sj$gAOYvcf@U%k_*A@K@N5=x^uWM zDx$PU5RxeYH@~uErMW&bW(@k)BbF?iav-}G*tmn}Yz()`M$%%uQ0?a#Zs2ggNPKO%Y6Ns8(8n(JHeQQG$5h03ni>KB1w=j(9`}FE?m1<>Y4iq zfXRA$n2(Q49k}6amyAWUDdA)9wm!Uk^b7$d*-AN-sCjCli;(g&A7PQ|(-St>FsqYV z_(GE#2YQ76LS1~3jOht8IsEaL$ib!H3=SO(HAvB}i=gsX_!Lxn5UD1LtpF{obj-aH z*d%Zh?I|benwgj_RY!{I`Qs`JmRWJZe@5WS`C;*68#L~81VU2$QfAaOa)}6qz3Ar|iAAC132O~qp&BL8A0srgajeXq`4Z4+ z!T^w!5n;+{3hMcIG{R$u<%_8KY%K1%|K=&YG`aKL}f5V{2K*FjJ ztc|iD4uwF)aa}A5kr7E}Nc6ho%yEE4N@jU?F?6EEpR_F2-_TY$fLhqknIR}iJv88I z8%v`WGkY5>Cv+^Rk|2|)9aR77Tn_QS4m<9EEF6a*Q7shJil!L@(SbD;Yf$BpVYae{ z6j~}5jm195RNMS5*nAS^HEV4*ZcBstxnZb`HNyZ2O)WyYZIih}yo3U^N#%th)?s>s z_PHkn!!+3frJR@9Oe;O&Ko559sfdb$Qh)fBvP1NoxjCn2IUzQ-Qp0$Kd)zY=ll^A= zE1cy4&RbaPKH1cy2Gr0Scr-%u45F8)@=f#$M&=%^7Y-U5F}fF>>M4gEvqk4DdzDXt zK)zSP4#$!vzzthDk%*G#X}?$SZgTNwGg>#pMhb-hoUgo$aYC&y?YM?s9+TOFD!^7* z-#KP@GQD!jm9;qlUS_LP4h2Tgk~7uDX;fX%#IWq?JOxG;oOM!}0&7f`r9pm?<_M;u z0vROgP@%)3BuaQ0H^NO}Iu^==09sCV@3&TvK@P~K(%r|HK+RwrEUt2dX9G>33w|d04&K#^+Kq#AS_4I!h-gBtP;P%{@0$Vh zYF#yn|0pA5`39Pe8$5vm`9ML--E|QVF?qNJrakH=QO3O}(>{C71qM)3qLo2S4xQr} zCH7;MTX`?4C}dK%f6RR+0l`7n1qQH(bY|BIsKH|zwyC^UF*tZlXS%1@cU^PqjualQ z+mZ0#y0yDnRStxDWk>BJ;VzR4iI}3#K*bC@_{yf@_bYr;@UIX(r)+E^>53_7kwHh2 zV!qhkJt~rMBn%x`;pkMh)ve)>l;cVzQM{Mx6+qM1CfhL4#YKpMw~JDvqG~R&DtHnM z6QFJo)71tc;0%PEMuwVHE42*`Dl;oPXa2NE$>S)-DkeWXhjoU|lr7kN9Y z@dcJVKs-ty+d8XFn5GX9Ms0{i48uZV0aPbAv-Zl`G7$q zO%y%SD$vFTqAs*?Oe3*W$RH&gJspMr6qM{^ZLWl%4!|-J?bN8+S(7r7`Y$pbEsU5Z za8)xR&ASI65y#{dpYBJ>GO%d=r=do4{)jP!E&`zC6>C&U%^e#ti@CJOQPa5RFeIQT zavDCisZH7t$0_^^ZOz^m_b|FX#x0ksO}(xQDl7`H^$z$2RiQpcisP*chJ&8N+$e#N z=>nLUsh?CzIhe#tSpjD8d=wUj?S^x@S%%K4H;x879V8*dx=>`9q?}^9LHXj>2IsJXRy3=Ok}2Q_ z3riV>Aa!3xT;y)sWU)po#$#OYE|4uQiiKfj;iz){Q&?)6@IhM()vS_2@$q|(9)_V| z7*M;+r?M}?Xd~_}F_&#Oa{>$E{EDIw(Mx5|r%q)Gs1gxLf_eR&17N91iV`CNRg#og z;YKtp#&-nX+6J4p0O_E2(I^{woU<&+-<6|<+6wMIZ!W0={hf!OI;=+21&x~hD6;k zI}IIiS&l@9Cx?q9a>wLNO)SHPjP}z4fuE2BnfpK!4omcpoJi66qUb9%vO>qzt=TpwBD}OS$}KhkW33fw z7Lg3LQ$mmdnu)0dzfj4eM3ZcGAj=}-S;Em?0F-o{Xj8ygTw?{VBSt3pY-0kg%Zjwf zK~~4|k4bBN7lBm5nnjTG1A=uXf)uFXSum-6y{9AslrvuO*N_2LSwz^QeiC@#A%Maq zu)tx`h7;6(r~^`}1{=#pp@yI7Hih?HoJy{W%F>*_m`wnq6NR8+U{kbR4iSaZJK;pR z!sbXVZp0Wp|Cy_iehsqu1)DvY`@>?gCc#5}!y%|FRrT)fGIk??z@2vKXnWDK{c|_O zJ3}QKYm;r6ctJ8TqQu!)o{$7`gn7L6ZHPT~9Jf1b!!VmyMC}*0v)XAjlmtZkI~lsK zqT!BAL=pmpq>h(J9*deti<_&=^`XFlKU!x$)WiO{qha9`HTL`gG9~RZ)|QM+oCHKY=E{n zesQ^-;tU;?QtF}}LZ-vhL4aCQjzHs+7Ux#ljC*#4D|xaLI^wa~j!E5sYY+ zrA^(w4Lqh8q{wj36;>C1oOIm}API4e$iK_tSX)Dvr19^bFEa{kTP~xlB8O2FI`1-} z#Xo!4P}i~>!31B-ss8{&O_@f@hNWu+V*)ObQ_pOk^@%{;549uZt~8KV@^#_bi}P3v z$M@DAPyq5V6qZ4zDmNY-YuXK95i47T(f=q$ zNGn$Ftpcd8p_Cz-Mj6E(i>u;coebEH<39KJ8VOj#1r1el%8*Wq5cHLyh0L)XsVjqE^*r?n^Ga35bb z!_FloA+&tG{vU+qHM7qxJHCF%wKCAdMR2c9p!DTJ<|j!T>RCtS`0%R2Wo zQ^S&vLE$t9$0p{_Kp!<4GeXFE&9L;*@^cpR5mA)t@6iH3t}<627gTMIWEi7R<)lN% zhvTg6jT{T^+!-TQ*bWy}tC{0&2&XPl9Is}hTJ2;$qFvh7iMc`%x3fM-ag)jAK!!|iC zgo8^6I*xpz2L@nenAJ$C#iC|pU9hTAL<|{oattKEBjcY6zC|Hk6fK^P)Ty{sTNGfg z9FZv)S>$ODG(RC4?R1r32>cRMr82+*(?8Ej4l*E|m>OQ+2+iuF$s_j}#1M6D(82KEPW#&&dic@ObtdOc}?FaGNR$3R!C?=%{>KRfwxh zm*6!qDT)UoLeUx_0N(QMKT7OeG(}3{qdYht)VA4hxPBh^<51L^p|}$iJ*xI8!Q+Sq zNl(&b^w*GhIL~6;M@QMizNr9N(aKYC_Od;Ay#8g+ZVUz|edcG8`6*Q7V!f=Z^ z;9^jN(tr~T1hd+II1&Vk8I>SaLXqK=u5t?Dn;<+U%Y+r?A8E+X736O>8;C(7H@=kV zuE|y2Sgs&kY!j+rG0t5}hTwx>iYSFyS#H0ui+vpRwameoIT;-qngZUd5~VJ~R#8dR z%qdW;!EL3Dtdbo)@5U~1;O5m)^-$^IkqNa>vMT?{cxUY3aYNpggR{N~9aj<<2dA-6 zCEjIO7IUQQQ!xYl;?Kl14#0;D&8K8t>itrH1L-yEnY+EBpuNAzIKC>*H;L}rM6#`XLyAPRSE9|nyeX0ow$Sz{aPw0i)8o_ z2Lb#7tcn=!3PTFi4DCl80Yz_jYpTeAEu2 zBKc6ErYfJ5jW<+gYn!$}NV1NJr;08CD#XUuV}+$-skStfGI17Nh)?X<)CTG%y-~ro z#~U2TNxo{@Hh&VcP91D8JyKa*DAXnjS&6o6+Nimr1wm3#neszYRP-13LHsPij43M^`i*$~Kv?MYW3go4|4yLR#Fm_UlTLStN zn?Q5SH3bz^T(?6cOxfqEKx1OYxjxKZ=4j6*+RUEr4A~d=K$?P9d^nXWIMi&hoE|+< z>M90nU;#j=MhU_q#1Vu@8f;*rix7ac{rajwBj0Y84XYo@b4bCd()~u?Jm2sj(k?!` z4DGvtpiuPtW5m=D!-5zJAT1!=gz#}4Ve^uJ9Myj#9AR-_C~#DyXcr4YF_$Z-7o_t1 z6V7=OctFYMl1h&S+Zi&6gX~pG#Z@AFgojq6g+^WcD9o`G3@QMPb~+BukxddGX@-1b zY~N8!5rgsK;L(Yhlo~hLaSYQT%?d7R`zcF6P@=WwfKx14Z!^Y9dNYPhIEj_uQkPJ< zYkr=4_e)1Kmd6%KuzDZ^;Ag939B3h0z+s|=PHIVLs|8iqe)6aj^b}aJBb>UFCrOD@ z0ANPMY7Am1sEKeXuAL6@H-ji{I{CdZoz!;Hn%D?y-1QQN)}+ z@c}%>xV|UAy$w8~2LO0gx4i?9FPzPtNw!xr)?fJN=2m}K*8qCVPwHaI4L!NnV#<9^ zgz6g(9%b>!OCw`hCeY_pvwA_>mvhN)q%$w9#;~#+%A`F8RqP9Sz&2xiisV8R{oaQ? zPyldA0a{0_c3COjMOpM!i3ClWF%=-m?&dMTedso8svc^fz`9c1gcUl#OejXAi)pAE z!U4iMv~q7~47f96F_S2Javi@lS2yxeX*-l88tS_|X9nS2-05#1qM)GO`Co z>MpAA@01rDjB>WU>QiaiXt*ufZg;z@qdltt42FS4*hi3gT*w24DHYfwXbJ#mbC{~Q zaMm9{2tf0d7!DMM?3_Pzv6h{dEUz|vb}6{LYE0}I*AQMSR6xr@P>xiHDr&jA(9Lpu z+E$)fHHy7WPzT4=9Io)h0SH14QW4S5A*QKbe7}Xn1Ia+g@kAjtGoK6Mr2(HT$WTOz zprsNx!oOX%Q)1OtMlMihN*=)Zb-n~`1&F}M8=`I`-t^R}RA=H%LfE z-ou-wP3ojUJ;JUZFkq%fD#S)rmI;n1scU;MWQLR{MvG88BbUAbs(=WJvSNkl0~~rA zpPE90eK{4^PijnzL3*3a+DHNaVIHPi8gm^+1O{JyI_A>hU_`Zt)%6dX-`ms_E`l%f z617po6%uoQSTxC9O9X^b5z^wJDYL?m(+`K%rH^IoJGLom4(^qUP2}u7_eN!M9jwb-S%P?)Da0_4@e>+I}~<>CY8hob!F_@x;kUv zp@Z`LG83kO&KXKLcz6MDthLbrsXzS@5wBM) z6j30K=P2$)|1sLkk{tFFas+^$#w^j%oVQ5ug5Z}>de642d!pRT;=Cg=Oh)wX>Iiwz zmINW_F@x-pC{Sr4N`RRXn_7m)AEOAqLU$|}qApc5`s$-NOiOV|xd}Fn$FPANkoeun zTkBLtg6354#%DNH08)X+3;S*+Ds0kaZ2`d70>LT0P4f zGlWYcQ^6e8FyGUiNKHuB@m^F`yLraVSZpp~@KQb`LlFZ~vMVU*%>5IA-$E21wSzZ; zYczw-&i8C4Wv$}D@S#LuitDj039~YIP2tw`0AK=}5-NBh*rws7>m7tzfUVvs0og89 z6t2s^bUL$k?`YHji!}ih2)4xy@hd^ga*aQ|%IT&EAZ>mXaMCDM05q<6TF4Md7l;s? z`4DQ#u?M-`Axp|sc(9DB5WF(SPGBpPyaZ+Ybw(bJ4f7yBrx`t*EcLe7n)v0QRwXHS z@7joP$&M`;Vo$9JLuYz)M+uSM&RRA;18yrTHs}wOTcWU*lCX9bZjmMT)%6# zG=ZwJNpPnUlr(N1^fTWvHicrjLdL#$#mhn;%e} zuu*z#VxfF7Q%PVt-CpPk=*~Pm<)HSAFp=jbaT@fWBNE?~B&l-&MPahLfsieY;}o3p z<|MN-7#tr1a%mXJ$swkLF;Q*!Ydp`(Q;TSuVFGZ_IE=9EI=}kgMW#tz?`xzBG@3{f zxuOzO;US<}-US2LgtJx5!wEGMhw@2T}SP4uFDizTReVa+9!4!vH))^LSFcu*<}u{5DjGhz{>3&@XAm8QKzYQa3Ehj3VW$p=h7$SxOEn70fI#wB~_WQI-hr zT{w}P(et!_hJT|;7Xj4sRk&f$)ii{_Xa%GgUB>`GLFOno000000001jEdc-k00003 z000mG0001EPyh;Bp`A@1H#!FQB^b|z)*AfS$?h-#z zF%<{}%zpl)D6LJxJ%=!%Y`Y~~Xz#*N_9}Ic7kw0GEo1R|RX0q?v?IgtBq&Of zM?LQ+!iX>PgwzjF!XlYe;qziGh(EYh>it+2qTDX>X8GHqO3xwi-S!SCKZ)Sw4VfJJ z?z>=XJ6V{w{3tx1ZHv|~lL+-Ul8e?5!ybv#h|g zNe3ZxxH*FGzC5P|}7Z za|`K*`61Au+)*nNFH?77qY_RXXC+*J_7aZvFX9EiC0uw?hx;79`LBO{`WW30)!s{; z#0f*F=$ai(?@*zeXSJ|8^f#oK7P3KuCb}=NC*_#)a5Qi%$@kp^Jz{Hwmb$y5Z$TnC zJtK%;)su~WcO%1f<#^Ucw$8raSblA{nR;zBW{)v_g&PxP>i+w18Q&z1MT2dEaPi9( zIAJvuX7z3ctrah*;ek2To$V%^ee@N2CN$BIU&YXAeOqjf*ez*z-VLRDqS@b}1P+yX zf94i?_G!{7zZ?C5=kj2imk`XxW0+Nq7a%}PmOVWSY7GZE6IBkGp-RKOzRP~Njt z6GvVN!miSMu6j@;1QvXx0Ru*2lX4vEByZyJXyJ1QUa{vK zezsmA^$e+$R;5-5Z8K!h|MzmP3GG4lGnK@#Wz%u@_wm$H`4HyMdJpn8IpqD2>DSar znDr`~E%L{Rj`=NQ?0OR{o)!!K_vc9`C0fJi&i?pJu;8cfuAq^%H&qN62kQ>*q4A+D zqOt67taO;o&}!q{{p1-;FkK{!FWt}m-LFYLuSlaCcT;$lt~`$O?t+_tUeTmUvw8aQ zQPNV-ctRLy=XtEk8|(;hU5CGRs3YQ3RhiOPwwZmYQOki;TD??!6@B~BGZy2 z504)dR!dF9!9QaJv$3+mG?OSUZrnx#-(`XJwMv|FR|hx9N5HTti`nS?4PnmZtMpa9 zK_d67jlvhLWz!UWOi&rjQ@?pgE^F6GRP?S(%xB6_>b35auC|HFAD+Z$-z8+e!5hCU zmSMjQ$&m0uga4Gv*J*q=V9zg;;m4g=da+~(&wu`o4lJ#~#;zB*du<_J+?)XC^Iy=x zu$SZ;-9np(_Q49%?y&v)L^0IeLbUolUX1PD9~Tt=2L?wJ1edNN;aKNG`dynx+KW0Q zE!zdMt+^pw+;yHVtbIk7UhC6i+ffV$-;;ux2`gQD4&Iy2Q}K=fxNrR&QjVS=+bQ{= z)36r|@(!ZUi~~3{F#_%w`H7)f7E344l+ln@W zc||fz$UgwJWgf6|Qao)N-3`6dB;fj7ANE#j@Z}vN>ei-f*Hyq!X)kjJ+-ac#lkY3y zXCFhF-ftJU-4BB`@A9PQCN2@3lU1qZTsP-hzdtyxQ<+w{q|hvi>DEQVBfI z(M!o&@(w7eQdgN%;H1RowIb5ACZNPJch_6Yj2!gU0<2 z=-8j_l(o15+QzSh=7M+P10E{OcHD~23cJztKyPvQp`kpb@(op=kf)`VdvN*IGQob? zVj(9ul}bkLlP=Jn$uD>I$3ER1phpl%{0`KRWX3Sqz0n<4UaIEnAgFUo5-1r24Z{Ij7hjSB=Ss_Hcjv7^5v_3f-C3OSeoDS zGC#?bC*z-=oPHfpLlxPNV(_^E^m4DFWayR*angl7c>L>XAy#t&eR*XD)tmux`^`z; zvlEm`OtEU(RWeC!;en>jf^B~rO14mjzsG7NN}n!3*N0MJ+~l{SBD6uSUq5*7pu~q~ zPNRy;c~WbiPtsq*E(jj&=c#aUXS_TqeAgD9>~ElB*QcZOWjMFYh~ha- zpQ+K`2HWTKg&3_7EbBIbmh{p>L$@vH-BB%m(RJt1%?IgKyb2i{SH*3!dU1(u1w5(g zgAq@|@L<&oF{d+(B68)~I3h*Z6ueye*jtNlxy^%-ce;bBaTIn=9fls=7a={lP2-|# zNO#j{KDD%pqJ8~IHs}O-y~^O5jWyWSONI;7--7nNK%Nww1Zr0`F|cXB$Q}yhW3w8D zIb>2s-WjYr(i>yqZVLyp7qI=nk^Fd6G+c|SB*VaGuy5{GHr%2Dhenx_IOr&RJux1< zz0>Hwl}2c{BcGmK>ZEV46w&PG4&mq0Ay_FL$T5-eGmQ94#vLi;33S^Y;FoOS=CACtcbw6fAX3vGBfIQTpq^uiGL#Uu{b3_sd{bw;^C;944B`Y+##d zRruC%48AYehvU~qkd4J2>8PD)Qfa>_Jj~=NRoB~#7Dnl0zVaN}El&{r)pFpToDpB& z>L)2_|0zA_`5$LH`{GiAbm;bjep=fgS$;GP#Lv4i-4)ffV#QhlpD32O!MAoJL&i17;a_A!Eur zG2&RQXm@-v_BuA5egy>JlXHDp-8cYrzEsjqt$0#cDvC~%)!Fl-8CKg~LG=Gi)hmjq zct#u>Prn5>ZGH<%1KP-Vq@uL)h&3zB8!b(t-GWQY2s}D^5VhO7isj=AL2Ko4q5Fpm zkl81Jw(@pKk@7=W7dM`2j^9yt41 zj(Bv)emb}86DVX`k<67Y*z&pu$M({pZuR|nXX1RJc)&NYxLARFe=4ErS_SOvnvNfT zYeB4K15LYrf~H#cKV6>}|T-t*K z_q+RP?X6-SSK?3Gy!3>5f**cQW+(p+2h`uv3vXV%E{JDUaQDdlXesSZAKN=9{!<_E zyt@<@-(Nr*_j$19xMX;uw*@z>O~R<&PssVL9S6_KBm<8W*tT^rPhMuix^5|W=x7q1 z9k+{94qc)x^-8E6d;x~roTjn1ugGGoB`z2o$vQv!frH_2p4uY8z=mb;{mOk|Va`){ zd%&Mk2O|b8Rl{c;D_QoE4o3`g5WmOR1fDKan{Esn!hCtr@U3*;s3a}IBy*r#?1o#7Hi?hV09|}qXrMw zXro2L9oF9#Lw;Tkl(5{+N>&AOub< zqxogCSSxS|W*7q5iG#%_w%Po)JRIGv`_M+yM64@*D&GAz7wUVJ!Ro+7c3-4RkAJq( z`Ga&oabZX@!l|VXdK@)9nRO5bjR1HRm&twR zYKca-9BAw9vA7{ImM$*#;JbTv!=29E5afMdcqlJLmmQxd-Ozx;u20};@^SFz-yZjK zT*~6pDh?=^h~jEh3>|wP2EA0_z|iURZSQuhepM)rP`XE++Y0b|4yF#h6pcuZhC%8zE3M^%f0P z*JOu{&L~rTlgiU9@M}pCoiBqjaBWdX5-l(-LkbAb}kgNV& ztlsdAx-Q2H$L(iuNyK@vHQWMR0!l?2xfd{W>p)KJrda1;VUF*8(?HjD4=QfCE*|@S zO{{&<1*y*NeE)A4^_lP&I+oq!=8I*p=iYl*;cJN1JNCo8T751tpNUTkYp7{pGyYZGQ;jm#2O^$5o!J_+>IxgNZG*V6r^`$6u_ZSvHZ!85nJ z!rLE_(w&*RFyz!AnklSglWiWXx4Ao1e7yjd-mal%@e9CXMKg4}I~>hL@+ z{-h3Ba%pV5eHOgwz5pileE|2(`eAlLgTzRCJa*1XfO+R$vtr^YDm(p*9_RMJ2qPPu z`{IlAx6@8EYM)CNtY-7`Uk8PWyE!J9$H zaMJHp&@)P%H(wmWKK;*-!|xlrcZ29IeHrJa~VtPy~-%JUxhfPt?Zv;YEhBa4E$35h}X~jOr^JD z@bzyy3|Kw_FR9m3%G`T!*)M^fDKDexGhTw6Y!8Z4H zq4d*OT-a?R$u2vD!(L@mqGa@jqE(kWS}UeQO)3OLUXBhq<-hqE}wY$B?}?4s9Ry4c^# z4NtB=DXjF;!RH^2pzTWoTDU#|3N|g}Iq%!Vs%aj4aK8iFb&Dlo`x*3WtmT!pugTzR zFCL}68j7zDg8N>YT%|k-1xtxgQM(8?RIQS}$Ve5g*J!h=T|Cu?XNY^wrqOjHN69gW z=jr_`AZBqpue&IU-%4yKU`!MqklBrKD&f?-dozSM+VT73Z~e@qT{r-A#2(Dlwd znzZIE=*epF_n>Nco0l&&S$z~rKkNnbHeL2P@K})ZY`~j+=L=_Jt03`N6gP|p81zbs zhxY2t-Q>2CVM->BKX4vBZ2H0Ql}owbLT?USG=w+q*AX9hIB<@q3-T{3a?|WjyPml6 z$$&HeW>O+~@KO)&RWByJ!cTDTKrEcMSS?0&8v}ZC3-RJ_8Bo159gNIN$mGZi@yOsl}fjbBBihI&lgrX zexjc(o5(J>H%j%|#IJQ~@XflB)YkckeWv{5PW3C|E9ZO|%7QTRS{`Oh8wJrG#=`#U z2Q;j+4R*916*cazW(TFWv?0F{0><`(SHrqFugX$p+fT(%VKAFhE%RVv+C$nqW+ET# zu*YL7-+4!aD`((%uKh$Bvp>=Ga*Guds zI&nj?hF~46j!hXGxio78zcbTBd9S0axlSJ6{IZh#oHh|t!i>P}`X^d9Or83!-byu# z2cg9&XPy-BK>S{GnHFuCfMcIM6|6nYXpf=-MCHeEkFrDLqn5$V=VNe9KX43Qw~^Srxjj49xSfO zeIuqVxKArff+^GIBQ!Qz@!?(-!q-_BXwHSZV%(9b7&BraFL>%NIUV$ss<%uBENT(% z^|Ry8f-{!(HpT-}NAZtCk(hC&lOEU9!#ztkRv2VJv&`&KS;-jsw?*)~P=<@AyYuOg zMR@e9f_Uh(yU=jsl2fI6G!^7)V|0%)c3on_nx!A`&jC--_Ja#1>>J40JD1?*{4-KJ zmGxZW76PgZ!uaRn@2I@75+05%0A+_j{;+=%pBrI_wJ~K>aU_z}(nbl{Sx3c_ZDVkW z@nJ~UHJ4WRUxs=qCG>i9163*R;QhnqLrC;~_8uLI&GUCaz{rk&d>SRrT|Iyc_WpAe z%{W#!bK}t=hq&wRH=+N`9?<`rJHFR-#PC~v@V$8oSgdztxW5~&r0vC;W!e~a_p10p z&y1^l)u=j6O(-9~fO1F0Ap2iH+w1dq=e=1xe`E;X%L@S`HCwp+?zKkSdSjXK zXxRL9BcFS-T~Ii&hRm*qqu!X|93K@UEbOWhRvEsB$I@N=w*4h({W(iPxoIG@pMf2{ zS5cc4qDOp(sJ879u6QfbCxaAz@^vITMINSgJ-zVx@A2%k#T755st5~1O2y!>-n{f( zKb|pj9*Ad>@V(9{QD?d=->Ux#yB;fxvuBRxzvE;$d-7gx8}=IJetJy@TotkFy$ud5 zFuqW04-YjiCN1^K#@RH|p-t#({qFq8bB7P`psdncd zAqzpbXbPk|%Hk=tfq2t*0^1wQqk)--pDCeXzzW`Y+Y@`O@j)+{dYIU8UHW#r5|!)8 z;ni;v?y=97zj$ck-RNAhnQ;UM?5PnOta@XCl7t7wWm1_+IrVLlQuP!&JmUHS&J2#= zyw9rux&&H1_)x6T%N{j<*uGsG&&P_C?-SsQ^Y+y8Y1Xe)9$0lj77xS^@Ksz;U zIOimLErnV`-wF8-WQBny&fF?rPjx?JG0wqE`f|N89=%piPsjVgc4amA8&gdubbYCB zpKjdlw-3w{vN*tgp%^7L2~p<8s8(iypMLJAC6{_&#(=BvvuF>FoO%w%itpDsl|dl_EVrx==owYkP95xRED@>b8=RFxYKrw{qy-rxgptuhg6 z3&wM2L@HcJUIMqDJCn4n2PYJ%vj5!fT=+B!O-8%n;iCpMnO5%1LEl8HPru>)f`c?( zNrpdc+r|IAsNq)h;Obdlp~~4Ce_x&qCayg(c5x0&APFgp+Uf#*yz6Sx+OC zoGs;Gotsq5Nm|XjPHXTwJj*W}v#4pwG7R$7#cyTzsi#FAy$rL)G?(G{vMiOZcohrk zy>@fQ$4OjqrplPAeuYJ{B& z)nHt}ey9&Kpnaix(BPXj=J@9G6aPrKI;xGnt9}RFY3ukxVFsDn$>0{x)6ns91fLC9 ziYHfW6n7o9fJx(*@y)6eblO1?w|)Ld%@bc?==(UnJ?DTVx_u+pt_Xl%0neyBW@kG6Ib@+^40&c=8V2%0qj+l3WWLz~8p$h({;t!#`c)ye}7NlI3D9+*>2;yLlF@ z&kn^)o2*c_BbM?8t^!wgIlg<;f;v<(@br_*;@J=Tg)m=39=$UTW(7Wgy6k^G+Bc5R z+b5x`syf?QEJpEm8!g^zj3E9{q?$o;ptHa|VevcS^u|QZ@8j zuS3UGWgtl{q@SV{O^v1=3zyWAvasd|lPou`hK<>X_6xZIr zC*I%i41Tsh7f0nB79N}~f`>cCW4&j#a3L`VCmXJ0o4s*t(Uec#%k42N{}a6OSivp_ z)FD?QgZDSYLhy!Rm?1NrADLEC(BDKzF)_rI6Xbbxx*sQ;vcW=wM85oUA1sdAOs>D> zu)rW5TH8{=_@^xj_xiA!&MJvX5z)Hi7ih4wfIlVa;$j;C9LyWx{yk;#o;5=3_t*q~ z-d@P{G6PueuB!9zVl6cN;sWBlL>{zYH+|VT2IKY~qXo75_|DJ$V3y|31!|5s^7d4* zd4~!(erg19Y7rIK55uO|6S!qt7hMmN$Cbt*PQOg@z;F2xA#2Yjev;e){!{{ z7ThG)3->%x5rerGBuy+3hu`SQdzGtku)QbPjf-UvfrNG?f!tWOkqHz&(Ib(A;4eP!LL)O~j%--jv&lK*EVVEvgMxTb}{l@(L z`)=v(b{`yReiM#0{9{tRM*6;9Fc9{0VlZh!|6G*P|9}PDl`J z{s=ryaUy?qdm#9)GQ(w8Ci8jqbL2PN`QOcaLfuQ{;Be<9i0_CK?4Cu!<~yfAt6K&< zbJ6C^x!uGwP>esGiGr(Rf3E-aoHjPL!hDTkm|8x7yPEg#<-so{mFH4m>9Ha>^Jh0) z?mL`MY_&qy;hAK$=MC6D$Pt65X*j2ivc!k2%52gS&;8GAgpM7Gc+b|IPfT#NI!SYj#G&>z!n@zAc#54r4$O04pUal) z^WG1h<~@dWXfC~cb1fA;VptsPiOPj#V%_55 z*8+`8fwZi0u-wF+W#eM_%On-C+&2?lEALupwCh3!30i+ZFNW4MjfrCriAx@V(ejCdYp)w@~vD z71TJ^43|%6U^sX|<@_NWv12ZcDH$zxDaT4f!;GQ%g9E3`dk5!~qafqY8-9oX_;cVY zNk&Tqe*4n|Gb>f-b)pj13VUh!;6hkeMVP;!ZcYlBAP z_SMg5_vOE^q!j-=Sif}(jqA1vwHsqV5!D4>szV$pYwUj=<`hPdU4_#0};pQ@|o{9xU#f?e(aOw(ur!gvFVRs`(pvF zS>S}VyAz!ZT@4_p$%^uCoX3URv<1WB)6n02JP-c3k3#Khh?f2!y$w$|XVnaDUAl;m z_aBePw`sv~6EA#|`ybvII}@E&YX4*Zui*K;Q0f!*_Fsxzp|gDqc-=e&47p|rIX{Nt zkdQGrV~w@+!bdauq<@lz`%R(Q+xiJ(NA|_j2D0#2HXf2~av{k7mvH2146E@@YS#WJ z_DHV-`z0|jdhtLpR4E?Dc1)v~)T2~8`XSk_d%-@xhk&}MA{nx6C%zHt1nI0Xcw1i{ zZIhM7)vcM>cj7*=w4jH$UF|b1jZLS3ldpvr1p|3j7eVyDn&&T*=<4$>5LF-2uVsC4 z=l6M}`|LA)dRs`7mzUExD}5AmS8&}7fuj`y$ssQecm4uMU9LxV^KEH?<4}AKRl-T@ z62ZB=lj9=ot0m0`|BWePAj z4rbbOVak+lknR3j*m|vs{f?)?j~^*C&DamDR*mF=X1UTOxrr$IL0Q=TBU>;%G=Qr$ zuTaq0#dO%G0`9tMgYl&ypm(_$=G@p1B|D-qzN?c4-agLlF1^@MS%k|Yp2BTK2Xf08 zL}M?m!i&2J;`KKk2_}vLx!dH`L;T2I{VGLf19s-v&HN+)rV(DA>Bx%{pMu}vhERR*{ z#={r)-kmID!B7`FZMFGQb0GeA;4%!hFu{utzrnx} zlPG!3V2p{krfQ#4(BJ4L{WV?*F}fkAM-r6OHU5#nbq!qw*7j$^qmq=24lEY1RJtcm90iBLQ}DU6C#ZJ(;9EUsOSuOw#}2PuHU1QXTG#oX&O7u zdJI(tFJQ>Dc$_!;I0UKQ7X~|=Csgmw%g2iJq*<5eybOg*LDqT6l2;IL%JHA;9O9zC zcco_clZBYdSK>nDPTo7h_g&?88A) zb3Rz`5r>6LBmF5~L;Wu*PG8D4*j#g5Pln*GET7frb%cv$4HTYx^D zw@BjWdLHN*pv)u8cY|t+2(BNu;&8irFlFyt)O@p_cO4dl=aW5o;DsnCc|2GQ)z~Z< z*rtvFopq9%>el!ub)PuY;VF$MoJCei!^MP=j&QxFJWsPf1(`)@@WItvxYYWHZudEc z*W3!IWVxL9LEV+gH2w-xvHTxv2rRu6C6S#x7c)28@tT@+xHoAuD^1LSvB2ct>ki3h zpM>hkNf>=_2Q@1y;a*RPs1{QWx~GRzNSF!d?C3!Q{P$67r@+>F*9G$N#O!kfO%tDp z7jm_!A^R76ee4Po6@7Thbs79U%#Xj>hNFA3G5H?1LL2*|)ceUtN*z8$di3IKo>m+Q z!;YWhp#Czek^~vy$8eE$%@U9#F`2Fx=NuW|sR9!!g zE^f}FqSXq}XXij((z}!_?K81*(>A*O;US=m0z11dggOIXSboxyr)zkUl|?!|IhKus z2Sm`HUIT>iL7ifXo+@l_a0jCRSGM+4qD_hFbrWQVa(et5ae1#8R9)?g$t&z&S^j(|9B%0<_j*l-2Bj0$TNv<3wZ5zXpSI&t_TW7H4_$E=WbQjk|JchEdyCCMH zEqWbj0K?PcsC`L>#8a&m)MaeArZtRB(!!{(|9+t>O->?4`-yK-`(S~^Je+%uC0E1# zxmO^fxoG>L zuQ((74P;Ci%>gUjc$@t^ob~J&fBw4|dsQ72v|kRvl^iFgt1sp}qtR$T?J{kqPI^47 z3>9w=gvRI%^wV}0ClC4nr78bB>Qp-=Hyz|Zj-SXv-I1pKM)awuhF#Lbbk~L<$w^h* z;`AIc1NviK{cCZ;h*9YBCxxodv^Qu4pyhjH+FFLaRbPa9gm@&uGFSV@V0HIpl$w%Dte>~CX@F=ucOb%_0u|xIONP#X#>gp%qZ3#c??`D z24I580cy2Xz&d>?huNK>W%3=u*a|lcc@!iXX6KXsus*o1&JujLZGqldJuz&fx_CWV z5p9>RBMrkO=;bBH{WrAJ@tzMz_17wTYj~J_FAZReCs`!>xj(+`_zq`>_Ms8BYWVi4 z9mEaR#>y=MsJ{sjHymuhw!RZ+LSh88E^^@6KemACeWDVzAiig(#?Pld#T(B3c<#b6 z7_~BhHS<+*>$8jWM^}%v68A#;@J7r&7*4k*ev_I_(BOT4<01S0V^|w(%?Sl-p`#JG zXJrFKEhxcy#W0qeew#uzCh%BWCtOh=cho3wy(-_TWiO&8Qu7D$;5~IQgRt;rSGaXXOI|Jh; z{U==5bQ6EX`-6*N1;ni#!a*I4^l)8YcHK9P4{P{hklHCq%|3;LX8Lp9O${itn#^~r zr$g}9T)36Af%{&_qRq2w@cCgY7<q$JhD_y+Vb(fSbB5ys4koPzh zivIDJ+P*>3`!!cdw^Yg}ynP|jTA6N^x?!W3BJ?lU!+Jw~^tDrlmmtQNbw9< zX-AUZ@kD$w)1Kb{9SNrYJ%K*%ld+>f7ByDy7nH|zQRTLNR9kaMjFfMtd&yB`l>I@t zr|}nm_nU$$h4y0XNf~~-XFi)ds?b57OuqJYmr&fgODORz=VHSIPTYH++>Ih2HSQ%O zT{!_;zfDGqA`4uZr-0u~55v`)Jvr?04qoYzDsI(WCH%b_ht&#(!m>6sly9$vhK6J2nzc4iBy;A^7jEJ(Qny$*gRHVeCL`<^BxZ3&l;yl z`LPMVFS|EB+vg6*rCXtyn*$C>J3()16G?98DOyz{C+RDnLQTUq(1b-faAx3Kewyln zx9_~hvVWX#spy{Q{@agruWTn%Gi~0odn(@@YYX;)_8bB6)n2&E??&eA5^F)K;Kg2=xtq{0YgD%=_;2D=paMnMM?EC60hgpo_6B7$4 z_{~=sKlqqntk_Nsv<3$`e}QIJcaG$ndf|dadMnL0F2`8MbEH2$2-Xaf z<5%wE;r%Xai1RYwIam9z--zQJ{dGL%nz> zIEu3#Kc@9HJJI&FueZ0=zDut%`IswrgdZrr6;e_SB~b3 zhfV?nWq^)%5-Gk_Vy@Z&zAMg;H!gZg{Ov1Un2-(&myZ|vk64DTTeL7VG+k5}ZYjK9 zyOuZ07@*5n4LJB-TUuYFE*kAtqQACU*rb&~OMjRPv&;6AwV4k8TzwMr3RFec#nUi< zuQof*_?Q1enp4~mWv;S+E!kQSh1LhZP^s$J3QmH; z%3TzBVg*}18%su`RqDnlNc{uhUgxIM+fZ@AE+Iq#r8e9aBL&I9TNrl zGA8_YSOfJlEQalc2iZQb2nu@!({87Qc-1Qs(yZqRFYKn`{Q_Mcx>*qVRhVLn&Gzw? zH@D)}nXRJswI|}jQ<_{|^n&INHKnmN7sLZCL0r= zwd%@(rx6-_LFc3R`PNsA?=ur+ZX5@#a0C8o*(ol3d{{CmV;6r@YoK@kI99bp9V728 z7e}{!B(M5g)b88`y(a&rljGOYlUs@6bMqxQv&jct$|Gvmx{n0q_V-k~egR}%3t;hL zEG(J&_ipxg1;oi&V1$nt} zPCpnR>>idwj%Q^VVv(|d~(GD zUzhIX`zvSh(o;QQ#qFIi+d~IshKytRTpRq66AubaJz!QpXOs?pOEG>9q*2w6H-tBc z<$21KvtlYKJUR|-=~}#X&k=r}sZ4h*tT6a#Pt@~0BrK9u5q=b`z~TGSgk>3f`Dmgh znAaxqnjNoUE^Cp|VkQn*zrkJ)jZI6zhrAIT2J z;iG%;1-?!JmRZt@zrl>p)SzQRF)jG_em=(@gU^`loYy=7U5{kao?YGW{EWr4PDhpo zlvtv}>jE%Q?tw$z?ZMM-@>JF@fLfXiSu$k-&Hg@ssy9rd{s)iotoOgExa$Ng8_bXr zd{OXIrY)E|M zgy(~Lb9wPkq0%T^I8@@#ze;!FE6>Sr^1331dAM>|jvU(Mn&as_SvLOElk@HK$?!%3 zADNxW+q(XOAI^rQmVL3#wKp9crj5OuJE7*yVO}4a%6lID0`q}8QNvOLnz}1-y8bPp zUv?rk?V3iJ>YkiDVmfuyPom^uT1AFx89?nI5aXzB(Snmk#V!)L%NdWiWnsti#j=4@r7fk&kUf2Ji3CKcpMc z9!*X;HIfy6e86ri)i}HU0jQ>haQ)6CP&-v5I@N3PU!4ZnVfWA7l560UT0iu-GmFEs zR#K0}OT@-g68P-0g66FFOmRuC=*SdhzIAXrPf}k5I-NHlWM6l*ezieR*>PJKVcH$z z?O##IXLIa2xtc4Bbf9;y5j@qPA2xk%6t*rOO?t^T7`b9AdoIien*@2Z(O1EfM~8F7 z$WXdiqmNsvpMYJ3GCjK442C8yy!z>K^eGGGj~&}dttOVn9f+1DRvJMvaA|CsIQjS#aQA8x{bmE+wOY+RUPQxFN=JSF55l_ro8j=ND0+S; z1hucMqur`j9P3ohFFzjBUXb8<|K?#%IG3n?9^NRE_cH0U>XDD*tCaiOsv7;Lh4}P!kp^ zoEW^5KlRhZ8^?6;{<{cj~clF^%w){o<27h{}1DFyVK&cgcf|NO@(0mgnw#r-L7 zP_>L)K=5m!pR?Pudn)j1fbBainWp8JGEiQPK0VSLDU zxZtnH)}E#0mQe-KA1**~Ydl=pAHk(rmNawF80l{aga_(JNM(~E?{am*L3Tf!yf+Pn zE2^cu#;X+MUG;f>;0~O1pn;Ctl)`z}QnAH=?zsh zNoyBJPq)P}(f<5p(ncI-RDkim?;+{UBd5dN$J15!3y|D~yhh)cyHkQRQv3i>$qRUN z*BJOPTANGn48oupo-}QahoIT;3i^hf!CC*AVd~4(|1(^kfn2sx7*}LwMMkAaAqka4 zB>(3eMN^VQ+G#2cB`uPXRVktnC262xq%!``IhBSMP3?g+-ZF|bUf-V&&wbzLT)*Fi zBW}%LPAR6`W+Pe~b%RP}?@{1WTaL3GDfrmS;ewYj{9G>u2J0W7^LqmDY`|+;QyfR# zM{fj|UZ=P*s2|xT%@Do3jqxqN5}WH&Ag=FANctQLefMl z(Ro-F+dx5Q4xxSEGqTZ{CJt_h!KEYCLCxv@cam0WQl*C-iP=NHz3D#1SkI3E2Ph`qnODz1n0G-e*F z-AYOA`DWN^Yzba}Ct#ue0**<3BD8%sCb|@E0E*Aa~EdCZ!>$ zq8^%E?}wLa7m{k>L($Gahbz}7LacXJhRqM8jeDO6XE$cix-$_t+UuHVD|eDg(2Cpj znqcFbpAcXCgYKXEM!M>`xJu&`yPvbgx;2J;$o44=7%`h0;53;Z+=R(@&x23gaqc(i z6gdR!z;lb1;f6{>{x;sM#VuzPf{dD!!*muOsv_!W^$G z{z8ikuS3=)32bm`K<`#>wvwBOt70awbwnNH?Ow$ttH-m!K6#w z|C@D;+>w#lOpGC#1pzc zs721`H%o$|u@1Tpeo6abrfpXgj#Iuj#zdthpg4Ce={^FO;Dtox@g2AaJTJ3h^#-&ZFK7oFC# zr4^C+K1a@J_W5sn&#V$RB4+>^1qnwIkr%dE$Emfiezn9+mppWx^b;9L8 zK3r?90*!8$;M?WiTy`~WV=U73|w*0lWDt zuuMq5aU*Ijz{bi`bjju|wfIHDs>Ge#(KL+BYqs*Tl^8fL>^SHI#Xd=Z+@YI&m%E?og|Efe;}R1yc*~yCRQRi-BGG9j zY%43L6(*WOYFBRy>ZZfvZ^>cusZWr!`3s~CYa{nvEZW{e%{5Y6DZZdlN$>Ft`R;5Sf+>Yj;zoh>l>m#xJ3c`S8Yx-F~Nw#`zKCWdqNS>P(KzT&3R>m5n3f|JoGDsE^DTiNCA%Cl;wEqkL0O#0N)tb z3Qbk#B;)=W!{=p$r+cdKApJlp3e)75|CPYJx@sX~$9i_Hen-C)Baj;Juo7am5-55w`mqYyDaw2qxKbH$+Cg^*z#fFBzt@rp(Zm^A7i$j!MU z(F=~{d$ONs!IkYWMR_eWD|EvS%}MmqIvIzQX270hT}(^8ho7H3qk$VTX!$B9&I~P} z8OnVqpx&FG&zOO-yY}LW*|wU)e;=J3=K~lrV^RWeB(f#7~9n+@{fOnSU+nv zcRoQ!(gMJxehLJ5ETg2il{nZZisEZNNbVbbp{;ItLSk#4px=K8ze`XAU-23Y{}RSC zM^@41KZoh6c0E)Ld<*W{@yk`ox_loz>}r!(t0o+Iksd%@*Ue7sF{t z%3}UBW*7Z&oQ>hpN_@up3C&#B9d>P-hHE7IdC2`&bUmRzm-P+@LCrzDvwD*FHhDJc z%3s0jW=A?EL(vqgiuO)06Rd$zr0l3`YN1lG<8}3%LLwO69G9fH$bhY zIhtKE!r(ck&Qk|VgSzi zEG&4~jh|M$gOuhMwB>ytKK-*B>P1h3hAI8Hc}ffnSrWnVnLpv{qVwYM_%QGsY7W~X zvPf@pBpMocVziMt&z_z}BTr{j+;WbDoPKqX(`KN{E9hH)Uvvcu!{6Q)otVcHn z*HVDuN9w<1Gz9%#!=(2NMkP53HUUkdW{Da$y-kC^1$V@S#X1z=Hb;2;Nsk`Qh@&$f z&8P`&L^+S4sHq#zTbw1Jo%(@ls(nG#>a0X&+$`FmxD|K)+r|0^j4;RbJTE$Hj{Rh9 zXoL6zzI}{>nQ4otWVRpvuss9c+b^<#Za1RX3|e_Y4=YEUClmL<;$hb)EDzQNl@tP- z3Qx2+ug2yH*GcjaEuQQdA-Gi5!MPoO;Oe_J+V}20_0`*i^GArFvR0Eit9Qb{m4*0X zOgNhj8pcl(-1xq@4?eEeLGb9#vMt{DzO$BcjC*iQ#VFkJ_Z(yg#ewy>*V1uyx1oI5 zP$;z-#Kt3IP+{N&^iMY6GwrkZ$@#~kf50g^H*6<)Y+BBx!wpe2D2WV$yf}QtZdOm8 zCQY?p33_isQD*o!kj+=bNefqlRL2reo$bZaZ`%07f05wew+nW}52M7yW|H5rA0~|b zN%DtN`IY|*@pgX=saty>H0$(2(MeZq9X<{pR^FrivMVSfF9Bv>{foJB3cN2PU-bWa zf^^TWz~B1)>9=M98&o^cx3v|#Yvdl(j(i|!oHa)G<2$KL-=0q>j6ykaI;;71$1)QI z{wPi7KYg`nb8CC0J{aTph__;N_!W3*KLX>^f`p;@^6az30G}I~V8X;t(59A1r-v-! z=Qe%Fzr%&M7pTywjn8PIX*Azk83Hx;L*TZ~1L(Atc!hQy{F+Jp`+##li27O9YkcHKh4w0zS>l1Jz+O;71=NcHX2%LywjT z&IKFkRr?NVjLXC!=9bK>1NqR+~GXD=y96E>iVqd~acm4@ys??d5ljmu<<{Ih;4Us-yO6Ia1a4g&}+Z zzpQ?Yi#|l)Y~^xj|GJ15IjrS?J4T}WoC;CB-z<8fr6Z0C>6EUkS}j;aL}O3;DH7A7 zIQsR;j(<0W3PW0>V0m*Ey>H0E?q2_(cK$X{duqgq7nSJ0{(adoVGNJ@bDLJXJr~AZ z{R->aV$sfMIa|%^O}B05^79|h;M3l%v{SBA`eaHX)NM`|>{ZQiS)V~JLuQP{&E}rs z@u%~6a8?giDN3dNSJSvkIe@1R)W?E9r>K`xZ`7Y~Ks0gK17l2A!-JD{eERZYIIu4R zg0|Fy{Wxb{G__F}lG!YdQ1}F<#t&%Cf;{>f*$#!@zLR*jhRpA#;z(UbEZWin*H5eQ z<*!;4r58-wwG}yFV>G`lxd5qaUyE+C>X0-6YW7Cz^}_+rmcFLNjXm(2ZXYtMlv32RWV-RB1{M!phdv29D0)QF z@bAB9_sV!0YLGy3$rk)I$(Np}Gmc1IN&y}jq&TgLqLacaw{Ch0yIl@(;D!j8_$rzo z^d5}TXZqMbu*<&|4PlRb9hx3*gS#7|q4$&d6nL|g8#0V>w(KsPJ0T5z#WaZO31;j( z$_Kqa)KXjPUix6<&L=XmplX&oZpdqZ>8tCg&#I4FACiSfn=VUTHoxcP}6P0X$lQ)X)>6A_@AQV`>w?6DvIvZiyAL|Q zrs4W&bFh7A8br?9i%zx9G)Z?i=w2!&*_gS|d*&Z9f3C#6G7pF~X1g)4R|H(Hl4n=> zDLiACAFVYy5Ayasc+l%9;_RFRVf%3-?p!edi!an-@q@(>8>`OS_Lh=X?s2f45I~FG z@8pViIUG7$K^R>#9No89!jUIApwJ_dbZ0EU@u~A^U0OE|a?cRfy)uWG{1El+h2e?S+vuN4m@xJ3F$hrXiJJ?C^Rs!bEScy)#Zg=Fx6yEX*Qv@Sb8iy`J^~XB zD{S5}iCw~zY5a|me5_CwWm+$izRVVBq3T*`AiAJM?0v!gk0wqrm&NVLDw28Xf5dOP zEwpv(Na@<|54D*tMzD(K`@)6>Blqp@EKTX+rctZ|)H- z!JCrLR4BKG)h_sh<=e@;N~sJV%qbziiyC50*A((tg!c-%SMg+l5a*#Fv5INMky6lrL8?dcBQ zY3B*IY7V2zxHhg@kqbv}jONv;5{Yw7uvD#p-LQXm})=N8F~p zQ_sVr8M6Fs+YJHVs*`QgELJEU$rB8Z^QrHn(INgSnD{J4y>)(M*XjxnY?EQ`MJ0|% zE`iAS3LH7u62XHEv}S>VMTCm&GShXhW&bC{c>wJ^?n95!x} z$L@1hO2@s82V=9(@OfS|em;{1RmZi(@yfs^pPGbJod^mZqsI^5^x$4{i-mO62((-0 zj@cib*m9#fl|0%<%f}4@yHiHoyzevV4*v=#O&N~{NGW^RIe6o6fz)TIqICTSvB}tz zqb{7Mp3mJyC-cd0`=K)4+_Q&FFGq_rdpVHZy;^bgqY4^PwS}Au<#F^p1N^B~3^5;L zxh27!^9~1qOwe>3allqQHL8t1xc>nSw^FQnRD%CXGhy%6da7(zC9iZj>iuIZ%hXNh zoB937LVqXr&-(gmEc*9wr)mVk{m#zYQew?}F2)r4l;~LnovA5)%b89I&K6guKbX&a2Uaxf!J2b+jc4qB9ZKiaQT~<5n4?`qCN6ox_5HGdoyzP-Q zYoAW#L7qJ&4ITU7g?TWp{~3Y@3+h4YoGDgR%i*up4*Xtw6h0l5LBZ1w!s<9JnD^9# z>_tah_tT2kmFQ!BU<6M8GKg=?=*FAh9;4T~ld;#bNn+Cd)!b)Eg^)gJBAhsw1#d%U z;z1cp;>d|@u*e- z4BMOpH;XP&FDxR}19H%AK7c*521p)z%HeC3>-4TrkL@S}{-N~P@97j+l^1}$}O9_2m{4t6o((2nh}eUK9A z*6-vWYqTL*`+(?Q(}N7nPjHe(vZ%GlPtdK5z@86=i?2VkH0H-ScrfCY@Oj ztUV1suEkSW!%aBt*@KENjo{5iW@Iw34?oMuK-bz+lrHpuh>A)4Us@i0^s1AF8I;hs zz+mjQEKT~vXS*Sn3o#OnOy$H-A@uN6+@kfL*JW z%ZNrLPW-Ed@(Cvy=DA}J*#Ug<@mIR!dP8`6D3WVkYH-9?3!;jhsQTWUk4$pIZ^jDH z`>HKxOcrR=uoZayzz#l_wuiP_j?>? zx$PIgdh;2`su#$ixy!}hI`h3Zq2i6r5x|K%*=KB(^wq)XWHIyzT-RP9>P24{&Ckf= zkzv#DWLYo1bKy74B^_=s&Y{|dTw#!^DsQ}#4XgKbr&lAJ1lC(kr|+iW#an&RZ-2Z{ zvsi@_6|5LC6NM>{O}ORv8?-oE#v|t4q+=^wc-ALfaGIV?-*W7DsnHgko^k@F9?iq; z9aF{f0kQb4*Edp{;|JH4j}eDH8o*}{#!D_A9>v;qZt(AY6(%Hafx;S1-rCwVp8;Dy z@r8l3chB{#m>ESHP0{>1V=w5uy&!heoQjpzy8JgR13v8W$L%9G2@yN5(1y>U;?M+3 zp4AwKD?GN+kN;#aJ9IGL-TN6PDDH(9Jx20T@jI>F(FX&w)uAY22o#Nf^ZlwDtALbvJ$125U{7cJtkL<}9D~mGV1nu_53*X(o-q zg5NK|XH73CxHgOB>c{fjkM*KUT$ZF=?my^)r)Y0zi-pIX;jPX^GG2Wb3u;L^PxZXG z=-481{aFh0zZ65-;TS$MyOy+buT|diOW~P6Z1CrnVtDhk7xJX8u37Serrzs?3$qRj z{S}fZ_RMK2SF1w>eK*du?*ne!i^C4-;nK1KxEMBtm6emoE;9vBTsh72J~YCb(5^G? z%?AB;9g4RZ&G+gSVs6qRR-91Ivrm?zP4i{YoxT@M<7V>VW0Rmfy-X~<8%mQK>L9Pa z%R$c<;LN4{!Q3efqf}PXxTLokeU0Eqm-2jTMy@PxGCI9(efn zDbhN&2{*0urlU|UUT$uLe7!=NTGc%STxhoM{A zQQ?bh3M|Z8AO=QkmNqSGl_Y&0!dqwCVrWniZrBjQ)>ET}Px|BeYpg#`pFNFDObqzN zD+PFKl`rbAZ3KU-IG$_&2d)nPCv@aCL;sV$^e5DS`~U6o`url02KjKbqa*LRX36$J z&UiLqGPvH(7lZzL2z8#CP^Y5ma^}SdDlI#S@;$A2gxVXyH*X=SM#S=l3qF!i!vXA& z9}chYrsMm}p}cm=3_5TQNNczhw1U3V{)R1V+nx>?nj_e(XtrRbG=^=?R>OifdxY@i zCxqb8vydD%P#CRU18o`$S;k--Zkc*W;;y(1by7XZ_=^*;*9#$QdLQ;XRw2B<5|V^~nRkV7y|XZ|V;yW;a+y^69HiN9 zCO9X0gy1&dHmwr|W8#^4ylvcGDzfV)S-2$*-jP)~gU&bP#&A z9>*?Yrt23$%-g<(DS0;;&e0*yf9YgtR?Z$yp}hWkH}RR$TL|#og1yg-hwu5}XwsD{ z`#P_~^I?VHT=0ozf0x02o(A-)_QVMJbK-*y$N9^=*}UqTL#0xA zIV5d$0Y~}sW`@L=)4!8ReXXj7k*_q#R|@j-%pvn(s5Jn zNjTUkP>;40xR$vTGv_+snH}@6A5Fq9FU~;tAOrqUx|mH?-J#XD(rESy0gQGXpc(H! z!i!nUz+G(#SA<*gq+z1aKkF5gXRm>&bFPt1^dFdFqlP-&qxr0^244RBiDJ8Z;FyJv zB=usn?c0R-D(xvN2x#Jx>$qkq9PFC!*2GD!LJ93DY}2Lw0Einci54 zmI_In_(ByX70u;}x^P%{LQPa{{SBtyHBo(zDt5>w;+|*P_)@QdHm5EVRRWcH`MokR zchn?qOpc%_MkNReeesL6Ck7i2VGRW-{menmeP_&VH+w-JV{^goc@sPu{74u(WD&2t zT0)PNuY+Oy8)4x;sWeUQ6derv1=}o#;l&9Hv3hPLm~2wzCx6v=Q$PGCRxe{Y_Wcn3!I zKPeoz+y*_hbHFjw7;N1_g`ng6xXeTcb5Cn=$h@IAbH5avj|Pr=ut)_J#!TSTRyA-> zV-MFJn#ScD?8$Pc4DQdCL)QffVoB{k*uUOG?EGB|s#6c+8|zYdP+topc8}%a`Jv=F z$(QEcI!#6&_lWX$?08A`1dJcH2Zdfi*e}(F52{3Du(9_payxbx(yi3cT>lRzof&X-&pKI7w}_*x$!<8l zS1~1?--loBrr_L7>v45}7Tiv;ZyV0$uwmc{6IvuOFW8Y!!kbLbLD&;ERV7-~7HTN8M_EaXBcLQPR z^kFNKvl|~z4MRu2%TT*MjKr;Dx&I{{8gRs(r$4?f7Oc%8zwb?8dt9AOEyuBt zRwKG({1isp&c(BSUNog#7cDyuiYL~trfi2HtUY-FFZ)*yVPX2XrJ`K$y_PB7SXft? zI{6j+x|2ogn}X5d$u69sK0x%SeM^Iij|j5A+Clf(OR7sq;2D;>>{zdiiKkoPYpXBJ zs(9GN?l3A@=m&pdYefT_VA_+F1gCPJqt|3pUV8qhq;Ta)4rw?B*VQWM(uRZd!tgLO z#%qFtL><#3BhaeVjBmWJqCr92_(`xCXJ$XA8Ba}F9V9sG+b23<6o$tu zKTD?HpNSCx@;qz&PT_C%c?xOX##nS7f85f7Z~jUU*K;fnDRhO~*n{zb2}{q8;?|w6 z@F>3)8(Tsdp|Tsjj;i8?ooeMIW3)L_Mzc6bueTPRzk&C4`Dh?&bzz=@6R@SyY-{x0|{ig5;f{*fY0 zHj1W;lVu<_b^%*YvBvI;L+IzUP_)~3S0Z1cg|A+oCY$)7KXk2BCPXYOux=#iD%1J@grdu#LvGXIb87zqQVNKhu^Az zx%EHz=CXlvQbzI9#kv$c{F?AAwJ(nQmkOUN2I9YuhlRx5Q)y+u45`YHBz$Xhn7_~+ zQ0TvaKWJ3Lz%iX<^;3ZYMty+B(+YU0cbjN&b~>(nqrgM6s^Ok}Iz0)oqieN}R5hT8 z%sxhoD-JEkb1_;jAC=cW9>;y z+)@V-#lN6tdMSm;Z6NbOcGU2DEZ?;2#mj;sA-QS;$z6}e(~m5{Y+4a`9ndiv z<~Qvt$eecbnePpsBY>K4k@|4J*R@auba7y(j#; zJB+UyHIb*K2C7e(#xM9k5*LJ$iu+^n$%asN@0CV|8+y=^_5Xof-4XJ>{JHDxq@aGV z6RN%Y^Q`^q@Tx$3xk8|K?W$5+K zp2J_+2)2u@LHV+u(D4}Y#MmG3=l2mD7xw)Z==Uq%Hqd+@+8-;#~V7* zdAwsHn+RS|n!gkCti!>0nG=oBkB1JcNc{78H%+{J0KWyz!1I2|()$L9EbXVv>axXx zi&LmzsXl~l9TLD^X9C?nrjGsJ#pARdgXrg058mc!#>X3v!TaCsFu-{UHEYkJF%~lT zEHoUCTFK+>_pl--tR3I11>9JzN8i{v92==mBONX|HvU+%qxOlTJq~1_QEyE|ceEb=(=-Us!W|;E8 zFe6HDn#OUuqj=5E`TX{B6`en>%TuS$!C>EBD0kn0WKs{n$p8G|r>QDFvyzb7uS0C5 z7lH;(D)3tL!&p+Q?Ds`(-0p&Fr$(@r@CAODmWoY%_TkHbNqEu5 znS(0z#J#mIsE_d*n%1$Hdwlr@`>IMSzl|J*{mk3M1eModz2P8SIb9@CcsBzxUi9WD zqw~;1R-W{ZM~k*+V#V^9Q9P_O1DrFDl5VXk=ve5XbW14gw%kufveP-FM+uB8s}bG= zc4N)FWNGVl5pOMvl}@?a#nDZQoHeyh_~@aBeNRU5e%Cmfc`6E>pFf7&AHnE4y@UA2 zA<1p4v21$IpO(+)&j-WK&@k&(*q3!5Hu)!VH~1_q_fX{#9|}RGrj!0CEvL|HyRmu0 z2K;082Fl|DprC#@p9tF|bUSLyHTlDNr`tUm@U{c;Kb*mU#3@{|MwbguoTY(wk05jG zZXvsK3|pBNfSGp;>GEn zq0qGG20foNioM$l@b$ZD8WSJEziq79P$3+uDsEQVEg!&ddK!WAgeCZLcnN#wIrBO&e0dR#mUFj?&h z{I!>1)8_p&afb~1dK>USe-n-h4#4U^sa$dsNo~6y_j8elWS!B3Vt3eA>5iT@3&5x$ z3Mcwz(!ssRk6IV-p_LXS8`w?!T{VS)OngLB!*ID>@z_|;S#+s>t3-P^-x>?A?4K` zf{7IyIWXb~C|g$0XTyH5@MotOV4NlVcx#Po?zE7VzXy*0w+-FL&lj$*@Z|9=Q~1-I ze{jC-3aR%DrM0h=aq^>+cvAH@QV@xo<;zwl<1A`XAF58k^+(mCfCICW8%XKgzS;}`xCgT_=sHY-S9 zlzpQB&;8(MV#W?v>N&ssv`{!ChH~Fe!nKa4;A`+$d@mb>ANCETgCFN(QK%U&&K@J# z`rU-)O(6Ksw=WpE594x)BeWztOQqAU@yCxV@Ogv{WNloCJLmP`m&IlD01raV`*dnt zegx*3xN=&{7a@Q0CuuI2qEFvUGR)EvziB)Jy@r?41wNml^T8F!R*%8g2lw-0ClhGf zmP3Klym3&Ngten3{3P-Lm>EX0tKD7t{nDI#4QJt^D05+=qqcP1!YGLPO^|=>u5j_> zF8rPq&&Tu&p|a@~-G*SHO7w+4v;R`l#&LMnxQtrg{)HAjPxfgzga-n?kk;$l;NoM< zw)-?;&+Sz(+2jIM*K2cmoddd7cY@zzQw-a3lNQ^IX76+Fgs2(mls+p-Txu1J0~_v( zmC858Q!;;O+JaR=@U(MMFC`;RY#AWv4nVxir{3NL7D;P0{K zq}MVSZ)cvOh${*7_&;wPIk*q%+-A7h;7;POAhB@JDvI17%bAHbJgr*>Hd__2Z=5;1 zj2zEj%RR8Ymm)2_x0`6#KG>jQjw52Dsm|mehvwXef-|pSzTzfu^*t=^Q)(027i!~; z;Cp0mzZGV!bKstElrd{Y@0w=OqIweQ4mwG5 z+mT8%oM@r!0j|s62$!$4(v1r>VEfmA2tbTsRb3E z&)}Ma)A`>>4=&PoFi$m*WZesomz}NcC-l_)_3)8rvh1KWi7#3hHW6c-o^bc9-&jG8-+Vj5u(B6Mv^Ni5K}{+)1R4j zd@t}lD3#~Ke5pEK&iCPsdveLTn=wjC_v4SBN5N;|PPY7ejXWeQ_A3iRCu4se+}8|D zoJWB2s+ClA`>liw)j8#548Z<9kSNu_*4f?QSDXs1x>^dNI<69d<2Dar zYxC`5h-VTjK2zkF8%omYRpYSJ$_5R)f3DEcGQ;||kJ9M9>B4yTJnnldUVLyiMmXCM ziof*JDD=Y@GPu|Rub*b|O)VRwZT`4nkU1{v-7f0vi6_kiRgiB#kf)5Sqphv$@z-G& zF}SENrbgIvV{SFP+#Dfj`o5sowaehbioWcwbPh9v2l4ywvZC23PxARz05cYyr1ZsM zJWf*|&KYY#d6p}bbPt6=8%IL^ty$E2N*d`uxK7ot7K$;A7wGBWt)fSv5k@w7;kn)$ zxnX;M{%TkzO)F5uHtpNO0p}@Pl=2_MT4>_=!yD0b)=~JOc}57!tf243V<=(LbT*o+ z!pnAM(d_S&dArsT(mGv7VKWOMQn@F-{yZHfx60wre_zFd(feRg+Xhey|EKam(CGl#|`5p zp@J~n^g7M-_)2D7925@}L(8d)*xn-vKYKo;Q~q9jGog)ab~IDQze}`E`hye(*`fi3 zVCds0j6V|2pF6!dEj*JxtR90wnUjT!;e+_^^P80w=fi2u!#><0+0V-~2GHg8lj%tG z2o$%g;@1XMG+W|Rv6vRWIV#%t9%Zj* zs=URe1BCv)MA_35IL)vgUKox>qpjcJb%C0Y(e>|&3NAQ2FOSv~%EIra{n)Hz$bY6E z6m`6A(xXUANWE>y@9vId^`hapCVvNn&0T@Kyc92by=1rdquAt_FPn}J#oS3cIB(`Y zS{SB>M&cT7Q1eAim&5Gw#RIQt#L&E^-@?M{CqX-H3R$EkVwpt}Z_Snm8P(JHY`rh` z3@DOr`BXr9_fjD*u|HM+?#20wE^+5~Q%ru;1II*pqm6MlwunDQTTG6D&(dPas^eqm zc2=hJ zP&E>+Pcy(tUg@N>W&+xLT#rlcn{m>MBWSx;9^%FifnrGpT|eZ=x29B!T63S#WYanD zs$l?BeV4iF>Z4D8cO8SEppDqPd^r7U>ZHt}o_Jctg?g+n=Nv~xR98JEHg~*+mp(nk z?tPBJfD0k0adRlg`7A=u*^xAFjfkbcbLfr9bi7*U%i~JA^Pf0l{%+EX|B9E`)yQ7j zPkT4zW$5DG*h{q7QcjTSI^pA>SMXU=6bp>zaPTjXZc{Yp-a2}iyQDkbS$+yu{+r(E&q5#rgMPp2lT%M$8jL;xGl@^j zKzn2amQ6N*cWYF5;LjcSxM>Q%@V!Dy?#<*W%c|g#st)F_T}Zy8ufhz?Hxlf-5kGf2 zkk6!jXmCN79Q^&j^n(T;D(X)I3=YxW>Jj`x@?>*=?O0EV@* z&~L2&Ha+<>F)^YM~mJ|C>#0NE;5Y;k!4I9$!9**mJl(YD)AvHN41Jjj49_AKV! z18%@b-vsI7yZT_7vqO0HVmCBt$D>YEQdf>Hgyth^s579A`Wqa9z{M9RBEp4lj(kNn zmEFYc-KXQk(AThSi#>knJ(q53?4l5jRs8R*D(AmjD<%)D5U&Tg;`82zF+hFP!!ado$;KW;J_NzKTWhtsO%03+0rbY0InxEpt z41M^r=N{;F^?I$YoQuyGPri?j!MV;0(!U9nWcXbdmwqhZ_M0t&ZPGFhobVVNFV(`j zJzt@`-5Jx;pOezF!MLE{8yR^G1LKw6`29_$SUArMe7_~rz5`mAx>uWb9+%}W#VS;; zRYR+z9=LJ5n1?f(LTS{*YVupRKy2*4h^<`#T}z2CiAm83HR>&2d{pR9slQ4W;Fb1B7gy6FF z_d>&W51y)i2ve8qV6x3Xe2_eZYc3Ul&G&20*$V_x@*corI{M?u>JW_G*-krOoAbyS z>O3XhkABAMgQb4Eeg6R+0(`3>CQNP+f=C9vVql%k3n3D zD%SlofSi62Xt<)0QroSeTk$Z`@84LNQva9qlhnC$%n+8n7=<{jYnN{-c(8ff&8K49Z_0rxEpvSQFcaZ|d$B zjcyy!q?H{2MdQGAKpr)i6Ab*jkUqcn5pG>r!~cdH05zk#H1x+ESkmbU*Xn;m{mc6> zHvJZ-Uvk78>0EpfsE(C&JNad~Db?hq;id6Qz^m)Nyb7lBx!Uz&Nr|#p^tlhVT-Z%d zh6lj+^SRLb;V5W*a#oC(aEUwYZRw2dFWNPI7dA%>7edD!5tjal0aHn{xN(sV{*Be< z;GoT%jG02u$QQ6PJ`@ViRFTfuZ!qLs3=B#3f{SgoU93em>k|tNX}7@6L=8Q+CqwMY zUf4~xHx>ov)2s9t>{(%o;ST$$;k+%|%#J6AE4{>g6?wj}$C}5E5utnR6}+c?12!b| z#L9}Xd@|UD|K{!xt@IRlh0HS0bp1$6R;AGG!jZUSQZnBgdz|vTmBfrTJM`Kz5S{1t zXM=rRzUy{D;=R@%4=azLkm6h9J?##Km0u#Wflbi)eG;`d#lhM&GjYpGeH>_I%AM}l z$@}R*zTNCAdYn8$KW^&4v1zh6Kj1s$hdqU(ANFCrojJul+ek$Vk|}rjLwfI=CC)mh z!3zhB!~ZEX55JzjFOD~)LPIK*Qm8bPO4*gq`y3gSXp!udk&LLMv5s z5{dC6I#<0F?emAic10=N*jht9%LLKn%S?E`B#PB4O7QRT&A1{)jhAc*WZwnR^uhF- zu;SoiQgiU(?^%jyF={qNMf5(u)mwvd>e8rB?KYgPoj|csgD}l&6b?+3LAM+u?DzO3 z+<2h?&N2JNm*&%@Wuru)L#Le{ojXQ7WNJxWp2y7%>7e3+h3C|-jTc+|65v?SN$MDw zCHXbE1KI{XA)kWf=x>%pVVw^kA@wh9+GRl(^GfK~w4da-D-X8UwMc$@sMCaxOEIvV z`F25}nE0h9)HqGVL78&2ZHzygE!M^dFRFOq^8}Rr*YhU-?qZ=$GxhHL0Q%LTaNwZ@ z=UVh->N>=2lOwSE*;?isi*c7;J>|N)piIMMQKnOl<9fBi-KRD@FX=GEI8WqW_AO8m zvXC9qUI-d`w*|QmYBXW=D%4rI6T6StET%a1!l<=1WU5p_WA^Ftys~jzTxE~BXUoO@ zLw94v6b(G^@S^Bq&`MzU>ak|pPrAzk(Xc7qNG8X?`R;N z95f5G=dXs_)~0NC)fg&&XEOo;>mS5kY7M=Q}znQ8&_bTI9FQgtj~F^>S!=;9=Cq-5chkIA(I8K zKuX3q@^KX{@qY&<`{r?5;eLGMZNUyhP4MTnXH5N1?H!_x9md`^E5*}UJ4mJbRA z>yNV}G8_75#40uYd}iTkRug zthB=srG2=oPJ@LsYY2;*&(jshqL*1Vi5F(@sfJd1V?Go5syqkPo}J{j&56=J$BR{` zSK_m}MDqDOk)7xIlM&lvTj3Bqs}Ri59*1fBg*^D3+l}uu=b~f3GIsPdz)Pncx!TbZ zn+~rhQ^nmBSs#w4uFb}oXN&lXnKmE%{eps$zrdTzj<`OfKT8aI;c4G8nlk7yJKsu$ zZxIKu>y9O^4ZJSZo0q_K&ppw*gT)zB;=oSD2c_Fm1)Ja~yyh3kbtkICyB^o*q)RY` zS%GM|dnzl1r}9TfJ3L-)j;Fi-5q7*2N%wv@4LcHxsoJ4b4Hv08PK#p{_3?9;90bq1 zE(FydAdh?*SeogF$}d0AE`?$eJx-jv%GV5B;x5p7La9 z^t+57<40qBlL`74cjNx=WyMoV&P!ikP2lhU7@@4+ekk~UmQpOos6iDkjBwa9A1Yrq7{a|rK|_zh!k<0X z9Q>s_?$1~!M$Og6o-J3&=x!|uE^=tL>o3U_yae^X)A>$b1rY`w?HT+VvG^tPBo{mk4JT%L?9?o^bZhKayXo&y&*RdblceqjMvU zQr4$TteiKR5<6eQO_vz@&$t{FZChwp+FiPn6whsQzX)E2W~fziik9eTqp^EGJ~PUf zZ$&Htlh9V-yS@>Qyc7kJrH`Rn!xV<}k>i><)o|Q19?f5#q$w&(Dd_Pun%A*iu)5Mi z$XaE|zOx>~#^YLi(9~UA^JWFB|MbMW&9Tzz3p>SkCj()o@L9;n4#(|7RJkVREKkhM z#N3N^lv^H!Zkvo)X1*T=YmN{u9Ehi=lgn7DHk!RJ#*xB|q3G3W4YRa*;Dhst@U;jq z{$;5oSGJwDO-|rBvx9KP;i+(S$~yEi9K~H(1*Bc1gh8_=li`puy4imRo|rt9Pppp; zl}4EJ*!fDBW6}rb)&He+d6h77b2grR`v%j8xH1tH7yY^72G2`4o2UYa#bmYYTD%iJmI2L{`K-q4C`N_m~ z`n_3}e`Yj+$)9`Tc|_7%I)}XP6^R}_d~lIWi>SA+QF?m%G?E^D2U=aD;kRcu{yINH zTKeZI$E57TWvw-^c1biAIrL(U1s}-1EFQ{HoL2>Q*izy~20AUfs(m3e6L#138F zCY9mF_%!;{a#(WMt&BXp-|?S+PVN|!PIt%lL8aj{*vv@Fr?TcZ&s6k`A zR$6x+e(i@C>9~^J;!P+-@c_sxXY-Ilv$oN#eYuq@yDyQ z>VrOaOA2H&hyQ3>haBwKV1qZ}HcIuBGHCLLMTJai4IDd#fH%{mI%fsL(+7;<^w5>qL;DK;h|j^ylZDXTX(q3(`$+muUOZ^SRNnNr7mqgzp>3s!{N>hZ zem!IroL(n`b<;QFS&v3><>rYvE^Z6>&C+7?Ma!wMn?2w8{U69_H^B46)o{k;s^FMC zM0iub6>hE@gUe)75RNUyJwa1w?KBmx-_eZ@_C8KlxhA}B{T#lKo{KhXZ*qM1vkyQjz3?E^`AaN%nlu@&vWLkTS=0<58e>Ayjfg4 zW)DRxB#GL;d+_f+voR{|z35sR4tP?Z^slN&W}NK}ay?t<{wig5Rk(sV51+EqyjSGe zH;Y#5CZM!SAD7=w=FT`pytH@}WuD20H;NxH^nny=yf@JE`IEVM>kiT2ohAjnUBtig zn;`DOEFA16;U@(z;D>fPY04FW@d0HvYu4rw{S+}_M-{%=Fq&=-{!S}Rbog}3ABwnA z1}1an@C*41&^~4k*e`UK`bRB9QR5Ufp0Niz(>5~P9ShstMw86NXSAm#PBd`cfu&Df z`NQnJ^r&?civi;wi({f&#b+(uuyo8YHt{PItBmD%&AEecYv&IkYV8m>wM_;s56#4g1zvpW z-BUO^b3GeOI1L?++G0!7cnEImjinzy)8x~I*lX!_(f3l8aCe<9ce|V;?Ph0g08|vzb+a$wt)F;oN#4?yJTIznYeM)RcWY&7rMRJ5B5n0B!Bxa933vw_S)&# z6`W0p0WH#|O+$G^a6QFO9*Cdp;p|8#W}92*NqBe`8Y0~A$n|-GV$VH-n&W-p-O?OT z&oJe}9WrSC?k4$L{iTe%rzm}j6~5l>h?^!a;B)4~h0#9E(kqf^Y7OnjCuU@!AEyf@ zQ)5XfXe6IqlnU*$9dWmPHMPW9vYplf91^+-+h#n0Szivo%}Z(Ysks9Je$MB};|&zE zT$i0~h6<}UNAUCe9l{XDS+J~U5fnN^K>FG1v^a7B20C2_k9ITkUi^@>pQMQAtCC68 zPp9cWL_ zU4r?R&y*H3g?=9y39b90N!R(Na7fs~=X`2-=(3*Ju`CTo?Hr71`xB_rKZLx7M`7MB ziCFQg=lF4s+1%a`k0}w;xT_{jEMH~Dk1uNS=xJ_PoMHO^w$+eDNB>-Vgs^@T>tS4vgf^0s}4$ej;hekHr!G$Jx&E4{dY(BQ~6> z;P^;uR2f<&>I5H#%#c@9{Qd}(ym7(OZ@bCv=`t~OLK5E)jrc`}JU?|Gg9U$NFtUd( zx)!v>eF%VV^dMf%I%7hn+9pZnl z`%=g0t=#4RT^Q+JK?w=%VEWCLY*ze+4*OSddG0L6oJlbC#c5&mnhiKd?VdPo;xLHa zp@RL_Y=`Mh#s9qB6DPm;$2nPpd2P4;Jkg^91wuh)*IF^4ND_v%u76;&yfO&Nes z{{N5CsJ3L?04WG-c7vhJyQ(DV0 z>Z-X8dh_zoy=Jpm+|iSN9c`lI%5`9K-;%6O82+1wb##2eeev7zeLTWg3rkl!lJmY> zkQ9<9Zn@t9vFpYa~T0fJb@BE@=OEST)<2uQ7H)Xe)-z0V#!;Mf4{P2AeRQqak56=`R z^_m0@hjgL5Vh1Y*I^z5Iblx1=3&#c}0_XRGO3r?XtM@Q&8=C*Lq`j!A|<#Aw_GKK|T!kcq?vsu4Fnv^@4UyrSz z=AF~&ab^q+dp{L}jc(H^y;e@$wvv~=c>o_c6CWQmr@Z2aQjZO<;rI0fEGzsXsv1n- zW54oo(3EXJ4^F|MJ)>ANNnXqu)emF0naJOR#C2YxN^foaHgY#^ z-=9mrpU4Sv4|~%|IawaIW*GhHGlU1K%HxwkTJY#$F+cdKz~;O6i%%gC_xVkiUOycv z7R;^!i%KU{Pz=W>z53#uw@m*fSaadG{Zt;^mj~b8Nd3e2kjs--{BzJ2(Nv`z2Rcl~ zody%3SNH^u7?c7kGOK92awe@>9?HRaG3fNi2Enu&JU=#;J-%+{~^hXIGj3k550Cg%91U$;&aEN;-djx zcv|=Bqz3t)~pue=z3sQ)YZIVHM4g$%XAo(LDJ4Xj-s7 zgWktC;#;o?BpG}i4m|MUjBCMX!&cae32hqOCrA@Mhs^*DRTZr9&t{X8eOOX9oGjZi z!Ps;>tO@X^FjG%FV?F~1oLYcB15D`Q$-^{o^Da_--VV1F`*Wr6f+DTA{o}oKKA7z) z)^~M7%i)XA*Lk&QyCj(gJ{$!a`?N$)my>k%b}2n}H~`_#%K59bUJPHEBg*Qp!sXVF z;G*?T+P*9WGMF{6Zg=5};*#XuVK)ELuG8nFD0JUG8SlRdvB z^QeWUTovgGEoW`ecx;kT(&2@Np8tlT(?rSPL@F`;jDY0KR^e zfQAO2srXDH82G+Goh|#|M7AJInYoph|CdVTL)$1Qb2ab#>mYnsXp6_DMpA`~3eH=1 zQmp-WnOZ%2apcQt$Zxa2zvnK}lyqHi>^RPQZ5zZ`0~zQYHwWEsSW|38qA=#73%*s& zfbYLwiZ@@@^B8Fy2JSAQlZXC*f$k#itj#1#+XOuPw@8xvc_fuxtK^$Cm0))5JO5Gz z-216QtdS|k%Z{b+URcB}9dS^o6Uz$%x?)BSMxJHe2O&@q-S6nolu5z*{qR^* z9!JR~u|wrVin&=x{&z|_;J7SjuYZr$`YZ98bAQZlR%SF<1U2e&l%*c(}XZKV#I#`oe|G8+W7Epj}z?KeO0Uc!~tDm*kZ6PuT7;P%jD zOx;uiikkKCeacT7o|=X-%hu6`D=o15+Z~!7xn0n%QGu8}COqlgYr(6&f6V0HZt6==Hh@P5l+ z#Kh_JAUvCcbbrG0U+QqJ(gV@{JdG;(kCwF6Lhc9|(pGI1=6=tEaT_*ZMt5~ox@aZt zOA^>-o6NbSk#hXEmMHV6Hc!~TjT3yX&`_^vj5~4yGG6w@Wo^N1Wjzq3>6_`R-3wv5 zl`ejg*@w?N7jmwzBBc!3!Wv~~z|-vk9UR`BhXhz*t@xi*dGC10JhT;a2M*;Ii}J;Z zE2NY(Zy!`Bx5I0hM3#5mE;eM$#?rCDqEpite56`NJ8Z0ly)V~-2%EZl(j>Gxgd8-cGSEp4wT zwb&Rnr<+mSQDxS7)ka}Y^Kox?71k`SgpJ##Q0K$37_cc-ymdF0=g7#??fd<3L4y)W zw;?qv_FxNzD%vM&A$p8BNE6e0!S3bBFxp8A$E}-<+h5huM*|(2I(sHtRSkjNpT_cq z{VU-9&;DSf<%ZAu#pBmYhs6g0=g7TVt@L4tJOm6O=^gt3_Uo`Buj`jZxI^VveV1V2Y~kxgeRr0;5?)7BDP`C1k6<9ix6 z=o2-a(1K1^cU(G34Xuv%i1ZY<4;wRnx(=#di3nSr4sSdt)N`vEs%` z++{ooQ#7^;X1`p>LCup3eI$5hrxjPe>`TcKZ8maQjFqlgaA(*Uc%C(nihE3;-1ZUh zH`s?4iMzxL23M$iRxHcjU&h6cTqS+?%|;gv5H&;gLq_~cIJiZE^FnJe=kzq(KBJB9 z6_s*iuN>-lodFwtN~n3%L27sT1liH^FzB`#q)yt;vrhJd4hwVV2j5lD?t>X$3M-(W z3Nq;2V*{qxwm{13W1wVX%UUMOMSLF$_DkgHch_B-meo$h&T)7?v0NPKIFCP@rts7u z^1{~ZAHn5*l=xKj5UmX9hph`n@us69Ru?71z^|4#v2_>^yV#E=w~Y|G#xLZsS+d+Y zI-dXXGA;-ogEKNrQEg6lacjs5mI?Xic1s7~@Nog+L+wrbZv_wH1yi-zVEY^{H%y@SudB(-!;W`88HJChzXhch6~1k< zfX=KpAvvXZnD;M(w{D83bAzm)Dd!M`3|_`zudh?fpJ$l#?xs-WSND%OHuAo7b6nlS z5w3k3!okNDVQ*mz_5M5pYZg4A8H+V&yIMRw-uZxri3<3tK7h*m--7VTCgQcaB+%Tt zlXk~Vr}9BvLY>iNvB)f&ghADk3hgQoIw$k*WlNyovjM%ZpMWuXt6)U<2Qs@`4&&-? zQsvPPury2=b0SUnMz;ylcJEr6clE4rKk6AdIS-)Ym7XALe+`f5){$bvF-p82&&x+^ z;-f5CJfZlDy3!tz$+CfBVpjo|#U$gz*l^U`a}(zN-7myWZj!Fbn1Newj^qJ-d-Id~ z$n$O&@rtaMuqM|TC*=;tc^#{rzn;|-_hs})qrF7y(xXY{WiGydUn?9gvxU;j;p}rl zk$-Kkg3@2-Nqzedm}_Z-vSV)G?Z7LvIL3oLMg~&v-My(+x`AvPqIkf^r{M3FDEvAS zz$5CeLyP%jn7YOarAH3Zo(Ik(m#z)P{`TUrxnt z#fn*LL4L$K^0r$d__mp&^6Gdzc&S5ZnDmZ(&I_ElQIssW*jpGGvXt#J2I5^yH*VU! zgU8HU^)EMraCYCZxK%Qlt1qq=FHP-+S4*dex;ClspMwG(jz|!v?E5UWU)7g0Pc=e$ zWWBgswh!NUsYf~?9Wc!1C&B7N!j~}_v^(qwlzlz`H;*19W6KmMA`*=NFyM(k{&gV4mziszh&hUnfs zQL3zmHZ_@?T9t+x16I@M_g%u2Gj)UafcTgSM{d~yY1ej4a7|X4*Q2xwnQR{*i%j-Fy$*oKDu&of3jzr;} zS*ln%B?ZGYHd2?D!0M^%dB`zEKD1Yz%1zF})oKgQYf9(Nv9E+5+RnKD+rM?ON1*l0 z2GB|h!ug|9i4TtNqKOa|S;`Mi4fMKS8_YW8-$ zOMdffz^^WxqnnCg?0(#jbdWQ<$ro*|{C_n59-_8}< z)_AS^8FJ2RgbhnF#2s&MQRN3soTcAPy{&S1XJ8Gs{p^FhWsl%rCC6HcD}?4g{uuGk zqxxDa@9g#Jy*6BuEK1+M%-XhF1|}xNaa^1vDX8U zf~8^70^9j)c=a)?oALzgEyHk@{Cu>Vcbxw-N}#1O0emXb1q0|UU2V*O&_TU0;qX9I zb}hn>{(tH6%xj|U^hhI+6z0JfhYaU7uQcg@_cZwTzH~NJt`b5k zPl9$?G%5$Ci*Zql;Pn+dwDyh=3p0mvL5UgfzM6rC^4Ga3+Zr9!Ejjh)jMFFyEJq9zPLlJB`rpN*;~POJ%!V3xx?YHsi)`t6+U*1htL`p>~>zb%W%Dg1>9n z?oS~`nx~<~x&U!-M=LcAUC1-H4-;MLT}I@Qc^NfiHciq)!Xz1b?EIIooL1)EaWr zP2xjGj`6bS#W4KdZ1fBL0cz`>!rzj0LdJ$S(RS!o-&V{6BIlO9K700MO$CcG3FiG5ikF3}8q8%al=d^?H=JzG>+2mnhuKj>R zChmg^=a0j$qkV9GlN$AKQ)cb=Ay{^3GxfSKl}9dKhM%Qx=(2n>JhVMQJ~O7!!oS-= zMNyCX*p0wzJ-q4b*cX^^X+I6fwt^8!oB84K--5d3Y{~DIp4|J`54b;KG%rypgrk9S zxbb@d>{6IQJ0fLyg8n;D)f_77zPKUojeG@FHHSd$bp}5gD$tn&-S}>@JvuMjNmdX3 z3USXv;N5v0ToPBzIT|{6a?CpM##>K>P%EBmsLkaMd%Gzi3y`|!1DjQGjDKlalTI5(gYbh7=q&HEZ&+4e}X_v~Qo zSE9sndMZ32bb?s_ryGy{l+BCH=JN%eavC4B2NK_Xm2$ub7^^S=-OQBGzu7_@n17P` zpRz)k+wnMN<#&M+8+G9TP^CO7W1>~9vqzWgBlGc;oY8YI4dxTgqXK5 zC#sHCcZ5h+t~KP=#{VF9V<(NjdL5ijuAm-o&p^CNvoL>(9xtiuq)gW&oU+~m69-?0 zQS+kd+~on>F*{s1?H$YmhG@|*^%vrYS$(;ttOb1+_~D*qkEAu7E7?1&hNNXOD7t%d z@WBJ1`Yu7p)_TOY+kT4a{d@7ck+QflSR{$ZA!w?L#R1d4!RM?A+~;{e9$8&0`n{h* zN1POJ+2Ig!$aceFS;}avrq4MQ-|$}RU3faw4HPzirv7DzNYriw?aa-rI`e@v{mmii z%Xg0Wes%|yl(ve~68veoL>-z_cEB!8DS2-E00&nW(}xf_?4uUIPP%O%SES7SmMLJY zYoa*1r6<{E=7LYrv-smgvw| zl@=Zh<;3g5V8!uj+8d+94P*V-==LwLwO2l0`pTa-jB}&4dE!w!W;u9$CE2HlRf_PlJhM*9ZO>Zt# z2;DcfpUaI@!q*!-aMT+odW$jQthSF7y~-Ee!tJn1Jss4jmQrWR!vL%U@8lHP(>REA zK8?drEMzNnO*9$#k|LA_z^gx<((Da;Xs=8te*0KL(}I(@NzD|d$tYp?c?ZZ}Y(`23 z-)ZY;TbyT_Dp@_dN%-~sKT46w67TivhC;}CIG}GR&2`^PF>VEL;7h`}fn(2#_Fenf z>6!@!UYF&WJ~r5EfEN!=7%!f6-Hf4~CSaXo5BJQUgJr5Uw;laUpRZ?8XwXSv!AW1S zuKJ~?j|9;T!{7kyM%a`4X`NC(^#s zjn902&;Db!aljizxVAh4Cp=q@&NUB2h4&2kcUq*)nk8V_k;h@?3;E!rLBi(A0GDG< zK#5){9bT{=O_LA7(!swV!R{$bRI|8I#o&BbdklWwI+@Dn*TKS_0(9NXbc%Ia7OcDUBrG{w%~(5$r?*Z8zXb;&VPO(1$Tr}hrX^_b z>L#dlq@(`Iujf2=x$%t=*GOjICoph71TCA@+5TDz*){aTFNQE)#1_@S&9YZe`4*ISFIzlS5? zemA(_7eJwEa=2mAVEpR%&);!BMK`P9kB8sM=Xoz7w0Rrt-{{9vx^00qZ;#UU#B!9; z`z!o8$ncAi<)x)+Mi zYtXy7lR~f}S&b%`4ILe)Iprkf!Z1Zs+clhK7VNBOfco`VVpQ~DhsvG%uc##h~ ztC(`l6f2HhH5`j9VquoII{)3QO5={5hH-!2OXL^Lg}Gt=9CKzf3@_?OH+{Z9ciSFf zx$s$3O?nIFuMSDCx!16APvoK9?$Vh+d-VNW39mK(!t5W5Vezv-SWr3^r%()=YfM3( zioyJM=`8r9d`b+{kC*)TZwQvP58?GXyLi3dR!-Ssh<)Bq!{+LExNCBr_DSXObA}5( z(0L+yM7q)iGbb+8n}Vg=VuisWGjPVUjpVIWK-05^K+Tx$9DZ~a9;wlwwi9OTHp7#1 z43tss#&p<~U`=vHB{XyPLNu_d1dHgEa7=A4KiRKOqn&5b&h^QlWa36uN4#jToHcGD z7cgsBj3a&4(`vdW81Am66&;<><6R+%4g$Zaxgi{pbmtqf@i0-6OYe3sfE;BvUTtgw zr`jKb)UG$EHmKtQyJbfuJQ=1V9= zc`9zK_Qb@c0i?IVklu&e;7R>BXq>f%bB&hJ1(ir_)4D@W12u5?qBJsF-VTTVapJb8 z1DRH)2ul_e)7eiSK-sg1ckUR<56fl>=lZ++n=yg-C?|vVw>$*3J>{Z`K`1WyktV%9 z_oG-xL-@}iYpk<;K@0AT<}BmmVxNymd}B-!L>w{1w;?eYw(zL3zw1HFFPI&J3fqE$v)8aq_e&-y)Ibk-`Tc#F{ zzCQ$t>UNmrJ%wW?T5?2JH=Yxb0~%w#f=kaTN>%BJBddbMRF^{Z)E<$zbX@)gXKZr7yPKX0BYliunP&x^a;O!`K5oXk5l&?57>oNJ zMxdo^5G%i!$b+m^xzoWBhAL-^D|52w%|ugt7DzbweFeMe9;f=e2Xw013oYh) z;DbJw|9npVciun`w+)zZqMWAR%7?O?NqEimoT&2EmYuRk|Kr4+^p8pK%i~QnLiq)_ z{aJ|%&Um8!;};O3tH)WX%f+S6$lvo?LF!D z0zJW@>NtDN&*q7SA@tHB8nen(FjM0;bnj?{y|-?`*>x9$?~VFcuxv2|2U^jBnXS~T z_YR@#Pk?yv^9S0vb2wjg(89$Bx}yWFz_#y|v@?IdczS-9ctYESY|;*q%E1X-Vs;QL z8&Y`VFe^6PkSOd;j6uEgE^zzEE{ZDNBuN}z4A)nepsTJWe4c2I87p)+TV)8xcBpX5 zSrfi`+8kB7FQfm&PB8U5Htv>C&|-^8PFlXKXtUbJLVKqt6KV;V|bP zzxd;%`IqSveW$Vgzmbk!9W0mX@D032hv&HQxq~iPyWgJ=d+&s`83X9Z&o;Q1co=pL zT*vQImqBmMe7@oSgU)Sk67GAvhacNRF-h1e){njbRr#Mt=Zz`Fy|;qYQVYydTFTSU zo5AY|Qo5mSj_$VWsn>~H)YD_C^yKrNuvjUAr+;$96F1VS^VJws&%Q}{1003Z`R-tj zv80*07Tqj-#0Bf3y^nW@@l! zKO>&wXhAJ@rv0tbwS~7o7AaoA#WP7KrG&WuxSM+IzeZDc=GH5Uk^RedhFdXL{&!9dE zJ@H3YI!sY>=i85T!D74|4tKf??eYm+tu+v8%->O=<7?P^NtS;F&ZH}K`nbB-mfItJ zXvym>c=~UtFl*RNvKe5?nzNO0+!u9R;@O=eY<`es)-!s1tDQD9&xXhTr$E)v4=T$m z;hgzC;lRUKsG67rTe6PxTkmR`bHJInAr}|SmZul%D#UwU-LT`87G{iz=Tpz8)8Lb{ znQxomz>r=P(yRm}%JqVlLpz*bHUUSzU&`4AiQJa$DLz~q0;48hvoeG?<;O@2=@jpMa1BiD z*cG2v&$ zxQ>3jYw#`@nR$Q%Dz~Eg&Kl^uV;ojk45z^tm05qY434@pi?6-0;iK)%{NzeD_YZc! z&viY)GshjTH(rFJ(FIswYK02tcHlErJ;KEaN8u5mO39MZ=Lhv)v^P0 z&9(-Hsh?t<#8Q^A*h|{`MKBU(pqW9V^Bl!l_+tBZSPq?F?>n0n%-ccD5U9~W^Lunc`0C!MF#w@OU6#`43uJpOA2!|6 z5Hv*oGCM?4{pBOMcS)hL#^eKbEZaGd~NR{ zns{g$=eR4J|GIS@zMk3-wCDcY%ltd^-n1WHITnFCG(W%;nW^mjqy&tv9T|5m?I)xL zsX^uM+w|9>2*$=Y)8ncN_~rXZ^!*Zq3ySn8sP7|sSX)E!Z<2(o_fnz7U!=P?E^>*? z5WFtPL&Qo6*0zl1GxNTPt-dBW^;smuZ2cgX?HNfUY~wM(X$rrz-9i$l(fss#Im8te zf!&pp)N#fU4}5Q>cYZZI_v217(o==fA(rT!*;5?myBelu1)#5e8+5r-Y`jfLTMB5F zY&i`WepcLL{FEl#+9`U=7~{8tgQ)MpOE~=7GJe*s$e%YT@X^{W@W;~_`!1Zt&QTp; zs=rl?OV$(pU;6QrO>$6XxC6fXZHAhrAA&}&#q?A72nGg;;^==lW0x}>jZ&TqOO{m& z*VbyW&c05;Y1a|ZOA4on)3o{Q%I+d$8R3hxDwwU}LQ4{S#a7QBLUBPU9BQwnu}Rwe z?$=v<`ot8A*Yp;q=4|1Qd3|_Z!f-4(ug$xz6pGny#r$F4Am|sCfEVTmqVFDG@@&Ya zjaQW*CLU>p%rH)zo&xccK44A9XbuzJk^A6$?)z>pTsSfd6gOvynnqfa-tRd3FbbD0FshMMx9#QWmGLmKQouQzA! z*2Lt<0CLRVfDhhH7iatJrzAG#{~ld}%7u;2T&2QO7M`Qr=hdL47|({+)j`=~DxEd0 z1-pCtv|0WP)W}C-bFCa`YMV-H+O5z^N0;snek5u5w1Gx`%N8DL4WnrTz&VQN_l+8K_;ftx09I|9}~@#^Cuu9<-&T zfwuMu=4aWuoE<$CJa!t03sv{Cn(TY{x^XQ23W&!UN+#krZD($+eg`i*_fqoM--628 z3lOyKA-;7m6K73*N&}WAbMv-c;_&^`Vf9Wm9+|jf+?!LzlHd9hSmEeO)NCFo3_U%B z9veeg&44W}i|O;Owb=jZ zTk${5p``V#4@b?K4*8AQQ1omkR1F9A|EN zO_?XEU_yTd?s_s)G>Y1VL(CfK+AV$FIPEXVW|vT4fDVSA8^k$p`=ilkyM}i zoTR9XLJ8TFQM3@+k(N+Vky&IG5~)7-Ims3(Nf{v{%9j1}`vcz3-q&@#UXPBG8jpF= zA+Ahp!X<|dP zz^l>gVMJ?xRI#+eN89^h?u-ypzO|Y3G7Y64mzm(zu|$WjDR9hUsdQYJ4R4%pia#F2 zqG#a}unv1iH#&VuB`s6jJ?AD_1~$`;yd2v2uAJ?pF_>KR2I#jIYDZlE*OwZ+eCtx& z96o?kHs#=?<_Yj!H<72cl~V4MR>9_VAIYwNER#3ksi>K}1occFI}KKSfOA^ngs}6j z!rYN@Ty^^#1WYWK3Y%xp(1$vlvF-|Y4w}xNB1`D)5mgxVE&)^8pMYyjE{-isg5lF- zXxm{WRR0#p;o7^n^}aa_oHtk+n{Wt}UDWv5oNv%iI}wxheDLVQo19)T68sI5Y2l<4 z+`c|mlE0`2Uz1hD9tYFl>Z2TvZ8*j=I~tMmOJH$%8Hg(na&Uz)etf5no=+5UR+=VT z1ssPqi><6(lnQBIQt4`#J>;g;iQV(2gG;3o-XC@Z+g;LdzpO7u^g$XNzGILz?ag+>~h5pevG&&u%QP2K9NHQXBzV&hj^$vJ5%yL`~Y_E8;jqZ zTGpr3Xh-?-R1ng)0jh7W%GdA zEFtb6<1gEy&sDR$c=gv~+;edrR4lZoFMDF~me*^+B0wE4cJsm4JAT8cT4vQZ+4QjK z1AX1G5FLEfFnOK{%-7n8_x2Z)$`>~{Uj2vs{c5nYL6^P*yV)2%O9~YUsLqJt5j-2a<6T+>z z-;^Gl?YvR=oc%?xcUjKiszvmDRT|qg6;SvZbE;czgiVf3pqXlo6F=XE+ChgUX@_!n z$k&%}d$&8^xp)nd_B4wXerC9P_ZZwCeULUBPow_DH&EJfk2X7ogP&A}?UV*#piZ`M zU}6|Q3*9Zy0iv+?giQs_Z5Ik(^g&Gz5I6u)-GQA>^MnuJvsbP^*qh1Tav}o~F zpZj8K>_fDpJ-8!jHhVXDvOhII(^_3jTJeD<>Vy+50Kuh|c8jZ`6dWft@gjzVpJqu)6MpZiT<#QQ&pDRsC6X**66jCQp{Ei!+8{niII8eJxfEo#eFr^8uLj z)|3aNy{D={e?fUmD(%a8&Y9IVP*G+BQ)1O{&yWc4Xp#r}y^Ha9{YU!ZvX#cSoq#=m zuTq3t5zL=*m9$FNf>E#!se3Dv@t`f>TjnipPuYUwR(}`o#~&3Rr>x>}1LnacGbOA@ zZle1$(uDrKpVEt{muxX+4Gl8(##5S6=>Fw3jH(Ey*m2k3!17$$|932RHCmuY)>ItY zl*2&-&XIh)20#5C3h-}(qVyW6%_AI}8dvdP882L;;>>ey%A;(eGCv=(0+f~-Fcf%d{wcwe!@V+89c@)E;tYp@{ zxCw90?xd~L4#Crb$kmb4$g$TKSZCiNo-&lfysSN_`r!(X7ah@RLk78P_7#pCe?pFK zHY{^u2j0yeEPXPmKW~09kY#PAaokBQ(EPaw-t&B7GjmfKW1gcISCEhi=O5c3laL}f4_)B*K9rR8i8AD&3J7pmZZj!(P z+s{<-Do+gE9s?c^_R&0ZdE8;Ffd`hB;lsS$a6@l29}js*UB@Qz&YCmQyMH9yt)>aj z$q&J~1I#!hY7I}_J>VZl0H%Ibj|pGoL&jTY!){5$k4;Z!vO1SW_t^or`{h%tX)Kw4SkJLh-c&cg z6np&$!gWcpV&%9eH2bG7DJWcnkFFm4E%H3+XN}>Ld!AEnkv^&4*GApH--K9AMT`+H z3y&;I;80y3UV7AquyqO7-co~(=yf>Nb z<1T{iBz4lsdoK0qqkv=n91!b+jVLJTGxR!t2>;42gu3Upyz-DUOV-U6{n8xZaGf2y zdL9rOE?&a7lLm66>UY6ZHjeeDHA3GV*086?IO?#QjSJ2&vVc8?2C_=lBJpsQ5*+QPg>QE*r&F)3aj9}OoC-__+a9NB z+u|e~@Fxckx|)g&t&8~8zYW~y{0(j#JSl#?^pC5w2J$7%Ts+$S8QI^Iky!gKt zXyMQ>^ywT;&OXs_=1vMf3Vki6OfYoTeK!ykT>D{!#z_{(&PJyzsnjiV87K830rcl` z2CLGE*VPi;uai*5pon@Xe{!n&ep0A1Yl4kE`{2PZMrd7|z(*pCIc&x!TABU|2Umi7s_NdEOw>cAsczXA{J}(8ddE9y=xIo}y_Nk9gC+m;+^Z|E;> z+batz=X>ykiEpb4r$%#e)E`LruN`Zb>(eH6EAGnM!nIO2{Asrjs%2i&YuE1lJhTS4 z_USX6!8PP?b1V&9M3S$*pbTzerA$-xC%Vq%4rDk44pJQIGK zFW_Yf<}4}A;azs#JZ!i!?+m&M>I%xZR@D^cwL@|Bghn{&lP^9@jp2}%0+?T}Q2q2k zca&~)p<~BWaQ3e%Vfoo+TC1E3OWu}p{HG4GyIq1)K55{3rBPU+7AR(K8HAocw$Z_g z0B-IYjQg#gNXl}Ka8!v41ittU1*49_`{a+*FXb{F@9&7e9jZ9ztUHH3E9XK(C!C*U zjwYQTrgholerX-tkK2pBNuN+dRR_5Is3_ZEz!m2XL;D3^+%6{bkkiNM+DQdo-MST; zd%19OVFv8?xlDdvd*Qi+JQ8$n3V%=9pq9E8j4PW=f#FHq>am5@PY1)cM|t3WY#Q3# zH4={61>w>41MzjYP@F$y1HM1$2`WxnLgd+8+VHOvu2%^>d9^)Xo_kV!bLBI+y<5k2 z2_ZOeqAeuJ2V?%WO1k;*HgrAy54whQ(wxKje0FU(j<7h+0Z-j=v%Md@QA-gPej1FY zobA|q%NTs6JD+_Wy0OaZ7JBAW3`?aSz+$NgjPT1cOwXQ9_nsh|b6yxU|t&P|$&F+!UK6~NVW%_d$`y%E`dXk@miZ z<}Ode<88AjH@1~3bzjkq7h#~kdI-d6Z6hBmVwVk>Fsk}E^_{a8|BRd|ocdi28;`Am z3#-EDludUU(6bYaU-+O!J>WOjwV>e9k5jj~L*KJ=cuDmr`gpZJ+vg!0l=i~qj&d|E zV*SoNxEftDT*B{+*euctx9+8GaOfq{(#h+bov!oP>}xfzJ(N9eS6zNljgmrsGtXs_wAZ6@L3u}oJ$qu zrz+r%vL|p@*^I4MTH?1nFLaQaqoQp-Ie7eIfpP7^^h-LtPGbhuC~EQc3)4Ahy(X8H zmf>FOt#l(|2o@HF@QEucFhHq?w5_Cz423+jQ;Xnuy&c%&k{-W1JRU7BoS|cXyYXpB zqhNZ|n>RkYN%O5ljF@GK6;VCWCfk&IEjv$hcTS}sF_2edoDeK~96NTbrE~8!@QRZ* z?{FC@j`UKLcAl}})$eoR&bTi6^VA=I%#PqR^|@p-Or19hb1)*zmj29sMFDw=!koD^ zPS@K*+0X6+JX<{-y|i5Lb!VBF&^MJ-?EEFEN?Yh+{RMIeeg^X$Jvr1F@oJ9^@Nw*Y z_~X@+P5YR!>eg~lw#cXQ7jkG&S;!$j5j!s#aH?G*{8(2@{S@6P$s-Ui6uEM5>i}|@ zlEjb~$)WD|VDz`c&^>V(GM^V6wmRY0slUbSYm*^n{snH7c+<@gd2Ud(!-(Kd!sU1) z+`YCPM!Q`XwSDWLMK=op)46%I`g|F{b70UR8jNpKs1qiFKj&C8~xw! zgWkifS$2R7{Fm{Lon#-t)MjgL$ytGYPF{cmIv>IF?mNaQAFs@0+_+)ZU*Pw0=R#fVpu0>Up01_!v#| zIEPM~8hEDSF_4N6drjdB12%H=(*nUhc|Im(%ix0UYsH-Bhs48+YrubvD;~Mm4<1C^ z19k?)H1j(edgKMP;EH@mc|l=Gl`nHHy}U5Cbf?_fe&9jfe~$Z>bnv9_-tkC^ito@7ZK?S{OevtPf1m9Y

+k`d+eZu5yHe>!&=^e4RX~&TeKA3KD~5%H+oGL%)WgAN;nDo zZ34Jk(?Q8GuP|_`O6Jg_`8YG(4#!$$fOb#}FLn4O&geE07r)pplvnp+THHwGYo@_y zaS1y#+tUdr060L$zYmk?cDvjCf#FxLAV^6nJ zu%^t1O8PdzpuR5b8~ldHejX=&zh;Pe%X;AR0}h=lN3XxQq4~!gA1x6*+SuC(NeK);BH80^}yyWcBm%V4^Ee+aj2(+ew^+uj#;w(-y3tb9p8-x%`m}p zxk-|S{99c4LJ>SA;$fjL|o?jXWc7`mFX8reGaNR$7a0igB)j|$%$}J@VS$g}TlGma5H`aI%L}wQ+m>glCs6*> zAA(B8NWQQqiW3Izr69>dT=r%zRGfYRFDKgYhTelwF4cp2E!jf5o7_ahf38~pv52?T zbO?2Kev*T#6w+p;i;r3tid~`eaK!HbjJUIr90x7Ooic-H(}Hr*KGB2s*QjyA?Ls*B zp9j5=O$C?FTX=EfchY#e3bs62iaOI%!De6t85CZG5qW=v`K$cl+@y0n`A->oJa3aK z)o%RfKTTxg*&tQ;7>_UN#_)07W2~{mAM-m#5H1bIvkBf@d8bIYckvM1Y0@O~UQ^Kb z*-oBenZ?ncmf`3l6Jg`EIaoEjALLZ%;f=9d#QPWZ_?N+PX_Cb;{8ikSeNMli_g^I( zzHl@A=qHOU#)H}a*b6WW??=%~_M@F?C>l8(6Ki}ud4#V8H_okwxo2&;|4V;Cv!xIe z)0g1c&vh7DK7dbLAI-7*fg7wmgq>rv$vki^?=QZ=GJ_l7il->#oqGl6>w5AkF&!3o z#pC8h7lmHV4=8q`ytDbF>+pPF79LE<;0J?Muu=0eHOJ59Uk-yfI7Z;&^%iJy{5;(m zt^>IP6xc3aS?oNVL{s#}aq{0ka9tV)=4z$9ahJefA|1dcA{X`6G87p!iyCrz@Gj{Z z6wV8z!pGU-vBg1n-ET7Ir1gL$^3(WlFD2pUDtB>aqZ@60YKh}h29e$=1);RL05k4= z7q$MDKte|vKW90-uQHC#ME#+mg$APHgcQ8re->6>_rM9ay@aB^Kj^&w7dp9k5DyJ- z;5NSzsBuz5I98Aa8`BdgpvDvqZ23XDQ)=m6%1zPxpp0m??l#@gHKLG+WAOZEe^Ij} z2gd(eKz7$!;C_j_P-{4fqDDGUfcXOK-0}&%ivMx6b|f9YbDT=O7K&}*D@fh!@`&ubvSQWi4F=mY)Ex6>d8cXkHP8|_L6x-|CtkfypVBvzs`*Qa*8@eg z*twlon6=Q+U4wa(;cmzra8gfKwXm*`GiVFKX3PbEOp!8DjzPr^H2`% z*vTmq=F=O63cOn04!fp)fGFSb9CL06_EP&P9xDr<8CsKT% zz`N-xHPnp5(BHZ|r=bpJGlyH6o< zTw}uGyeK|&zmV&ul!9u=Rj`&V2ha3mn!ClC2M%+?R7jR~O|AyHBg4g}xqE0v?of6L z(uezps^P8PZ#Z?VMcOugt#s!>J>0TjA)dMvNGYCK_~LDmXm_<1wi?Xk#oM2gSH}!e zZF1u`pI1`RrC+T0$dT8Y4`+Wb7reT)3;I6x#3gSxV9%FTu;f?{Zrn7K`~Ug{@lDSu z#(4_X=Lq!Mq>H{+RMXNc>16V;ikIL0Mq7@Iz`5Q{aN2$}t{tQce(KSvvN=u^%R+eS zM^AixH=dKforK4iuhYmyg~IxK{e*EDne?EW6P~L1O4@_A;|Tqyf_Kvb?s-UqPxh&! znza>x5n7ylCI)Vg)xxEA!&uQxnNP$jI=9j`81%}P9S4W=Y!;s_gTmH#KJJvE*hDwc39Gt+5BOT7Dic=sHH9^<{XbdlJqc zmPsFr{`p<_p+ZXy&mxN(Y^7rdDA2VAwIaPsb8TrRy2eLH~LYfO1_?GdM>p!ed% ztiF6cNuMJP4LSPoBIGG2;In!@Io`A3IVSR;Y9^rHCPhBKy@fvM*$PoB)!A-m3dRQ& zQ^&hz(OYz96N{aY`|=I+?ytg16OQmLh3la7-~=6VF~**n|B-#l2I!Woi@~1Rw8|x# z8Y49zBK}{CQ=a-mRd4xRtN8{I24?b_Kj7Q(vaQ?N|pk;AJYCEui&iMU+-RYJb z;8P*Uy^so%l^#N6=6VwU1cBV!KcFLbNf_+cOy`?=S3i*X2|v#6<0YZ#I6qgB*S0&O z_68$N`Em)SPuc^7m<(>TXi)&_SE%?R2-#M6Ou7mm74f;mv{xIYU!mk@Cbj;w#?SJHX!3#rjN5&WBM-RY zm*>N%wb~80S-NwiPadz*Q^j&zMONO2I4XTAG5pp#abgp=dlgbq@i*b<)N$g+U-KDq z+<4`-E-K73h4-Ns!SlyJnC6`+{MVWWorn8D&9P|G;Ybimv$%QkH@f+DJ3U=ujGJ3e zQ*gKz_uugYqSRL4l~HwYw5Jch{N%$^<5hWMVJ5g9-T`LX&!9;1&v84tV@>A)N}L+W z53S~lM^|dX;c6v3wp$M`tbGk8TU+3KjSWkW4B*Mex~MW}Gv3o_mkjDNhaOr4@lzX3 zJb&^c89wXIZ59QPyZbWVQhmom+k^I?(9Q#!WN6iuE6;nGo&m?iUA*f#MM z_BI~G$6bwa+dmiZOPolJt4(>juP=`ZQmOuXv>UzHmW^ke)nJFt1BrHi74esJ%v*m{ zym3IAJ&WGbEggNBchw0$*dBq8Jwt>!5jFImg+A>IS7hHh6~5J)%5h0e($u%jkh8uA z?x12we`YJ0U^N&k?%yCN4yKr}+v4tDDNuSKkQcjkiXN$7DRJTn*l7_3HuDfB^E=ql zCjw^WSi`#$H~D-2dYDr=Mff&K3lBfsLJPc>(&3Ryaq!n<{CqwKkJfyG`wfw_t}cdC zqr=2eUl;JDy%VWW{6km9Zzb``R&nZ@I=cMuUk6&xqH2eeVCZxhc23C=?(B{N|A8H% zzqXRp$@?^C+|&czPx71wD)?maEV1i&B}k`?!#_K2Lgm{%JY?TQP#M0RUhQ?nsG$QY z%zt)@_Cqhgoi9HmQB5_J?{^pvrfPGn=X+^ufd{W$`UXyvnd0sSeKr79FtzjIQay8i z@0%m8pV1u}B(Fer$bQ;2(Gs)f9Dom@Z7`unIabLJC53rsaZywsfS5hxI>4G^Dl@rg zZU^-Cts!aPXx?(7j+Oi@u`*VPJpE(v>V6iFStG^q`beI=wg>PD>Ov$uUk98^U^zrp1KS2_x-6_w)27zAuGZ`PcuQXU@6(I zKZfBy&(J2*Xt6FakYz$n!i_$c#NyN^l(BRx8uxRe#v^5tmFO>wu07LIVS z<+cd|=BFo1qGo#XqxSw>r7#4Nf>&Wi<1X4>AVm!Z7WIM$JZMt#G*Ubz@M>!fhJHH$M3_NA3~cLDf)rwgg`xOmWC z>f_*wtM;$J#lPM_mgaMM`}jZpHM#{}myFAUU!wXAu-l*@wqaPUYhqNlpJN1&?oExRxje~^fA69sTy#bo`W?~7-Wh>hXw&GhShJHnV^?x!uYPm`6woFo z2IE#O0O&HK`jf->z~~@KHg6>L-z`*gs}oCC+=bJ{X6W)|DPI_0O14GTY&m)s&pp0d z2-w*OU+SLlj`VV2(kfH@GDsa4xQ*aGnia|sCV^Ff^5OudAEo8)AOZ;Ui?wVFFV zosdOWOH#>wiZxj8xk&++nrX7tTx_Tx%x>C`sL?1>FfG{wsp&J}!t^j6eXAX^ZD+x= z!-H}3_XU`1pe;Olb64<~qt1)_E*G;m3%oS{ym)toA7za=!U4;DplFRez0DhfyY^X& zKG)M}%Bb;prDujX;qV){ntBkHOz6fdZ+o%BGl3T@GQ#46$6=i1Ihb$x6I$sbz*P%= zJ=7Oh+0DWpi5A#B$&3?LX!0@L^2!R{NOLCCk#0X{P>_wqDZPRrJMA58Smef&{a4XT z!%q5K{D}$|Oruk$+R^)2I_z8go6JOa%9mJEgyR4@e{eg$v6Q3U8@l0!`d1XRtv_U4 z_vL~np-t7{zxyJ<#3)pU)#*7Qae85`HR-B zKMix+;^EgULwsL)5ylvN6#{&&a2D0UiL^qtbe@LyaU8uK>yG~Yt-!5d5_vg|!r!je z=6~v(&hhb{^hwrvSUOP4A_5% zhE_Xs#(GE6$#Uh{o2zkuuYB~r-5U-Sn6lat3$Czq;Gk*tywk5c-&)@fS1*!9AmyaTYkmtp~>p7{MIA8xj^QqP_ZYq+4|rH9g#LS^6n)cFK01_E3h4=Rbv( zhE6&?^a`Eq`pHj*>XE+298wz^i~;}MfcY=1sNvK+Ok1Bv9n1aTx$s8R-EGbfzE)w(d!xuphDf?b=XkTQ-)~o1dkrFYZW{ z%goV!%OrjRkQ1RP@uDH}u&S4V--*A4n;~vZ0KP;}S zSuFM+R)}*BPveH%5Im6{0^TzN`H{{#zPR>3-W;fmzOqTseZ?ePGbIb)#7Hz+=uA~g z75KWh18dJ#VCCE_Ha@=$qzSK}YrGFd{h9(>PwW-$jWeT3MdoEXPz{yQKY}zaOQL{i8 z@w^#*E^Oh?owDLdD<`%oSOh*bGik#l58fBL2D|;5jfZNNa8BJ%kj`$S#XHUL#p*O{@ED);X#|sVRU`x~Ws`X!G-TH$=|!ld55?QSZRTO_r<2Z~ zV-h$}aW{55Awj1hD%jo-2X)2+pwq`6HF~C_+_-cuj$I?TnVzH?#la{$?l~md81hk9 z9eiJA&2ok|bf)+fE)I<+RQ{K(B~fhqUw7_i5GjWI3gcU*gYZ|;NT}(aMgHSesK01S zi{@Iwv2nMBgBO=bBzgLh4$UaR`?5aoxk00TVP)1_zQ&=44!o%%kxhv8b*E~>? zUc1!|zYNpm^6$>D-qf7x3N`Szvq;mz3aQ7&`Jl3~T)M4aDTX{#!(&I(!1_Z9_nT=> zwc33++n`pgeWynpOQdfs1iC{v!vApR%l+;Aqh8;r-+a0-0eSKYJ1&GQHq+7U6lZ1KK>Q% z1gN9@Rda|I>cDbMA?8EX)1Ca>c+S!=}f6Mi`L#$Fh& zHUM?SZmeCQjy~SHlo!&UKYITm=QS6^h?_d-WKsp6d#U58N!RI5%o3^p(k9B;c$%tq zh_voN51RZoSQ>QVI611lMubaCFI8s$U%n8nWilWQ*L8V<>!EbB1Lub>~a&YT%Y41*@L& zczc;1-?dtVe_cKbKWyJZ>zXfgEqFK1`_7!CJ(BGsE>VDq4SuwjVAqUpeAU|?t553l zpM4`axQD-V&` z3w!+HHIJGZRu8FqRRhTkPUi1xQ}O*@ zqbkAK7R#*q^1<3HXjak%@y%qO6lKIa)?Fko!%H-0$3@}yHcfn#a#GSH48^CXjG)bL z7OZMcM~%>{{LD@te}8{Mt9`cO>-`^SXQdkV*gBMcZC4Y2Kh4BLMX~tnW3$lhX#nd^ zRAJxVqlIkO-Q+UTohHl4^Gk)Bs4}mBPo(VR4MUERg5D)ay{n3~@tfKIxjl}YeiXd# z1~D9oV_VxvY%;4@(A`-j9313=qfJ8asGb@wc29&b`2y&px(k2Z`PVBwE{ea3RTzIg z7UVJ&=&@xnxoQb~G2yP*x77>tok|E+pQF0%0=v$R0>#@|klfNnk=Lt*{Gh#TA3qRV z9p6G*aHp{JX(fGqWD6%2+F|_7`=VC#doo?I4fPJ}V6D(}{65}*U7Z!sHP?ZqgIk0# zt%zNNURTCENua>CPw4siBDZd=6PHgv%$FV;;?A^CDv$gvW+~0aA-#Ljn!9EgUG^T{ zPicWu*@ceQ;U#1+IgZwS`9W_7=g=4>bB;3K11@!=c<-Ry(zZ`uC70V9L9W>yHAcvg z=xh$_w{1k<4LBOM0Ec;cF7<3)E7*@iaCV zab4iQcO|Z0R?#7??wB&t9p)~&Kp}4x_|@szVvE)YXndlJ)55bsGR_AYprQn9MXLwfPNi{5MdqQ71YJiO5j9kLd{QKL|Fv9u6eUN?|V zk8SL};0C?M79rJLhnw~eX6Fw^RQ)vzmj(}kI|sdJ?ZhTJal08-KK=mT3lq6eVFBN= zPnIrupUeGMo8rPn`jWP8)6nh1Hp#LX&D8j_8RXN3bN&2wa!@njn>~*SvB9gwC$kK2 z)j)6Duzx>z^gROS?^VHzzghUMB%d{c(kasW1`Y0*jg8ORgvxzWIof}xaK+&gzP~xQ z%1fyek{3?p=^mZZ0nVCmzf+bqE?S6w)Imqj4&nR9YcO?sE8BZ*gsNj9JUT2EFKYbr zi_|!AQLPbNe%4Nlj!ayQY4IX` zG}v~7CrI+yxbFZGD|h4C(YIjEK`mZZEyCGH`nbw7oeNUr$fL#{b6=XESFg8Xb2SNm z5*b``B~@5=Sl}6>24mK}cpj~^f$M*&!|o6(j9QiE^l4`TDIR|h_Ht=>Z&<9LFW;TZ z$_`@K$5N=-Y(za;2JnllOZ04fCj?*h;9J9f(Ur@Oh_jk`lVTq9otOn0D{^q`5EVLE z5(jF=v5@*Ko+lrANsc!f(A4NKWtf!FA+tb!U>%MTYy0D_lDFh|;sPwsK7c*#`|`S@ zBpqmF!;|*jg~*A9d_=D&D{hIc>LXXki#<)m{f{y^T2>yv?uexy5QX<|9D%r%D{-d8 zNG$i-i?`nN;m|A2ynovxQth??^F#K)^rA6*c++)i{`LWMCcEPO$x)~`U=MVD8o}{1 z)p_p2iTpV+QF16?Jp1gq3aNS%arNJy@Y#Pm21Si<>Q{0T(p4;ZSojx`h|73cKXs02 zNahz1E65KWg6=72;GXI|TAW=gooA_ufloZa!i{L6lPs3(&1ds^UousWqnmeB@!l$M*TWXZ!=@1D{WA}suDB2YoNX=j1Cki@z$Wh;NICO`jQvds@ULx^f=7R zxB!dwJvn0AYU*l@qC1{3;_tFVZk%_U8Uhmjao}?CVES>k)mOoUGEdCbdJJ>(q%b>p zIP2Tmp+oUtJpWXIUx()7?SX3Cccv_Q);t&IOgbc1?^6V6kt^4G&Bv#Mdg9cAW-4#0 zAeXQdTDw&XwN37mx4}(mcuu>xU{?>kVcv`~En7&ist{w;GWo~15E!D7O^!xAX>RQe zk=!LbFI@y3?O^JeJ{JQIWJ+vyT9fk+S#)@sxO4z7d^i(hyUJ);u{QUg z+l{Ti4TD=rwqXB2BGl%of=Bg0n3)|2Ki|)!l#3EPufGFk?wZA_-xQ&1pg!0dy5Nhi zzv<=VQ#8rf1*^{Jv#=@{J_on*gb^zEt-*)PQp6*|{MUhAeVWj3^E=3x`U%XIoe(U_^!cP~7oB)Ki^hgU zi6%dniFd~hqw>@1@!nWD^e7r2oIP`qwr#p9?RQ|SXn9JXt^LlCXHYnwKYfiRo4zFP z{$D{$hQ%c>3!yGa0wp$=VT|8kIC$G1hxOkNPk*h&NJm=^nWoIAlkIur`Al*;Wd{Rx z{1z+MMWE;0rKH%?hsxe{=X*H?(EFAP4bLp6{Fffm3E%60M=s+>4a3klXdmm=%>kdn zMv`B7SNvueh?g#y@dbH5eE8@mo!i$zYX@awwX7K!X+9C#hOg$^{`TNuZGp)$IpW+a zer&q;DL5}ore(pSaA0X~E?RY3dg6g7ls-RBPt}*g&y91q?fF9pRdy6+7{3A-Dg)OI zqXpG$B^-TcGG9`7A-0Y@3;m9{p?}U^n9L4z#^e@F>X}Y@Jybd6LOsnqtpMG^6x(}s-zXT00VHQ|nU=(G`9Ii=7;#qO|iwkDrdpTWCJE|G{H!qfK?@qF-J z`r0Osy}M2ddb@5=>ymg(zt&HhGP4v?+qGF`r389kpD9GPe4zFl*%a3HMs%O9iwCw< z&=UP0!ue^%bhyA@+@iEcEJ=7yGuB7LaF+pm{y_&?2dd%o9)8$uxHr$ax?S?@Z3(T< z^<+hBcg|h19qpCVU|y&PA8I>KFRTZV#CQ_U`umyOUTu@UI#DYuh73Nndmnx}6VK&E znK)lFlkVQEf!0x{MgI&Rw(e(x&c3ni4nh+y-0Ve^Mn>9 zYk0dS5&d_`u+FGiT-`K{o$pjwYI6v3KJry0|$Pp>HYfCMTTbV$kReky z&OWv9b?XjZ{i1}r9aMw`XS?B*eFvd6>>dR_JPh|=PZT2y-$QTJt29mayD*|UfXvqG zgl%8nWy7Ka@B?9-j5T zL3YZ)5NLk{x*2TaoR%Pr4%EQ3v{9hbOWeB1 zg`I+ut|lA5El2w^X)K=@19ktusTbNINyIyXxz;pJec^}J?kXIjdXU=+i%6k;KYS?P z1go}J!7eM5svB&=`H9s+*o{l{JNFWsnGEH&LBs@^f19gp=Eqb7)gEh8(?t^dtvqOpUd^|OIIT{qoRA)rKp#0oSN;-R7 zTo*Njd>-E=mHJZ{|Dh67fANr5IX(N!8IdCp-|6| z+qya7l9vsVlkXcK+R2u8eGU@WX1^Dv#&wBqAL1}KVlw^0CgIiuS+;4J4m1Dwz-k3^ zM)iDQTTCNqrw+uC=VH*Z@HxF-zJnD1J|cYSg-7RSl3c14PggCaqhs^2zU4D4>Mw;(Mfj{BWc=ddq(Y1Z2_uyuQmaC!MNF}M_P`P%8Iyw?zaj2OtHwigI3m+~lA z@495(kcn_&@ld||*c9ETb_!*Iay)Y52H{R|E{u=^wEqa1JYESz^GKi!E&0Y)lHcc3u+r-_#k_W7k9!gL&i(|ouf4_!k0=Yv1n>8&m?1`{nRSvusq{;fiW)0458^ ziJg_+eD$BF%#?j6nA}vsbMH2b<(1FGrN1=s=i)DL@wtNl#^2zdjiB6&1Mneo4~?4n zA8YC~f)qjD&WOBO|N!8k_Nu)Ejj6 z$$ajySr;U$cjL{#akT4&5{LIPV`XV8?M={wtGJ=s?xIA z_S`n^DoB1$=A|A2pARpG?66-j{Mk9^IbEB(21i4csD85)Z|$zym*@fcaQ? z965h7KRT5`Il4r9;}uwDfgd{5mXUwwaXi+RFI0Xm5V}WijK*y=F8)S%(^q<-PEqt~i3BbTjqlH(W}z@Z6~Sx zc@TN8KMrat8^ue?kLj1%QDNQ2p|~#ZKaQ+EhZD!9@p+>mcx7@hrS4mU!&9RrHK${E zo~*5OqpmEQt%&1Y{jK?1Q~{{(jK)8&2ZGnr!yw-_6TU~T#Y#Q`FP#hr{c=jd19S8#_%KOw(UBq2H;Uyt*J6J}pn9Q@b}{{9RQ%)nh4V{uw16@=t+P zy<;)M<+G$}O0lqFTNzz@@Rg>;^d+UA4!m~j5qKW8j8@d=vE_jpu*g3_FDL%%T3`FX zz(2~k`nMhK?{CbwNr@#I8R(GZ#0nTsE@ubwfl@hWemww{FOA@qJEM^`6}aQYe16h0 zf>uYlK+Bw)aN<=V8NG}YI_Uvay6E7q7jiiH+Ho%2SVIPT+~G~$eONQ{fH1&kD0`-P zp|kWZ*gRDbRA>`7w)>#@@B*Q6!EFfd`YQGPrYUTHdJcXV>ht#_2~==#8_k=$f;*l+ z1BcpgLgtGN(EedDrQ5HDx1Gb$Wy>1Qs?LM{L2mp&dIsX^zE`~6e+%ABQbWCAo@CRb z32g4JfX;0<;qa&uDydJT-=!-=#b4v$P@h0jcB!Y{<845D%o}05#FW*1a@cgxH=0o} zR~!=NhT|i4!AtKzl>26cqH8YZPc8wOLM5Jm&WNpDKa=wj1#*iUz~${qu+;?1l`!G|=GRQ`VB^?;)Ig zhUlGHBsgh#{>zbcSS5W$ElXyxS>sC@IW`A=Uo*wl#CY(PsRWnLAK~r30CYN;g!VNH z*b2HF@P5*UuWe(*}@#t!5DM$3Fs6K=j(sENoyYkWB0q^65o$G-1nCcz7ZzT zIIV3Ub)knF*jiom$R5VC{^k%rTSmFlB1ra7I2fyZp>>m=u>XB?>}jEdVcTU8N48bG z%(xD&WwUU0upH;D*Wi}^kyw3oA2d%-#Qm!W@NcC=;dZwX>|86yb23&^{<5Vs(!`wm z-IK#z3H!-x*b#`Rxki(FN?gsK>7(G(AiNp;ALzKu;?ft<+-ucdzH(R_rYahs^3-K; zd+In0^Y_II9rJL5I1%1xskpfe zAC3?A^n>MJwz0j+YnVTmC@?FYsneUEcj(}uFNySdmM0IF*WmzX4N@-s0-sL0i0yaP z@lZ$>L`hGgr+hYBANIrizAh{q+6R?3mWVSi-4W+~)WJv1jx4TjV8t`rc#PXon0;+A zrq%R7pZQ*J_WW6R-Rn5)Dj3E~(;k3R^I$9-P=r3S-jjEzJ$Iy(Q|SE+II6u%46O0s z{zGK&yibgz+9Cy)b=eB(T~QDz7spW_NAbkqKD5BGlv1n1VY9k3TQ56_j^;1Rl_Fk( z|FQ9W+MAvy5JRkQJI!*g<(AZeX zw&D^x*qo1M!U>_EV~@ByT$7K~S4uL@y@H)B%KV*l$x&yR&|ET+hlCml*QEWZ!gDD+ zEm6kQ?HdI%Z&kGIe?WZkP=>3r9q|3KNYI?w1#iPHkb3Q5I^=#&(D1JzonSvWgZp`r zqdR`wc@ZpCI-p5On=|(mk$Pw}-d4<~HMZ4oF-HfVDHvnpQB{7KxQDdcRq2MIitqrB zQFO&6`gZjMZ&^A6)zk+}vY5xR;N?k-e7FdJS)WcDXzZbo3L~`lQs#*!_~xKU*)q$aFfWf?LS0~}SWa6C)zLAv zom`W43A;Y3;l)0kLSeEe|Ek>0`c*4%hyPy4Fwn%+UhgRE+ZN&2{>|`d=S@O`g%~^X zILgmWr2Y>Bc-#;Z(z7a~RM|XncH%&md|)_WrNWI5O5wqw1DI~&M@q3bq?wH_+;P_y zbDI@et1F7)cg14uH-E}raGfgae^ZXdYcW_>ktY2Z#~STz!hb6Jp#D}7+f=#p>62>c zQR{~fPaLEpJIh5=J0*-6&uX|5>=Lv)&{L>T4<)pOVc_KU@;S;RL0;{Y2}_4$#-XUm?MHF6JKUhGOS5 zQT0^>^;tty7pBC*tSM~Pq(l2HqA>pRB6c@Qz+I2bcv^Tn-sFx>bViJlr}w0Xc({PU(+kdr}X zNzPn;u^TGv4#dab?09436TWdT8rN)%;Mh}$M`UKQug^+|aM#0{1~uf5Ykgb|dUid%{{)yK(HGi6k-FfK8^u*xdQw z{fn9_#Q7_7^*ed^5Ln21V|}5Y({A{2cQ_7sHIz1aOX-2GD|Sx%KzYtPvFnpP{27tS zKC6#YwR;u#d#uK?uB0r5sswX`ZxAI+a*pMP*Q0K9-;cYJan!YI(jf& zOYlJp=?Z>cnoC8l?mSk1JLL6T3Pzz@MGFmAT%Wd=_l5n(-v>KjQ+S!M%|Z?T4jIJ@ zJrZ!i2X&M)4*-wlz3_fqDc|-9#pd{zWU1OAjPDl+n%UO`Ip<#3^>Pea$b#F;d4oftr$wX#4IK(Oy@XM9uE__RU+=1tj}NOeV_xQtA+3DG+@G}04jJB%s0wS@bJY;VA7h8{br`p zrVsC_<;@4-jm{YwtgFNo(J6c>{0PVf^+EL)lbIhLqR4?}EE#DhaWwuU%}VT`1Mwa> z-Y@i@C9Vr=uC(*x4XbJHwZ1%Xus?QQ`=`7yaS)U@6ra~usisp{GXCMX4S2(mzSLy_I-~Z8*0@tiq!cH$%d{so3|Z1y9k8{bwglfUHnzb6bRm z^P6G)%VnsrbQH_mpP)@9qd8>!bF!#2hts}0X|1vWH#f||?zheUxn~@%l2>5$gcZW0 z{X4{l-MUFs-qB(>y&1@lnXBjpxy7eP+)bO?p%+<$UQ^E364W? zySSZ4-CIrX6L(05`(3A);0QP~S)KLei`msZOAOYTDgHNM2ZkxQ3S$>z7W9~;j3`X zzACZwlpCsRWW$~x%~X7Kx^Vl@Ongz`N$V3%^6mEd^z`^*^4r!29d;XYNyI2{eqw`t z%ZgBLB0#tC7qC=e6U&S1#p&zR$)rO~T9Q^QmH%%se;a4b%{^mi%)Oo)Okvv#Ghbc&VK4^-bLXruUz?G`Ee%aS8#ncz_0+xvj-xHy)(M2{S=~Oz7P+P#drO1*&7iYZN;q#;1=xfxkaj<_7%!C#5LapS#!Taf^v&WH6?F9EdW8sy zLyrVVyi+SJ@EL?Zm(Pa>DRH=0ZaD7`dIb^rbE#8sfh*4cp3m+f+`Og~PRy(P2T=oV z+B<-P7i{F14hg1(+!Zv_-a(t@L}BQX8sS%NcU%%Uk0+nA=KPaRth4=-crmjHYQsOk zO^-M%Zkz*Z5A&h^WRXIc}1l!hVk3U`+j63i62;$MpSA zn5Y@gi<&#&h-y9r)gBfjQYLf3ibQ&Fpb#F%e1vYRU(jyJBD&J}9KM?k!1cP07;@4V zrWD;2UB4)^Yl)GoZ|Y{cQIHN5dR6hW(3(B!1x+hB8j#A-76>bZCN1uu^ zrFUMA;z7~j9RK(+ed;xt^_{$7Z2#AA(KHEq)(WWq(~PWbjIhv z^Ra8`ko+(Tiho`bF)^C$|3*oeZ`=+z-?DpGD82RN-gdB}&+(fcgJr zqF0}4?mO2TQ+yuN^|^yF~;E6m;e{cO~|4moFhU8(&=d%g@*SBp=;|?NSLoAI3$lj6`4O`|L^&% zV>=FXo-Lqk+e8==r!2kFl0h~pLZlMFNP z))8}Fsr-gEl%1uXZoN@8Vi>y(*~ULF2Z1!{6n_3}0G^X{(LyVUy-f#;M+fCfTUzWy zyDiBSk#dTj|1K4h&Ywr8e!IBGn3jrt_jmKUXOl5ccbaH7+FID!>m`Kv>+-RpiKy7L zi?_rN!K7mbbV1^b{a#!b!XoXtCNBg2J3p8;YwIa~9~DQ zb;VhQBP?@Fm-ip{zmZnydYBUDJQ9E28IPflQ)$1i0q?NM#?e2P^Ok5!Zg<$k+i!=1Q{y(_sr)I*zxe~Y zPhNpT()(kr>}a%@yd9lfH}L45nw(fzOmbBUpgQmpm7f;)Vf#nHW>hs~`}DyTvK~}@ zuYkOKCeyDCDJ1hHUwGm@h(B~o2a74a*(bb?ZR+K@ms=Ht*(l-YXLf>3>0B6@6N-zX zCh?p1gIIajezKcB4?3LeVV{-~tH~z7*llJQZrdnv_w~V#SN2MdDA{nI08hGMDvBFD zj*6Ru>*(Cr!4N7p7*mXw!ae)RxFO&-7<-0Re9y9{Ri|9}{NsH>k;@w1qFW4r(i1HDZ-7%2z#G8&S)bDl_?wdFcT5rvy@qzou zX-92EaGWysIIGSsUD|A{7K27xv`N?DB^0XnrZE{N5PmiZdJhWcmsiJtZ^H}@3liy8 z0AbaW9H>{wr3aB-oOre$9+w$_{jc?A4TW4K}ynP5)vUx~e& zD%)C3z>+Kb(bl4X1tl%#fFRmFuz9A(_67dJl6uYv}D0Ync4*qwuMIFjHEL zXmu}|-@LI#x4!xOX|;hkweNJezBLmTTynu_$Mkrn7Gk0A7pOV34Tl_D$z{DYdD2!b z4(VP7-&{V3C5;W_uzf9B*R19q0~6u%tQIa*pRaLFuOx z-jylj#qWj+s*l}iot`@OEePP)FWHpvBo@a_)qo|I?FaQA*NysPaDdI|9~v-5kHgdVRL_q=W^lsyQEN&_Yw$FWmmh z0)zBYU{&L4OpGuQ8tqo|fCvGzUIbxmtrMquJrrefhtd(NK6rLdg?LNRn-l6DxSpTB zPn27D8;pJ4;qPz-471haC&8KQXzeW2-iZODNf&6Xo*JJk-^p_w6>&?c6_53n#r2O# zgb(^SHNzU6`2$_cwuE1;=4dcom&No2c&62lkNsIq4RMYvNxm;eowmi4d5R)jZva#M zNw}ac4Gfi%>9c8HZfj77?a%I!or;v+CPq<{cPw{kn3H{xAMK7EfioT(K;(RNabw3{ z=%w<nuWqBsFTX;&!e1dpeF(pwwToTW#3|c98Q^=34KbtL@G{#eTFm9c!oNf zU9iPrvk!|0U2d_89~U;DpR*_BnZ%U(Mah2k&Lm~)v6gT=AY{#>C z@wXc${xPm}t#7QqrLd9t-lKo|_?SSl^?+&8sS=KU%vJ{2G;jW0LSzB0kq>b$`{6+w zKYuySJbtecXPq0mo?_QfRdBRNbxPc(ejmY2@=1^5UFZv+uy~vVz=vy!z=bZF^}C&Y zO7nIZQ(cKQb_YxS7mnYx08RmuXh=RpGBHLOS5@^*fwjYXa9%s)| z=EvHJ>AUo(JsPh;823N29scc@WepV-tD)qP^MNRGWkgDz*GX){Mv`Tm$||sd@5}v$ zw)geuciZ2>Zk#kD>CZ*)WSrJ2kVOoiB$gohM>xe%0wO2vZ$3sIQ%J>9I)QvjnMGsF zYP#1TWEtOhniN~K+25nNU6<}?2)c|ncdYQ-bPzI`^i$*UT+8p5D{us1=Xg`Oekh{e zJ|6~C7&AAkIM|vHmEQCF?_FyOKXli^1MZ#sewyn&S=n=*_%q~3XSV#Fok|TCYm;74 zJezl@nD|HMXY-{n6tkbzq3?E7B`O$4m4*znFXtg#Z{3YVz5nCH5fQ z^YGg$M!wwxfv(dP1ruy$ooNPF*Tm8u_XAy<>)&|w5$!aE5>txUnB@y)^7)KQg5b*8 zz9XQZ0ug8G#hoa$sNfWYtDEd5L4fvgoF#~q?NC{FTH8ZV86gzUI-;WWc&JF|dk07M zwbCQX^$Y8?%e#{7Y;8%JV3AJgkaxei27i^?>7?{^s5;lBnExM}zL~IqP=9l%bAM*z z(S1D-+)c^Rl@9@p->6JMoKw*=WB;>v(~)UTA2r=VMDmiFKMjGIoV63-6h|*Y5eQQIu{w8mG*={k zoA;X}1tExv88Z$}FefU`ek;L!Dw<6iK^UD9R@+bI1aPL{F}!8rb%Pim{ZFWlw$Cvp z;ffv;(;APuOyFa^y<>ZZL+4Cd8TGFPB?)f@48~oBkt+m-@`ut=E-#-6s}T96am*Yd zqP57j(_*hp9-8?^25++Jepf1X&72ABwVUrIyCFgL4^RZ9guLgh13ZYijJi0*P%4%b zgR5E@o!VZB_4O;lnj;NyedtMzK3w%(dMQDpVU9bwdggmB{*-6RjfaIg7;^IwK}SBH z9X8W`9dFN6*14RZ`|n)_cctkEDia~)RlFcSklOJBnZnI+)O8O2==ruwVfg!HoIP*q zVXbAAHvR!+_33^{jD5qnZ)^H@yOcTjOE1mN#uXV3TjJboJ(= zQuR+h2-}Z@Y>rt-THvNs+jD)uV z6IvMJhaCl0W z83QpDzHg+I&CAD%-^kU6wr3_!;xJf$#-|{0t7Sc5G#>pBYf8A7#|ND6x62Uqb`8(t z=%$>v;?t&;#@TyWURHSQu(T~yH5iC-^HWNblD%Q{t3$al3F|K^=R{D6R|< zD@I+R83~3F`;^veYyOryTo3W8lhq@c^He;8=uJZ$N-N7A4==LUpeu&gx^57i7I`1f ziWf-$MQ}xmM&0?!C+C?B29m^N`jpIpr|rX65&yE9 zJ`s4|?LH9DUnZip*Rgw+^0TPG?EVo87ICPR(7GyXJK1p*Orwg{r2f2&!X}Z2V$bon ziVPml`&)3+XNJB31RnH{VmxUShR&H*V#p%=Y95W_FZ_@4gd!$o;=nj~GQ$s!zqIQ> z;p9`z2d-+f65d)l`K=Bt7~~`}@kt?G(u#bjYV1MxhNiHGw9kY`zG0h+O&|e~N<$P+ zk(RV&otABO-AgXq!Cn2qRIZw_L!UuIcj@FC`13$u?NE8mJ4LO5dxAgX(%iu#{PgDA z=WGQ3kchO6nZ-4Pvcn7M=!{O4)+2_K|gzhJ0a)HhT;g(OhJZ=;krzAyhT(UzbG-$lbRMh3pBV8>>PkYd~( z<-PY_bM#T04au2sI*f>(ZNU#|YSinDZy3H61$IO5M|wzvd7|V5amd)z9ec-TZQxs3 z9b&VutK|nRU-Ztt;wX7o^mmZ5ChYwh;VV1GU#c7lZdq}`MJX=L87mSoizp>=0t&VU&) zak&&@ySv@sI?pGDf?`u)g51V_CI9$-{S_QOyqdv^pMO9bL}xVKIWk{RG6!U=YmcjU zP%5TvvG+Uhz_X2}+r@T7zFnPZbZi^aMbEvdx$pOCRz6xZVH-$=Lu|Q6LXK&d#Y_nX zO2P#~Qq-{3VleqWJ;>(nfDYFd0(1pNg1B>MP@s>-<8eP@eT@ah(Bsf`qD;@_+;^s8 zsaUhaPMZmxqxU#+z#?`bz*`KRLYCJX~pKVp`ze7L*hPO7X_|Az0J1QD8< zNYRySw@rLU)FX{4?BVLR`iPTkBVR_l!A4s)JWbE{(+&cRA>?*tr(hV{FpMNP<}jOz}nm*6$32v95@MHAfpw4%JwAvZ?%g zw4mL^%%A$W;S3LM3=>E*A*bhUTWsLdu3^hh>mTdkj-->&tp*uRycFTNV!5%NWb66A z2}I;Rj2ZL}KCr8p%RnLDHD0R%;vJS8G5r-fks?V;f-_Fwoqgv8dG%^z6sB&r`%84w ztN+9+0f$uYVqY%bS{pg~El?4Tv$k5UFs#O#f20flZIu1NIQzy9qHw6AJJf!?IZWpA zeTXgcdR-v@I%xdZaVa`dwSquN3*ELOj=S#APSrN4D;Y2j@6_SQ4J2tAxFv3`W17k0 z%|pd`$BlsvS1q6JdBnD?stWx0l;dn}&W@;{xz`&ahB9McpWgLU<@N?(cBt8);^8+B z5h4aD*G?gv93M!nnOR;*P0exWeTzqUuBZ#v6<{C~y42Uu@Xz9fn|%la_1!xyr+UO} zvT%cJ@sjgfO!yRu+deJ3iCo++Y(>T1X>HOwf;(0WeNFEfS9Q{*`5Zkwzg-|6m^g*} ziBn+#K7g^bjFi_WtqhIy5YQX`Y{xoQDYw20Od6JmGu3Wvn|N>_d?d`)p@f9$+iQ`v zoWiN2rYk<2lhcJ>zVTCS!U!7bB>!PX^Vi*nH=M}({>*G%^VjDW?j3bojW#(L0~*Z$!LbW-~5o9^Y`MCBb z{AcWO>BdkKap0zb^2MdC=}j*Vl14J^Y{7nha}w)ya4U1t_ygHz?e<`~bY=^Co}9uv z^OC_@lxAW9kXaTcAdO(`sKOGypx7_iDRFDz%Ap&kmk?i0>Bp4ARQhqXO>OJA{T@8G zJSPw}C)Qmox3A-CyGZHuj0?fIOSTH@A^B|Sp7!&OWd~^Q{k%9G9)nH4n=M z?dTnDDJX!Vx$P(J-vB2aJJ`=!Or}+{Y=4g{2PShXg#CSJ-E?>o<@AksMRQ~Cp`oo# z-u2r?HyA%w^(Sjo`=c)o8@ww&)gOPmDmPFfYY89@IO|fx$52FqwixtUJt9+&^@57F z&KqT0g~Dcump1*In32&~y|w z${g7YU}h6tk!>afY?$K+FmAPRRMfKgCEzDtnhJ*bq=L6be)c?|)OYtHkH<#s%M7Vo zjSZCj>tV0z&);n~j%6=A#wexD_=5MH9SO&j#Wxu1ABnr57$mex;!94jdi)hiW z6?mCilN*Yh5T{?L>_oJHIVuF;%6P11qlCuVnqI!2U%BzYiZqFv4q=|}uR)bd(p1|_ z9tzZgyax{EIIK&sMStbc40pHgF-LEFsoV%YWy*G92?K<0Nek+PIs4iuXi6N3`CX>%Z7m z(tzdLMRiL#O;{d%4w30$RGjD7JHR)ZO#M(;FbLRkT2hj@iDoXY<_+1<+jA0Ef*!ZY zGwqYYW9t;bz-Y#uL*&sLRz)|dGf(Cjx8i;+MM^GQ ze(fS#LToqt+mcr$SyLDJdw2-H8?)>uP0>aNy0vL1SB|_Or8R3xzjaxNxRp2ktCf4- zkcg78F+(MWl_c<)Mkc{=T*JTTxmOk(Xxx-HE)5;u;dWD%gc zYU3oAc`b<_rR0E#fgm3gQd<(pBcx(_>L+pPjNQs#z2zXZN6~h`hs!KVP=P?yXD*{> zb|y35E&|0qnI`FfWy{Yy9&Jm^tl#`LVH~xil}Vl}>59H~Q|w~j?U}aB z%MN4FJqtMEvi7D_6Tod4~sambn>#YAe`N`=NQsbZ-&eiePyLJJY z#9fwt;h8yi|z$K32kbb!~w@KJE&lPNrtSCrCtV4CZw@O5<0d?utCS=fhbXun@#Ly%3 z@%ow-T_G-fp6`nt=63w(s4;gJgZ#YH+hHEyy@`K5vsL{TOl#?0r*S2eKDDZZF*>E@ zp`7nz_3}lxZHrxG_FjAn;5yCG0qfEmmfTa$6>xJZS9?c{q_=)7?UUj*S5E15c5m%v zf2K%)zH+%UeFiGKL+C$QBlzJ$fj-)^QS>I$5hOEDOUYhIPR^uCd*KjI!`u9?oJ>dV zH=hn*gKY>5((;1_d0vLV=sBlZ3YX)$4T&m^4ZlC&^+}D?`TxRuG13msavZvxUr`G+ z&EmzG`t#EV^D#W(qB*JJoagqZ zG$SX9nT*MtHdeRjtUzR4)0M*ox30|gPdNV)ho^}R-gTYyZb>^Z8$Yr`8vwe(bmc_n zHfdluEdk-`^(^yj(I^}t>4XC^y}u8x{7R&xl8e-?TkiEN2cram3V+xWggJD5Z4am| z{5IttdVNd5E^;P|#e`oK2(G5$a0|Li$k!CmzH6Ow)tyT5o6#xlCrov>kMp7_#y1~4 zg_wUC?ESQh*DA4&92mwdbFA-7RwYmceyLTmc&Y65dgOMzZnKTxnuKgU6~WE##*sLV z`~uHTK&SuK1+XpxzGw9EJg~tDe{3otzLug?uYDV~dc;u8EQxXcO3g3YnU&7P5lQUo z@wKW)4AYa&{v(b3n)}2zXA1}A_wq&UrExQ?5^iU{Q49V8H;?K9K5K6CV&XkX8Z8XD z6xn?p@}?9*qrU++`@byvQ_FXq_ihqHem~XB+W}$M4}C8m)H<*rCF>Kfo9yi4UQe!j+3fJCn`Q8V+qG9QRL?-*|Tk}<@Jib ztJ-T02W!qnP0!iuAZXzdZrB|<)bMYsYr|!}0%EHqFz=jXxJg*RP*YwPwVW0P0c?a? zgz-d%r`VvC-3yeGDB_t=yQAQ*!sPJBM70i-6HEr4KU3ds(8DjmX@a7kbw}>V2Ced2 zVQb85cb2qlM>;zhmGWxCU@8@x;?7{ zgy-%8E!@n-ApkM5ve(!}k~dmWVt2wlJ!0)n!SD%(;obF>#;qM!SGV>j^kUMn%b+z= zuUi*P$D3Mk8;wSd!CFLSN4JjYhNqL0=mcrrT)TpTf{TydF+$8 zp3bu~YZxuaDCxZ-+7ZxgvDrfEUL{l9cbUn17}wV%{Y4 zdg`+vFrpL{x+&l?;QNz7MUMZ}7uMX{IMiVJS&UzRw!01~(4242Ix|`cfoe=$IrQ^(b z8<2}~8t0}u{^u<)tLlr_X>Yfy#pkYT?vcM0MYF>e#(!0GM7wQho>KQsXF4!R-i#ST z7u&9$W|g>)_e2O&(&S(D;@%cMraO;D({BHOjc}LLas|wR- z0l|k$MkapQLueKgJ7se{B%-qAuenCmZHAQ5*#t5B&d&8#ss7~1zUw+Ftcgdj zP=;^KD8UwMm+xoc+dHv@(^HS)yi;Xcf(viAilzvAZVV_WA2mO(OyH|9oVScrs_~ky zFNVgoRQK{!4XR86W`7Z5#NL=M3+jeuX?P}%!uuJ%9g-S+*<^d;Fv5C>d8Nro?}@xm z_b))WB@W(j41V0ql`ft5d7a0|GRFj?h;kq4QqJ{7j5>^S+!AFj+_QgWc;D&!i%0g` z5)pWtdHtzA23^63Q9solZ$Xm&GRgeeu9O@g(HK`aP=dMsx`KjVP1GM{fpU~^@#BZ< zTKf9h`>tZ`=B&z}DEH=d+M&So{K;_A97aI?OI@?F-J8ATE)1*e1mNMYE^2avuSSz=qT7co5i*TvkR~)&O z&qFaJpdwc!mR_@eN%@rhySyD`+>smV@Y}I?+rD;^d|l3N6s*j6A_3nn zTem6KOT9h^wCMH+Bj_|i_;Ta%U{#F7wyx-rWnDW+0{rCLv{0$ePPd_=uIJEE$W%F1(dt5f z;}JBD`)f7Bxg#p4*y$3t{aN*`627HB!^t05XtpM;v8_}Io%ygV@6<-92TqmHeg`7T zo=!ctjHp|2BPm{}9dw^+^lQq*64+fG=E*E>ZMPtS&^qr3A4d|0=xGDj$aQ{be2GKP z8#7&`Rn*EGSS`?^Y^uVpsCuox>xR7;W`*2Lj9CNE^{nQ^q+$^aL+lS_f85U~Bc2`( zP)_zTr4o!wdV2>APUyrGXt7>RNA!?vY)`rnZN64I@j;Gy%S@-ZzmF}kez5QmJ8Dc6 zpm)Of%In1TR4Eo%N(ngq&<)`2%!LUGp?Q3NV$D6zi!(={{jhi-tJtDCC-#%KQ#TVi*T&Uno5UoMqVU1-N(IK8F zcDJ1z;PB5^!oO#-hYPhM6FT`|`F1_0q6P1IKhDWUx-DRLnKdH5tfS?R50^QO(x_(F z|Eqfq$o^O5N02=CyrInJ&EOLSn3lamcKb=MDh_1gv7a0u*Yk|neeo~df4fN9tSV_r z42!7Li1Cg%`4Af<-enEXX?xmKuX(Hg39m(7q|~v!e4$3qGM?2xTGT!K*Dmsr>o4pk z3RxVErQQxWpF)&TDA@1MaB$8FzTEyy0ryw>z#B!a?Z{0}@z+bam{+_}E>kH%$3+%j zcRwk`vd&1ZuXNLBaAMOhn^{6IL!c(KLTzFqG;j~U_`qNJXa7cA|7ueC=oF^%w^`(_ z_Ns_+659cDws5O&4+ZMoP3*a6wSA-$A^O*hYjwpzZJCL+9z<|js8=N>Vz zvCxkXtNL!abDzWjqh4>vewX!%X$n*@PJ_4n*J~Rr^O?Y{ZIEkCXa>EL(#$9H>WI?h zmG{DxNckhtBcWF!Oi=689=N&;TG{wstLbQF5PEQtWu;s`E#%kb&_s2cnsqd0W-CfK zo36C(q-#6%E9sFa`gUj9%lGRRD&sL?*V`xq)CYiKB3R2?--c|sb$ndAdp_`9%N<-HMqvtl_8LrWTHM5!T;d|%bcFS;Y!>decmAMrHY^+^c_FJrVwK)tkDLFf7GjnupUS1H{CV7v| zdZ|66=4pig92bF!^RK9*pvBS|kb=s_cry9NXMg4;Vu`zIzj#mWlBH)2D_+EtoPf#{ z)j2T({^3TY-*~P2@n%m$*i(kuy9&l;azla%4x63+}y56#moDaQ|SH^347O zJ^y`?eBDHpl)XaGhaDN*F=wI~Sr(jq>_hpB9YXHHB97-DJSfFXC(t^OV?nyZYX<4$ z;p22yS@UW{7RIRdo%wsMV=(s{@9~}DzEJqm^v6fyy#5Tqwge2UyiJPXYFV7W7S2yH z5s~FSAPyk>urEI*r_QLB?**2HfVZSc+`kE&uM%PtmZ+izn05N+`p(MFK{e+}j&rQFfTTk)nbuL-SoOxc*8Y zQk4T?^^juy6D7aJf56$X1NHtSdKo7&JLqdp#IgYH;}yQ^)}m|)*zor(TS2JB(EA#@!!Da4 z$V_evLjw*D!Y@kPBwwH9AEq+%r9Uo`KsxTXFRrj&1EU4t5vE1`W!a55A{@evXX~FzeH%Z{^J!Z zlKO)F`ybC4Y;RL3GI#FurCRN=8&SULr`{jj8oj?v?-dlA=5K0*uZu`OHdspL_sL#+p?-hTdi&i-0vypog|PDU zNhqIMfeJl#OWzG`sf z8Zv|?KN#})sYVjUY74-x&IugP{#OKa-6YwBeGT{&`x(UMa|1TqB!KANnF9Bf%>Y-H z@Id+RgW$j_Q-J+Plw`4XKA6z44?;)H0BMxZ1N51p17Tx%fo(`l06Ru~pn_Z>$d(NW zBHfz?n8vx$_JER5CJ|zMFJO-Sirl#YCtG61>i*B2LOL?8;n^%3E^k2 z20w265MQt&0*Xqhg8d%X0SCmDU_p=wm_aE4r132feE(PvK=m(yVAYQSbS?qF#o7cw zMouI^U3D4MdzJ}wD)`c8kG~E!lu3g4S|I{I{-{9&dc}d8>ph?;WeVVROdjA-_a3}v z8zK?Fj04nA#sb#SPl5?2cplo@{!8^OFbdKj2sWM?VjW)u6rk|}W-2s5V12(putdTEx7m`w1`mEn3a%zZ zHa;8RJUnoPrVw32FTk%tC}0y%5nz#vHvk342(*Wd0oQ*g2e=jnLcT{$i;3P= z0AWp80ej_o{eU+Nzz3uSggMp*lC6#bZBFn5vao!Lq@ezLDF26k`VWn=H0Tr6?^yF^ zjaw&`jT})|mG~+JP*+mbp^#RUP>`ZflTwF5{LjM_ivP_(|7Xsxjr?ESodo=U(U1Sf zNHO!?4tN_7!P7jFmFY_>#r%xI?e&9Zomr#%dN~rzcHvcE^|F=!k@87@wQwj?O{XapD8U44te>(mv zNKG;W>=@B>x)fFUvK~37U1cRTIdwTD#sAA74D|mP`k&YJUn<1o#sB|7{ayXza57ApT+-BzDSAx;;jDLq11nq;D1*fB_$=M8ME#P4^_{x2y!oveI9h0 zd~S<7=L0^H;=L^yQ|8nlcuT`0@~qsSWE9v8my{Z87=d_|rfnh`dB>&X}Q zFI?E7nJ(Td!(zBrMpxCRPb;`g;b}(Zi)oZ!^p7WZ~q!DZS~mMbtqIFmRuKsi**LlxY)UsIB--5(1jOw4`AY3OE9wi;?L3L-v!2 zLxpQ5sw35=w_tl%W*@(czB;sA-?lL_Ppl7ka3Pnn{ysJq=golwNficKHDzsHCiA7bDoyM|2`dkK!BK`gD^J}Bl zyJ7z|wSwrq;8R)J4+|PMHA639zSCVU%(dH;5>2xX3gm@!Dm>$qxyvmbNU=qQtJlcs zs<$Yje9#9f2UnY0n`fH)zpVY_PrEiq7g4DpXuOJY6zEoZ@SzQqaz?&k-HO+Vd;qrX z9!*E2SR)4a!{^?@-jph`Dxi68J?=uOX6WO7*e|8E{E94J!GX0k?slp1IT+6V)9Jv> z)Lr~6#-vIOEUig3RGEe}67~;?iLh2gtm4J&B4eve*bmsa=l7ai-wDD~pnASveX1^6$l`b%i1>s7adTwD721LAA}jcHG~Fn|tgui! zMkPO=J#CIFqWDN17Zy!sz&k%jXA6Q$v8{z$K+3}w3nInWSbc>K3iJ6BOA2#IfbPla(zTfP|2_Qol1ltI?w5x7^S=W!s%@J>X6y z<9~)_nDat5@1=^A3wLsi8T3b|vp4t2f{DeCDQK19{rnrN;S-khGnx%N7X5LbbY=}8 z7Jxa)7OnQ3k{@wVG^`#V9vMdvM5GJKRva*b&361X6o*W8IgbAsL~QHCzX?xp${q*l zX}8t2EjOh~)-zU%(^)nu75iGLw zg)hwYG#xc3$wte>HJ$?E`#bBR{4RdfxO6Ue^yQy_i{1vNetd1iH>4%Ox$-W}LrZr1 zs!;*wKI)GDED+wf^lUw#zO>zlA3cHj_*Vqh>FJhBaOtCVNll6Iw=O|NAQwOc?CU*o zFLd}LYB)b4Yq)?6N~Ig5M{~xDKODSoIg2kNs9;0-nwy=nSaH<076}4e-2;MKG{-Qy zj?lkYameqJ`ykT2FdMR?8gT1484vcgjS~mdZ>ZtSUVo-&=uL^*ZEa3>1s!z8_{Pj$ z(p`aZ!(f-Fb3R?h>$uSCp{Gst> zm;NlGb5=`?%!_nzrNVrruU5`+ZZJ_WnjNR(n*B@CTxsH*DLY1FY<%5UZDjVpaqyJ3 zWJv|%H-_SlqTiV7ClOdNZrUxEe}0z45dz1vH4Y~b@0Gh38>PCzSDFdPzmWczx|f-v ziG?1}%W{XRa+!jkCeS!8E*89uqA=({lCa=e!3rE`@GLo@RsJ<_>fu)K)AGv3iPU(j zQO-A@lX46M^}94cM5SEIPX#xs-7q(u{CW?vVV-inM-173Ww$Wn=IiKsk`Fn+4mgj> zZ4qJ=H#`LJWREK|39IT6&$1ju;XgTw_ZR@CgvfP{CK6Lsm)B6*Air;BcoI+rgpIUI zEbUfBP>)PgL<~4mROm@a@~JupuxwN=3AL?17m0hX-T-Q^e3f;0NqwwMUSSx)^>92? z8$#Av*fs;$L|LC$xiCMAEKiTUaq^ezNlCb`jQtI4;!|$ityP&*n^Rk8Tlxe?pe&2w zr;cmg?e6+w^_WFACC&GS2}luc}QG!LS=W^g`ns-JKdUZNqkGNHXy7ddMccCWw*g?EAO zX6@Dz{$(I6JKb1-Z`HC6gZDqgv+e%0xgdY0K#vrtU(4TixxRN4PisA#amW+R*_ITR zzIJ1BM#WmQIFwS1tOE4C-n1}>h}FaE>gZECUQUkd%dDCmqF*T)p(ynOx7Z0@zEiHI z(#F0?XB@A1zy-t6H}YAO$x)@Q$?%wD4J^lXZ+iH#eE)}}LN&!6n-Q*5qrTp;Q_rPv zeg%8zN46`5;od^2be15E<<}5|KWKKDc#q8m!1KY==w@_GC&X8)?ddrp9i5s3BcK}F z-&eI^FDTb^n2jX;P=&2l;?}Y~ngAMUrzThi5y?!$X#Ckfn~Kmu`N~DcHXslkx}V;K zd2AdSr~K#w7o^k7YMe7(8G$)dcNn8<#R3%FFA3D2Ys!};gHPPJeO3*k&kMS3s1^7X z!*MTY*JBQzoee%Daa*WPS#P|nx=ofwiWG)$-1tS6d&}BZ1?y)CxfnX?<($FN$2fVf z4O#FN!-e=Lgr9ZU!_$}MFsP#&RSot?GyUCFoprygiV-jh)A{^5=v}$GUQh$iDd4+5 zDZKENtmFV%2vxgvKXuov`>ZR5x~H;vStKnyx|dFjv1zQhPssTJ{tS|L;$rIcC^IQ2T2Be)h37%H*|iS}&lNAZb;0GovvLrI)k5YpgIx z>+2}17%=ReMkV?&A(AUhxIzDF1Obg=g>Y=dVt<)PEOk{3$F$5m`>FN|%#m%kL~4q} zVYZAsCa1~30U(7PwAJZll3$E+2>n2e0FK&cEH5-BhN}mc`Cm#~Hb{0#k$LtrDP2R& zrNH-PrveBA%T3mJ;+Kln&0D5a0~E}EoeO_yWfvGa#ShZx#LK@I8JR(&lq9=#)p>EGZmHtPe8cmf@WWUfOxXKBa*YN4-=;uhM z#*aK`=*HnL2DFeUnPjAIBq6-n1MPdEQxu~k1XmvqCfhT3k2>@+7`X!>6ALmP_!I_d zT=rPKg2bY>x;l;%G*3ICK?;Z{=8X{l+wjVZZ$Bz8(KPfV$qbz>rDtsh&I1OLq2|3K z0@Di~P-VI($-|t7cl-GiKSk^Q4gG{SG-K*>F>GTX%;TPjrN`bZ>nISWy9<}*&E~_5 zs?q;*Heiqs=kgR%bgEfR1kg4oeffIo=vQCiN3``T0M?gu0Ze=PmC(HBeA0%OMFwfN zW9m{XR3=~MSsQ!9G|=|tt|{mXy%0S}CH7FNcF8(5n%}@~^Obs;XpW#Hr%p`(*R0Bm z62)fJfu=W*EzuoiIEW(oScg!Y1Y5rHhjV=IJE}jg_fka?SgguS6DWzj#48!m`aRY7 z`h?=B2-n9zag{|&$i2d%JzKA~BOP{zFlptCsdEMXi*StDGn{bSYy!=hx*)px!@473 ztbkI3&YAx_Q}Dqo|FsOf0y(C(2U{VAc+}TP9Xf0*SZnB+O3gbo2ZPtXY6`{5Zi6NY z=>>m2qH_BMt2@RIz*&Jlj+ydvJ@Y@b5`yhiaG#Fay_OJiPMctjiq`*m!Gy@ zBz(FUnSVQ;hrUdbqyv1xq|_|!LJdgIqIbn8fY8}%3GrWy6S+6c+wy2nG(9o=f|=`t zx2;5@Ngm()pNAIV?XYDS^`5dAu&|$kErJii#|q1STpLYRREL!dqAXj@%$U&4i*{e8 zA;{rWQjt{rmgruUxh_hrV&c|X&@yp?Be3bIz+eH-bI4iEE+1C)Zj|AanRxQ*%NvEf z-SbJk{I;KvoMdZ923fXhfo^p3Qiv8^IDdo&?f1}Zj6xTXW@ZnBS6vd0%mi~%ZRAA< zMjlAR{;L03`Bl)1OAZHwMyd-?d%aV%5;huH5%@%Rv|JF0$@r3Ezdh`nwUZB9z8@ze zJwXOLRjZ1B{tFrn%OUjaiRVBQ8)Q>^^a;SjT`GV4}whBxm?dPsRegkd$J+@P{ zHaVPH*i3}k5c(fdxy$`E3NBFCD6nd%=cVouAK<{7I^#3HU(A%}9QO!i&r(OeJQ&z2 zYaEfMIm3If+5R)x-ZDOH--FZ7x3DbZ?lfWuds@;l1Mk>ZdiZA&(rv;w%NbG`&pWIW z?y=_;+_?f3U%y-`XhZcB#i{~RXnE&eVh^eb_q>1^j^j~v^K69E#&RL zy{Zj3)n~plbK7#bJSUa7S)v*|D`su^G`2bx3HRiP;O!CD(7ZlJMtTug~@2 zamOM3g@X0P@@JbA2P7DMkLvoy=;qAlbf?#9enG@Xoe8%gXp9|V6!08?9^Sfa|BeL& zY=tWzUZ%Oiz+19(WJ=-228pjLv23zbIn?IZAOmEPibqC5_Sf*z&KSUA(^ppS&k^2z zJBXx3HD=?qp|ArIiSS3(-bE9Qmk23HmZjj*y?P^))0oBRdp%>*yGiwNT?J-r`D=^|1>@1d7SVOv7u86o3-?5$^Nd zC!dhtb|rdGkv>0ZYzTK0m#tZLjh8v;y~G@f(wt#v`KrsEfUYi%R)gcL%5N=zH-os~ zIeAUzAO3zp1;LmH7S`3fF#+pvjIgaZU^5~lj;h)uWLpomC9on!bm0ZYm7c`)pOWvr z)N;>O8aqZCEa(=+x&8GzZJN(7Z)swhoN6-{WHFBXc>e48i+@urJtCD@zFLiGhpVIqPgQvcd+&-IXRl&~8;j;k{ZP z9sV2wECZ}kwZXF)i?=+sG3?UlUd4C31_3%co`S!M@_iGAIrqsJ#`(xto}9RTA$X1l z7bsJz&PbThU~e7)xe#QGys;nnZV$)mtA*pR?~46V+3i!fmot2-Ads0zN6ahRJ4iKk3r78fptIh zBpQy8{XU+0^9fptPTs&T)d6FWGS)Po2%}j*r(?%Jx+Xrx(#0Pe=R;gf>{M$9hCkod z^fg#qapzuiO+xINZP$~IvEyPE(=!c5eN@lRC%_pbN-Pr}HgdtSl5v)06}WdeAl<-V z0gIb3ch8#EL*b>w=c%_M_W%MO_4P0sigI;91Y(I!T|n`cHF1g@>a*HiEaq# zR$wkd+m3l9X3?5Oq@X=Yoe!=YCNx&Rljq(Tih8OTltxY-EVE$z+kJd+-@JgK>$jbj zl<-BbuKZV;cLqA#--6}MlzWNC>K|xKVHYrXzAK@r%R;{e#=%GO(D;bTZV|yTspb~Q z{Z@@LX;D=|o~EMt0PUEIKQ$W2mZexk@XWRn`+rZ%?7}0}UTx3THPJE4qq^?=@`uHD zLNNzJ9tX`|3Ea=V!TP5e!Pd0e=zIOXaH0QN6fmACw8HJpK-g+Udp!11J#d1!atb>c z()*D!&SdBti8U)WcR8sH|Eb^kVJKw(Xm#`xB>%mw>tC&VAN>wRRn=k&wpNN;V01CLt;nz%JTl8)CE8+R>L-fdK zvgOmYM$uz=bgqunKMOouUG|=nH4T02EafJA%q``piO@Q|lccc@barGYwLVUmrDB}v zC&pN3;!Jw3?&KN8s=fra{Z#B~r8;n!;-gZhD=#6buaUH+OW^F=_Q`>Qn_t7TPpNs~ z3aWCDzK|T;4fMNKkMBhMK&QDRUZ8!Q#Tt&~(75Gm%+T-LJc$a)AUNReKK{g$^DRak zdvCyuj-qy(#*Lovjn%AH_<&Q(j-wb^v(_M=oGQUBTsLIEAb%Q)+HzS8t~A|T+-kJ? zlgv$}U4{D{#=xwouV3@!a?+yrh!ruTi2>4{c`{c;YHp%?*(aIh54LwEU6bcyozlJ;TqygbtSz>74w6x;l6wSusIz2Q~9%* z10AxF9E|B^nYtqU`n*q|gG&6GhfQx(rWt09Gg*jkjzN^#2g0y7XVE_vcG2&^uuYZMM})I`FP)9 z#rq7kgFNk^rV$~Tka|;yo!^~X@ePOED6%_I@;=kj+TLf-xQwYfk+hcn7PG*MTCyzb zT%JP;*6|&=**3H+8rPTWXHx;O`ibT*MdFnujRWxtr4I%n=hD-I)JdG>0Q#d!H_oZVT1L-1;I z9+#Mu`{z3)Y4H^lQoj}BUv_3g9HpT?Nrr;6-pQ9du181Q*OJy?HpDKK-0OHmLdD0(XZr`kF`W>+S!#S;|v!|s=!1{EB@ zuJ+rV#a>q-Iu$laeFj{>u@x)JF@uC)!C1&kc@v&)4XDeN1^kMT)sV_U3O;b3FKbam z@dRs{;L*$8U|C!$M%i+N#toOaC_)m(9Mfgh-{m5)5?$cZ_KK$Lkmu>CBe%+`XO%%8 z;M0MsTJ1yEFoz5p#UR2by_V}q^zabz z)}muOj0%qar_kgOMxnBOnC`%66X_#6@yn63`L8ogHK)?o4wvbvxoStrazU8D139w| zN97HL`QH>=VthFL6thqZ_nD$TC(h03gRsXe)kb;dNpEUZf_{dMGMjqPV6pU$Vx6FF zj@@fsH>9|=nU$C+qKT@bqQV0gY-x?C0eC`Jrdh8RsReid&<>Tt)jSU*6csRF$f*f< z0U06DpNbk*<6o2EVF4JA>X~^ZM7bA++&D^Josg7PQWM^D8P*$-QD64|GEyoUHvC&^p`VjL?!K4WU)~oCQ*W^QP#gs<620ARd$9F(q zzSsdkVwti4Ja6bKq$Kh*YkRV6NwcA3#sLp+yH?2Yj}ut3foX8o+EyLD8T}<`hFgpd z;2<-VTC7k2%(W(ylPX!o!5C|AkkAC9pmq%fijeyhSVCgORFT|jcAPH9XoNd66|k!L zyJDN(V4_eF?Md`XtT7UvF>oO;zMNYhBFrKVRv_vZETPi?ItK#C=QQrg78Ej85b0c` z6XEx22!*>6LUTfu#-+Cnx^Si5pb@hUtg{qB3~($X5DjY>!JY961eO8p^(Z|@Z=-Pz ze=?DhA8m|TZcUJOW#=_bcHcloTD!5+_?nISxfPVCF@*=^vnn+Q8N~pwTNBHqMfaY8 zRY=aAa{Rh?oXirDq7s}7n4wyZ37D#x)Mc!!BlazhI)PZBOYt7pieR;hqMe{`vGOmB zC=)pbBKm05DtO}nq2#R8M6meNEKZnGXmF8E&6TSO&=nHyb=X#T(8+*gV=H5f037Z+ z)QX7c+T4Js;7Kra#bQ>LNQ->R+`sl+xfWsiB@S#m7&dhnC)An7k9mOO+}V|-mCEbB zU4p^yfoW}6r9tvup_3f8{F4+^B4>&dj(2#}aUi@|WCvPIo+ifGWYzs+yDCkP7>8u4 zB+@+J$OLBX23WoJpgLx5w~4Y)*jX%%gieww8Uf@N*|{-e)&i$(3RMNOnNgyjIM5FY zDm;49)qo}!h?OED>*#E-#L-nHWCLS}UOw5y_Hp@SR_gFAib zM`2_ul+7s!8A#-RVs*PaD3wov$0miCG{z6DVV%4|W-7ad0GwsLXcMA`W96U*rCY4y2ZW9(q7!uR zvJU$Qk(Qp7Z1#|d`JOi>r_~3Tc$_UP_~-+jjmj@71#{e{VW2}xW}4(B1n~eCv5wSX zK4R+PD>7&qM+sCq3<@}+A>+rK%_hH~dLGiAcppEyC4rfzj7C(Y`m7a?J6%oKECHh> zYZ1=LEB;O>&lpc@lQOCmsGEKU6-#2Oyv zNozgJv4pdQuTCxoF5ZHP83x-NWng)fW(op+Smu0c4+)%;qS>t~u1QhKAu|;XwYdO^!3B^{WN6DKi z4oVf#d7ZuswI`nR(HQuox;1!tLn>-46ODuN11}j{Hp^{@V{cuBrcQlZF1>7dtSX;k zs$9xu!dgVOiK+x)&CA)*X711eqNT>zw0(qATw0lhF|jYy$j0y=6jGd4CSJt@%FDyy z*q;hOV@3qA3onbS`N5e^Hm+2eNNSdGTfa=ncA`b}+V?F?g%i=svT8QGbz5|$6G3g{ z2Vri=c@jyBjtc=!x9j7(R)#hB`~(9Y8!EB{IW#vR!^`Xdioh%2qEF6H>~>IfZ^l|R zswclHh$D?!7;s|{zUb1&Msx_;5hp`M%Fkv`a%i0vN=X#WsT*gM};UrhZv@rleH-- z-j=!&!&SO}30l6<>`Ig)%wS^qNAebeG>#O=0@qE?HYt{{DEab6k22;xa_5Pe(8r&E z*jrr8 z1zN;EDpCD%vTQI*;nT@nu~Vsmtd@zz@UZbKHxUJMp$>ARg`z_`9}onba4!!2ojD7E zr3+{|LCyx{Y7!S+5#G`cU2z5a$GxoohA zI}?+I@|ief_oN7@Ncs94Y8#rM8s?FsUUQauh4#oT_P>OAmj^ANBLxSzY+(ELHV5{BP4axo;a zg2)P$tSixFv?mc+vPioP{w-%$h`p|cWl?v9Dz|W{@yBWPbr|LHiz}hjo=XbveOTWd zBn-#}z&IJ|&8@z$_^#wj6i+cdd^&`dNx9a;%Oqr}84;bNq?g#Xhn%8Vy*C>fF~7Qa zi}~16cXDsyiqW}bI#2Ym*ZJU(5`Gulb4W&ghi-fG0ocgsaZU-#P0Y8 z=G!4q%|r~+&qU#x~;Nrblu6ur0>nzZ3-Jn%UP$)R`18|am`38|WC+6Ck#!pG2G zs5O5ykb}5F;bc_;@Gf=h=C$Qg;1mnj*`XOPW8w}2kM7$lL4NqA3q%vPPHS>~!zzAC z7&4`ll3nu6RV?giX(9V$6ABsGL%6{is^QY#Y$3C>U<`hna#M}p-B3@L7-Us~ff~lK zSgfHonv1jX3l;c>`A+Xbp_*E#8Es&>mJ&ONOu{tQr5aF zZ8SZg=-dVJerCbvrJt)%0wF=|Fbc>N1z(zT9oPRMQTUSBt zRXF%2HrS?QF*AR1BLpq7Y2%%)%D(%sRsGbr~cXY;FL|4#>!<)g%b^Gk;3sEicM}l#!KF>nN8Vo43 zOyi<%8?4SADi{)5VR9wZLEJ$c5<%JNZJ=u9$RCmfuClPb2YQtVhDt27w#x3ny%x~K zY%3PW^sLr+B^U^(gDbvE%vo3(W2+F+=OIHl4upe8FDbpsD{pC2093$9=6X%|&612^ z(L$^dd88>`9%_i0B^p!b@|u3fy&g9MJiVM^EuAPR{&Uk~B1ND=%nsbzL9M+e(E zUnR>KYQf-_BQFLiI=q-}M!_;K(##rt-7wn6_T0vr^U{l~G4RRsLJM>ijO>ZKwg| zkV<`MbOFFQyX7m;6fq*|b+4mFRY*jOx@HX6}1 zhYdo(496M*Ym<_U7%T3pVPwS_MCyH8;4IcSs#jPit&s8h-{I-OwpkI%FdNOvllAIC ztU$SeR@6Cxu*$FwL!gd!kma*7MO~vo&FS70p%Fr?l12_{UL`kJxC5iBqPa?^bt*vV zo27tZHv7YzHV&V6StzZo;gD{+N%YMY76&JSV{uj%2?7jZAF+uU3yDrH@I^^zDUs(` zm2yCn0fmRhn9LwLsi1yw-ZA&PyaEX*Rnq#o7uhOEO(dV3!Raq;*dsBZ2zMo4sfs!} z{zNk2KwK{yu&19FNJq6c88y761|MBhs?duaX7PJmNH&~oJS)NpuXX5=$e`x(LL>%e zVQh}D+w*(#Fn+I>>%s>csjrTLqn3(oMQf5#nNMZn<(u+Z+$MbnTD)5T1VU;4x$I)kQzgM{y>S5^q+x^s z6s@p*M80Qer6j%@H;SQJtWH=`5E6Ck$wMwxFpOX!bZeaO;06){FOKIH7OOh~6_F{! z2ALgvlT{gnUi^%uCTXVdc8{L5sg>F!MfqM8W+|?M(nOyocTdQo77|CeUv_}8-<7-u znRM=A00t(oLBTZ`_Y2bkh^wl$rEibH$D!mdqog)~l!P3pM^BWF-_R}Ie1T!+6Xc{_ z>4?bSTIBP+OoAEvh2Z5?5~+HZF)9eY5JD=zB7m`FW{GaR3j|=c9s(SeAE%?cQy(8w4opXP(Ek^E>R1jPx1 zO@fpXjLu;Gy&4>PLX)ADV;7QHhJZS&f!OBD83XHRoPnhIh-POsPp`o*2Ax()sI`H5 zL`N87bEQ9yOAr;9@My{VRHW(VN*<98thmF^UaP=23ucIE9sK#_i2ZAaDhSD>gP|IU};6X1{hwgWvT$f$LSl0d5W?m-W#SAk9s-t_CsixNMreT zuo$U~sRW#KQ*lh?Oo4;IEFsl^^+U)pF)Mgfia{JPOk$g(sf*E*e zSPt4wD77k5o@L2s^k5~z?vV#GG*00ZbO@oIb|j%u zN*&z9R{m)tj6kB;#*bV-Yvw!6E+eU#w@K?o*;p4x}Bt4V%1Cbukk9yiWHfH zS8P_6ELDSJBVh^S=Jf490-{|)P;HZn<3k=`US;l>b*Ct~Hz9lwqZ7OUtDKA}_^yFc zO0LdjBb!AzpFm|9aiQcv*>s{1(lY2}4{PYBb(|vbRYHpoN^1Md2_U5-pbd3kh1xJ4 zg_4>)a>CCWbQvlw=J3eIC1st6t1)Fzqr2bt#ZFqGD`YjIqU!=ni7}SNWoZXx|_f0uclp%tUh8ej2r!=$XRpB`<_G6|VR36UD7yJ9LKV*M zgY6Oah)9zSgO7qRtT+4tIhJ_@7!w|AV0L$8w+S%}BIvryO-q$%)S{!rAwY$y;!}=s zIv2g040(asMu|*NCl^u0Q!y+;&>^c-{Qi4qVZHF3XXymxy5&oBFU$7xp72C3to(4Fv zt38|2SmoqP!XOMiLL8V9%ekFn+REMZ!ZtD;Yu+c!?D@~z2?uJQ{e^DfGZ)!RaM zh!=BbSs3wb_jC(TW2v$+7>3oDV>zQ3A)_9{+se8;T=R((o_0WyX|jCFIbv7PIryma zlZk9~j{V^UYXA0pu3FvKJph3Hin^}oB`8f08)O(;gkzM1k9zN7c>ljC=o4ewPS&Kc zH+&vyvXTO{IN#qa{oys|ckEehW&RRh1}Tr%YbIEM(aHaB!fFztait$32bwsWpw$$K zc(Nhx8W#J|T2NtDg!kjzLXkFEu_%oip*Zo)O%M&PyU*ef5pH60+~II^y8X*T{O`Mb z99m10O|=k#Uw;TZ={@N3PVV)8R_-1tGlFYBQyNPLHq@87_>rv=0@;rzu6`Tu4j^*B zBZ)fFJ;I!~YcEaKO3?x*a7nC9i!f^MLkzd zP=hG;%J-hn(;_O|G$Q*~@Ga{aDhl1~lD=^x`CjjHy=Iy+AG`e}cQQ3q0_T1>xBFrh zh*eioAP)YS)*WsBP3_!lCTxGo^DzYR!1T&lQkn3}bdSGFo2M6XFSl?1P@E|%KBarY zc!4hV?vO61FTGI)5PmZIZ_`t}9SHK^hL+MdJ`;;H<3%*h^2&3Sfv%UI(`Nrjh8)ob??c7zHTo+*1tIlZqmDBrG|9V7Lb?)w5PwQ z)3Q9r5IKR*hj+n$PKB9fqCqGE7CvdDl3Zo`zAcF}#J-h-#Kt7=fB3-}kpZ1S3F|bG z;$Jnn=(}j1I^~qW1nY#ByB5YJ_2qu6yK$tycd;&a@pu0bx9O_3TCLMW`U`2G^bRBI z+E20CYWF`13PoaWIGX{wWC#qupE$L6u^d)sj4EjsT@a3QYLw^tqj@g?clry*NORV# zrn|cbGblxL)+D^fv{th^1C!_*NtXi)%M$e#O{$^w|V0W_az*mNHlL1f+sHK z7;bG;6r?=T9lkFHMKf_H%e>v#k9VC4lY>1jl3ha^<39A2XW_q0MGbMMDThiv}E}}Je7%A%tL6V(qQ2$2h6!3hUmHFCWTGR(rId| z61m7h#@OumSO#ylj=UVM^dt`At5Z|XA(+!a90};kye}U=F-to?5^E+z_0LymH1$m# zo%z!0BJK6i$mxEomL&QvC{TWR4W2JfO{hoVpLZvilUwm{33f&(Sa zJHB;j1}6191I5zbdP$t{A#aqFw^%1g53)qFMX#SL>G~@9*e?Q~0Su-K+dgTK3fo_+ zP7JKAe;i|RnlAE#_F$3y;T6ZKLRqzZDaG|=pXgzsBTh8WK_yQ^8jN&M^pai2#R3y1 z%^*K#>+7u#|8g}{+i{vRbCWSzXTKmv+j!=%(mT_1*?BBuMHG*U0?`zJJnOKq%Je03~2 z%+ozOuQY_cf8mbj*&zAk;OHTqI$e-%QiicK1uC3VnXVlC5gX=8LC1NAeVet@gG_uy zIY+@>qh~u&H0>F&)V)^Nvmg(TJ?R%fZKx}0Cei7pj>p4?PSvghTJ@dEW$wOlIHGgI z)T{wdHnexBFHz%`Z2tbuQ)UF)0{XdgpUtYk|gw$WY=t=GJ5qHX%7(7P6t0`(!Y4sem{ z@U-nq6U%2F>~<0MVcvIGZ1XodiRiT{|B0vFZYt6|+&dMsMcIttLdnojih2@B-h**z zcHp@60kD6VwXBvo;kyMtdp`%2#qwWq1#p5<*Kz9|_rvvjFMKU>7s^z>VqL++_{Fc; z08qncb_S=Jlg;IXa|d1u+m^V!*bs0~s0l%3`nGW`FFs%IApWEwqB;d`AxP&}a!3#QjSPZ$r@@|e2=MX&wtB%QPhFe}+ z-Yk0uhw1Mx<5Pd7(Uiz=bWjhow$S3L-yCVa}-M)-rqSJshgplklfeggPUm^(VVPbi>;rAXT1Y~&>$1ev;@>5j4o_yL zvCfCyh^)}QdxtrM$T?_qnG7kdOUPtPVlWN%*1b4#*Ghmp2zi#PTtY+ImHzkxS^;*wYCj4H z{Zw*?NT`!J6hc=3w;bXv>c!-jU~PFwr}^dG9Igj3c$oOEs(RUP4Fsp3Bj>)%W46-~r4T&Xu4;%_kB1k&IJ0k*z`mIz z9gS*ZX=sbF&P^o}5Ze%1$6(lcRcwF^+$wpXRn{>wxx`wTa^KrYBKKtxp-iDLQm`MA zeNKS5Ev8533JWZF8u`X8KXS0tlQg~YoQ!W%6`GeY@`P;ks(cdqrS9e1yg6|;G+@@8 zmyny~a#uTMM|QU|E=F8O4{Ft1i-)!#&bmc0(quVr@314}@OC6;ke_>-J&q^s_xV6f z84Ysntwr;3acQ)X*t-+ocTRgo{2kpdDZETwgj&~bSs5HWqA#%a%K+DbRf16HzLP%K(oFBFY~Q|zPZ zC{vUEbFkkVi}iW(F99-8-wPG|y35*_(J?tqH>!_L2(b355xzV_`i!wi7d2(vjFT_d z5#+ZU1AvTKfI62O%{XONyHvtj8QxJ}KD@xJl2LFda%L2QMnmWwQWzQwjuKcjiQvAs zP`SkCXI19DaSn=W!p5DmYf6)sy;!|(@X>?6U}wilr-^?N(XNUv4n3TBW-XUy^Et@k z=4~YM!4tDWhI>49`YAF^0NekYlfR%l&CofZVsPT1hD**l zMy2R+ZwPBITLLTXRS@^Zqu;4KRV#spE(H=XS55zfx3%YY=F^iZHT~+bvKwPd)9YWr zGCYcvVb-dXieu=mqp6LcXlTBMk7uUKpP?^p`0$-ogo{&d+xq ztb0iWizGCl+j#erp%1(AN8IVEaaEh4B21-?l{+nul`^UDCDEhwhceMmK`E0c*0BL_ z71zA(nyCws03RuB>JpoDYb85M78gP8RJ8RmAe7bpou8|Ye=0)*$j?-^te3tzqQeeI z(HVzv!3kS>I6(RDkp9B4`D;}z<_!khcNqwiP0}nawkfGPC309JrIlA@D=13c{Z4<_ zn|dwwX^q@?1Q%hOFyHeVZNoGDGC-b5HuH`zQzeI9(4Kz#w(%}(H4#DNOs6&qs|C2|G|*7cu^t5*d<7amv2Z}w#Dw1Af_ zZENI-P~Pp`WcPr`?9`aWw6zRUgePl*X@IsIi4IwbwU!0j(CCI>ENfpx(^uL@x%`P& zOq($R-6VMetOM~+0N+H3L!;?3a?%C*TPq+llWL zPn<+~0(x_0DMcE&{Vssl7_v|6%c&v%_BV?tdFkFqE|cVTdPwrREg>MSN$3kJCn%$d5{HB=|IgM$qT+z5F(gCD65 zJ?_Pia|6TgCO|{{v&4Xm`?}^1BP&4K58!83Q+<&H$*Ijks16YtA7M`08?R1m>X2w@ z#R4P!Z{9M~qs~lqmmitW{mQ=Pd1v@T^=vr_+Aj?rTNHx1&$BCwHM-xYEOp)=pIKUI zH?wgJr%DH~aHbp@5Q+=C00ex#hUDA93H+FE@am|+$^OMjk{ru2_GA+38#bJJ z(uTQASB&e!cT4ZUzAYTJHWC(;YLWz?uAS7^);^cbl=X`OkEuK?uXc9*X6Jz!NccOe zuS-lXVExt5`=!6f1$aQA%iYdfw#9`QD6mZZ0SRpP!(}T^fO9WvNb_NpEC9>}F3}j7 z=aZ(x2$#*KD5O?WmEYbMkMvG=pd!%@ZB^HN4CLqvNOuzBaJm30juGrGtOXKogGQF^ z)^9zn?hE}z2NIbVIkF}2T_%US9l;xHqj?f zPPCzGmT(T}^Q5~5G`*^Lls*rtrP6kf%vx3}(x^gbZm>b#W7hboTi1`x7*Ek;cj}4` z`eg>fr*VI;5-;*NtdiJ^t_JdGLo~PN+u|qz|IC?2mlJ{?c9Lo-Fe!b@6_crmXLKW8?n4VYIpAW!@bpm$0ikIWZ3eYFdxt4~0J4paU_Rzt zSXp#{7;(m;78b#Eumn5I$Pw3Vh5TqD={w3{tdCmBq0m0QZ5SF7YUvNqDOV?~LHO1f zNS)x*?oP~$o!pccGgKfnq6GMKNX zav<+0i!FF9hWU@JQWcLu;6MR@f!mWgq8ROKl z6owwwwUHY{+a%siuud+gHGHiVd4v-R+O8=Rtay<#Qa|mhFA)0`qOlmq-*_SAPA3_E zv9F`hn^MA#BMkW7m!P&*#K(qR`Hk4+g01rypXX0$<@1N6XorsX4|Amze|ENOo1E_wU{>n$tR_v<6qcq=3Q@&n)4A?S~y9Vt{n9p0x&q4mAWG0FY zkkjdFve;JUz_EITW@iT`b~`}w;B@jcb%3+a%V1NOxE|J~wUkUf$FJ}l=ODJUfdgy; zwL?}{;>=w}PgG%dm={ zMil5xMsv^7462r4KdTaPJnl#}#ii4Z0*AjNMp2ZWQ=pTSe76!Mtdho& zPu;mz{WB&MbtRQA(xuuudcu`85U*Or9X1%Is1SZsnl#5_C*O zBHNwBv#yP36J+<(@O|Yv z?#|Z}_QWOEVeUzcT>Op#;&Wml_$5(Y0Bo1AT8*49(^MrJ_1ZD0u33{edKbyessm{4 zOILM)=7h#trJjW;=ZRowSu;L3p_u%MbymBhDPfHA4vkWgNldjK)fkLxXe^#2et`ex z1)}#nE+9+#v^kC zYL34UI-6Z<3?+zJBSjy#tpLt*%0O_vPcrxCZ1_C_Cd-k>^I$YMqPo#ZIR|$B?7kW_ zB56|7UIe0?lyX8k0+{!oNIhc5P&^2+%&B<*uZ_#%fm!^s$W|cbPnrwz7b75VQjDjJ*ha{Nd=J9mH5>qD0r+L}oHoYHfUOyKC^#WJxY8=6pwBZ4*IlX~a9Sfzo0kmMEe+ zcM3|@BKFnXkbIbcc=edJMT+>fjum3_pJ2eM4>d44?5Hs@L$qf*Qow_&2fU#Hr+4$unL&)m=+=DPy+v)TQ2 zV&yo~en~IS8XOt2NuzCP%GMaq-q98{mk?x3h^A{<8B85^^wm;OdwN0aH@_!i|6iPw zlJ3a2FACl4)n8?f=x4tZq@vE(=}j(5J^TCq+OWfBf3ch&cOGheV;U%m9dSf zNo19$i)XzxSmgd3pXuU1Qinw1-~+?)E{9qf{wE#V*Rhv%pvBx*rd*`8y z^v>K?p1E z#n0rcMth0ybi~R46}?gtFTp;ujBmIx02{~K!Wh#H*)wniYCSAc-V@RhHv~*pFn5Fx zpId8)DVlnkY*g^nKg2N{W)&tX0Y*GD5l6Qrq&#G^ONH#KN)p~i52hqLh0p=u=JnI~ z4+ppcF?M@&3e&U=W@O8lhU!&#Fv+zN>k*sF>g>AnK>j4bFs2}dFN3c=40jcXy4Le3 z>m&71c%gvysrIv>-|PvHy+g8-_ToCy%FCW8>N>R(BHLH?uQj&bO|IETh(3Djfw8W| zWRlnAPMX%vV^7$hfId%ccO$YT4L0(_Xj(%!;{JNqcAc5*)ZTlc!wLVTcW%LMPlvRITxY_r?YUo?iqnZFlJ&oq z6IdgR`}>UNVOjXGV?Yj{PW+(YXV2Mm=tebw4Ka4>pV2Ff7YbDqs5>XN)Efq^n$ya) z_K<;nuZG%c=L7DUx}%6w6eqjPf8-3B*!IhDc# z$!h$WRNw`NGjBaF2YY*qBi+LdpeXt0=8Hq&k0@d`GTqoAcW+nXXGNO58BKy2SVlf- z^2>s#YXOtpn@yi%=jQK-l8?u2rrei|>yA>v%P@AIGP4ql5{mdC7>-VU*Aj!z2-F6W zB@?A={?7^h+R)G_21h=fDQI60*RBO>?WDU;$IgZ}WPYJrSz?|iE$)oqzR3rzF+*0| z@1n~h@X0R@#cx8;uJh9WdlJ)Ah6Pa<0S_X#4XgDsPG)qJa{#Rcr$V%iGQ2N}t%^Sb zR{Df*?I&JVp;iNX?gHq3E8LIF@nBmGvFvqaNOm*LIz_e1D zR9=4Lsl{NoRK(4c6mxu!XajSWzS&V zyY^q#CPf593mUO%vh9?37RxK)37tTOZd(kYoDm5+Xb1{SxD7n+_g}|R_SxeGMM?h1 z8e#l-xIV&f+E92#CIjsbBmicc4>oP_h-I~6{I~DB5#$tFzdRx9n^xR&S$wWD`)Rk# z*?ntOU7Ca}t#1+8lOiH*a9S(KL`-;b{ovyaHa7P#xba!8ru?$vn*q-aMn1>F&4rXd zEoH}*acqC+Y#ZyzI{y3GR;G=lt8;~*jB)@Yt7A%55;@^f5=zjC7BCod&>9lZl?BV zg`+1UdVP(PXLY9=g1an4jhbOgPB>IcktFh{+daxGn2h&8X6IZx6C767ix3sBTi4LA z4%=*e!6pS{rA|`Hje00jh5${H^6eHofbjMY=}(;2DlHkJeAW13tg7}craQ;p zSru)KwO$4NtL#=WPgXZ>&?NR^S;+mIu{tw5omD*QW45c9mu$*Z>j&2W7)b#&@T^hi zrv=F|y>aPK$X`@CFnu-G!isMV?Ac+y)zI1y`s{9*2VF3YQBhQBgF&g(+M*=c@n0qu7eG9fS?e9ozQ@cp{tY?6O`w*bJNt-yy zE|ewO(eprU?q$D!Iv6(il3~V6x1;`&u8NN2r)ewac~?qfaRs1a@FXVIg-{_=lzlOa zi%X4O6+gHe(*w5e5@luc;~p467M@c)oK|6?yqXMA8*>QUaT{?t;8FpT)sL z346e%C*6(LJ1BSo?DYWNU|Q^?b9YWnvKTVpnPENCzdnv(=B)?E_K1u{H z+F<4e?DZT2Q%o;g|X9fL;)CS!0}R52!+2(GHG5@&*adMh8qf1i;Z{dN?uj+gie)zK27Pz4?wbI{R#|Wu8eK@Xc5#-N)&k}#SuA1dqYUzcB%3N7h@WOw?EF_9& zZ-rHp&x21yZh<_L21PQBW?hqK!9(=CiC6+5P}@HGaA6P5Wx2u^OYkYTGE z^8aP%i7<9(%|aRo9>Ght!&+E-UZ(apS#0w}S0RgE<}~x(-X~xB&kFZ9$a>}@p6)XZ zY(Vn(F6zPUcw1kb1nm#?>#%0Aei}^2=KS7Mo`1XbL z-uU{ny1P61u>nf?lg)bRR~@-s4M8oMGSSF#|C#5R;UE`aMvHno5qeX(@#Fv%2Z#s38B$*~q&)(>GxUSMmNdwaPSWpb|-P*?3! zf|R+HNw=%mI^?y>O$8UD7r_fZryKy`u)RrkhW3FpLU~m1QI7iuqBa!oZ?7rr1`v0`Y^vi8{Dxh~MK-Nun^v&m{#_jC{)=r^dJupW) zAX>D<>NvahNCPs|D@%tGEoaQ{6~g91t@1h>nB^+*wmD*VnPv)}z0_Y5h}zHG4RVo9 zT}SjHnI-itkAwu_e=TgG+9r{5>|;c5;_zqLOsS3ctv|NuL%3Qak?BWIVgd+HZ=?r> z)EUNx_Khcseetu<;_H^^7 z`YX=6{S)`32c4l!w^}Cp()2{cDaj;FuAHcdKxNccH0HBwT-G}}6ihz?_Gg|~iECE< z2@$yt854mjrm4US_}1k?Mr`6h*1LQ>mV6&(ZrHl${7-?aV?Z{cBB4l1ILfD?OY?Kh zYKr`Ges?zgBU{=6) zS*mST_2XtLaQOE!kg;YuTrj*1Nst}<#+v#}aE24Ls_mpKKiH(7RR?}WC{fO_k?Fco z1ulMYMV?{y9G5bGx5t@UHk41G<1)zVceQu$BxOK{kg>os8n(jW{4w%rTA<|e)v68~ z3Cz*otXuKA!9v#6cN|E~1`I|I6PiDgo7txER8KEK?%aV|6hreNYBoMyMHe|f_@DOr%oVsJ5rciBqW z`Z0H^;f*dgEA_sl)Vz-{4hpK4iXlNjUe_jdHV{?R4M4$n6KeWQF7$(Fn1%@|(j?Mf zwj>+2#W5WEPKVS!5m=BaxFK&}DNq_r4;EoGf*Uf!=5Gl4f>5SM8PDN!iSu>HWomE>LT(D-LfySkAcXxNEX&f4NcMTq##@*fB-95n_f`=dp z?j(4C5HjDK^UOb(yM0+VyXvCeTI;hJiR0f9rU6c=U!0<+lM=gPr>+^i2yiuwo#(!> zIPTpJQKEKY&#B(o6WEedK531c{DkEWo+1hn^XPg67e1NM<! z0z3)T=Y6zv{N`ma_w&ta%8H2WATHo0^%I8xw z)9|yVz(1fRuNNUAU*KiGzOcYq!jxQqAnaJxH2o@Q?vsz`hy9c<;LV`p4%ay@11)$< zCBi?d@r286zmt!BZ$m%nWrYvH+{>ap1q;$`=P zuW2XB$sfI}K5L|$*|~MHb*q5}-zKvNy+>T@bjOs`C3R-s9x}*Mq3@f?nGDFvlo%pX zS7glDB%sp_V^aNgPwa+XGIp7<8)?7O#Xj#A&MBfuH^PQq>d(c%$zH|$uHJ24vgZe*OvguUpZ4xxtGNKtJmFWcVNQdAg!L_{4&s5}?4i(r+Z9ez6 z)Q!8l?KIIQ;6Vs+TIJZj+9`qwqilHmM721qqHnj>suu0lE3NBVm5siBqj=upIhauR z(()X{=}x4Ku6**DH$=GiC85jSw#imRjzpl8Oh@CIwDR8~pA3@|^1Df0hw7t;mYg}} zEt=%i7pzVVF)5!6{4|HT70j zf6g&0GFP-8!}5_&A$ET(#wJOe6Mg!b3o=(})Xe+th@AQMFjI zx18+V_%~k}Y|*t5CEM8*>Cy*PvBoF%+rdSBRQb&+;VeEqpM+~y4LkMi-eCKE^(J`U zk3~4Z^YK2+Eo1z5K<_jD1^b*CAbeYUQcxExvM|8Q0Xh&m;V}c^uFd|Qvi>GBUdf6# z&A$ye!lUuHeyhFU!T5CnAkJYZ;D3DJG8jRSE%|IUFA_b6_5jN$BO6H<}S2`wF;a2=;Zk(Pg*N-x*nWZVe#3myGa zOTpUnUBN@}=+&jZ`+&n8wkQVzN;yxVQMd1HF{^R-oj|AX? zN{(f`xeC%H)?v($v74$Vuc{&Up9Vnw|Ca?o@Bdi<{;x^ke{Bu_TfzUc0L1)HMeH@C z>)fd6T~eO?zxn8ZI^K~I?s-cy-2WvkauAXfDQeA7tL@z!^~uK74-v;}xt31YF|5Ny zS!(M!FppYf5Q@q-J-v78h5d*XRMvr9;YtSC%VVESLfIt$wQ823FyJT3q&2x25U(X< zR(}+Qr3}K|;&+c&a2N%aY-_yGG;cbzB1N<)??pWY5^}s_^7Fy^@@D@iCC@7@&u2Jj@_K z5=#&IEOvP=s_9B@ssXx<^k!Fype7h+Jy$=W#z4NjQAjOtqbUj3qC;J{&a2AL%iDzE z*u_@U`&!W~F^KQhjq0Eyr)f}SXA+M6UhLih zwV!|}B+u)+2Zh~2?f}A(B5bxw{%>2^i6pf@j&|-6=d(m9G2Nvm!)5u~-7R|}W)Xwo zW%GSpC$b=re$)QcFoY7Fsu5@7Lnq?KFW=LskZd0&^|nXsXa33w1mk@O33UVHssb?|+ML@M9EpJk{?5l+d)w%7JZ7Np=NEIYD3}{PHYG<&oJp}m zZ=_ImpI08MJ612MlDFiF$BLOFd~GLO#bUfdRx3oJ2u+l7TJOvr7f9@F_~ZQ%Nq@U+ zuVV9x;E{BAsU06%y3cpGYLwLzf&O+UrO>NGUWOswVKh}*@RLhw5a*@{Xz{>+XcONv znahLW47(H!1(u}7&no91#g4wOjHLwskzv?Ki1YFhCFq<)NlRwNTYZpq&G(iUqgH%k zd*Qp0z8Bl757SP17ax-l4F?Y?A%k=_Wi^_IQt)8cc&d-no@KeiiNoyijIvHfhm0Jd zP+p)TR+5AG8t=<4-WBIQLmCR?4I8Js8Ku;ics$$3si))FGL`#w+f7E1*HO3gYAX7v zTHX^Eznt(>x>F99U15oZK+c)%(Whc-KZu8lZS_rj`3MDL3qC zMTe+Sp3&;z*r0oi4pU)D!Er_sKl_#i-P*%wIz*E=WvMG_tlBxoiT3@gZ-4pJE;GaJ z5VHXB=t3FXAZy zFZ87fy~aNgBO=w)_VkpGAif0Nx|Ml(I3UwF_^^Y1INmB)cgrYeR85nJC{*c~7?A^n zsNknJg-gd04ojjLIS8osFTHm8X)#?H*{}#lKxzqNNiAhOl!`DzR0*1Wv|9E55<_Wf zPknt*do&A2o<|6FkiA>L*3sC=CRnrRAJV^?9w({N@ive6hY-H|Q$K?GqF46ZF(ZEM z%VLdcSi&DjdTV^c;iA?-vR+pRa+CK|MK;p?V1)bXRh_f9noNz&lyot`4uLzmZn``# zhMgpIL`a&R;G-`TIS-MuJ3mK6CK5vleQMlf>s|w23GDXViKQX@v?5J=Wa2bFd{YnYXA_ zfl{myES`VX@?^f9Xn28h!bo>))f_cSZRUc>NU%)N!iSF`VGBN-2Zq5Whp&y2ST2i* zzQRnz7|h6?*+0-xeU!=w#H_n6vl7(uOs6)@d#UD+so2Xu$!q2$4GP!m5UmXVY7eF7 zhzY5dN_@mA;{UjL>Om?_=hQ-2ZT}xLVy&(@K&A1C&;W5ijw39ek^>j_KPKs5k#0^H z+EsP59TFi#3w>k=KkLJw^-2A!0EC;HCy@?Ms6h-VN$>JZ|)3SHmrfeZ|X~9=Wp&;8V+C(C5rDI{ao62VGmB zGoAj|F{YPDgZfLCZxvaB2id5t;a)l;`CDxR=`*P+cE&>GmqgR|SoNmA3OklH(H2=W zbzg>V{U_U`+FbQg*~4{&bjFt25SAhdQ4uSc`>A>C3^?Y}wMK1HUuAkvYIMY!M!KpQ z834~UzYj7ywc-}V`@GL0_DVOxT@CQwmx|z{Myd0q+>i=B^pT6JElIsACla-_o`6dw7dAozj>4m`&qh8%;o66S4V#0}V(e73wn)o< z<2C=`EmKOJZfA)mp3!7|=4{jZ0~w5n@dscB(uQE9|3$>ghm{VtTF`9?S6FU7W`6cY zfrW^5KJ+%)ddu?OjlGD~qQccA33j7wSaAZDSF22B=~4S)cUw*@lo8~JdB%=uIwD`U z$J|;f@I1bA=v15;kXJ?Vo^ZEp&W^)XKJfqiGDId)vMDDM!?*EaQ`{|s`O<>MHogv* z0s7TlMb0f;?29M23<{cnZcv4?-#7TND=&_(g!;*(1UYEg3Haj#Z?nGIx&|d?HBGP~ zA*M^HOJGCk*y;s@;ta1s?L9mVRY=?9STHx^7j3FFwXltE9#Q}?(F9Lf)( z(LtPKV1OTtc>hV!zCJvxBqY-swC|nEr-i8FD~{a6dBoBI!uyjSyDO8X?f373^E82G z-_(+%SnCzjkSNPQ2o*Uv^FW*OV4vvZcrwI){3eW+Dm$aJjrP3$wQRYvEU1#{Kd?Sa!ji*dsx%#0E*Li<-HVJLFunZl!@Q+d_5}oh3oNwrv zJC=G7UWg8NL>;(E>=(XER;8vIo>$HJFrKE6m#^y?Z3tUSavVDgYZ0(NM>;$ryf<=O zU7_4xF|^e=u$wS;873U$@1r>&`^e(4dYA)<(0O0WYYwVm{SD z_IqKFkn3~&x-VTJK$yNSUks1a(+xc*u2jovEei&L7UC7%Cvl4%-omqt%Eg0B>5 zBHr52q#lp_1GU@D79$2r*zDG}0)emSv=~icIAqXj{iyB;Utx|zrjh3AsP~*F=auUCa zv#}0PM1l&cA!{kjEkv&*B=fyZ(wJ~+uZS|2QC4^#CiBEhI4Bw1jhQh@zq9k-Ww4XS z9=g)#P~X-D$V9WuO32@79DnSP#8Q3{h`vbyk!(DN{8d4Ch`4Jtj84yuG?dEMl9R?u z*76XHy#~wRCh+$BKX1=!uz||c zWBvOKNJ(ZF^MYjKa{=NZS)f_Kl0&g|R_%my1(|@U0vsd1@O%kiH{mp0R*#plQ+ftYO_M9p#>fIb- zer&Kp)}jc%G!p?XM89Cc^?x%zMV0wPORYX*EF}>+{)o&yr0j6~-C!;C#1-y?E~|5a z5kgXBS0F%G8QHptf?-9Sj_r#)KVB@VPr#mPOqDZ4vq`=X1;#$DDE1TLdY!68DD#MF zi7P9mhr%T4vG8!d-SWJC82fhhd-FInj*%cWZH6eb6^1iqNGsk=JWWA$&{{U6n)Wj@ z+fI~xf0|^GFcCdfR|DWAt^RPJN`-W$&O|DDSfTnVaQ&)zW%A#_fAu|A@nLg19i^7m zY|&M2CDc`;)1RyK6+fT2cd!!Mwr}OgR6VRB=8ksnkL$?`FX90&VDg>D!o+j4jlMro zwb{h$>qKX+a%>)L+g~C8vo*Ta!$V#m?G--PMDn%nV=GGb_#6#A{v0|am|B*%*H(wW zjvFPBNHZ+;HaJPEM%4IuJJmPU38G($wt$2g1r}^x3gc7Woax9GlhH(VN)#Ecn5-Yr z+$BRqPzWHRetsIURq5O^AzuRFtCCs<73)FfD4*3D{$XaG-nIU!Le2kcR+=OjUs$zO zikJ^;NWa9vTC#ybyi&-O<45TZdx^Si3e4kkw_U(#UeWkr#Aq;XQk;3>U9bm=j*T$2B62~r ze0_v9)UfN0-$Yz$uL%&8Fq%nllwY-Pf?hnLbz3`4T}J$)4P8f;bR)*2fFLtASEN19 z6ur{H3)helDXAVVW}oN!$z;<9097Gp5m&cL(9f>C4Vh-aAb4fM%T;+vG;NM`-J#1O-a~k1ZgzmY8cf`Ww_5@XWpC-TD<}j~mgL z4BJW?W{#@nm2hhld0~dtjs-J6U`5=_m~)QKwF)v`^Cj$O9H_!)XE<9iyFlY1{LYNf zmeulRfXVG-5-Br)%-R%xjin$)A|%_R{dyOMI%S8jt>CMPF&xawA|0 z4C7!$z|Ul>f}(5q4Isvuo;cTuwakGRt~M@Vm$s1&O>L)al{t{KA#>?ANxSjhFD zS!hx~o+l^cPm{2b<24ca5WqJr&q+?9bFbpEZq5v~#&tlaNx$tcuq#6D)p9wlW`5hq zPDWo6+nXgMCghzRxpK5?AzkRrRG&Iij3zZ?B-G)(^60dF+sQfF)^lIJUk8;AfXd>u zQ^tPnSKYMg(NuLOBwJf3e_}xSMPpk_mA{w>n91=RTy|m=z~YupI=LZkjOTRD=Zu^~ zuPe7-1IFn!=VH;Y=VFoo<|XqhRr=QtJrJwE$aEGi_+1KqwX}~|Maqv9Ep--CGK<+e zHLiHY3xC!e1#4@kel4!{umn_D$+Lq^!%ziMyoLlFI*73b5wO>!fTXfsi zu8r7kX78vZU1Qv9yo}nbT&4lw?~;- zSXVjeN9q9(szMujg|tBE@l8+VWmbAMBEMn=$=#7-1wwYc04>d;3nL~&vw~I71dwYz zyF$7Ni#tZI9A8uux4wVOyi+=$mD~Y*$ScQOh}jQQ_vI`9_9X8G4$QieD(Uo5Q)AJ% z#qiTJw?0;7A89k;fJHRjaFVi2cB1q&yC#OcL@3JkNXHf*$nkgUnr*hX`O_y14uH$4a zUGGd-;^9{b!J*tcxRb)z!CbU^fCfW-atwsZJr9PjWrV4eMs}E`93tsWAI}IiRm&;k zylIay&oq)hwy};cu#L_TP5hZyCr>y@Fz`LD^vut5ZyO41X}qQo5v)Ax^xR29M3QB& zRGWa@$y=N=XpEabaxdL<%crgxRv)0A%N0cWU^uV*GKy#1@JauJA!+M$HvHR9>0V&H zoRd6lX-nNU%?@_qld|Ir+Lg{OQf#eMYT|`r=+JsFVA;xhCDdcP!MkJTuXGZ;HGAp^ z@r&0>XW|gtn5d*0uQ@dVfySPpM3Flcdt$xDha=seAc78G?I^xUc4N%a+fvboPy^@T zWSrCfjnCtAU<_A?j|Zc13s39yx580^Eg@mE3_FGn(_QXqxYGz(UVM+}kKwe!2j9xW zi8l7O5>!y7$V|J^V1TbP{sdDCez5pvs;GwXVY7JGlaBG&WJ+}Ib>}n``3+o^4 zT_aU1&931jGf<~xr{yyA7Z)QyaNq9dbn9)$_Fzv9ps3!8(eVTU?~{3&@P4bEMm)?PV$o4j)2pt zCwBs~{v!Zjj~X3N7w+MgN2r-bfC(qQ@0PX+XCg#rL_uYyf~ZKq-S{|QFe4)n@5Eeg zNB3MXgA1@;WxvY7rmG+@D9W0F4%T=dOqdAssySA5;qjZy>2qAcV_u2`rhNL%O@2aY z+lo_XE2c-qD5%`8W08pb<~O4QqpJOiIr~Y^I*n9o$DT$@PHxb3^$Y=i%eVQ*YA$OB zEwdKg$GVY{)QhQz#Y5tJ&W>w3ZyVWBFEWl00k%LX_;z9qW&LldvhuV%Rm|%XO<0y{ zkWOp3-aifng5J#Etsn2GblY+vhofPu>T#r!4_|6;(bxxV)jriYnEnUr!(UcYPEXsr zkiwnQw4%o3yWBz)>Z-Q5c-o7J`ETy8!l_+sVFGQXt!sMWMSY|6-lUf2EfndKC1xpX z>&KHaWLMAeI=2$x-MzR>b^2KK%OEm_Mpk-)YSV`p>rPG5ASPex;+f3Xdp+AS80z2y zW#iFg>a{`$ZwWldYbP^Xe3`s+N=kJ?X*X+dHZ&J;(-vhoe8JsiOs#|^n}KKpM@(3= z0XJYTLtj9QS1)izLZwMs2o4|an8enM)aN6BIxbtUfQuz*V~8Z<3mD6NotN+jHwp%B zX7I2wpuGR5d?-Ax&JP?GY+hkMfa#z#dlaWH*Ip)^;1KR`vVvs*TtsN(yy1=(+(_(= z{EE}3N)HM%tUsrKTkXOvN8qtAqTcD0lYK{OrNAk+oOwFG@?ECcMXnYkjC?Y2qOMtS z#g&Vqlps6JgG&Y<`0QWshUbaIq*Al|b0Ci2UT^wpe;mc&iTboS)w@~t$Unsy9&BXk z=W&m(p8cIrQR^RUuodnw{5mokK}yIdUb^l`W0p_}gwa9wui8_PY_EG1Ixz4(VsLDvYXl((mh z?m$VoQf-L<1nah5D(of@+c7nD3$L8wyr=}=kLQ|cIV;A1aY6%7 zP)#E70=(t4zC#xp!c?-3u{5a65Ov+Jj1dv>tT7%x3S^M$9i9BdN}M$!$ERA_%G`Y` zA&Rk3g%gOiLFmqOz868;j+SOSy6!DmTbb}hjZh-p9=pKgyg~qWS9#us7|}}poitB8 zcJ+a)b>3vLh!5IU^LxH8{p;>X5;DyV*nc(IlB+S*2zTb}8H{cwfLZS909u8 z*#q+Fr6nlppp@g6&L+McTdgaCZYVs!HudfIWQz1r<~4$E98#laejnH3@|Q%r5PIHux1+(?uKf#jS-^wLP1?j|2Jxy&nX=IBqpnW25%ilhyr_)LGj^Ccho=#0XJ z$N2e5Y|$K*^{!AOx#f;)qMJn>R2KWJ`i^oBK&1tP32{$*7s-(g5S85bhE{Y~h5Is~ zaOLXooe+7G?!~dvZSD)ad?NlI1Zh-Q>cHN#8Hw*&(y-O$s;|Y@fI-VSh zbyvy?4<#E*?~f_N7}oqyUC&TZ+C%8)?!&bS!qzAb)4Y=raTH9brDc(8hYDu+xzRkL z43;6|opr4%v$U0SpAa1AA{B~eiby%YEc zu;WwRRZB|Mve#crv#bn^G*^w zY$O2a8H^D2hI2|{Jthe!X~e!YL&hO8pX!S8Laf+)-pOSd${6pfA;nlrgRLPn4tf@3 z`PKUV{RUSuV=af8j!QS(Xncl@0Q9(F(>*U9LpK@q!XM=b<%ujOtIgY(buf0tiRJzv zteeKYu@~h1qrms$>rGTHnt~AS0jdRc5w;?n`#N<4vH!SPx=z&iWu%vRsHTE_YFbPPAufi=UsSl#F^n% ze*~Gmtw(aT2$~`J5NmQ6`G#b$OyrGZMkUKr7C~tVo#?a&iI*{PqzA$G($dxu49gWP z>T-vQIQ|h?m;+{(h3GWN#!~87Vd=tG0d;cFfvlZetJ zM2fsovxfzbmuwU?$6}3OfCB`-%dmabQyOR&PHkD54w)TyS!l{RrT2@^V`cML)a64-aOGMgo$Vdq|-3%MSJ<@OoD zH$ln>`A>Q93C)FsEkG6`Srb0+lFTz#uXjtjBsZ}V`b4J)r`+-RF=F_HPG8q1ZUadK`EbL_&8+SH7)X>eSg&J&LD;RdJhQdajR4IL|7LBnIfE^J%9CEQO29jKn6dTiu& zkSPoKVG94>IU2Uu-^l-2l1a{>q%M4VYdT?^os+dv`OW;YF(0(BBgJc$?qA1_oknOm zRt!7-_R-FTPDz$W-j%trMsbDiJp{qvn$~ZDl$Cm$dC5{hfbqEQF~;%cQ!r0)oqW|c zv!4&80lUF^ICX-iOle>WAb|!PZvsN#hEPLK6LHTXqCTNE_+W zG1U_5xIHXzr>9e@7VZn{CY431XI4XNOX_X1L(;^FP0NQ?51vo$gPBDxv zNtR$Vz+tYai&x~fr$teavvSFMXffr~ z&@C0cm6|wfTdBQ~V7DGSZXQsw5ww@a1W3B%IqrS8BWEUxxU>*cM3~2RbNZ;XDRa$3 z*WdagA*RbU=gMjkh6J5^r%g&|P})Rs%C#a*)TPZ%-+K_wZHw+;^M?5yp7l*0r49_J zs87N`TN#Xg^mP#G2Iu#NFI zmj7ZSiVSZ>vapkB`P)E}B2*eZ1iT~0VE{D74VKe$wYj~1}zO1z=ttgLOyn9SVZo_-^SU{}8N2c|PA}u~-G|iO3IE5U`k%mC7 zj2CnIStd26b3AfYsa|9`QLrg>!PMHvFpOL5jUG8DE5l4j4D|EiUae3(b>N58bm+B! zj(VuD$(fz5MC&_-_jm&4IA=%D6B2tTOMb;z3Bd#s;=2Os4ZDe{sB>DE}jJ5P;v@V#P0X}?VTP0!LEevQEmvIul;h2Q~ z?`j)9x`qkTls%zFCIX5XX(XhU`b31gG5V+7n{f?D_BUZpm{e`0*JER=6>}+a7)n8t zJ;><4_KCp7ZRNrvG+1su1+}aDdyk3-D`?+M!^0e!#lh=klPcVK_QYl}SBC|;k1F@m zBNFx^VI8?*Uw|(lgcFtuE7ww-)BewxdD3C#OD;lUspEJ#p*I6|ffu37jb$fJ(3+d% z6iY-ofT2%1+Ub084~p?r&_rAj<2De1W8AT9Nxtua$6q0KrbRisWPxn>k54ialF zSr&`~LtKGEpnJ~N*>8(xT~4p>#o#}({HnPjWFg7(O9ZPkcq4eoe@tKdWnHZS(`v7c zQW9a1oT$2i{kDo&kofVF;+wMmi4wZO)x`lz^X;M@Po~}R@{vDy`l>dcg`x5LGrj>z zVO0mb$km$x;akb1c3EBJv)6WVtEHYl5WEESNzp6hpf#=cc69-wJ_cG@+E4$dM2-X{ z)P(Ub2MN&&%bn}DkT1cfHa-bx0?ix6{URrSH$6v?EaMjV`vnk6L*~y+w$RD)9RjM2xn;t-L)|2O=$Gkw~8>vko4GpTx z$ES4sD~;o#Ce%*@mzTk{uTp@LW}G^P(C6;+Smx9Fb%P;;nk3kvlW>yjl|=TGiMaBH zqv(3mVTG2$Ajbp1_yrj!JB&|e%!iGxEjzPv8H`TME!v-CVV&Z^7sjp?boxE5*Q8$f zB$v&z+eY0p^M@W9e(5wmn!{pthroQMiy&g(+!s+HY5HqGL6%Hf+$IEh}H$p_EvX#by zmn=~%wUkde+w^4mn4-zpNDb2aJ5vp79EPlk584dxOGgQ-jeb=iEr@{U&cPBYC$f zz@FfMeqX48sc+uPl?N~v)(GdFajiS~5n-y#9%C_Wt-;h$YYzTbx(r(Bagwd{fK_%q zIc+0q@<&m6P)5vIU1>v6yf~s*#EZ@1)OEy2lb9c`-TA3Acfgl6X3VJYc||{kUp6ac zxQO;M-`DLFN7r_;U9C@$Ec|I{>A<^6D;)F;R{~=M2s@pRkO!!LjUhE*lkmqe!cp{`W!1sTdbO1+@=xx_qQj-&HR!U08-HzqJ3K@6lLZDnzqn`Z%Khj%*i@+K&I^*<+E?O-jml3oXAp>@rlW9@N# zw{@4c49RAB9XI&OaullIwQQ*TpEM{pwoc5}lz4pc+soKnVeREH4ht^CClYqmAB8Po zK{h;O$PU%T;?*rtj9+TqpzBtVkJBQ7S0};k8W9Y6^LuFvNM@(HkuqfBCUlzDMHJ{Z z;XjKt0Uy=R0@Z@QC@8J>xnK(n!QaV@e8&?zgIZ?}&J2H$1`Dzxu7I+s3#K`jrd=O~ z5#ex=x8cxD@>n_cTX>u-8YDz;K26tarHz4=ka04xDUzF&AL-&iiT#=aO93G^8KNra ziapIX94&IxAyiO2Mz#5&c!9XcyleR=K%Y9u-j^?E{qRFR`bwG-HLsa7 z=+ME3TTNgE58VCujc0?EhhG?19^*t{Ke)iSlq;-#ajrF5*{WjFjN1$+#5 zEMKSLsM=g657l@acmz{fPb6^>KS^tR@;uFJHUIl4b&wZn+QZo|fD#4}ikl!x7h5#j z@@3B{w{Q-y=0#pk9qe$yhYqpErGg&^s_$uviT-A`3yVVkX*J9kQd@J zr=UlQdg`D~tnQ*5W^^lGln(@kPk6 zV9USG5Ylx-mS>S;a1IlF6)!Uf{mH}1WRFYtwCkJATfQObOk=W1v$+(x{F<9TqE+qW zING1XRP`azuKYkcE{%7uCP9r>^J17`R7W2F1X^xTaUbbGQ-iT8R|+XoM5dit@jjx^ zj&?=n(EGg9mfl%s%=|YHr!I<%w}Xsi4nM6v>w6vY9xv4Jfd1AbhpfYcV9HBr*IJ}~ zFTe$Xmw`PO<^e7Ho|$P9OYP~YiK(z*++brNLqnE0fkY+tEL%WqC`TITu2x$ayx)md zhbP>m-&8|RuK2Y4WV2B?TJDh7iNfQcCnzKUiEFArjiTTS8cWX4ZwxYx^&mdKO}znbUP>5LyJMDWio!bjPewTf~D{2WEWTE~{Y zs%_ktwEbI7 zLXG)rMVAJ~uV?VAoz6~CHjD|_$Xoa`c!;-IJt(xrOVJ*5s8pT{0`!!M6puPwX-ni? z{x#zL_tz%ZI3)Fy0<3W;CVq#}f2ji=Vc9aBWpJMm%@M!_VB#2VcGvoZWj*`qkRMCq znhQ$WoEGB*4mS}q>k2H4*T2F>vV(8lZ(Nb=h?wF>Y}4tAcSR8Z9I?<7hSxmzdHEv6 zF93gJ{sMSuRgX=3y?+~VekX|F7*k}L6mo6xPpTSanj(wuTMThQ^yHo{8+Cy!tq;FJ zqhuV!r6;Z2Q)RF3Kr45{zz?KA0QrRp-etFdjrhNPIe0{zoNiz3*`S>pR{|#z>~RIW zfPkxfeHX50=lkCnIOv%Y))1$RbL^P&-o;Ehe{yFdfe|1>?Vcl4&OO75J%oHKKn7yJ!CKNP@Aa3 z5b%fHFRO45wieL-viscroFf>giZHpSO>T@KFTQ12QX()y;5R!XNL+hL*CwIvEgNQB zpu9Rv;MPp9YhDp5-s@GfM$Of4Q~Ty-tf&e?>ki4SC*y=(?X&P4tx%Go38{0nTPLizC9|D5+xg^>qD+sM>tsieddSF1?$8ST@Mw<%Mn?1^Duc~y znWBWPuml?V3S*T9fLnsuw2z^=e9mi#uW^{xs0bmCly&0i2?K(wMxP*UL-DOV zhK|X^=|*zsjuS)|UIc9uAV6M!&p(ib@#kn{vS=$+1zF*C#el3Dq zoT$bdh4(x_m!Uw@V01JVMmoQypz?_88Z^csxQk4qYL(*jDJGS06dFpal|l=QxP2=- z8{(WwY=x_d`%Meusl?#}MZ6ou3bUQ_j3(w6p;J(o(EUtkiH-dl{k`xc{s0s>AhC;H zod}5Geh9XfSn|UHrsJxUlT`XnGDyG>s(%&@_itq0+dbg%VH=xwqNy?WYOE##Q0P3* z&V@`FdK_-QAJNE+lgas^mO`!A`rUsc^AgQR8sJfj#57`jMJD*UC=;$E#F@sE6I+0W zJM60d;Th(!rq%ngwNEd~MaTwi*|tBQ#t-hN5JQv@C|7Ldpflo~f83ZNY?I-F+(`a- zr?@(q8;>S``qXBuLV37bCQ7cvpr5TY>!!kk=Hu9z`&c^2H@-cs7lezoFVctMjKe}{Ot`!vG$3cPlxYW)K0VLy}A(w8CY^Js)e{hH_t8i1KFW$aZ+37 ztVBP_Oa{uDjHi2VO4P%IFO%*Fp`6u`>ETyvIhj@lCo4?c#(~@2v1f0H&Gxp{-%A25 zRGpb7_`xU$M&=HQRLd>8^Q;Cwe|u2_(1Lm8BnHd;!qTGjlYVtD+PJT8{_%unc=3-} zLUf0)uyAc`I40pF+3;}2@#qj!wu6W(jb;17BpdX9rs8-~#wdTI%iYbvsZo0k_UyVdUuzsXJbOKqCn;G=+%uKni4F+;k4woq~NzY%0-TSbk|Ia$Scj3o5l z1*t|Uajg?alCA{fWrdKQML^p@5#i35pS!tYtb=@+^G#=5ZdyEJZlc_9-AFsB3HIPP z=Y9jzJ1T9Mqoeee6%BtsMvThz*qZlUm^cS5hG0B{*iS^u6fT8X!wx8>`T&eZ^7H80wj`V=1FoY#5#5Cxmbvs>q08D2bKUaWR z?CWlYPsE86Swn%=hgUtTXie?vFV=*iql8TS%cNp$Y|L+M zjbK{0)sO{%1eL5KE|&Rd-bN$q(;UJsp6loX20LoafBk*!z8l@Lh#593-PL4Mj29bn19m(XzwYaG@1b)q}{6Z3w?E^t2|R zY~pVIbIaOMo&~nlGx}-cS<4Sw zQ`M+(QPqYuexhXyp1fhV7MK_TR+9?-RiJ34{^UCY%QIqiHAFi@43AwOtd=lN)Fm2E zbt>{+T@@6yVRwpk`P9K-6uwi^7i6`fzuq;hy!yt|<&Eqx=2PGOJl8g4^LK=F5uCzk zY-SfSn?c$j0SG@zF)I^_=P1{*3sa|8HyU4TKYZi++f_8fnHoDwjz^4fx*nHVPP*1~ zSdA57Zb?&s7k8@sG@GT#1w(hirm@tev*|Ujhc(!>ZReUs=Glx+tW?qUNIR(!(z)>9 zSw<4~je${~6s0m=Yh{_k zhy{*q{^&GsFW&LRiUd!cv~4vegaV=uNi|eylf>vYo}q)|blj&;B0G z+K~tYR@>ZvETr98NYUE#%{Y|?oPO(}C22S@_lWlcj5E9eT;cw4B5HSwl$P;l!_-6m!vUd+d)4VHqheL$gVT3jEyLq>GLha@s*I z8B-1nGICX%ooB%Dh9Gm-PPa!%YBOd%@s;zn`5nkd zm(GRC*U^8Q4^d`dKLG<*QD3P=wCT?~QblHIIz+RqtJF7Y&j&2a@H`IlE~f|39NS->hI@aLGzgzH2XU~MqcMpWZAmyH#sPpaIl72oY|~%~tJdMp zM}x|vI-^nNc#K@{e4Il-(C6R#7p|NoIc@owJ~J&|BbGJNZ=L!-{JEWC<60|=Ng@Mk zV3ty@_NSXjK@UQ}67}vgauwA}s4RYZIEiI%Y(plWT)?}R`a z)JVBlV1Fw@qYS%Tn;c_2?cLd2+DMC)DlC&!z0ZknhzZ_gD{Y5KRP9`OpOAobQ-r-7r3rHN1AtmHfEk=9 z*&lH*hn6G2e`)b!-3TgzX-oJ=fmP$kGp%7-6~?-rJ$T^tBBvCmAq|9WFivP8zP>In zKmb-VQSqlrBCfc2QJmfOMU3P$3^@rns%k~Xe+~7{m3XzxO=`71Qne5+QYYsguLg5E zjDQ4tpw?2DcmyFDnTb*@$W|x#{5#cfCF#oq2nFbSDNbQFE;ijxiEuAu);Xt9jBxmL z4Fn)7Imv~dfXJnc(_k)UAYR$V*Jh3|q=&F+IB9Bs>YX{2rg1DrAUmbuY8K38+Gn&w znRH#}#4)_l219{pl3ezb)GtNW02#D5z)_kan0kn#fpw~~8+;e3f|=P7G|A^a4I8;a zjsXTKppbO4c`9F%kAyFMN>vEgS7>L?_@Oy)QkXdF;Cu#c$Hr2xCyC|+Yyu^W>edVR zYf2za)reN{9)rSgM6}}{ZuC*E%c-g8-I-!9(Aru=vL}hW_l$BoqX14s6m}wV61Dln zOk%u)1Ku#&*p-rI^jW}x!!?NvE}J=?@J=P$WjPlH0{nWyBTr;4Tg($u%}B%>dUh?y z&jfl|lY+$Yj=*XP91)?fU1LP+>3SyVWUY~!SaWn?>SLpYf$%aenbFkiAKi|Px(^$e zQBN9;hK`u-DHT5|Ac;Z&crzTYP**=m(@CgwDt>JWZqNg=5qCxe)6;^wq3Z@3mnE zYu8L_@z_&RjM%z4-A?Ky#F8<{ z{{b{tNpNckF-_R;#*!yq7cx<|h@e->4Iu=jjtAKLGI3h}hosmn3hjJsTPbuuXcR7K+ktb+6im)x1A zeL#Y$NqEAjI0$Z$S~$VKoNf}Yc?WbEelv^RU620=oGe*3nrG&BosJEk9(`P78Lousbwwp z`=N4BYNF=~2x@af_W!2R6ks?uW_G=f z4pr2kcTu}zIx#{4O-vA!2nttqI6+enhMIFTWuxXO07USC>-=vT)V^+GUoOd3dnwSZ zCQ>_G6XZ6fGy)9GydxI12=WD8WJIgfl`Nb76`?A+tc#L-bLq@yPp*0PDgm;MTkl*; zPKu#%=bfYwdO%xtl{u!c`3*QqtQ5#Kl)Nf@;2`zee1RMHe;plA5PR{7Q-nRhQC0j> zLCoATT%a&0(f%AAgzu;2LC;0^^tHEvl)PLfhx!fGpNBeTjRMC$C!!`v}>rMJ1pI z^G+)1%SYZ84;m&46VR=Pfb}=)rbp7TBbuSG@hGjzM&{R0*by3Q#b~wM8YD%1rqe#_ zxVNHmu`oX>2zI!$v5?0d+YbTu3TUb)Uj0sP+5QCY3>it!7p*Xq!)h?X`F0&{axkUS zpVykcGJ8SxP*+M>g>oeVWcmx@NGZfdBos@IED0h2lFkXYFcsy7B%iIyokzzq+`jy?#^3Dy>G8FeyeAUX~lVWCk<2lyAugpx!` zFF@EQ^Ui#ZMYe(kN-L0S&aTx3#2>>>bonC%~RvqJQXV_}j%vIR8_^PP)(8Zs!RaH*pqHoF}fcMQ?+E?|)Y^CR zH$dfLBnN6>^6#Z6Ah~cTBU3X^gbjWNqF&YaDMg5apm+`_DwOjL(c%YCt$}>186%MR z5qzC+FHwF@@JgcMnYRCPf=f7uBv5|HT!kPd6knp{I`x$*uhJ8|+8;4#AZb#*M2@Kv z8OJpd`Ur42gj)O@JPF-qFm3E#wEGWtegYSC?Eyf7_AqRACUU6E@DTA`=M^{Arox6}Jg=+dY(Oi@^U-K!H}z$1*g zF~~-Cz1={B+hn}kVqiglzG-Ywz$D|K5IE*#tKc;pwT%X(^T4fM^t!~sIGQSLu%i26 ze0X0b7X^_x_2#B4ZqKV?UI*&{PNf)km=;Y`O+-<6`pwRBESSjjY&8{}Kwri!Q`F~{ zVDXZpmV~Lmqt+s}Q{DC-2y_byz!7ijHiiiHNp)|I*zTi3AzG%7^TQIUqnm|2zX4B? zc(y+IOcM`dwx;8wb=~{k?7%lYiQZ5-83>e2TENrvI0cp(nd04w7p`=(y4j?=Wkn7} zGxUf}4<#cOg}0g^m7SSU<5*H#7Qrzam448YQGqLDt&AwCT3)Z4fIS(G7=Y0Q9C0BwxmDiTsJ9BQJztTByw zxq(p@jYi2NQ*oukE=0RU{AbcdNfR4xGZ@k537*p5yj{ZtvDx`2l2XN7m#ZELxSWBz z5cq6+b5_`nBg8jK8pq&q5+kGv5TJvpZ-9WaYM6r|sOo5q4JTcGgt2g_agpg(=BzAM zvg`#w^y|Y_4DrR{6xM(-No`o=cHu#;+9mLH>4%QZJ`P%v6p776%0!UsTu!;Y+8r*F z`Hkx28P+BFUcSGki@WfWnP1`nj2Mk^RRK9S^n~&&)&)>K1cdwpE4qcLz?6F#g6$%` zmEp%bF>kt8*Tf|;jFl5jJeqwyhP0k`k(wT10kLE8Zf& z>V4@rK)aPnJ6V%3U|)|t8u79LG`KIIQP>#%$<{B)GUa}`9#QVK2lp~1< z!7c*+Eal)AE@w~5R~?wEUx5^Ul21rD0Rh$_&JFbnd{3%um%w< zAQvSXhEOhPsM^AUMT$d@vWAIgC>p-_tR^;Ix*D1yS05KP2g=!}N) zMN$bd05DJT-xGUZ4p%elaetFyz>(^vg%bwUoW4!~`FSOXY)y2=PZfdE8nD34=tk4y z>C0AW@(Tr|C>og(nAnQ554H!S_*a3}0Rn%q#7s*j8@5IoQZnkdaiFqb3L8=`!Z{aL zrWon>p@s*zZ=}zW!@2v2GYhp79>*$6CjkUthKL~{Lwqo6lP3w$ScXOQ0 zjZ!50CcTN3qAH@+2zc3~s6it*MVZog;7fdSGR9@>11=3Sd@&K;)<-Z}y>sPZFjQ}00ibSuam!bwr zeJ~SoNCl15a4*3!BibnpbY|b^gaAM*4Na$F9!UzL>em9;z%?)FkULgzOI0`;6d{i- z;Makj!cLFh&{&_cCUSjFnI1KA;s_)V0y08MWvh{&&T3mp2?837$qm2D7XRYZgAahJF6Hnp{013xjBC;zrIUwAiI|VHqSx06WXYOM|W|L3je&2-wMZNZ}w9ElyF-lVgU0@}$_n6KpKx4ta&> zBSUzvf-;54>Xd6Ppav^GLJ0M9+G~cM>RQQ3K*O}OFUH$D3W4EfGovIQw_2v2rI%8%;u22PJvdPE(1^r?0z~)dyzo}nN*1y@^*XL?NHUz0V9gU4w9&L@#`&+bX3E8I z23*|?^XBfy$Wqikj^;wvx^q~bW?3(-9(1c8Zo9GCDhm$~69zC56zU<%R#@B;kwafK343n$(FCZEtX!m&y}sDA~dJrp~9L69t}X;*S9$;5mY51I_SE!5&2s z19h?;mV%TP0M^j}lL`s_$4(tnLiG0#c18(AohidPckV`YJ*z^Z@fy=<`T&o;hX3{v z^u|&ur!sBCs7Z|Xt3`3zlW`0u)^5@SAjUkri95-X{G2+b%e z%;;KTp|S-j=>sj_F2zPoEVrGpGP?pcCZd+yk~#6U`$%Ymv0_puKg?E=0O5c`yHrT$ zmEsbMXQ0*`Xd!oQlek3-4IC*@9-E5k6DxF42@a~U#3_)*w=P2-YNW_11ZP4yHi9vN zh>Od~jFT{QJqVs4qAbEemR5OHb^yT3S9P$-l8zWCXZ;lV?X!g~EOirc&`Sn$wb7DJ zhnU)k609s1qXBu={sF|CFmr{|La~;9_Cd+J9J1=$-^X87l}QfHVGx7qch{JDOB`0t zJQ0+ZII3c~Fz1*qDuqNnQ0g0#w)}xH(c}fe;^@`i>p$vwUts(Zkc$9$y;y92cmL+12(K8Y*UJ%2}qsR%GX->w}OB5ew+GKyD=pF@amf7^k`#62lKfN7kT& zK)7BqZ9fYYYAwTIPWJvm+mYXQfxTR^p^y*b(Sr!8%q7KR#8-_&UkphFvOpNC0tNzF zeG5RWhCDOXRV#Z3u$%^f=rJXF@`E)&@WQ1@3|=8&b^qnxg3GNz6lyM#WDR`5sskc* z<~)Th^CV=$Cfw}+#nmo=r@z291@I}Mh;NIJUMPj(A{2ByWy*=Vr)8+Ylp}eBr(tx; zie3`47!%${GnnlvpsD27fT9wLhDi|;-9UI0EOe0r!*+F^)A7n_|Tm1QRA_a6Grq%_5|XNGKwUCi=Hy+dPA9Rg#bqLGWq=R*S81h3Vo0u@u7wSoy$DrAa*K2$DeDCtcIKGF~#hAkYd zNb)WKTPxd zRUk`xBBaikBt~&;#H9=yku{=2X%UnQlgQo0OGyOXiV6{Y#YB8VGK@p|VcQ2pj%FAU z4JDNBIXX52FGgQ_OTMO>!e!V)=2Bvv;eG!s?R+MNA$IsKND68E#QQax1d4x_j3fGn zm?EG+D;4Txv18keYa#9uxE?*_RYn21%NS$8prRZpw}7*v1_jx9P~LJib(xFf$-Wkm zgrxq-vA$Sg678*O3yQC?6vWPOHgyb~$|XaxrI^3CTxbqv!(E!r+N1W!SId}_Avr%! zUW3@@t6(*#DM+r6vUU*0b*c&`nr^KFIp8}k^AUC|%zzaYZPWA@yIHW7J96qYbFeD} zoE8e2{nzY5pI8Z(g}%;1@}0~9eWK6BCuT0tR$tbPkJ!{}&+ z^O-U3wzVZ5*D_k=@foSWjDLyoIPxFHh#3Up+&IH%eBbz|?A;6kmf`H0jDpV2E&x;L z868cgSm*+jKv=dC0;tB|CCNi$?5q_&f^ww*ATK3h!qPO`m5q;!f?;(kRM^zY;FFyiM-tjZX z+QC;(5ml^WSB|DFUD8~sGyo7SQUZdm$C=EAS1Qpnf#PxE{ALM38(TB*wN+q1HAK#u zSUhyPM~eQ!fN}+ryp8Aak|mzGkvEp`(`xop#fmem3SGKB;e zMiOipyaLB3eF`9BhYAQlpMnqgWfbAtG$^dCg_~oY9x%FKtMq{uZEE2H8KQ~10(&xV z3x;u)k}!NS2&pAiH}=VrDE=OcE9;pJNUErWx3>Z2V&?#ed9G~0K)q#BY>(J_=}iFr zrPe!Gp28v=yZCa%XC>Oj1AflI#GJv(?(-MgD*L|_Y32Q>x0kh^2 zA8e2YQwVfvoD~n@jAp@JSl&J-)Y&X%M zwT=>GH{*%&qToJIBYI^X5S*VAK;2mcJl#ur=@MveD6mhVd9_?>f?zlBNezw^9$JhO;YlnOb(Dm zX5^G7$klrq`4_P5XbV82GE0<%VAQtC5Sr(BtJpXQfwI+Vf2r6US)>btL1YIJ6^nyH z1+t{d97QEHuXAAot6(hKMrouVP)@YE7XTZI118ShEYT{PX70Rbc3_Xl6wCh37`1P0 zH2!AErcG)y<@hGsa+TIFV;xSuPRBo3!hvSw!D#QQ2`c#T!GdBSsmQ2gcS#3ak3#yv z|6FB&bU7~mWt!Iw*O-*kk!i3IDpic{90wpm7k083WVUtMz)-Mcle-xO5?L}KLa_ai zrAA{Z$gTs7{M25!irh@3E?tSIV;H%a$fYF`)8GcdkFUc`ZCJTa}0AL;9 z4oOiUsOk=>dS*xa%#61L{6{eAmQu9%tFtNbuMUKdR`nV{d>54761GE2XS-OqW|1LM z0n2D_`i9fFx*FE@WpWSYdT9)X*6u;KI1ZI(yhK7l1wuinDeH<545sRdp}-ViLJZUk z%(m&q2xrYfFtn6?XHnrGnD59R8|4py{!Qo#DS#-7(A=xGkBE^PKLnM5b}2zALRX<& z4}LPqy5Nq3r3m=Ez(0bNo-gj8SEradnXPH$AaG!o!`KgsgkiA@L9dK56cHSSph8W> zVFz^t6%ga#-;^03sK%njM$$JDTHp6Ld+0}MttR|4qR>FkZXj&v+d_HvRd{=5vqoTL zru0T8Jf!mggIK7j9Bh$2c&ZXCYJ!FYRAsr}g(@elBs$VIf{aPyMk7ECFwI7m>S)bo zy;u}+pCo-n<*;En%&ycZK!+T{gclF1CeNX`sY&erNg4B?3Dff1hVs^vkRZY#l0*@W zCb3o*u*b?3pgtq1X-UBjIHduNWaV8fVsI6WQs;!?Hx4X~q;3j9ER<@Z18(IuAut3% z9SK=%9R)iFN-!uoHsn!+(`kA+ zGKX3$b88Gqq;wH{G413ZX_vlXAcz!=R*q1wVVI1L@@M`tA_(e(Te~(=7X{Y7 zW5`^}&jA4SX05hP8nE`JIizKe`Jv7k}J@dY%h`?*JA|G6~N>$8&=3N#C5}j z8j3K3yfHT#qySVvb=;lA+D%(-KWbnLPUj6A5xUKG*)DKBrCFsYMW~oAiF7nB0qp0F z6Dk#LdKx5pzyKAYOF7*|AeI%`@w#aF*@uCy0tzHym+fs%YD|2BHG}Q5XxaMIake4M z6A5BiPDE^@Rbw0UsIi+;nG!0+i&4-ZVWKjKkyZdO>7!%|-Ib&(w?#1xspiY6>BSO@aou4-%kH9sf5 zgBRKdYpLrwl_d_H6SkJC6t%APIZp8nWf{l^Q0qnm>~Kp#U6=4JGM{?0e^jpFb|zv- z)y(qxW+QtG_%fn-fSPE@p&V-fJ0Ui)K>Hg>VJ6{oCBSo`=EB>ZlVb5@qg8DsP@N-tt?m1NrYb=exdr8T#a#`%J zP;|l1EE*_SWmEeI7M6-3*g>)eZR;Vj&p73}cr88Gf;Sry?T9A!8pD(({UUa!T|>sA zNMOgb27&G#M0$5JR;%`pO*^)>u;38h2O{1I+pCv1C7k z2{Pi=XjG;)BVDQfInb!8_kjl|Q3*Lfs-PV3Z}DY1yGoeXh?;^kA-@zSdmurhlh4&q z41=b8pmjdoRhUv5(z^7;X`&pHAuSh_>IL&S2Mvt`6J^U+_YJl%)S3=^U0C*)X7A(>$rnl9HdSUP9S&Oq*N%uhYCloumKn1>@%t1 zWuuCY&)OOeUHt2j8py_C`Mw64bV>V+?+PwhWnx0*`qxYR+gGxPwXLnPc{)P&<~Qq= zOfyQ4`(UGb3wrV~9rQT^S?0F!#e_SvIbYypqmPKrUwzgedJ%(R7!h{ptVC*-W*|q% zp+e|^%SxSqj=|Ap4tL5-3IeX5^Il4pgrCxts0tXsbd-+FYV00L%%ww#Gl-XKxP+wfa_=MZNEbY5B$0b_!( zAPm+dkS7zZOCFI^{n$n=fZXuS9A$g<$HXotaD{j3B4B?UYWL#?sRu@LG`%16YeSg1 zLdrEB0zfusIYKdIepHyu3qsS+1(`t3=#q*qE}e!(5w(e;9}+;XhW~M~h(rya%Dg_Y z4VjusXWRG(m>Ot|V`y2>jZ!AGIIhVJ;HPiwl+pe0XT>&V2sTiFq$~}+iEJ{mnzo6l z2<2{3B?Q|h;4ui<$HZoLu<|&Q8W9>m9D2Q;?c-gLc!O$_xCkh`d{PsAWHfoPG(uz^ z+SK||A#e^KQhK`w5kRLZbqa{V64G3s%?i_qCZ{#0Y$wonh)nlr`H@7SIIlZe9G4+U zXnKN#?N+S;&C^+3@3Rh%he-mx#bj{dxIAzjwiuWLpBthAUesad4I%*cV6qy_#=eY* zD}8tDFK5efh?BNSMq*|lULAp*wY$sigsJqktH zXksBtx!@mtmg3`4#o-%)UZ%Q}Hbjst#A(PHH*Ulk1St@7cu8j!FUt9KB(cnG5{qnP zP%>>{Os8#^6FLTs5>lsj!i7oQBvK>#t zLaSk=TVke*#?OeD4&nVi)48j*R@4Zo84p4c%@`g80(=(zrii5Q&OiuHgz$~oo^jeC zFR37myu4zV?}42aFCd+_#D>bidQQe(h!+@4*2y8xd^i+%*}k06MTs32G3hs&48QPh z5#6R#GJxnFg5o+6tG~2KR|F1e5+YpW{ah`9UV4$D)g0P3xM7uZiE}mO0CWHcC6N+M zs*u*4=IfxRh~t~0T9^Ks*!dwfW;+r?OuRPWPcUKbH4~~Eggc9#f2c0Flr9|{6A&M3Itak6 zr*JgluF#7sXxB(aAL0N%LAN#e!Q~C5WVF#&pcZaE7>2eywy+lk6GL$G!y%qHv>lLa zL@}_~!%JDVs&GfH7K+*~1jE1z5`m&M zES{4aB61P+t-n&$&l{l6TW}d=h!p;A${`Jj#7H)FMv|ux%iJ(H!g;TY7>B?Xm^2G9 znP>%T80#C$n%Rac;{C*amhdDVF<@Qe+jjXAU|$sL8hgu}Hn_-E9BCqwv^vw+CoXY% zV?+VCN(TWHeZ!GEu`sM?HBZLu153oh!G0V$Wpy>ao)|Xw^;K%`8AJ0C=lCs1wz7#> zlB%78zlS)LI71^#XaEw-2*i;p2GvI81}&K@J%eFlu0qlXqH46%9tg{m=W5=jX^a#) zGJh49!l_`m4hhz=R0XE4U#Uu>6BorvPbAyNoDvpp? zz|A`WzRNJ>YbF{}JQ8gyv<=2vB9#)vW>_*RZMWqkKwEo3A%MBPW_r$k{Gjl=4p!ly&SkGOGluL9-B1<6N0|f{7TERQezNl z1as9z4Xy1`9xN*v_TIm7tZe86))P(3i5a6U1mN(juv;V)@s0})?&d(Du3v3Av{O}Z z$`AB^;86n@n|?5uc}P&UJRg`SaYwtA@%7dM0VSl0*G|PjQi$h3vhA13pVO|?Vfmxt z)PJj1lCXj9tyo5_o~~?IX&^8qi?dYGUJ-zrOd51U&4~sv0H<*$by{f)r%uosRp^*8 zIw)?j(h>n=V9U0fMVAi?J~CKzN_w$@iUOq!{UZ$ZXciE_n-J7qg15yr*lk3z*!lC+^MS%JaVi;;JnP#aqa7{+SN8v;h?$9>~UH z)oh1c(njVjmiaQUkQ>h!n7}l+n+`V0)ZopVSMDAv$wNF*S0l|j=MO4x!6px9?hClO z^5hGJyLy-k^b1AAn&8oyJUj#GLI$=RhMMO2bQefJ8gj!x_t}({6db3K1e1|DX_fGI zg_(m%y35XBHS)~Kr&r2Ek+YyIh)u%YRYHBF@DQthNZN+Woksv&oY+Dt9$r`(Xy^&V z!Q0#ZQCvNk-frJ#mc#ia!)K*kskhVKM%Ny3~)V>6B6#v`I9 zWK|{13!m&b{tb0vsOhE(*b^9X-orkX|8W4(z&DF&@ODuQOw3s(^n@CS5mG(PrLlH5 zzM4qY4ao& zjriF}NRqInS75^?njSV8Xdejbl{nv6Lx<+cgAIet!eZ)y+zhg`#!~_J0rmM1;N~e| z1d6D$z9T4VY|j+wcI)I{g$RpHRgc11$5#_0Smk7|qE#cV6FmvN!OLbVU^olS#rIL@ z`nT1;4Arp|v|`BX6I=k(yz$F!LUg+PwIp}McT&T&imV2BnlBg7O+;4*Ty>V0M4mWg z5mx?o;$Hb0^D!iCh0)Ns6nM&9su1-(!PGhGy7Sk4K-}I#J0-3qG3`V}xi<_aOJvfe z2iRtMZ^8hmPjLnZ=~g7t*lnpK6iAiCro3ZMUP}RmMw4;UOs}T}Foj?-g%e71n z|9hc?&=*2*ClvAE@Y{ZwC^ym` zWlp6zbX#SDKjGt%cBk4HjHQPVL2V0!ydue|xK=_6)ItaLqT_0}w!qt}m8m`{feMZ8 z!j3G5&&yC6y>Vd&`lzRyR(HZzu)3#2v8k*+NZ`m0pM37{1%sQR;NiO`ACpsvetJL( ztrU(R*^TIr=vN4e3Wb=1&E;6_6lyoL!M7EG0gzHY^6D>IP5`;i4+im2+SHM8uqE^g^y|`1ojQUs@>~UDzw<_<}ocL=EzS0 zPrF$$-Ni> zFry6VRi28lU6NqKeZYi2x&QY;4#v}YRgQ;EEFUjlCW=?nY_3tp0wc&vf|}2mClY~M z0F!1=fCQY9VladqvWpb{zz!Nek(Q#YusQ=iZ9}-?$WZ~|628HmYpmj2w68fw5XVML zl|-}x7)qt&wSJikAa9SUd&L?;R5QwaKU>+Kzv$T_h(p$#3?{-!00b2)eo$*%5;T$w zC^ZDJxTAC06q49 zy%PMk%GhtvhtsWM1YZP!wL&B6si=npsQ#=ZjFZn8&nXM0BhLCYURsEvdNL z#YPVthQjRKsVMi^ryz}(`wixb6-&BJ)155E!^V|RCGIMC!2f4Jzbf#|J#E4!0ZK<5 zmt5-Yrk)5tQsWhiSXHwHLt;YMx&<05i*wsHsq!TRX-!}tfWRWFdDm^ZKK9)ymnDOR z9HK_GvNFe{d^ZA;ebU0$87Ti9aUey_6iJdmukhG0CNhb)M1VdC9jh#nq|RV>C7-HH z$PcH&M&Q`wUKmGjraQ`O71XrH45lB(Fa}P*yN>huMp;v{q(A%-+deYnv(*XpmmFcT zM}kO-7aC3i92Ie`A|i5)q1uyg_=t&G08LLOfxR0zK&QLR0Zn+0R$TLSJi_-(d+1Rg zz+$UpD8Vq->OiWCs&-JgBC(0nhueG`r=*bJ9e4&v-(x!#RQ8`BhB?uoTRC0}mus&@ zgau$d!4mZ{?VgxgvP}7m9vU>3DmIHZ9r5(y!SM@zsd~dVAT}(K2vV>nP@=YxV3`RS zO@$0J9MQ(YFC{M!@1Rvw74T{*hPwGN(+n?Yjuw#=tAo0NwcVkfJ6L)j()JO=o5Ed8 za$iOCxYv~o2?&&=Uz^h4zeD|#mQhHXD45F_0hz6{$bHXi8_5<@*GW93F6()cSK!lB zB8W{y=E8!tWYUxn$>mo-I<6;pJ&M?};%>E~OFRG++Wz|KR)jqgT(9L?D-xtcZ!k=| z3Y4kbC=p$ZvUzznEDY;%6cQc+;qixxibiBJGBkK4j!*#NVX_*RJ%51|`Q_OQml+Kx zl1>$-m5s5wo&e>7rM9)mpMlXGC$+LU#Q^CooNBL4ZY2(X=sR)O(G`-zc1QOi-<&J5hxQdajve z2t@}QOp&5iCEcB;W2Me(*F^)IpI`|d=Q?m}6?UyrL+Y#!lf8&V88?t2Yzf=rp%y(A ze-)F`=>racUdc6B3)=W1eIzm9FrET+b*X7W+L5BDhy-EX3`jNhmKPb!%Cp?KFw^?c zWEB7~1&E|FSinmlXA-oW3_)YwolxNdEc!WmUz6YAp_DLS2B<- zDC&@(n1|~?d9q4Oyul2^$WlE4$BQILN5ML-uxhg(3#(g-rbryyd!TwVc@(ECADLAU zRlH|FPf6w%e(?wBORI|v0;u8q9;o#^715kx`GZ0nkdVbq#hwF@(?e#>$AbjQ%wIq$ zToWnnO7buhaxqn(0I-y|0_%)`+?^etm3Ekum9?X9dCsSFGD^Zi=DMTmFu1qkPV9TX za6f*OYJ@Em^6@f|t`03>d1Fb|C!c1admW9P@%~YlM*4B%hBPQ@jHjds%@u28P+7s` zjA4-tE-idALP6y=8IO%Ax_u`^Cl{MF0mG>K^|k!vRY2-||Jp?K0s&8_PVO0$#UI zpc|UMIS?htJ9Oi;MNUfqmAOL-!Z&%u0kx*ylZ#ojo&}K0jKDRht3z`2yf{kO!nPn2 zX&*{9>^78;2#q!xaai^>FnE-PicLxgMajkv!|b*km>3^gJ9`8)hmFD}sFKFbg|F1G z92p~eZ0kD{JDF%=PtC$Ni_JgS@`78|R(Z;tu{360;&p$vLSxMql70m8?Zi?t$K zAf{9X+ zj{2Gcbc+5{@fE3HYBR-ZQJTB**b%-phpH}FS53faQfP^y8Fj&&UM1^Es$ZdD4+lh)d>Nxd&jwOD!?Ur)YQM;vgMXa0y4o6OHHlCoXFeld0M_pXwjhXj_X`dE z=%FTroYlGU17n2>oIuDSPF)AJ1B={E<4z@PSlDY_3Ea11$qV#F!?Bx$%U0$`5v2}? z1Rspvc}j$WZ4OG#aOqfRnm~tZeN`^dHR#mxq=y(g&DrGu)K!HQZee1CL*_UKiVv@V zk~{>in?cJI3wqb(=d2TmViW@4pK486!jEPut_p}+!XtcL9Cw^))U0MPxsj% z35T6Dh#K%HjJ|OV+i)YHoQ?OiCo0(CL<Ke=F#|(_lj&SjpH`16JfXSwk!& z8Z?&lC_)qj-O?3I8bSc$L>nnFUrej^etm{u;WI~n&WmYDs^t0td@1*8k1(ezkyn#5 zBryQHfOi&(k7HPpbfmD}f|_NX4EE8mM9d{?H?SNKsc^1IM6mNvrvXTFcVMzvyka;& zLO)K{qdK9;>S>77mZ2V{>=4G!4$J+8KB{agY5ci9&% zL@tWWH!9J1gxlwvB_A5kk=ADcmU}@q%t{NXa&Dk6Q~vm z;mKb88H6PKUu<|O&pP4efk?kFb7L1s&;>=~aI@k&Z`3_*!T%|(-zRFPD3T@z3|dHv zhW z2ewzGjF)VD9wd>PRt)FIi^O&>4d7k;Op&5y&d6HJ}YHp!)1Q-SLV6KFL!2)GzVGJq*O);J!rDLIaRkaLR`L@Wl zi{$XC_yl(_cfct@aXciRiML&P5d?ku6$t>OfKw3V2*a)!pf`#y(D2!fO4MG$P3P|} z`4hAs?@7@VK%NYsNLRxYw-eaHCUT938zq_u7tzN8_Bm}6mZBK? zcIO!PlA={bnwOA+FELsLYYF=;ENR>Yz`;|riLrELBcDuBhwXjTr`EQ*nIJ_Xfa0x{ zQp+@qwfDNmE(`Txy4cjnl>rFB27!x7hKXp~lt6l6aZw|f52uJ1z1db1sFnFLV>!K z@2oVW4g+DMls4%OD;aOqWJP6^1|)CkGekaSJr|k9SZCm~2+~G#p&N$C@wQIjKYp$`R4Fse$kq97(<;9}y4Jaj2yTmPwKosgp<@&u)n71Sdw2 z8PW)YR^I;xDI2BFO-pCPvr#~hMLk>jw?FWR!pIIo5--BFzFN?zr4_`u^9CgADjaV8 z#v`ONp4-v2)Bxh<&LH?>5mIA*B{50>tkMltN(G?;P?FmW6LFF$q$-BML_`9adSjs~ z1^0-g8EV3)q{Sx&{-mo+Tc%q*2a(5-gse5DtuM$5Qa99$#nuRl((9sE{Dmo1(sn3y zOYdzE#ZMUhUPm@p$}vOSzcbJ0*^<E?^0cvYb2rzu$y?_jp*Us98*!(tIzMbPy+|KLmfY9!s&!G~JYatHoNc&cYl+r7_IM=NgHTAK( zr-X!Brc-LuMoE1Qh&s(-B1hoOKyB(tUL#C`HwrcoQ4ebHER*@cSXX(&^W;J+hiqwp z8=E<+f}5GcZn3L+SrsDAb{golRM?jZ!SLyIJMtI{NQm}by6qv{BX1m^ymfIPQ@gsU z*~}PCQW7?cnW$%*ID>Su(P??6W<9d$1-)F*YOq={P?+AZ)L$DYI=3Y`Ph*pSn_I)M znLTcf(n>LAt8lJpa*LsTJ|*rl)q2gvYW5?w zg+sG&D7pVSrH_jPB##?uq3y*a`vJhPH5axP(6bo7*rX~nQRxgFaSD*OG9N4=S$WS1 zyzIq5aJE-NG{8K=zHdSt=`yomOM!@>J$$I#lbE}?^Ie^@5-A$qFX%Lm0E^i6wK{=f zf)P-9ug|&+$bp2vJ`>z0C&Grp*T%6jIuo3-40O_36(7fB8ydKev(<+ z`s9PbrCFCZc03Xz9= z)00T1<1TQ#)RIQv>KoE88#H-cW3%c2cR+~0La0>72wzOet0?xSZP;S76P#cu%*tX5 zkwRpn=-pa<~mo$4z4q_w40fuX|fM2Ns+X7i{L1T|SMEoMQ zmPWa<=VDqoYYNi_tSOopB9D5^mIZ;aO!hhZ>QX}Yw4nZo{bhNe+fh<}#1OH<3{bIK z9rZlcY9yPbtsuO`9n{PWoR!!sDc~&(rZ$hSG!bzXeAQD5Y{pT1c1{T!GC(L_)lag=e=1-8PO(d|q&8ik7Cuh(~+W?{NjixZLTp46nTtbcO1$cRC zrfBC}&r*vX@-$&K-*a`Vjk^5^GR+bkYqyg3 z%Q%`kt&Q~^LUG!d)p-5;N!$_P%(u5naoX=7w0&}vBP4p^u)m??^5#3_xcg9{{~kVa ze;oHHyy3comCgl&6wtFY75rtMqejw@x?wlYJ6}*vS3&GN<7!!h7+a6fyo{fs>&HiS>n!JF=bt*r z+Ib!d+oQ1AZ**PRm)Any-=$(f!3MY{8AY>>*V3%FX*kE}D104LlLDC2{5IAX;J)&Qr|?I8PZp+v(c-6mitOTp{^cm2%{eMui?ZYUYx%C7R0`br{sJS zo;XL9CC06WzQf0ZlBKg?`PvlmQ->27#o@_hdG@>bO01r7O|Tu@i~sxy7yk*BF!!P$ z7~g!1kMk4pMC1+}ZriI)HsKJR9bdwG+VbH|jwVby9R>}`55%HHS+sHI0C8A~Y2D$@ zeyCn_8jUqf(ddW~JKZ`*SN?n!Xl+U>B^P{0x$}o6>MW15KNrgVDfGB0jr;OHA_l#>I=Z znVbFC`i&$lTr0=ANjqS^<88`a<0$wKF&92G-=@GB{?xEJlMTjA!53L8A^uU7sG)4g z{RR&f0&^{K$}&&1KjX$%<{5y?$V_2@VOWiol)JP4l(WLk$9-{ReVH(-UnFNdm&g30 zGE`}xit9AL!GqHSg}s4IWU_c18NM1NZ2jbhMm-PN_n!es_lc&4J!?SnUos7j4d+{P z&Z8lkrF*WD0dR)tZWp-wXnQ$9tjt#oneqedEk&JbG< zwPL8k9Uh)}oBRV^c<75o(9jY`^}(LPunX7V{j9MNxZu5@rSV00@-mmIuH6vBEd2SR z{3yO}c$H)-rFmKY8T_dlijO6>!qRb9#1Mb0a-^~9$!;c#!$AK^piq*|Laf=M>=SbS(1hTBZ1S+Oc4KYkd` zlqeEBWAoupX&h>vZie0KbP;6r_|St6@!v0d(c*r$AhcW+dcAU}E`J;^JXicqcK%&7 z>u+ZnGze!N#EVMOrlK^F(~C@)Cwu-4`cnYrud9_eFcp{ZPNd0te~KL){}p zhk0sTWpqy5|H7TM<-(>9D`@58G344MO(44mzP6N6;el|>-1|$^cw1Wg zJV_E3JG~~gEm^$d*l(_V`UXl@c);teYhl9S7MPXn2t)m|@nWGZrLOEv`znvZsR5~c zska1f^9?2WywkjR)G(anUCG;hhM=7Tvylbj=1qaH zdixKkTK^SW90e$PtB1c^-c#t5W3}sdTi4yS-6wV|PQ{4^GGIH`9kSg5#ob4fgztJP zARlpDDEF6f8FxXUPRI8FJMVYrruwIFe}@hB3e0ozwOA$O?7Akr(;tQVbALi?#4WB! zMi9(Hsq93qP`ccQOlAZL1~I4MNb4Ssp1GeEp56gF++%3M^JL*v6@ z4!F~(0&yy3uy^`ca{E2~zuEfX-2)n6w)V(>d0stE6isO={jvF;7yAdrAl=)*C)JhkrR_{M z`|%K_PkSR&T8$8%g}nyLe-XG-UIqgOjYY%O*L3r%38#0jqKbD4yr9PrLWWrJfO~e_ zbvgpOUYroJA0z&D8_LE>{kgk$9B5dMV|CqPC`%j3gN7`o)f)!zCyxvv-g^k`?&Aof z^W8AMA`r4`mxI#fJ)HHWgqMLaY}(Tshqz1P#`Y_;{^n1}atgyO6bAhkCSdof`D|NL zLXA_rnEy$j-RPnC_Wp2QmVO>|e~+Xyhp*98qX;be8C#q6-4&BzC_7m?h(#9~sc^m; z%Nccxzn87%6;-~1R{l_Ux=<01eoPh?k61w=!CzrVzs2OvK6(PbJiHZmoS4Dl(zoJ*&Dz*pql}qn zhS%2X_UF(b3;GbD3nA5J=s)|T^Xsee5R~y4qT_uaxMTt+p0N-$Ung_zj?vKQFU0|} zGx1c40mdJTgjo+0AijJbN*q??h#GZ%lABMXIu&vGhG=1%pv6j|okITRQ8*_cnQdOF z!|dNy*yNW1uM~T+ZNz1&o;?9ei{ioZnhEVaI*h-aMx0Zaz=bZ#@OQv@p``60xIXj5 zx5iy05jGKnwFhB+kq_?39qLkT*_VB0jbqgp`+5B!eW>$N7aBi%^3mud+)lDC9Y40w z(1CfBQ#qGBQlHV6)*<}k({&zuY8hp8o#d&{O{fI!!lm)e&}_U@^jf)$)%PF91BM60 z7X#u%W1F+kGq^X;u;`?ETMb^~8YoCx_eI+q8^B6w2+oa{$0Ifptg6=t3x4lGed)i| zMf>`5ft?B0omIztvjF&#vYO_YSinRqhkd$v7%-!$w#+G)GM()izAvYJ*V~2d8;i(K z;TwE8-&*U{s|%)IlcG7!IygV1m=3v~q$i`2$iQ2Qmkcd)_PBEfCj8ofkwto>t1Hmk zXHvX;V{a7R9U}WQRlcuo;BxQm5eil5#}P;N@;5Govf*0)b^bma)IOC~Im+__M>W*! zNu{RA{v7nylt0e16`I2DLw|Wq>~Cxh`^S#QqO58tZraMHqidk$Tp)Z}p^p=`sL?9> z9J+JQ40HeE@v`Qz_n`~3Y6RO0QM4p}6z=(1 z2`A;;NM2_YD~1lHbxVIzjMZtn8-Ex)^7f<23~7u>m;|lX^El2UsJ41S1Z_&)MK5&o zNMru(OSuz1+^zpkIl3)7|W{LH;HrsaSzye&&?E7{E5&c-lBdIkO69*jJ$myrHn z1Jhe8P$O`X(BS^wIpgyn)($%+lw7z0x)VBS^`UD**YPq+)m9T_BZ5UG|47WvKTJ|q zFKDHKEKl881j1ES46i*xrjHeQ@8~~_eLivay?bC^vkl8_N5c9r9nm<|7$-kUMa$u) z)Nk$+>YukB#}qz<%s+}aLEeNFt1gPWx0TjDzLi6UI@vJlVJugw48S)f)}r)WN6Z@} z!>f*e5X!=sX0vEB#%}tCj8iE464XohNyw{wAnC= z^@{bu4xh}d6);h1| z6OYWW_|iSHU3*N-eDNN#yl0B#;z~624H1-1EyPEP8MHA)maCo$G{#pJQ>P~i`YO^K z_je{qY&w8nhTRnp`T5|hj#e@e@>hKAKJAReifh)i z!e=hr-s{2(Zx6!nC)A+n-gA0yDM>Fo1IRdkBrnpsE%b}CX5~@);K(6AVOOLV=IA@3 z$>dI&89WZmRVBed_8QL(Yb48kjx@Y#Ix3vJPelfP6r`<;bu5L_^>^V&PY7D7=VOk% zFJ-U3NGWw|nU;-!a({UaUO%0jwb}wGF4wL;lh3gu@(s zdpy3{GPQPn6@ts7gQDTlJK*|i7na1z@QN4HDd}xC`S17*0dEXA&@Gy*#>LV7E*e!q`u}SarlKxT`;n##a2G9@jDarr{jz`6|iQ*OS@u z&ObQhAP*;vM`1wMdFn{M2Nt_}3j-gB!oW}~Dt0pE)$t~9c&v%g*dvGiY@`0mmtOdD zV9V+qrqk}J!_ds3 zo^D_hMcqmu$x&AYh&Tai`jXr_Zx(uMZ-?c}#=_0p5)7MPi8ZrKu=lXJkhRuYyt=s` zP3Rf~xBiU>ovr=ZaMMHRJuifX@awQp;h_-H+YXHrjYO?Q=gG{f2j0Gnpwvlfyvgnj zw$2)S>F@OO5K%dTO`=usM*d4-(^@0`a%C5(Rc+vH!a#g@_azt>wZr|?HA1?jF*jW< zg@|9~{MySL3}c^&eo!LZPHmy(0p$=HD(`fm!UBJ}9jCb|5j6ShG6s?AUH z!CMFJiLRZIRMS*LS8fKAfkib8Fj3{LOD~gIks5p5)!~BPF)+*hv2&?%2PA!RhxH@0 z@p;-!kS%x*(S!D*-r4E+$@nr^dk67w|8`NMXuGh-HAb8#jN~%2k>GH7HJC}4W8AYy z8j*ilv>js2!P_^3+P@e&v~vOLP$XA*yo5>Fx#((}4f}3irf&hG=+U=+_|r;F_!lsX zb&M6b@byzD{OiHv_Bx@pPqBEgd@v@T8VAX`<~;4_S@@(U;A~Sz=62x1*jg$ge@x3$ zM$@6De0%Q}xZ&dsQFrbOTEFah)m#%Sd=U#J#l3N`@jv0iKQ~e1&?@NN`j@06R#Klf zXY@(9AS9_C7X1VFQ>1?qE&X#CMwc`Y#=WWCF;$YjjhxJipAvAY+cVJ$x0eYk^*VMJ9_gnG!c23%dO42oWHrGz-Y($wbKugQW?|^U zc$%5z&rRRkz*PP?jQf^^&lkNUm0yGSrpt8R**urj>yLtm`Fnc4Z49ol31wfsOq>>Q zhW_r|DY)G1A| z)p3&8a6^W=>zb)4*^M+G27$`1ufpV{AuRpxyr6UC6X5(XFz~YFKhuCy#{bs`eP&?e zSQhlAl~C$eM<@yPMwe&RJZj=j>^cKj9Gr%4dyMIA!drS8AyA`a6tmMsYE!9Yqet3;VH-ldIe!659D)e(+jQ4EEP`T<%HeE8CcA8YwzU%uRp9Xlc zO<*LXd$oZ=+;NUMa0FjnoQH722J_P=2xlWVar8VXyl4~4$19}ZbJkt|GpKLhiGEtpm35ppM}edW2sx~Ki}+?N|~S2o$KW`k;>)&vRTXo zy=kjz`}XnW&80K(X?7QBEItY)g%!2;{+J;TD1-w`4Y{K#jnu201>rZaUYEj>WGhMq+Yk3h!L3$hJKz;N1}uOuK4NClW{U{ufK& z_pax7(5QedJ)hN#`jg7`$DFWT)`p7rTG7*458y{g8hjOvxZ`&c9z8b_&*&PhTDb?Up-&leIFBE^h{dwIWV8ze^jEmz}}3<8>rq*N63-Tgk<@nd~L|)@mNDL!Vt%(00ZM z_x4)KxB5F#RnjrIWU`Mp-{^D-X)@$Dt^;8GlI;wEH^Ave0VI6*2wle?3bO)-(2>Q~ zm>lwqLK5WbPV_eCfZoS>L2fiI&K`)LDx7gwhc#BrilLRSC4@R=XIsw%r0%VdL2x&l2iDt zwIi)4^@WA6=Hiry4mcgjLTKeexIgih7%A+gwyo*TGe3*Czb66*ILY9-mkYRl{%4w< z(N1PfihN?(2)<_?i#>TKpe$ex9eai)$@}-W_$a?pH1*iTZvvv(R&@*k@q42&g+@UuD$24Y&>1g-jH2?0? z2i&gi;K0qhA#L(sxY7|O_PVhe+fXzmeE`u=f&M9zLItN|TRzVN$fI_LhcwAhL0lhkex_v{@(d|9m zZw-fP&nfKS&`4hM{t~~oAj2EsAU>PNX2$6(UuOjO?*4-kn+=$IGlM21JA?ZYf4E_8 zfyd+}c-;Lr5U*&*oBPQ?+<9ZjToWgjn4JM_g}YQ~X^+>>45$mxcnQg~55nU4gYm=F z80f7&kauRLWBK;XW?CC z1a4dyiE7WE3Xyg`R5E=f7qrOpgJo`9el3$aKl<{Z^(}&$V;WC8EQfDXql9}h$-?Dp zsZfw(UYofn3fq*U*@R+Yx|t%>Y^sOI3%x+?Mr`fh3vQ@8?H2_Vs#C!GDBd$-8~aAC zq-8CU&{ydd_}tWB&7MGP8)*#cxm{2;TOakWpQK*r5WYwkoF-|F(aU7u*gh(_^(xi&9%mP7d+cWFi2x7tN=XSn`x zs3`9n4AQGt;K*=asCu!SD#E|R!za5?)zOLm7(3zpj4|eTHH`f2g6>~>C?~`c^BN|h*SA(N`*0wa51+>7s&nw6^$s3Kc8=!h%KYrG*uNzBGSMK=6W1BFZF zvoT3Y3x_Y6O4|9a$>(1kKF$jjHhbTLr`?`>B+Y`CA^B3?V& z2*y92Buc;c<8e2>L!YzuxLx@%2ur2-%7ZJEnoYsr_S7K3a~i4fMOFV~*+6~pCas75*$jvXFY z)1S6dy7W_6;Xn{q6^ncPCeiCh>rwe;0y&$>;2QIR96Q&R{j1i|J)x5LQX#7C45eNn zld-S&X5O07CV(XNVFW=yt`R;RNU3&7%zOsd(hz4MDnbDgJiX;fl)L^k(8D zj$0!qEDWv`Q?^Hl@fWYc*%^i8Wm6$&eZLFhn>{#wL=t7!4rKNIH|hSpG&rIlErv_a zm&>?uqBIQtW5WG&zt$6O~Fdr25t@rGun?}eQa(>T@Y1balCrd)m| zY$szZUXumWVxPfU7i$byHXY}_D2IKcr=$8e2jN!U5oj1~!8fht_)g<18fSEbBBI`- z*4wkZqh=a-F3{((=?CH9&?gk(wwWtO1mh|@Utw;Z1e+fG3`Qj}*xS$wj$C^y)KyDz zz>_#(@qT-5E>_}gGfjEWpaANnv;(tr^PoXJj*gm0v&CHt(9rn~Cx&Ly%~CHY_eXJd2}qKtQ$hN|Kq~3MUO?(O*(k&?gv=g ze+fM(ucdX#$`rh&3%qZBz?c@j|9nS+-Hbx`y3#8uIk-~%+#bYJKRtuV898`t|35Oe zp9R~@7xPYs7U665Fz&V+LRRyWAlhOCSI_Gr-@IHb9=i!D8(OLAMK^6<+X)Ml2BBAf zU6#mL4fC!Jq8$~d@zwqeQu)#-7GIL#$VcQtH7iUqzl!a#T!c(BiM%witTr zJCx}eVPbI@DHUck~f7Ezxp4-Recgw0{@q;74)AHvMh zUrwIo&II6)4caW@Sq(NeMdFuRb3})*KcKYEfk&C#gQ>?Q>ozZ#Ab73*N&X2|xcvA- zI^w=rzJv`w`HQJ%(>Qs)I$tBO$C|59lt7q=gIH$i=$}+*g^>+^?Y=H8~Gm z+hxSYjIn6{TbYH1-L=Yr*+TzFM=tQrhVmJwvDeo#nDsXe7ZirF_qN__?vg^P`3~X< znaS)p*Na728P3vcha<)>=?9tNKDEnY$C*d)_>2t7*bZR@eUB66Vwett~wpbc0o71uDoC#fS@Z&Y}wfJMDH@c0y z2O*1piuq9nd??cmKj1(JS#3@~H!kBf-!14&@5`inN)rp-?-y@>Sqw3L?_j{l$1rAI zHg9!Zf^F~oL3g<)<~!UK8a|YZc~@&;^W-!KUrBm>G=;JkZdCfp8bmpS5A3|#5>&e1c7uSAe*c8@A6W52~?z~cHXdF$wCVFzs%5{Q``Vv9UC|4}; z+)HCGJa)bm&_m?3AN#hI(v|OhYeToT)69u2P@g1=FV0Tq9Lp&*?XDM>e6oX=5>ov6 zqAK1NeL?=ev?A|hdS>((95}ySVufF8B zV#ONNSTXu1xPVGoEyYB#@zo*c0wQ7FXQcTmg zXrQFKHI6Ij&&6tfV#|*({8BB)-`4rE!@_a6eM4VvI&>9oSj5p_3ny%wR{#Nv*3qqm zHn6cU;it}WVvpefVYJ+F$gQpu0+$bEg@*Hxe%BP%xcfM_3R!sY%oj@3do4DvbfSst zM&RIon_$Z6aQ>RroZ6)vIFY32_p3=x+FQctqh5;hn`R}!WaX{e zr|b9e?ee9hXw@Gkdt8C3lbmrVW(jwmFT(lr0?5_U9Cod=XQ|UqxZhF*c=^~00tX(! zt`H^eZkmW5+OlwO-$W|YyM^vIE1^>JC%i}r=Iss+!md+S=^03I(aJ|uSeO8-LeueT zjS=6ezC<=Vn<>igu~>2FpU^qbm1U%jv9;GE(aEHyM)Xst`*0x;k6eD~9J*#WPMsmi zGRaNO=k6cE`$@;}qh|(~KFfjv@4;-etPDq>$^kpgh2bXo;^@Lb7<&F5 z3X)&odS4qlCCKpkSM%xGgG%!FJcFI8vw2YS3+gkM;n*2_)ShKPc~<9y5KkFQ@wyF0 z!blo)#~1yS6WOu3NNgT_+}XG50XWSo6K>}0=G+axKx=>{ChWoDu*bS_YV7 zcthy2+(8#sn!xthPqfq~3cgjBa8}n|Y;`k$?%iYX)b<`)sgg{KEX)yHEqVAdZCJGM zGGw_G@fW?N_$R50Dvt~J?!yPtd8kIcw(4MpbU!Mr>tO$e3Mx$~z#@|%Jb34ZI44V< zCo6d1Ap3I2`uUwY${nz}%LWaO?t=>}PKkE!Iz^2+2kDHm0ZYXHxBG~D!rH*!&Y|rd zyuw|bFANP8n#}&d(_fE4F)K?5{Fw~xx`PFK*KvG((PZjr3}+fV7QZPN!>~VIxXyAP zoCwySgY)8r(9Rgq)lL!DyvycUXUSRd{4h4Wrh@+-dclF)itww@73pUZ*4ShSnQm9e zz`~mK>m>QY8BN?6QbMBiK$K=T7KXp`?c;dDB1>bu>-lQ%V@hKvS2w!1FGU!3GT zUtSAZSl?ya*nPBaV;D3`H}FgaOFE$9#k*@Wx$%b)YPv~laqX{Rlq=|Q&?0Y~A}xc` zhf28g#du-e-0NhtPaTz?o~7xhpTWNl1w8QN5H!~TJQ|oR&Ry(*VPjKp+Jy=@fBGJc z+@`?mwMDWkucl4YRQN-TG^r?+!AQ&f{C?D48vITje8UdFNtd;dAN-xpURjF)QOEJ+ zEkLF2JSU5#(`oG0LEMp+F8rMm!=*Oo#bMLKgxkgUIj8gjZ>?A6o9+I%tj7^A&4~j0 zXb1ZnPQ+P1;Ep$qDQleZsnV#*9W54~OVu>|$T~f*ZOOV%6tVIJc|Q3E z4qb|LTXHD2&kP|MQDlXb4(G!CLojf{H1rwLEzCISOgsMC;+C&_C@CkMjn5OqnHa8; z@k5UtE8)R{1t@7DLdM%bY}U$y50{4Vc#kO7E3w9kem<~R!5xRit)(A26Y+Yg6j(%# zAw%&F)ZSao!EYzA#djB$$jX6F2Dy;A`L^(Bs0Zq=dj@;3N3>7v#qsc+GF-A@_U5&4 z;LT=O73c|H7v2KxExO>)VT56YW@!3J_P_t{!xN&%uusrXQtBxf?_2F8%D9>Es6Wc! zYdwX8f!cV)!c;u|r|wdpC;F`66Dpi;NPxG29wdA9I0k;aCk&WBgf*UQUWfq-k0$E;#s(|B^&k~PQh6>*Mn_B6v?>8yJz1Bm{iNU{}Q_7Xaqw+Rn5Uhb`-VF!o{SV2YkXTJr*N^`!!6Z+T9-C$G@#Ta+)i<&^-M0=Z$!4r56th?dALV*{I4<@kbl#{Y-GDym+OdoxpEc9Mq0(TclE<}9GY*BLZqEQD znQ^2QJeWI+%0<_j`u|*^nIeW{V(#)Bba$B!o4h757!j>KDxh^tx%hfD^8Bm2Seq_z z)(mTQ{ags8GaVt$voA`=z85|#L?Ca>g9x{K6m+Q!CLG&E1yPT9>~a~tSQ#gT1@1vP z?FTUH*<#pstQTH*c9({%ox}sDEAV!<$F#qlV7-B8!U9FGekqS%9Y&zC(3i9S%*0J2 zlOfJn2ldwLvF4zcLS)-(D9$St4s9cG_P9SZ=VB_i-}PjdDb{f5>ry1sl}=FUIE$lx+X~Y&9*TBOD>+e3AI%if z;MP`m_EVMNZ72Kk`Plbtd9hcGr=l8`Z3`41MRZfVW){XiQiJsQ9|Q@z6A-;} zHwH&d!8>oeMTzy7Da6l(g?JTm?NVpk;y>by${xsn)0@Ne4r9ZYjvDRf2{5#4FQ;8< zr8WP&AjmG?>CEDTP-ZS&S6B6mrj)v~-TXw5P`V^cty>9ymmNeI&u&QGb)N?Q>g)2! z?N2T0defu4!8|m4IrTgL8C>gP`NF!BqGjq~*hh8{>i-&ZpT)t^&qU*IZsUy}a{TrD zF$nlJn{73c@OP>O$lh5)>&=(4UU4<3bpU1Gtta1FFZxqIi$ZI1XvXr({L5O2cVGGq zGry`~Q_pU)S?300ipC%)1>pVTPU+f~^V!6x|yR3x2U7tT%WrD|sGO?#j@2^9^^ zOYv=n8ehCxPiyydfy0Jju-e$0_q?)#JE2!Oq{s=??J|X3r4OK`V2+!hpPytIL`Too*{b28gk6-3>^HmFV~EN z$>;iD^cnL_IG$|Gj<>bNa})dF)~-C~4>1vVO1X++brcBBxzmnPSz+VE-{SqMMV#DP z3TA4RDEC1m6|K$x^=AjZGXFHymVF|8ugd?v=%L*AIaD|3;eQ#qo3$QlQc3uFSUKh$ z$lHZLMMxE`-}MSMuN+8`QAV|EC!81F%}B#xMtA7nj$NSgyPYmMm5Adc`f~ivDeSuF zCR*Ij=buHB(A{(dhfiIHcda!A`8Csdou?@{JrQ`zmxDay@CjbOOrO`ay@69&uK04n zLu#68g^H&#;eGue{MLFH2kqQVHQ$Y$7JnVfhF?NSN>j%fF@8p_g3)f+0B)cLfOtgOlS1DH3HotZ+z&xkcZgzg|}-)Vcn)&A;->y zLurE3s^nbuX!OM6U)O`H@(R4EvXzViE1gs7cEiV{g}h;G27c+cn6Jn@pzGa_NHkGG ztEUsO?Ry|sY5v!J2A-lfsZo4rP#})8eM!ao+i^?psZ^W44h{*Ygyq^=+-7BqgJTY} z*LWhOzu7f|b$8*`jqSDdf0OCKqTNuQ*aF(e_JUNf0vFr4vO1`01OL$$7Dd|*;6&HfPsvv0dQKap5~rj;hB zbG$G2nb#?f%+lpaLoJ7wvSKvgQCHyf#pRw*asGc2!X$H|?yh;y_wCw~i3+CG9a9q?n3Qq;D z#-Y|7C;d?OjO$-E_`UdX1)p_IjIyg`?kgX~;a8kkq+&`GXcgQ(m zg8Bi9#Ui+xr^;vh@1=;@m)NWHC%nT0{5F3&PWIjhW9?-jA$%`1E*!*LUA^(@Ung;B z^hsPB70>Y}`+yl_ zA3CyaD+oE}sJGb|O|EO8-`S_2@6#%l&NxJc=5BDp^)S!ucO5jNnw(#Rh|nGDDufoC zC2JFR+}N;-&9mCUKtq?;r+frywejNU=1`h7HWywDcpx75ZHK`zC+TC%3JiH53)B9L z#@|=doTGA+pwz2Te0B3B`Mp0&KQwNO<*p`ldhtHIw)l-`{3e$&Ja%zs*?nQCrXudH zZ>6FqJMo#zKiHV7$59hz)9kgX9GvtBN(#5Ljg%7Y(nVNb@e{vVC4t`yB|bOs68VH# z!-1m~D1Txl_w`Mp!#Qbm-sc3TJ}v}*9?oi|mhgCM9EGIa5VfwFqUD?I!q04FysaM1 zUDbt@Ipi6YM9Sljff2OV>>_Mh*dO0+`Uw|iG>eW?bzs6NOaAa9j=lY_Ir~cj?uwGZ z;m$2$xctvro9+7e!y^gx!qa)(yAl+?jbUfSN5UQ}kN@7Bz^9wcaLS4u?6IzpBOh%; zw(^8W#{)4o-k5WUAp2M+G~J4%AK`Xvt@)&aW3rI{MXCCEnnK$$6qjmo#c! zmT!AIQn!<`Nrr48PBH9eJ!5?px;ZL_Y ztn%>02kF&Zao&hzpZuX({j)IQ@EWm5b{>6AT7qul6=}uk7GZ9SItG&t&NDtLdfiAR zqh8sRH+UatWPPUqJ6keaYQy&0yYNTxFmfBP63m2AJmkhu3`=hXovr7{dqrFAkf@9N zNvZ(%Zn4MUU$S%~s)E`zr6|wuAhJpZ#pYc?Shilg6%a+ydlmUj^Ki;p6D) zUa;(^g0-U&FIy(Cf{ioA+;yZET1j-fsz0|YzoWQYOYukdF~K7!mBYSY0-K=a@O0xC zJhSAe=oEBaIGWWTwF)J;?U)vu+Rx(@gVE&qb1w>0T*Zqgid&f}&f zlI^8d*yAvkFKvE<@4h7pGq+gduMMktcna_fSuL`f*q7HNEa0qXfLljv^2wdeaN6`T z1%aT6Cw9O8egXY%>$0}gG75HcVoEq{L(LOZD$qS!9 zzeq}H;jpbj;A2nqc;=tywS5om7e1JWO`eO*=>=SJB} zCUKF_CZ?8YbAy5nZ=-&cxx$5#W0X<(=6Uce7=XK$PJwejcaZvlelEj52>c{kn@7Bg zVwF1wXmV~a?k_jx<$=05FW8B;J16jqtFiF1$DC5lXQE3^7um-*!LG@D@q_XSxb{Au zW|gmJ4dZHfGk6F-E{-L&@`>o-a*hu6(!?`9608E<@N2R(;#mHAaTvFK^Tpv_H@_Iwm{v0n3 zFWF1CG74Zp=v)rn>NNhUbSA2LwTOzV_mOkYJpOPX4!`I{3Nn8OvdQSBSp3ZnLlopu zJ8T0*94@7!I@c%)hOkkewtVD`jgaqtYaN&Y?(CzlJ7Bn$k||-~ZixcVFCl&+|NQ?l?4# zG=!=3@}e5{W{vVXD9@M01MTxjZ_GVdrhSk~&wuCF1GULz&`f$!cLV;sd_*T5*25N~ zXbkPyn^TsTlkcWuoH5Re>Svqcl#0Q)^v?&-zt@`;wokzA?S=5*MHO2w$xC6I`r&a<*-*_}cxHriPVy8&$bz?qj)}CRBsVu!vX!fp2IvX zBT6}-Lbr5`xX;rQ@b~^f8v7r>ynd58@A7$`J99c@tJH|q|MrS&*(rQU^Fh&a4tBRx z2oAb^@%mPY#IEMCutR+cow_-I?xbbY+xx-vy5_xb<04~%Tq;M*RpsaF(n-;4DjICk zg46fRx#WZg6!b3y70*$ydj2$)eFU7)*aEktC!@aAQSb@U=7&>v2{RN=!m-!iA*%8g zkFYNh-(4QY0crEG@x*)>6_^5gIXh7;)PNdY{`K66%W(euTfuk!K-#`CN-#HgNC`9l zb>s|V4$ZqJsMWbcs!J?x8)V1o3leFXPvzYg+oSr{gYd_Uq3ddL&8KtawK<$9LmR#}Tx@yQkyah;iH}CK()e`*YN~3c)Hx zhD^+T*d@b?tWOoPr9(aFgfzjjonv8Udnf%JYEKRaTrf0iDqOf_Andpq%;!6f^SsQ< zyKsrq`x^FqFFa9K<3Xo( z)1fX0h?h3tY{xRF`K`6+C{j8wNSrk)r=ZbQ<4Er(>dV(VmgG$lMz29>{Q>jvD7L z-v=k(hmpFJ3|0FDvE=gswD|49^UbW0{+hFUWDESxx+a!9I!FOsD`3!{LHMcKAG03z z7OqZM&c1yb>HW;%oP7U3nl(>~mGXw*Eu(QTZdf0o=}8P%4!;MIAIo9OnT1%taSYeB z1d4nA^oR6;?l>eeo_?K}O{p~+d^$T^G@tX6B3pCB+dteuLGlMm{d!`bxMq5&9n2GU z^b(UFY^%wMItfp*?$Ee=UG#jZhJzPM@ks5n+>#rEXKp5u_Q2k-SX|1xuJp%up-T`) zAEe_`O{wYEIUcRGj{Cfng4f-V*w6kbEIk|{)O+_A+J7oz`HJgU*|J~U+7*hMS8wE- zX3bD8RAc0(H3glAFJGe>rxBZCTM>9pzX zGBjH`gmM~|lj2QFUb@!|Ot;C_&>~?tpABh;TXT-VFe6ud#^%UFCQ!zH3o?9KLOaF9bjvNA0;|{2>J!D_ zU7i7<^$V)hbLz48Woal&TnmK@7ja9c550}hqVYRY>FvNu{`57Un?4%R3s+TCa@8lP z#n}+o-v{6J3&rMOQ}XzBkkZ|Lfa0d5@a9z~$>a0tcUA|W)N?sabX&&&3 zSI16IBs}KLJnA~Cg*LNR;+eMWYGdRQ=g82lIG%q}NYSjVe3Ne8Q#{pL;1Of4Cjw6gp|CQJX1#&-}gO_iwtBPL)xyw zORGEdL}3{p3=5`qSH!SUh{RbxN%i8jc*mfv`d^ibYUxbdLqGIS?KZH*Um`WKUa z?^)E~8xFVc7K)0ubXn9G#2=rD5 zr{jMS+GrOl((KFoQ0ibH&8(b<(dr_tS{(-8ddOn5OBlzU*$2|wV(Hv7wVLYAhkU&4 z2rMif!eWjEnm!y*9Y3cAj2C(0Zo?Vk)F;z9=EqrwXBnY*5Y~fT{cA{TT*&>VorC*} zm(vA*yPBs1gK+BfGq7oXG&+dVJori!#d`;G{=+d`Q8=Cc^pX>-HkN|kr%u{^$PuHp zW%#y<9X!y;qi&snVD&x(UOGRc@fNNW_hBA-d@kl2vm;5S;|=xkNWiqD*PybvKYKKs zg|zod9HzC1JE~OJ+*THJp7q2W<&hY8Y8bX(?t#fuj*FR{=OO9A8%X@BCCI*x2TS=7 zavm>0jGZ=5zciV{Vqze0v;}vzeZ|!)U3mT4*_f88$ZhRCaN5T$blg0jwN>rmR4*m& zr#2Jn`qy#2&Lzn|u+Xxy#W+6q8|+>-3?4o6!o6bx_+u|OG^jX>*Dn_fxo!o$IdGxY~#}ppG@6_Dg^{Xo%RSDRJX9*x)8YQ z_=Gxa#z?+-PG_0luDD>~9yZRM2*+o?64y0a;J}TJ`0B_AZg{l>c7DDg-an~GmkxYj zx5`E`4l}~hv1=fIuPbO*o)TYaN8tD~CBm3YxzUAFr2whjh!)wC3kftO-29Kc+85={_sT z{f;%h8^ss(9CXbZ z<*p2eQ3f%2nR$?c7pH^b;&2i}s<%MLkH^qI{~_6I2qmpvW;AG+KGwb3!{6thh4G1BY3MpH!P)aN zb(}mzuY=a&jk2rak)KLv{Jl$@YH@;_cBpVtMn2TOHNyIgVyLUI7AEM}A%B~LmtRJc ze((=!c)651=ROAQn+}k!@`ip6d?I=`mB6Q0esp(tEpC#ZC@GVQ5$l!q@~%gjV$kax z(6XILs_)g{cS1G99qda_-mJt2nLWhA<2S*lU$X3Je1le%O>pSiSWZUnp~Rnyg`lD; z49GOXw(nNd_n|L;Z|@R)Q?=4Y^)gk37wc;J+a*ydWozJ|BI-6ND6gtm;I2Gwg8B^A)(FsRyoFvJICs#6$79 zNnl^(!;LLl=-smj@ow;4Sh*=(ydT$#Mkn2ei#u}QRDBSFV-$|KQAWmMy5zmsgYRA* z1hY%Ld0JC84T{MJ(_ch(>ag5bPbmCsVFr zS%Pcr9lh!Jx2#h#S55|x`1rtD^Vytd9fe65>Abn!mhXtpc+A07SYn}xCS@mUN=AC4 z;*8DyqVfk;!oI znlTSONGLti0n-$iosmA9nN0p`+{G zkm#@zx|=Gg@lv#SrZ^WKHorsC&4$w_awT{A!Hw*@Dr&7Zhn-O1(G z;zd}~Es(UjHJemqa&7Q(%8dI0#|P{J-SyqDaIFRhYOllXX^mB<-b+EDRwq1&h{ecz zGT{I0Cyh}w;NWF4;;>u6Lh-qSq?(f;MjQEHYuaAYu}R~w3F=fjJCCYrMq#hOQGDK2 z18?~%V8b8cH3J9p%~xx&qGBT+JGGfwbNlmv6t^~pE+&)_LdyaVSVH|C6u7WRH2S{RS zPebFwMPS@7T8tZW62`}Tp%7by^k0RrO)U{E6t)QW3alu!^64l$bp9GIjS% zK)2xeusH27&+7P2K6C47q{epi95{tT3;Ni*!Cc{_*$j?9Q(t2ey^v3a-v`&Tag;D7 zkpe~+!TlGG(EN7|2FltX_V(rHQ>?M>XAO1V-GetPTQ#;7 z+8)WGd3!o2Ox#a3Tj#)LHGyY#K8D14rBsyzniWfr?A$IW^STZ;gL*q>@ zb>B@U|BxaotuVyNC)Yto(>y-)a41}O@{Nv9yiYTBCZkiU@jp-OhVA2vD64y$gdRpY zJax0;fb@%e`ROP4sVzhD$G^eObHAYV`$uu>JwL47X~BE%uYy1_?DNI~FI_EyzK<06_P~GrrC`UW?Cc<0 zQ=a>JMnL;NM*fQI$Gg3KsNbQ;f9x1e&wf=?=8k`zcybR9dR1G!g!Q_BDuKJTrJ<|bLN`5%9N=7!Ru*u&h%#hI53cB9V1cGxJt9~U;Y zz$Wj7Xcw`ZJguDIVLw~+i0&4bSzZ>Rii_yXBQxRLlBbj!b%~Cd>=S}TU8FJUY+cX_ zk!gmUv%U^)KHD!;M^p)_gBQR888!C0P{gZ72EpR1-)QWI5LCYNOVsm{;Els-=&V&i z-^Tk>;h(jj=l!^KK`Q#p{6vi#6v%8{44;qtL{G+Vro-^K+BoMe@+?($bqgh>9&4c0{Wkz* z(wy0ed`zZD{M!)#S0~5UG+*wAXHur{pHEd{-m4LOxZpZ;^){n*);WTn`wzHy;T)`= zCrz_wJ>cAH`yDJ+6o6&(1hj&?G(m3yl|(GWjpIx?HCmqsYwbg$Mh#s1Lb~Qniz}PS zHAyU=*~Y!4UY?AfBDYZ#QR{s|#g@f6kNNV_7xNUkpY#7jCJvEg(p zF>}@z7+$GPBLd86>Y7bB@Az7LDP@L1K?8XFvf~sRyPhmm7(zY{!UoIrbla>321@Ux zH0KxeR=E$R?K}kQvK26;DndM0*eO10s1Xx=*U<98YboOJdYpYimHz}MQ(^ICa_zNM zXnE-a0o@8*px6P=UPOsLK_l5*X`vXWEzfFeJaOuzYC)-?SiIh+UJ}$x8K0ZUqD|;J zY&@F*R-+f-7*{p+8x}x_O zM6Fx>ejjSF7=Qr&4ogA5!c7Ejr%s#jfv8Nk~70>q2+%h||63$<_dDUs*5YeN++Z$IA&F47wg{^40p+8@i9f+aB)UdzwAIX6gW6*q- zA>Y0{3ZI7bX^5q@^-LVU=bHoevgi;gudR@4_xx`N)uB6))he73zHR>K$^HTf<&` zZ7I_$8g{s8u-;-z%zLs|NRe5NhyN0IeH+bBTAM_qVK};BIX-^U5%5*S#Q79fP-NQ*=ukfZ-ui@J^N8B>80HVnY z`gRqA|H9?SjqgdV_*>2K%MHToq1ov8?F0F!*g@SzGj={73_)tQ#UNWhzGJ+MFS!uA zWm~aA>`hAdIEFp{N`qoiEbi}ZiXJ7^U~t@mM@rAeHeC&Tf5jL-A1@bw%ls5qe6EK+ zPy9K%*I|0`@;d*xb{;ZLM$?tlTToFS?=YrYi&O?5#0fct;@CMN6xIzBpY5^W;G3)X ze7Yf(-qiyY{c4c(8Vef5W+;~+!8S=C$@ehg(UTO=C+eWM<)3?~dt9JVEe-&?D&gAu zQ*=KvAFfE!d1m548qtAy!J zTmG?1kA2(+V6Zhp=DH6x#YuVm(<%$#Q$Ecoz6VzQR&wzaDPiXE zEjZ8W22S`=CM@h|5L5u zgT!0<-mqwJ1RU5g4s>GXz}XGzg8S%|f_|%-w>!2M6CsyI_!(S=9@}Yp3 zMO$CRiVdUf=x<0khh|yfGh=rL4}TwirWZo#zl+4fN+a;MavA759fC56Ec%^yhHagm zbZ_=Bbf}eM{h8-b{nR&-A0&g~p-47svSdj_DXolHL$&qJaK_w)uT^K_IJ3p1ynnK= zv^9rab}P}Eei95S-za`Mwt-ZQ(j*=!uXxOk?J!&V-~Fl_j$dL931gC~;Kz_0EO$SR z7PX2DzeGX>HI}JMfnC`eXxBcUlQiD|3>ZK=OB48FUQb71W*&}fJ_R1zbXhHO4_}@c zi7TJF^Y<-LkfSh|qayTprQ9TRDaw+VDr=zIVl|%IQxEAyEG)O!N{(H3U~Iz}j`!2Y z@@3~J+b3MOF6YKu{l-&?tsmy@Nu#fy#$oo`{%Byahadk|rm>o(u(MGG^KG5Dw0#hJ zHuu6m4=&-bTN%7}!7+)4K_qSZZwtN&(C2$Y{CW7dXAoJE1A)&6^66v0plsGsOgprS zQvJ+$ebg7a8YP8(tG!`m;b?w2eKN`?raF9toIU7T-#H~%pr@9kMEJ}xWF{HjlT z)}->I3H|tNawsnDb)I(q62X4IH{?fJqD4zT;Y-(Uu=KX$iAJ8(*w983KHe6?E*Wsu zlZ(QEC4M-i$ zMK2$~I-@8ESpHi`4&G3cWpuwL?fM7MvHvZ;zVt&J6eaDLvhgY*8*XNJs(BJ7GiSXu!mMLsx^c`}{ z2H<|5(P;J0d7|G$igun#_~Fl2(%q&iRB!ynLx%6ir4E`@zJD*;!ZX^w!V=l-C+y8q zi2rx({l*=uYn zT$DZ{>{{4^YvjL@Rg@O0-VpHbh}ZPx=^)Q}?Ijnl|?hZZg=I>TQNV_E;U)%MyU8+jWR6DVY=08SQ@Z_H%JxG*kSR|?B2+8 z+H}z!!X+`ji&3%vD3TvpNOmXA!Wsn)4tDtp??f}|r19vnz6Y-yvjJdjGmY*)kCN$N zjZ+_8UUMd%j6Pd%rlKF6*~;+oXD`rSVhBHF9tr!_x?ybOc35~?2TQ%LV3Na0tn$1K ztHY-APUmfGKP#MXOH0`4T_DX5UB*kY+Th6WHp#oD`S|$hEOJUa0%Ol@hfUvg;QimZ zl>czNV{C-LD*|KCaZNTEjWq<%=UF@}@em(ss~4jFuB{1kH^h{%I>EwVCfnOTqbs(( zX==_l$(71_aYNGr81i@&p1PyP8;9H#PF$vc>$R|b>`OShsu%Blb{Li`KPF9yCvWcD zg}2mubHDD%R5WBd`(Y;pC#aHAx|@%Irp3P#lJz723rgI)>zPGm2(*X_L|#MXW4;O~VX3Mb#nh z6!fGNM@|ogiMh&RP0t79uqTVI$*qPZw>Pr)3J_v{>vN}rzz6@eRgVk3aYecYO4Ke2 z!yl>QKBWbq@OC>4v_z9A}S2m!2@Sb(6U``aqyL^q=W5(>#{?vk$nX$Mt!8L<7O-xDv@HA zHbx)&!DrT8p<2~5wCzt%ygQ^+oOb3PLyESd=CUL3!p@R!uHH>LPdD?~by0k?PoSit zj~yhHjm7Go+a1)J2ji%MOv$Nopuw{)f=g>u(88(l<7sq18`U|jI+lH*}JjVc= zHs~JPOXy)cfIeEC60GucQTf&`c4_!TZM{EIbN7EW^Ad|WZ{a!adXz;=K3t116O3O~RMF~+B8*V5N1Z1JuyKeYsCJlfskSM%%Q(1A3x;^Ay(g+JUl%$J3_0TI7>rjD5e& z=io{Ag%9~Ns&C91j6TPl;2O?hPmM5$+Ltf+88C?qGYUCB)|V@MWx4K3Jgm@o0HvN% z_@TI&9w!(_P?A$#`pw$7^XOgC zAZQPGO;CrAO(Ce5t%P&@2reCXL-VKoqWqm*^v1Q7$}>jtgB%uK3T z1Ktu71<475;4oWW%=2l3kJp1Bbo9HLcUf;SDzH`DE}IChCn|ZxgcGFM?=3`KeNNY^ z!ZBmVELOMh;0>E~SbUNKC%0t5fvahB@k3u+(OVCzv-j2L7t~1-y^rFWMp@BvpgNbm z(&1!bea&b$16=(~;4%8ExbkohHhDA@$1eH|pMTh(P26$e-lI7`W4bb>AICisu<@Kb_Ix3MIuBF&xaXl@3?GFDmP|GVv)DqkM4t%<`E2WA zHj~YyE7nIL^xPnOh0bN9ac3oZ$d19e6NX`aj|1o$34C_SRMM4o;@NBajj9YY9%> z`WU4A!2X!&Uab6DMT=hD1w*gtTrtaw0=hoZHoZ!6I;zc_9nYs@eBkWV;lh`L)_5vP zhpkVi!V=eDzz}ozd$4!ytx9XYJ*qdP9goDefBvQ!cZ6KC{=njmX4pAe7u{rc;Jwv9 zA<*!ac&_Ob#ebc|*7pyHQ8Q#%xz|RTJEI=9m(+7>_g9Jh{vG_~7(=*fuGss6AXHCT zfUl;`fw2d}(XLaEW*4=<$6ZMn%NwEUoFSQnhKW=E{uO3;yrja4jqDNj4OaRnu*6x8 zTO;p@v8}1%(R@90KPRvr=%QbADKsyx;ne1M47|G(^9_wr(eMyG|1g{PyRXAPJCu0# z(0mvEl&zNFMrnE4^hESWd=5bU#OyS+oofUvacw+u#7+DXY!fT+VsX+ z06!I9TpT}J@Q;kb?kXj$ZQYNdH)cW9USnJiPiWOkWr%D^5fkd0XoLJQnpdvRf81p# zV09c$y0-(Hr|FP-m@}U=SKz9$2#6g$nr6$%al}GX)QLC&ZFy4c8>GVfohn7RSxFUD z+Wf^^hA+&Xi_?YMICTK;cC5!DM!{tMRQ>~vMs9C8x|to%V+o958ap=vdDZlCFG zVGMscf~?>6tkX+C@D^z$51 z9I3}Y3@_9?Zce4y9@9w8dkGpgn4*dNYueRtlQP?+_|2+Su)FVmI(6)UsIx#%xcKG? zx0D{|C5LUXyCMKj@5u+beY1JV`?HX+TIFhD)i{`W5XHe4iyk>TFI1aep zn~N{M5y<#BDfKqso4-^Yx7ez1Y8g?^AAgeH2$FwyBlDyvsXCg7 zLl#|x&8C-X%&$4{8aH*}rGklIHSi@}S@N75+Y~r0t()2w`SGK!9>_P1@q0os%$fcb zRt{YwIC&06{TC);c6$iU{hJJrC;b#wPrXQqahIv<?IR?!&U6fv#B7suN_fE%8z zV6dkzUFc@oG<_ARdOLHrLS%J7@fC4EWDx&*xwtA$f=4~P@RF1#lsqq`<^2vtt7W(up9TJy?LF_7)*jnY|_@DHOP{PUp5y+`;~wiGOT z`%-k66^3yeTPVs{3j1DG#4%zP?+iT33*&;|(=kg_A3YY;lb+E@wOPRK2UKP-iX6^m1a1?{vb?hdQR_FZ-lbU#rXY>7M^Rf$LGQK>DBr>HECxI zA+hIY@(>(2xVna7n)~uuIUS*7WF#7U_Q5*cDdhU4miqnlg@sK`5Oa78Z|)n%Uln4| zXtDv;cl$t{r8K+zGUgp=3()-SO)?5effE^rS#xqU*u~3XY?L;h{Wh!Sl7Tz#x$T5f z!wypBglWRFUH@Uj`~zsaMTNGY0=rBP;qVh$KrZW8|5mLqYq2z???1$kG-dG6k6+YW zxfqHw&QnL=R#-7<15Sx@COOMv@H^)W`8Z{xdZGgVem4r_Z;a)V6OF=fl^po56S(N6 z24*-G;;(>S;?T13JPG^toab_m;$oid8~ME8ma`W25*m4 zG;MuKFK-;A1uFtc>+oF~R5}Q~hh*W=lx2{w(}!CdHgbdW71|bS1+yEhd5|Z8j6}n+ zXGl7g=b=z8U(QdrCf9gLFQk`~?oxiD59}8Ep_N=JT=-9pYmda@h2~IL|M@C7NA}^W zosY=3b1nq@bBRMol1P4YJH_B{>Z}p-^^g> zmA^bU+LA{d%n%)J?8kM}L#aM4pElQN;I1r3JhNjNUYXJ)R&I}`?2R_u@%Ftq=HUi@ z_U0J1)~utQRwK|*;j6g#mp7M3jicj+{h;);30{0?Nq3a@i1YTy3urYNw+qjC@sBjf z_j^^Nk(`X7?-T5D51R4A?v(%kM@B<>$nmvdC!wP2HAZ#lLeu^bh#It=Oa_&z+nL0MQo_&rgTz!ufAY-6qttCUq(Aw-I+(+`2)B4f56Stjfb zyH2+6Q=v&)0l)6pNxDiEaBlwuH2ZZ942K+H_XG(C)ija901bS_8~DFvHz;}h zNN!4?jq(Rbn}Ncz*~S;U})Ck?;}kHUA{1 zg-1DPU}vBfmVKFq-lv*{Z98QlS-LOULljnjuc39pqiI4m(FYwxawQv~EUOm>Zd(EY zS2jqd?9btz#U^xjRsdRzUW;~9HR!hMK$dUMm!zfjgLge`xyW4`_MO$iIQwnf;4u|6 zZr`byn)M!5mCvM^dBlkEk>gC zB9b2`{)Kp@%OIww!=_V1s|zB_>DjhT_{gn`&iq;`K1}b4F;Dez!3+;{PqAW84^8_;MzN5^Vb8^GTsl=iUi%5k^>i(hb_SC~>XVZt8RGH(eU` zn%eh9(V%BfAw^jMXX~nP#|>LFSo1)vZg#>c^KC?N`XuglP80TCRAihUigHdZVv3e7 ztBf?|s$UHd{Vg68R_D^b^kVwnk^>80MADMzIjBBs2Tu8Rj#e4FQ2Sj&zN^#|gNHBT zd*v^v&@oEnru|q^QbM;nHq)(*iu`Wl6(RIp1~mQi*ew&4yns zL^c9zk7Sdz6L3)I6lmRDAi$^HWSZQQ4U0m-McaW?w%YK_uVy@T>k4+>^9FRy0)*Rp z--ui019Y{-V8$Q~{IfI)dU@LLgr%LdX2yC+w^T7SkGUvWY@Q)Xs~O^-`dnDo1l6yi zleukEI~7m$l#I=Dz^t`{(b-;4xcu`y+&r*Ml2f-9t)v3j^2aeazF{4;TaQ80SAE4L zyOmh;>^@1t!F^Od>L7SGSKzYYgLvbGLqg^3G29elhqfD%$zoVE^WecXqlT(EuD$fn zfx@>?s&Wa(OdNvg(-J9t);g+bzxeN5tZ~YmM<7+34R2E?^5M8#`rzP8l|^|F?&U&0 z8IuH^ul+D_t^?PqDe(5@1JEOE9~jx>z~>f6No3En@JLP-?hIK#RsA#IjEQ2c<=8N| zIOitqpV0ze=NrL>Ne(cowiH|5gb^7rbST`HtRJ4l=U@6u#{F|~jW<2fwKkic8Z{8x zYvIT{yZQK#m%^KjX1<>IMo?X#z}@!!aB0&-G`kQ5P9=*lepRZduI0x*H~ziN`Bd}K z=ezi@*GQCVQWF**UW9M6cZmskBQVq91jZcF6x1f(hO+}h>0I_vG4)M5jqTpa;c*I_ z^nD78e2l9u-xf=E1yg~sCEj*w6b>}op}w>>>b@Q)30pQ9lb)W3B{T)K6-#KA^KoHX zS1`4E*3*-Y^JHdg!b8r)3st^{ILIy(mq#Yl47)T8J#2jV#`8pawDP&|B|n#5FKI;M z;&{~D`;e|UW^<4EdVD7G0UR+k0Mr7X4Sl{cLN5nX@+G>-%B2$;J>2jt=K7 z;%9O96IoXL;mPY~4T7a!TD5K7!ZNqfINiw`&s+=RbPr#s z=qrWhW<4=^!d-{Gw|CR&0ArjrUxQyR&8I1mSNZCkE0B7}g-u*6u=GwEtV`C#ksAMI z|GsXzsoW;H<0!!lKV5ipbfPfHW+?5vTSMd1@+j;2G=BTRh!*voB`7r?C8w%0sCV*p zjYiuNN>%jXvg_gEjU5JP+xnK~Pg?;eum9$r8(nyM_(&|0%7v(gE{J&clU_Kjz#y49 z_$*6F7$^_C)FVnPpU{B&*94*FOF8~#F^adv#u3Fn2A#D|yx&rdi@U}O1{lgW+y;QB zyA8|yeg}0Iy1=HmlW=zZFn;xID62KtLO(Hy<2=e?yRRl{uqj=58-tz)_K0?edti)a z1v$R3Ve|SW)PIr&@AQb{%#}4__{yWKV%#5B{p+qG**W-q%pf>@6D9g8(O^AW5A!zf zfI@G%+WW7T2~(?Nu`47Uw#qkAklW;VmxNzNSp$(G0LJ%Z_KBXO+SMDfpeEt)ZIvv_*_ zF!a{)XW7rPSktnJEgVd+e~czSK4FJwIY5(Y&V!55P;V%vgIyurJgx_W1Ty~YSuNgOGBcz#%X+fNhg zXZ?j~f0kh36@f1mnoxyRE`j3&YT3A$76r<&f@?HpSbu}v*Hk#syiJ_h_p7*~{WfGq zhjVm72{orjh$dD8aM_JW9DGv`d`~pcgZ^b=tFAsD=;#t=Nk?;!e0g!f#T7jG)O^0U zdNW3@>4&8(hl<5LAU`KSIQQr>D9+f-kK1>l%!^@YP~ye|l21~=1`GagMm?NX^kCfu z7eup`atK6=nln+8$Z&@f1?eRTrjyg*o`E(^c%2TaM?S;I%XvcR)hgV%Xfr6@n84d7 zN^|$1UbOR;GifH;vv=KgF>t*hKA#hYIvt(h@h6&JPg%*GhfFB6SqasHJA`QUcv_CX zVTOMV>?;mN>!=i=$jwVwG-?o;(1{9pZU$kt-|}H_*`1VYpsbA2O&z2zD-` z0se=D#y}lhBpXR_uP0HjVbUCj-V|Z~Rwz7`2hrRUjDF9g4(nlfJF8Uec>AHoWqAaw z3p;^FV!h~GlNzj(b>Pxo%Gf#Lk9hH#F<&_2EnKVHjRkYb(uvRh$D$w2j1pRnDAXTnOzioU!kgQlT?zIS$Q_W|tdwLQ{X>eI^Fz{lU3g|d^+7@GQ7l_ke_qFwq?h;OPU zcLc$mrIuh^mdSP-2H|ikDOj|60{$^uDVU6zLpK(CKtyj{UUMi0m)w32?y*u(XVWBB zH>FeVe=XuJdF1_?MvoiaoY+y;kvv}2;fzzETslILTbd%d>On8aoY@ECLZ4ImiYXX8>>w<)SH??u zk!(kc+Y(vFTIye%Qor5)$@I6f9GwuQkc&57d>!+nGCY}HMpf}${~At zabe07jF^>6z6}fD;Ho}Y^VbC3(#q*?({K(An9gFqE{WT?9voaA3IQap~$*~{W7<=af zbQ*2v3$I_miprjN`hITBv+R9UD{l;kow*kwA#yB_^0`jl8b52~jZf0fxBXG$=n0(t zYcJR>HHWhY!+EE{Q;C`TV^YpJO>u5dxKdLEzZdkz_4C5f?sJFGv%MGZxRnXdYb<%% z^kO(_8-z9|M&h+M-zZzGv+s4KjzZt)OYZp(MP3j5ji;1xc|X=u*p?!^nXz20)<_mS}4yhyyJx)FcFZ7sduoD=3BLz?L=C2Nqx$Ns%xa#ZyJ8nFK z{(0cz6p2T}$z~4}Q5_1f#u7~n=Gi8iC znoOnJ^c-?uw!x{dcDz4f2x{L8<8>`(#G4V%X^6}|)H@d}uKS@UIX*uP-p^45rxk|< zw@oVn!`o2F!<>xe4d`fTI3JQPq3P8->EVA{Ipf1g$gb?9J3q8()c#mJo&5?P_ZUV~ zR0gp0%MP&FqK;ctg9V4SI_$nY55ayWANm=~&SCpRNsu?hT@ zj?>~%)0k8b)7~X#AR=fd=E?662iYm3SKCYB@|t+oUVI0}%h*tDn+K}B8O^6xBsetv zyaWHExIFxNdb~K?5J|hFEl~&wA*J!T=afoDB_UGCmQCoJmP(sSDkT{yTO}opdrq>2 zP{>{>*-F;0-+yrLeVzNfpXbeDMX_aENcV2<=B7jU>5_dMs-Jhj?KbbB^Nl)1$P?Hb zY!z-kcVL-ki6DD!JL{AzW-s3{^q|!rWACY>{|yDAiW(uZwh(q^?uDd%$=q>O#qsee zDSR|>3x2M5<|3OdylM6tVPb?5`*#)b=pkNgS+oajJZ3_GydJL6dPb8Y7vaO!6>y|f zheKORQDcV@tN!^!H)R9)%b>Av*ZUqkvJvRje>0#s(wsDI59Y<8$V>g4Aa9ctY`yjj zy0Ri+^@1k&82nl=y;)8MHw-A>ya!*?l;)M!PJmJOc6*hcqBh@b@;a&od)0$5vfKOr zySs$9ZePLPM%ziVt|z{YUj>Sn)$wffVK7%a1|C^WxbdbgmNsrh&MtiNUx8(OPEz=L?UYjwuI`xN;0braOJGl!h+`_gF`4I`)Kfoa?#_HV32 z)k7I19_ZKZ3}+R#;_z9I;K7;+qHO9|T)uEE?HSerg?qetXitQ1D?6#{ z$4;6RzYpduG@^Chw*X{hP$A?KrIlPItI=D8Jh?P@5|>EvPUHDO=nDwCnai39OL>3j zK}v|7fOVGVV54;bY4&f1pDXmR(`OQD72DII#nVu4%5BhBS}OeRIh1XG{H-~-SWC$5 z{hb^W3MuyP80_#phrPeWP}<)tifr&@J@-%IvZ+@5AZq|`y1ovjZ&zWZ#YpZGY7X8% zExEK)5nYnH=xTxR~}9GLeA9eE1SssU2A!t%wb$Pp#(Mu_~T@g6!Lg~0+t+Vg%)z+4z~ba z<>|nqFYV;JLwkt&B1>`Q4zzzo_qc049~rr_e9Md(*rAnFDzVGD~BqR|d#@;Prs zrQWl6`PvMa{qQ}Uh&j)H^ER+^UXn0H-4$f<5stlij|%IL(p=3{+7le*)jGRLaYap@5;TuqG%~?A_m+AC>jMyz>P(Pw^NoXiTPo z;j`Io*l5mEkr69mrO?8 z4Yl!73x!k{@WaI`Y01TXFvrgoR&0nDJBJyHv!b_PMD9-*=Wq)9Rmkz!%${^fHcKiFF7tOh`b}w8Jq%op6k)c z&w|#UO2Yu{CD5}zoXe_|_+-CYSn*&#$X3X*<*FH^>tKy}=>xDKlz%$$?(Bz^?{=ab7@yrQXZQX*_CH^o6Fs(f+u z5%I5{A?A8%qC=mtc1kts_^f{l-f5HO4?}zN!Qob%D<4jGZMnP)6Z5Zj|y za8|DuU}rE3*ZTG6(MKcbTQ_UdTW?qD=27B)K1-~cy3$iL$~>~ZP!%9`=1MmTexE2gbc zr4uSKRH+e+e*3)mYlaFJ^&Cpud;NgtIlG}kyNU*S&W9V`7hq#y5loz!MDK2I;GQS5 z==P3OQavJvTV{X_8^E3mm(m#lzD> zG3=Kque@>wpYBP4`T}3^&BY}g7nK2zmkh(JtKQOz(2sPjS3PLtO{AlJj*+z%OKO$2zzmDyl>9kE>^CM9KN|@+dUAgpZ*!356-=a+jq?0CZX@MN zS5iQhyC7wC7;EHosJDs(>?>Hy=Zs~r$-0F2hYGL!e2#|pI7YV97NhIea6I~JA%2|f z&qHThaL5&3z8<0hSc_x3#Xv@Svf3RrB*ZVtPz!OZ4u)K4C1*V6F7C8 zNN=T=gTBQL;k4OV*nIaXUEcnPa-*M;ipC`2Kkan-aVLioRi9Jn)=Oxnq>s&Wr0^V^ zB8ysAioCF=I@ab0PyHQ7^Wx>O&&OhT{htZCeS1ag&%dJ+otE5^sZOz*9H4&^(O8ot z{56b8;nH@&A!;)F+Gf!C;y&WuLHB6SD=pMccNABwYKC&tGI45r2;TP`O*%*J5*%2A0ha1rJ^LE^?*^?hM`cO#aBF+u!kK^*@a`X@-$+?!dg3gmfGK}BI za&{Ns;N0WYxczv* zsI4!CEjz(q)83L#+Hn~4pQ(`5R#EM(sEq%Oi{KBRqdD__6wSK76vIg#{zW_zd#lxp zVLE|W`Oya_WD+d6*$F=_`%y&0Y04Nc$Es#M*rBI1tPB%{mCF`GpxjVyX;8qR<@Mr^ z4}alF;rALlt@Wbc*Zxp9emhmWd9mup$*5#!ji;BK5{hCZ+}5#`Os&2`GI&tQY$dk- zp)IOhdQUGKPVt**M_|3R71}8e#9e0+1?@hEsYj7E9_#m$7U#L+`%_`O%F-4`3ZjtN zrx%odv?fgpdCnQ4i(5{p;hROC+*Z+>-DM3}@8}rN*IWV{GU7=yqaQ9f{YQ+8pN;G1 zJEO<2M!fv2a(r2cIerzG~l zIbsRqD^G^ruTN1>{AJ;+p9e}eUl8LC?FPSN3A}9YC5}$bq&XfAI4*b&RP{)On$$ZG zup|ISO(+xcuTP{~W94blda<#N zPA`Cw<~`}`{4TIu+9aq3nsDFF-W(CVnJX7Z;p5q|I5Nr??YG(S#(-clR=WWI9S9-y zKcSR*ww|~5aK&v~ZH1NHY%af%2UoN%*2Hfi6^}I?)zfc z(BnAf1vJsNxGQ4fWCIR~P{PLSi*(8-kVlQbA+B{iM+pZb$!EbDo8I45Gm%Y{7=oN0QMHRD2d|jN zSJs||P>=kY@og3G_R>4ag7k0VT~i}8FuYABPm5sse)(GIGo|ENp;G(o@KI3Otc~|} z5LPanA<=dj1dk`37LJ*xz`%ZXq^0%)qQ9?UnLhD2&pub&bFG^RYe%u= zo2hJT>?ghpdqwwq4d4|A3i-^W?Wq6x2Go1auA2S$CEa}S9d=pF!|@NF(K+8FdSo+; zmsbCP3t2zlqwpTKCZy1RS8~Kd%BpBJLI79uwLD{928}y&n?07S#>D1O;X;-ZYE>4| z!xQ;%`*0>CN!Ih&TiTqK=)@K7y)bu-3K}%!pybp#ob7ZN`du4DhKslIj{~|w+o~ws z;-Vr{T;5G~Q!RPFPCtC~-yl%0@}TuMH}baDFTA596i>Eyfz;h&*vGz^PVLge*HS&< z@$Q|p?o%TBm$uNIfGahIc7~`uN)3XmzR+nM6U@4{3d%BCV8oVmI;oW>ahxB=Pv0bh zUUUN8tM7it`+77nXbLIbpM~c3SKzc|n|QH(3;db0nVvgTg5jed!ial=sOHTBp?RJX z7or0cP7C1czUC~SGlIuX*T%lBhS(HijGy-|hpTJf!_l4PCj_Kj2YSCIPq5Wr27w#>^?cZ+Th4Pc= ze)}`EJoIPH+EEnx-$0z<-}Qz&v?|zxBzR6 zhvUnU#4j#bf%+E-8kY9Q^3-s!v)?Z|u5rYPdS~fimKjs2zlmA2@5 z@g%8lA#kXzq5s+yu(&u`yrMmyR$q+}y#J=tv0j^Ts`d~ZQxzjv?M{l%HK{3yiQycxK7 z&RWiW`-09M@#1Y)`eEK$54L|;1_zAJ!mQ{-aK7>m(mf;K_<40+6Sa|Sv*Td>q8Tvr z&n5Dk_=a}QaOUyFSe^dacrU?4T+(T~fh|_xA7( z-IL;Yy{|PJVhqtKw-+y0$fQr#Y;pCDF=*5{0{^(L;o5tB=#zC9RX1&dLzm`rW<-gQ zSlt)zEHD!yN@s~e`wp&_O@Q)-DDixzKTf}{&jIDp@FMat1S$n%lGk^f-fsfNc;2Ne zId>`Z&mdm>LV>*x1@qy##Wm`e@6&48y}Tqhs{5Ixv3A8=+!d7!QCIb7?E+KSDzy?8 z1{yNdE}~SUK=wL45q~~w1v`2Rv+mD^$GNve*Z$w&#p2!K(A|6C*6s*)$@nD+aWUhQ zMk6tHf4n5VaRE$LG{POzwxi|kqjbgI7(U2*lH;&+c-%iz?6qE%^?RMGxv6eQ;VaB> z^XDN@>^Kc&G)l?6{b`M&qc;~kvf;xDyD4YPWZHUJ-p`jZg&h12kB%vl=|BTEteNi+lNBvuhN6P+rr__Zbd%fT*c2* z7Sn}rcN#MH5wz!tq^vj`buwpQvwkADPl?CAL$;7|xIAwQDW|dYm8)b7((>60R{C33@_t&qb@436^ za)=-2tk{O~ALSv?G!*Z(no;o3MtFB%dre@M3A^}q`|c)lHjDcT_B?dIJ@6o`X@ej^KWC6KXfK1~qrbuN0SobIp30nbBd}b`Buxhsq^{L!K5WR3!Q(S z!K+92;o`YBf?M?j@VOWvENyoe41Ubu+1ql-UfGbAE|P}gZ^lr5D;4(Z^u+0>GdS?` zX>6J_79?pe!CFa)W9?EU?)^T3=E5HQbLJX)zeJTyyS?!5A(3-W%cGX|DRHRzTr54+ zhfXLTreU`%!6|Vo_a7TeUH6T}L~lh*wwfW_H0u=A&lEuK_b1_PnJ2iWNnu3RK&*P{ z4c51wQ_Rz=;*ej;kQF^jTsHe1)jlqw2AdRaxc>+=n>$GV&NS>$)Z%seRbo?IEqu`3 z4n`+0LrV`?eEcvQt@6$ZoiW>BM~WYp1|gW8n99pfs&PPIEUD(|@qPcv@aW%=+B{o1 z)G%=4Uc;nu`>7x$mlG-{zY8DR%AaaoTcxCpziIr;>bc@eA^WRJB@e3z`8Z@ZA&cRkJOoesOAdefTqpM6f{SNakCxZUKU>;In%r8Igg~3-`;j-);Znj*<+irZX z@%pw0R12N4fBQLV`_Ts*8b(3orkOm#e-#HPE741tVhC%$0=fr6!9V#QJT~lvNpE`5 z(j{3`<1rtthl~75wI^>sp(koxj}_!^y#cj3N6Cz0QFW6WZ1E_9_>Ma~u;~?P=ljrx zf7>v&$O!eG=0oNZ6`Z79hmOj3#5{{OIxaPUS8sQQp?iD5@9IcCx-FH4S#5@|-%f!3 z>~UQFZ5loqFoXjdWpPB33*9o?3`uhzg2LTy&+JzU9=YbI;5!<1C4SVncZGQOSAlrd zP8lw>*zsEJCQ6c8ic20lf`#EnT7O2DTx?4vnMc2XLeXNrKlh)g)nWo|ng+bz`T_JY z$-}R~p6K?|fMwPU;?mNmqA)&`riU1?*BA-6`iA25+-6ERFcizL7_qF(Td>-h=5XD+ z2fuqWg5JBPLy!C8X{UM-NPb$;h`qyL-^ogGiN6{}TNg`m=FcUcqr=eTxjdV`IEfR( zZ#(23P{Gmb50ZG!pEtBgfZtkkew_=dxVp0Z`fG6VSqf?PWiWS25+7$zH#^BbaA?$h4EtryQoTgL&rjtr{gw=iK|ZATW)+zpQV>*Io!Q?kmvkO~hGG8{ zX|3rOmd!@ax-=LUZH~c19m53!g@OEP!3ezlMGK+ZDfN{si4Ugmj$c!utKS{b``#{S zjadk{Z3WP(v%`=ATR8YT9M_Fvau0|R+RL=qxX}<@YDLLLo!cZDN>S6NTcY!Vn>2g& zJu32^O`g~1VX&LBaN*J^$XKid^Rk!X&b0qWlr#H%ek9bXK7%KR`{G)eA9O0$4b6*V zVVKc4*aqdOxuy{JCl}I_%4A+9%ar?iCn@On5xrwVSbp&nkhAE?k3Y)syW%(0Q}ZiS zZd1XJUI`$c+10%vQlKn50#42{MB9QeYJQr*c`KGuNxxp~v1cd_>VJSj6U;H|k2)rw znS>kr-bMX~S2$nKj{8?+(vUNaU^MOq3?1slJr;PN|JEgFw=DuQJ{WU))JATMyiMi3 z_rQ}m8Zb3`Hm_f-jA|i6@asTDOs`sjRU;!w?Su=6<4=G?O%;ysJj{7+imXx8?L5M2 z>=`xz9}gPL-)rVT-c6<%p(T=)9#Qz`sXC6GIu~~IZKcJl`f$A*)4cY5}ey)J-of(ap_G93FygFT26Nvjw{=kL7AK?7E9A0>3AD`SRhyEs!0Qb~z$D|DL z<4_6KOWaZS!(O`W@{C8BpTu0LMUv9J$}loZk56SU2g}ZZxZ|4%=jQybE?N=FW%Ewr zj-cr{`+P3ERq*EHA-Bk@j^!7h9Y9{w8+^5Q36;s~untc{PWnXZHAb6{X%czr zRfrp`Lnvj=f9T$lh5IrBVAj=1yn1E^Rll80qr&V+_v$=WRrG{c2TgJM#Haj2Z-TgR zUI&fp%E6R0Remcqjwa5v$IWDq9)&6-rFI-kgB7^nM>!n0NRC$=P8N5!zo6+){P^rv zdE9zYkz2p-$Lh|1gu#{Ivq*`L&b}c&^I24VT~3xGR}RCGVk8HLoReHQG7M{<>%%~| zJW#mPCj3=Y#RpqGMEA2cJnl(wuG*z^#L_c)+LeHLNQdZ=8#A2MgW zhW|1&Z2F@AU@EXfLey5c)ybwCWM?6 zCT|8d3%nsdF22L=_r8PH4kze)EEgArzpa)tI0hSPEHF}S66aqoqkyJUY4uZOO{zWBQ2oN&5irSz8qqyn)L!7EG2^)ff_k`)mkRg&S~3oHXkcD`C*qcG2*5FFw&yPu>f3;g?}|>uZ+b z0h`_Mb7{_tw-f7fH}lE!sk{l+k;#=DTwVJd=B$}W3s2prq%VpX)8`i) zN}b9IgIBP9W;XUcvyLpbD&bF^^JIFr7o|HK1ZT-wwl+H!FPB&vj#6~Tf?V2 zz1bJTxuJHi*mH>qso$-j{C+anr`v;9C+47`r3zcbR6vl;E*_nd3B#2OB?C{Z(2(~V zL234T@JmQxH4}Zo%5n?`?q~(GDgI>U-|bxv+IaKUSdM!ahYCx(n{wv}+$W_$y|M=i zho^iLKb1$YQ2SUk9I_DK?Ck@CC&`nv$9KB>whG?9R)f~-@;qbV0DkynmN*E!Sk3z+ zkLekPifY5qag`rN7M-IF*GI#=LJf4=ZNfg%i+K4z8`v2=6(9WlC45db5S0!#(wD>u zsCdPg{v?!%U*(FS^XFnLQAwvAY(^kN6N;E#?i?DO{820`zn;OLlti5JE&InPgxp2c0BO0`Lx~&a$bhb%e_S;2U zdoav#IgRVvRbNWn&~1UfUHVYbEX~ffx@dCPfFHb(Me}db z^l4l^d~(sKc2|+&U%s~BrK;v=cC`y0k2y!Xq^7X6@=vhu{a&?3kp)cl}eSasPjCf44P_8&d#^zh|O@QZA30IvbOt9*F8wmGM>F6)Y!eRsjQ=`x(9qQ;MM1^!uJh}S2IqSb_E81zgBBY&?!S3ezGa4QPEd%MH) zVL)q_SaP26Cfe4}0?*i!jQ$fSGck~SigF}v2a6pnzZG!*`Xi$Kd3S1kxfwSvaDr^l zcvyL12>Lem=a9`$#W!8+xlZ#TI2f;|`EjRV`*D9T3T}ha;CeWEUmZQg5||ggK?qM7 z&(2N#==Ksl7*QuhTl;&GF#fZ6rE>>7zGlq|cH?k@+bY5Jc1=y-yF%IKYr?Ogfp1^F*n1*Ovz*8`qpk}5!Xm+apfH+B?Mi@7M66 zLzQ$zZWHVpzY(q#MDpE7O`vYVJYBLAI!ch~d_Sxx%mk+?kHGovCe(NErs*$}cvgL1 zlKwmbPkSg~N$GpC(lTOsr!<)KcpNTs?GRl@OlD(8E!_2c7XEtG&9NX`dVk-ED|6;S zz@6i?XK}mOqe)Kaw`(d_DcTCLeTv}d*A`&UKw)J}Dw$sFjf+&0#Guud^s_pj%U&6? z+rc^q52ZP%qT65i`@|f~FHZ#9hUqv@F_;IB_Qebu!}dwtJ2vScCD+Wu8P3OQc6K0d zQ*04s^)`TX`AEz-pisNSVvXxXr@yUK4rj z>|#t$RKlYv_h6y6C!a6UrsdxYL4K+|NBc|j?*kKf;m*CBY}!|J`ZJQhE!+i~Q3aG| zr-DXli?LntIHct62Lqq0l5aY4>~?QDzH9cWwq9z6y^2=z@t?gxJw`$3`Z$4G7B3J} z?mmUQ4@dEH)oPkuRz;e!VSGWRFUFV$Q_rt*yx(sHrj3f=-L=2TOJgfN(VdRAO-F?n zx_10Mq+DonN`(R8`n+ITZ@zNsH2?SQ9qcG_6f-h@gT>Bski6|bKTc_v{kJSPhX*jx~c_GSZ9pT{uGXX znn#BWj777IDZ;;BE5YXCCv>bGj0tjw7FnJ&ee@Pq9TmX4@5I-vJLrK9 zHcueql_$^L{DSgUj>X4MN8qwaDWu)kgdMaEG3c=uk4~r)-b9>+*Vb|PU&2hxOfcoj z7&URi{&{SXQ-nPee4*)}0~UFVUBrv^GN|;(SRV536KqmT zlKhPK79$d_!}LWnVQhahJgYCmF9TEfTV0)aJXWUK<6;Rc*wTxe+#kcG3$Ng$qd&Ko zEWvXH|3EX_4u{|-ntMq_5;e>gDsSoXqrJAg*pFa&pKQ2zv0v@|Gc{uJ1U(Yx6=27w zdm!uZgcL8u!BFGbXyiGDk9=RqFZB9zNm;sJIB^1gw>N=ZYe!>;gA839d4!8DKBK#` zMXa+sAGR$BBumFq2(8+QQ~Ju`v4vW=#&sKRjvLDLsoiE3uExO{r(oJSH7x(QjB1tJ zK(b8~9#o|9!>VWCv!q2x|7Cz_Y)Y?RDTznFH9&pseRBTOm&fkwqLfv>*kWRWbKZRe z`O~_b@oK)f;=n|5u~nuSrzi1GzYC&A^)cKw@Coj(JqXw5&fx`P9*NF>HR-yc0jJxi z^9A=@s5do6$@`h?-BwBKX(G?c*FlWV6)v>p3z&_M-i&3njNQb_2nN5C1vigq zj?a2X*N1e{m)YCEB>WCkIKKh6Cj&5SatDmLW5%8@eOS(B4rc_033mqfMGYT6?EId9 zvXYlVeeMM4{yg;1L9wc~ z(E1~^*>pG@Io~DN_I?KCIp%Qiq!yIeJ)!MjLj_hvSXyU5>$mTvAHEZKgN-bPzR!i$ zMqO4J7>o{jDK%ZXj$Cmqocj1bAm{H&IQ+p}R-Rb^FZ?56*yMlM@n8xb@|SVcxph~( z6_iG2UaVzX2;(H>F*N?#EFQIf2l;+D&5ic9LU7Soc;hx4PmF4ST1_`enXNvy95dm` zE>>LrVjgPl|AL3}eaKFTq3Xk1#ppz7Y>1ZPLkf8uJpVc-M=JCD&l0p;yq6c-HVU_U z+3+eqS8>qVI*@;60P{OyF>}%bs7dLG#xa(x{h^!O8PPz??O7)M0i6lZW33(;aCwR^ zD#wkav$Gm$7QV8mM&lyYFn5%Rm9L*_v~-5nbN za?336TE`VQWO|(5WY6SZ`+WIi*L4`T^9~q=X+tmd*EPYvTjA3YJG|KIBHsIQ4aW9M zLyMntIsVZ-ao6wwTL0XMZlu_X)2iLr_Wd*Z_-6+WU*SV-Pn$q3usg&^PL>!y4y3IAzr^wn~~JAQF05`s7v@unj#zZ zOsJXCH&}SQV>xKM{3N%SE6}m9H_m)4h(@)~#EJh(Fem3{bRK(4qXQ3Q>8gqEsjff+wiaSuY$(9 zUih|UHugH`gXjJ}5>^fgfyrL2WL!M}-7IuTDPk~QRWBl~wHIL2_dSB!IHVtcZAIIU z(PTTa9H$J+#m>Z^bl>7I&(OV2S%-R{>gXNxp=UU6NlRk4cLr!z?t%V)k3!)pTlRk~ z&10W=qEu%blodMBpNxk%+BSl%ueJ&I#w783{R*K=>J=SGP@{#o3Cr{dK1eF?)2&0; z@;-z&H!ffwm1%q|^)ux74&)BkbWvuxEgtVThjb1O;7X%#cG{Uqb~bO}^jU9E7Uc1~ z>vgd_vKKb{q(a)OHN2_gH*Fs4EFP=92;J5KbDoY6pDoqICyQ=M9>^`?fBHsTGTb@FoDyF?pRV|w6+3yPR9)EpZX_I2NY6N6+U%~$b&cmIsh;@B@5o}kWwJ&y}H zG1`2lRHoJ-=_|SH8ixvDy|3u4GFFd9#_I6#r=MwSU&#kr+R#R)}mFr!5s|MMz`olDlCLPQaS?ps4nS&=kK zC}++Ng9S6xaA_If%f}@&{=N}ARb7EE4~iUaCnXSQhT*o3*SznlBgCJK7OtGyiGw

9*AuQ8!<*se&e6Y=g z7Y#{=^LPFUTaJbbwLeQ?-!3V9c-S1R2Q+hCbTXwakzzl81sr$y6$Q;&C1n0wiAItt z@J~yJswJ}c$zuxt3Qb49w8La_a}pfGbiQ)d3S_>l?mh)76-X1`EsPTPVXx&qikqX)g~>>``r z&9wK;aCCZ`N)N*JLdk9qbh(rzRQ$Y0Em6Qmt**4fEHLafw5b& zxLeg%oVE8lH%GL9yNM--{n?Bmo+rh}S&Dc^suI*A`m*W6GT~l$7L;Ajz*{$MSo-^7 zdVWNXA1Pbl%~vmksXJ!#vpC&6DTQu0|tn(w2h@14qE1AZffZss#MU=%eL-2g&c| zI5B9Q2E9CCPpWt8s4j6Je;m38?0d!HsBSJv;`_t3^;f7ee2dUzrOKJ-yGT%>4#O34g}{SHczKxuonQKjMt3{# zsT;AP@A^8BTpk9C+ z*e@Xe3M7S1WpMNAdHNK-2C7~vV&6&?Oh1;!TIVZ8H_s?MoE(N}hL0rc3l4}^{T%CIks3IHnGpM9u z1;d8VqBTB+r2ozg$4@x}u14{E(Z(JxKkcF|&sXE&KDWquSZ{o~PKIkd*NHI=G8A?9 zEVa)u<`2~^=say4S}a;i$1<(CBIP#Fudzr|bT~6=I=gO;6h`Gm^MjyK{P0gGEgO6X zH1EjJ_G~GfHfk^~oiq(kd4GY21t%!p#_`@yJ~V zcJRDa6_jbx&Btk&8n6&f-kif;RsUc}z8ueeaRuIVdrw7rG+eCPL21i8Q1eg*y)^Gl zAx{V4hH4|I+2ssv)q5!6>s0g{(qCfdxX+=xl)3ThLAvp(9-cJ@((kROsKfL#3@bI} z^zQ!J5~l?&vPN{&_W;z4t|!loPFQnp6%Sfjiz!Yc&_qTS4;Aj@A^R1Cg@0ec0{2{U zelnKl~j_oLh z0R3O|)@uXH+zn$*qr1>~tv?z3>Wy=4vIKpZ?tf})6L=iE4}XF-^3@4@aoWT0r1ee_ zL%U?yaN}aobqk08dRcMx!TG#wN*=0ixepB*R;asZ9^XH)9+t8?CQYanQFjS^3$Jbmol*$B1NJp7I3@8h?`VX&L+=DIvf8%i&m=F)AJ~ zz>5$2b5@o=RM^OK+49+AVkp;}lHQ;pl3Bv_Gfgnl?Z0J+tUl(_pHxs5d;?SVRIY~BLC zAB#Zg{&AWSH-Rii8p5@lffOyTPX5!6!hqkN{MzLx=zVGzUFTb2?-~uhWj#t_sapp% z(R+o%X=7Ph`%icdX{RK($;?|Q>sW$= z%v{KN!DVhs+5lxyH%T=x0dr4%l-!cn!yWpCpppHH6m{Kc-IlZ1)8z(SJG&p!+b8j? z%)YQN--)6M1dfSN8Xp^7vb*KD1qM z!@;K>z}5rRf~}Dz7f+YK40}%wNeZM_rd>4k=o_jlzDMfaonL?Z0@(I#gYlLr z&}aA{YP%InZNFbZX~IbwFl;oR8)<_PN7C>_LkMLYx=P6n_PonY6%&tkl9keNn)*Hl zd&R|q$#w(!bg70MW77FtZirug_+Os6qVHbu8Ryb)oey z598~O1MsGFX3d=!?PSpB3eAuy1mo2Te7rFQ@{jMv_kALfl^bcNiYY&+oz7zp7sCgI z50u~0Nt2_x;Gb?THgzb|nyu9it`=&1+3zq7i+M@w%=&X{MgLvGS7E&qyNX^0WpgQ%7P^juE`tEOrJuRUy z{f88$=4aDpJ3U&KWlsO*7~zL;BZLtj2lC1AbK<+i?-baS#WUX5;>54FySt-WysAdD z_u{3RiM?Gg%X2zsUmwVis@?hTt>L&nXbLQDG{!n}V_LSz48xvx2m$hs$^IzA`i7Ax zIgky*t-Y)Ft`W&(ybn#Byn~*PIYTbhHiCFPh_{q2AhYu-(9m!ee$Hrz_sd6#pak=@0L)#FHTgi^Mizp6@mD0=DfT=|pqMV|599mpVX( z<^yOSB%_1sV$iW#Cr_C4mR>HH1x$r-V%{!{c z_l@I~lG4(k;Y$mZN=8vypXa)gnT$$8QAR>Tq^wGjgqD=7(vm2Itn_)VE0j^PSIAb0 z?5v;PpU*k>dG2%WbKURv>-EPyp(X?7x9AJq2dw2E2c3miVK?cP-e35%;{@4kn*w=S z9teMKKvu91jQyU*SD?R89yJLT9bAMzM=Da)icT6^d<*QO_hDnmBU;{U#x@7~a>V&R z zb<+?|F!W?2N``Rx-fm6Rnc|ljS6Rk(Fu(rX3!Uv3Lu>yyUdg>Bp=o1KTk(+u{(Qg@ zCkG3GuYr-03tsF9 zf&-gs;N`5|^tyc~O?O+%3bQtWuhD66UUC__?K(rDHXEoUq!QLU?Z$8gSsWJi8khaN zDe1`Uf`<*Oxv|BX!(R^J8w;fL-T5+<8*Sqo|7dr}qanO(i5h0sHA2V=RZ`0KUb|80_NepW>uUqyFa?N&gJLl7t-|u zrd+LF19m5aX=3+QG0{&B_pa&2TTC94{$Wpuc;E`VJ38RuZIKd--os_(a0u+`jyv85 z@R)9cu+H}*S-RxHoi}QrTL+syE;cA}AFZ9JrhAp{ocH2)1`m0u*GNptx&kw`LU2x`NI#uE!t@jeJhSQq>OLI7 znoqi+>4z42_P7Q1$n=KZS$j#Gph&6xM{)6ip}57skN-wSb93A)A+|miV!m0U*r>pI zHhV!vJsz(5>T%Y8)ncrE6mI>{Do#~1#ep>@|NN^b-ujYFXH75Dh_ay~l?8FWML_@9dgBzzuj@{(ueeQWE>rFUnv=SZ?IHl<0(?? zIzok)s?jqAgaCHH_lIuKmR~)%TVxV^-JZy0HG^P*PCvZc{0jY-Iidw_qOw0}e60H$ zTDZ*vqAafp7HJpgrrkoS(F$eV(Yf@uNgivP{Na`VA3=6!Ic3Eepp4Axv$8*mL2=9$ zR9a=hmeama$Th7Do$^4qSWyNNFiwnx2u|?#lbB! zq)!NU*lDuDoW3~r=w6PQ^jtjWT|kNZGttGr4?g~P29I83Lsxw;>y+=OSEhl`cv1=W zZrvfoetbq_C)b$CBEE?ntUo_19+#kNun}) zbI`?H`t3CXdw2Tq-g~~-Bd-CYA8dwW1A^&5^kBa5(*Pg%cymKw25mz(&`g>rULEPr z9%|-v_w*dPn_JI1=TqA{!fp})yY6_BDidW5Q1^4YD zBri3g3oA>-PCFIYdD51*SJ#Qt&6VAboOHnM#FV(z(MUzap zN3bm0dsc(>qe9U@ZKwD=NC7v`y3hU{8XT=t1d|5G!K_t-(R;rRcfYa(U3YE~($Afw zteU;>rs+7xXWGKq%Wnj6^++sv6$b^;|MKI;XSg1xCfq*UB>MP`;ls~s;aFBDj9j6L z{nXEhs~)_Q2HAGQE}wm*QRm4%sY7XY@M8!%I~=Fz89<1AD;$0JN18v<6!li-(SF>B z!#b3C;U042SPl)wDLW zC+T%238iJpILN;{E`;r(p}sX&dzMg4bRV4Yyo7dTzoo2@TLc4(xzX-D>8(x{L;6m@ zlXg&;YUgbC{s@LI@V+|hkBto$90pBD>Usw>B~=5}n^vmNpp zCcv)Kl{8cBn{Y9DDD?T2MxSGI>A=|atbgdNa9~mb=@w4F)*;%s@<0=~UK@-0^pY=@ zZiFpWx~TSNE{^JV3GVE!7ux^zM$m9`s$Q{{KNVMYUFuP%VO8Obm?FBesR z7YM4u{)6969z1Vn1-wrk$c@s`d^qI`jd~i-icbgOpT~vN`sM?C?%7U@R~cgU>>Cg} z`6SJDxlP_pbK&=pKsdE?6V`aC(2J5uR6O7`1^QnQm;c%<-f}xaku7`B%&ZtzURuGq z2DYRfZOz?}mBVfKaK6098~)sT1K0i2*=PavVw8wI86yU zb}I4c{92y-bSLeQKE|y%&!Fyl8T|OUg$HJA!hqcT3(ks8v?)-7@7A5g?;XnMA9xDP zr=Jsld^csI#8_|=x3Qsi58_)}8~KQu|8w$$0ed&4H$aj{-% zr03#AE&1Aeznkd9vCEXMnTc7S?g&>EX0f68R(RCf42Hi$_@`my;C{IeWd zVHR9JR|OSXO6c(80vJFNmbAzUsZl=#m5gvszh4TiHZ#erY6HCs(&FsDel&3SVp4Nl z$r}q@MAhX##RnrF2xIT8mn0lmBy@B1L3wqFxb0J^kZDsOHXCfm<>lIJ9bPTYci2mb z@{d9O&LQY_b`uAWx(cJ@Pw?gjH4e7IrWU*x0MR;Yf17c@H;rXf!Q1Z_s z?^kCMFNhU;y`6|%b(*}WD!xXwPpKGvt2=+(WKcU?sggaT`=VCszm8nE4i{eNB%R)? zQL@&VHU-UO(*Zf?^CXS});OXWdeLbmGpv}|A@nv|!5$N&q-L7N^4C+*eM~l8crY7h zW?1rzZ`a_~t_|?R^$uNH&_&~$-f-|2AAWWcvFv9t6u&md?`fOavVJX|7%?3lYk7f{ zwi@4g<%m*q#%dZ0KI{K||9wQO#*TvM1SRPXC^lN+ldSG#O%brlMA8Gn|>@N(Z`5h`rqBA(dNm(WiE> zxf(^g$9DoWZGLTkOHqTiacRGN2B+_Gsld3W>U1vdAf=-dP0$!$egvFAKd zqc8lN-2)@e91uH~>ruPIR*b*?T~zrv38ria<<9U$F!0TBa(dE1qX1k$qrXo4k{+Da zmtRj^$ZU2%X!|e{TDr{8#2)53`BBc%GW(J;T>0^jtB7p|6m=GJ`| z@#cVs@V8VB7hf}E?^~wQyplLPGiM1G^C(R4@dF*t-JJ8bAJ0lHfPr#=pKAh0#{B~g zPgX;Plf(vV)zI!~e;Cw59$((fq?I^@qFTZ+I(Z2xmsbdzw~Xdu$9y<4cQ!pdcL+L0 z2a~ugk2XG5z%A*qqGRKC@T~A9`TTHvo2kgUr+>mFQIAWjyM&OU8C3r_hs+iY$9;OP zEdJL{9s@SpwpJMw?hDk2NmkmaEE2}pSJ`sU2T?!cO zyq!*zDDZJxZ=O>>1}EAja!9GR@XBaEI2tD6wV5V-?qf2~R!f7=2~EPNO{1_vzL3|u zFa&29j-tXf2gBS_Ww9MHI5aa6IQI5fP+eY!A%V{wsWc%JKz6+YqQ&>zT=%h^?o0omJ`6L6H;N= zqoYFlie4z>ouU`vpJC6mCa?}#i1T8+Fud=1JTA518K*2MAaDUc4rvhXH7jre`U_># zg7Ad(TR3*agvTe@u&bFIfBD`Q`dm*FrM}%jrAZy%gzx8wjQ$w)QHgJaPQVvu^M$rI zkz^2a33d$)C;d0BxMrCKj<=~Ng&)LMPd%p|&E~jJWjp$;xh8peb{sX7*1_M-gB&us zl=hj=$CBjZAiKAn(tK8sw3{;yG7@2d=0lp}Xu|GOLRsm@HjWspicyLE!R!14w14CS zf}t`HtkT-!<_i=0n2edvrfuf)RUs@YBjz zkXToV7yiwPuG|fAX|N*rj#$Gn&(Bc&y3MZjmiuU0U>v*l?4Vx}-FZXvR4AIFkIk_| zA?3+De7_<>x+drqV0RU~n&p6T3zySvo!7$QL5cKrm#m<2&5CoE*l^YHtpGMY@U_Gd z^j2o##`F8B=gu#%=Atn_etiW(?UZ>uMB%X^j zIdjDlQkeZgEGnJEhnu(4(05DG`~4g62sr>j?`}{|{slN@nkL;}WzLeRqgYcu4wD9q zg~)0bn42=5f1iti4dMVyp65%4r+CoVIYGF)-dWr?<`}5F?8EDZoA9zedjy~7+r?kL ziX>+^gBzaIQiYj-jk6ALqTwL4Uv0-ahvMjDR=)7)iUR9>&Bytk%-gEp!YhXo_^vY< z18Q$TKe0lb6bZP;v520&F(rp5hhXYS1CE(xjqQ|4hsLX5;VM@?yVwVMM6ZHR8zbpg z^cJx7CY1M*@B@Rt;^UpktZxCA~`T}fd9Kc6o`$7+g zQ`Bnxiae${vizFSJU7E1M*4)}qo=RgO?H7~_uSPHkFF+7sX(j&SZ8t z)+}6;i{;t@N-q3Y18bC=dHu%j{W3VHFwHE6CEPa{2Uf!r?*j#J13_x=-6cJXKmTzC$&(){?Q zp1hlX>|e24(|Z_@&&$G#kZN;QgX zTJ?&W9OuBvu`eMzXg;UCmE*x<`qAzjTfFaOg8skG(Aqm~g7WwV&@#*7)FWG=_Xj^P zEbV~9T1mpVd*xI$!U40@C({@W7tkJR#MvKqz#^2z{avXrCDMR;4g5jPW52*Uw{&vd z;VzD;kHu{x$3p5)3u-IgLvrh{Ne*wG4R81Qa>+6e>Yt(wY8JA5ts;o;?90XANftuU z)jnu^at^=jP)GlVPPDr8ni%S~1LB+S(K)SuEMc>qN)`Y6*CQi%*dr5qwdW)hQ#(0m zg>#(wA(8})!c`4DvGE$<)w~1>ZtH;QSt{IRGLVg~L}6}9q0qT7NNPiGXUrC1_Dz4$z2h-T3ut>P@+5v|J#Nv~d zAs7>o5B&slc;7Xg&C1>(pM42QO^SFTb~C?P9tX=q%*n&y9W6DQ#e-k=W`oy$eDN}f zeUGYB#I_pf(#i&}Km#1N^)>kO2nvlJh?g@{c<=X0eEFgm#Eg!_lT(7&{f`O1ni(jV z?9!mRq67|^VU5R*o&ePeH$W-CieXvadnUX;8jykVd7dF-fkO<4!+$vV^u#hcSw7^>{Bc8DXtS6G7vlb+ML z9826-6^7QSrDDdi^(3v7A#v+)JQdiT$CbVlJc5Sv=)g@NDe3~vj7U=cYl3&L0c+Vd zK-HT~IMR41YSbsv-7Rm$i9NpvnVAPfyA9L1_(?9CY8m1b153=a9FP9~n}osR&e8Cg z?y!4QWT%?DH9%aK2X#vL$m!ZGl6eFMQ+yZPX*7w~F%5e&Og18rIHBwn@Q$K#W*d{=Ku zjB|z+gO)?vxuYEJw-6-_&!D}_81J9a=i!ld+}fpvnV)qjQZb&bSFYgL`gWQe+X%kh zU7@l*RoEP@h;k!mV#1Je@bfYvixrKMB2QB6lcO=v~Y^5t*M_|pQ z&8)@0=(fT{a;cbzwtp*N&*NG+%2T2L-V?&4v_zr#Z!7sUev|qJC1X{5Ma?_)XTtTl zGx)!6W>_Az10H2oP}s+CGJKkZ=RX#TTWZp!0ZPwFZeUAI?vpY&Fkgoo;gl;ptK#VB*1YM?k(OglashyPY&v(2VZAJmiQ z&w2@2yYGtDo9#KR`VP$Lb%EYanZ-V%TPUXc7HH28hl8{KqoPS3qKmf^ju0d8W=Ab6 zuCd@3FTc>|{17~A_X-w_bD`IduED*kJh(ev1N(dr$GO+v0G|3IEeKrAk=akg%+s12 zrJ%$I%dC0jV?7RfZ7r%r7W1kxT7ucT$#l2h1pH4!9X*vV!ogGDz&p)hQJ$3ata7&K#7UG>R>L+UVSO5dR*3gtWS? zU;`&}Tqd)bV{U8UcO@U!+M7pU#m0Hy^;wDAZ;r-<17>_Q74X%zFf!`h3dg!ksP^PG z;Y8dfq-T<#-(>b)e5q$Pg0e{2u&|_8_?Uv0D23P-w z8QTVk&eu;+^1&W_DNBzVO2Y6+rM_^md>gcCI`ZjKmonGR#&P8?Y>}eMZ3`{A<=`)Bt6IXE&+dqg z1{*--(*~IAFcfnR42H4<2Rys7ORBT)B-SbBp?ktlDpQ`!`HRML$LubMjF`ydPyL}+ zC(Ws{<1EYQ9f21<UP^wK1PmE}%z6aj?&?OsMbC zix;0CL(})E7-Uqa)V<=8r9 z3J9Rsrj` z2>P*wyym$w{pak2LpQcjZAc~L8Z6=}$yTBC%3-(>a|WKf6ZI^vp?x*|(MtUQ)cNT^ za33W%?>qyH{`bEZ(QA2%`4hqKMR)XX$)~96ejHMhL4U8rvQz0XmVI#q3br}meWjDo z-B3#DwU5N=UCVHu*EZp>{0>Nnt>#ln9=I@m2yOYg8!fc9kma{F0%b>O-?a}YUfK>b zBiq5@KoGyO@1P(djh4mP;n$6m!1Mp_YiFN^thsaevQG;3N@CVND34<{{HE(V8Tit1 zi?~e9i*C(mhMk$iVXRy^8>~A8bNWY8?>n<#zpgtw>fRPN{S8H}>&Ga_CyYOLCQ;~y zH8^^g5ni5K4V}}cQ{$Fr!jHoycelrl^Ct1>^Zo zpOGA>_+I?>FtDjh7sd2}Q46 z61?@FGb(H{=8UJ4#m;W|;yL~#_Ss;CEo7EhfQj+=)l zX6qwi-GxSwmlW1?E7!(_p$jPUpGPg}(+k}S&SJmo=V^SH05$XK z+;f!`+V2?5y@qVVNnTd`y?!)~JpsJ#!FD0Z!;`EtnrZK_ofPMFjy+SqyVl8tiVqFe zqUrzxj^ciP_1kFge^`@U#7vRooCs|_0+-}@-)0uI6HhO7nhi^}hLWNr$y`Pm0 zH7*3-mMZg@C8PMP&Tr~{R>JMh-7&ehttk0wfb}__gxww*I4AcugdW~TMPSbnHtNte zbCB47hdI`yNkz}m6>v(|M9lTg0PQS!9%3kmnNzB8%Y_NxFn$;Od1%Sq%}>FS6Lx$x zY9I&hosV|!{@}prn?#d+(>S>$fW{QugG9?DDr`H*<$hBs{QW>4v3MDb{1DHRx23|< zvHK_}Y&vdUdJ&xJXT!4#7vZn56}QfNAgDH)vDfX(kfZrZC<#jhwfub$J%1*h|HnoH z3(wP?qm>f*qC+@lNjJ>e(wB55&u0B28Z>=In=nvChy6c}XNw`@NIh>YrpTX$&OZ*q z)8n!HHaY(4_;|HDF(!%`eI{sX1m`bq0IU82Du*C<{4IDEL~#YREl zU{N&?@2DOj)r+2z&Z+7=ZqjhE!Ba|V!$wkMA4J0)(J2R1y|%l3B~V8&y2?lCA{ z>hkrN)T4F+J6p`b=na=C)h`c6z5JJ{-N%c@(fj#R-Y%l!S47n*PJ&*m3UAZ}I6XCy zk3P_4x!(t%*P%FEFXI7c>&vKU`w+<&)92uI=M?I??5E9-d-GCXBH2F%cxH2lG-Rd~ zdo8|0BTs2yN0vJm`uAt?-A+2(+YN{Rx(UNKIfC*Cd1yI(0A2=|fkBBP?;Ws%pH`T2 z(gJ<)%eyG)%JmQ7-ibjNx_L5&WHGF3*n`_NIs^|dC#(s(MP*J?c~tui(vP)ew};0e zOHIN-Q%kt5bqKdNh0*tuRv4E%4WFsZpy1!?c+zI1XuGol`uL5;^lly;c3=WDFP_XB z9(!QV5j)^(k{n&_tpzu`wbSKKBdEB}01Xun@|sM0)b8lVnqlTRA!#;!tyv5gFUq1< zg+EVvqRWFWRicX3Lb44X2x=L|{5{4Q3$@CiZrThsFVv#vO4__}y&bw7j*}?0m4Io_ zF``UKuE=X=z~GCYDJp0ZuHNj-A)O`^sXvxu?W^I&rstyC#xs)P0cLnzZzPNu5Q~TG zo`Ci87|ctU#VN0!*4*DPl*hV#keKc*a*4>6<FjLWekP!x()3M;*3rH)Ypeo2U_w2_x%Q1)!f#S-PHeZYsF>^vGWv8e(B3^ zwD(ZphD-2H%T`!kp2kx9RdmRWpe8hqpL$G#alhZw*1`d(_~z$`$@E}OD#xYe@-fUO2}X+wb0ix?7EO(4Ya=g<0`%MLoPeY&NA0z6h%ie4$l|>-m|(POw%g zz>miUb5x3)Thh}?I(+UN4AjbGmuDV4vhoWYJ=UK~WFkTBa~2+-SRy22+o>i<1;46E7atx5BN}u0*f2@SfRQEaq}CZ9xW4 zmpw{L$1j5WzgFOW>kRfT^QP1x$?$n?3QqOvq~p<}IX&k#Ri3cL=5iaD_bip8V^W|~ zSq(Kz7NPx*CeXXmAFbsR#o+Wuf|~6{3iv&p14Dwz-{S#A4RhkI-rt1{yH?}-si(nm z`bTJWnnEQ{E&0#VK``jsQ_8)OK;@aMSkJx*=3h>RIkNrH@Kc*G^U-RG zP}aiKtY$i>cMKmaUyCE}oJ8gEtN6@(eZKYX3>BuE(yC^G#;Jy|;VZkEroY`e_QP`N zy9=EVGJGCvOWgsltk=`flFeW=SdRkcZ|CrTtP^7kaLuc0Z{ZDU?J*X+2UkK_ zX^T)LY@{9E*J69mfzVrFB}}z`Kwr*R(T}5p=+&Td+Fvl|AA`@~$hH_zwlv}VNdvH} ztX5bm3=)zXmk1wD<ZzB@tFI5qmVb|ExP6XDv- zR2piw3}WK8V#hHB{I2-4#tyV7N6_ZiMF!O9vV@w zhg(6@rd~K1qe4kj=Y#h1G}1mz|3!#_D0e#z;Ef zZ3cz4|Dq$2M2U9{V1;5XbaR^mp(BEXN-aIGP&SA2{cQQc0t+rt4Pde7RCL@>B+kDZ zBAInNmd+m0#NnH*vESV{l=EvMy&e3M%zbNNU85S-bVWd-;(DmpxF#8!)duZ0+C0Q4 z7SjiK@H@2@s5DSvBY$;jcGQ6XHY;&Sgc^#a6X?sBWHufOkd_|={hTht(;xe#ZQ9k+ zMJ{VFN#BH~J;-8dFKztkVTo-o=fh>g>!R{2f&RW2g0%&*TvGOqMrlvR)0&F7kAGCSMU=pDczSqu0`(LnGLX)rEkMm!v7nOOadR@SwsoamJPap1$6M`z8MotB3v( zpMEzasnI%ol%{|^_w>co#EJa3>5^!mWX_JaS5hwpAF{K|gofaQ(z?1I!qwBhs2Xeq zPkvU>c;hoYP-J^`bJB4}u?HC_aOa6>Ehmu4c?zQV3 zN0xpTWSsBQ{As1IckgZ5&}@glq^nWm^Hw;bW{cS!#^B(30W-^<(&qfZJnVw17~H&u z9;?2C!atGRIzX3=@1Eggst~t-d<=P;kAQ33BdR={0XjqCvDfxw2tC#WaUKugP+>d{ z+xm>Evi8B$A)5U3^gK~_N`I~^y-B?SLPTl49UnW9z>|X;z_ny9E&SaVwTpVf+!RZie8LISRi9IHbuwJ? zy?~n*R>H{g1pJbi$eRLtvCa8%+UxU|O5~@(;%FN#8~NZLt4t^7A63$gUng+W;}pob zT})nA>t_qX&3X3iDZf7@@jXGCBYffLLldZ{IT2vtX z8Ws=TUuxj3;&+(#AfLJ$6q57XFrM=4I>^7#W6M=8WZBWkE==b$9jGL%~^;WXz-Q1hIFL1-9mA!e{pagOGX*aGq zQBNZ>W+9%b6DK~*60lYUGM~2dJRV!Mqy@5XV9)*hT4|(^U zX*^aFB{Igg*h47=)yA3gt~ZFReT7c^y~VwL%H#SWiM)>WWI^K(q7H%jgV#`=F(p;e_rdeI$iEF;WBNH7|e+YOb zd%tMB_5p1!a7Md(TFkTu+*FtrX5_+%3nld5sk?%Ywl=L?6)%+jUJKEqi>X_R6L$9T z!?$a5QEU57%KodvHoYC$H+vV|Sw2ZPFffAR#eKroz^&LXuoR}guNUZ=4d=9fAse;F z^w4D)uYS`5+PYoit4STS^)(?gNNxwbBcJ0!X9;lGo{X$x>*Z->}w&(q81jv z|BqZMgIKZd9E5otgVa8ql8=|m>AS}cQ71D3Usb6<*v7fy4f8w*ZZ77l{<|<#JDs%T z+M&{Ei`Y+N4JGM+1J|le{Q7GhEURr6isdfA8pq2dt7*(@HWA(ZnkNj@4i|=9I!&h4 zig5MXb|Et_7ByuMa)Xu&>o4o^j5o4uvBVKfRS$__8m4&d_yKM@whBJvd=+Xgm&4sK z9bR?Jol^uqJpMdX9V`=xvYWN#4CEpn9<|A>Ih%BNmr+T2oFg}GX_aCEEFbYSdjl_5K6Rei)rw?Hd;Ew1(%{#S)#+$+1EFZ&fZr`Eo zFOQ)nZ}za`?E4HU6ID0De$8r< zs**SV7f?pd(t&tWsz6tFsqy&iemwll0Nyy-9Gw+cOFXCF0&g8NUbcJ`ez4gNF1Pv% zo}bOQ`1>e)vg{J5B*>s#tUF6=ra{H*R(RC@jXq~A<)BV^UiYn#=ZFWW*)4{YUwGq} zg{d$i(G$%-UjuuKA{ybXf~%Vsps(+2vYk~zhkBLM((3Etfd5XAPLwLE%(@Ca?w1KF z`>k-O%L4qSQb@CGtyuTOZ4OT@!^_XT@3XO0XUfqjF=;;|TisoIWErE178;5ehQ~Ow=r29* z=MQaD9k7r6FzB8$lwZD?in|N{F;I`m@Kh^=|u(M2!Wum9Le10%gqLGn{>s7*`k8BQ%ia^e-yFqDI-8go5 zHf?(8hkas>GU%jJRF8R--yVTyTzlfZ0f9XI=`MhdEVA|+gj3xWF>1geo-4#rLQNZ` zS7qSPq0N*kn@J;L_dv-572eZF*G&TrYS%J!`0tP_Z#U;TdlNZ+l`+kDx{BE2*8%Gd?7cSVZIV~()@$0OkI+L^vZ7~_VeH-y}4YhY`I z86NH0LvwEBaOR>7@OQvqEFAa{vJ2!W`_*w6(B2bGH|DzrhK2IXDWaIlB;bnl+1 zVDz32sH$UIw=eJ`gy3+YDOB&-N~S;02=}8ukdsfLm|C)z^J`_;I{PEl8fbx>*av+Y zj=&Y4NL+b2OH9yLCR1}`^j+(QvRM=Oc#SUU9%&aG84DNv2mjY3$)w^b9dL1P+ zR=|h4UWhsK=;xkp_(VKSiogEl+UVW1$)-u@>i0sN?Qcs{hEzhN@k4qyY5%`j4aW|KvD9v`65Tkp_M|MmQH%zf#^S236<_mT9^mV+^m#FnzPc&%y?MQG3BWS2Dh z^;i{@dL)xtls|W7YJ%%22e8g8*l4*Czm>3SEz{LWVx>S2PzT#|&3rvrGOLjivL==Ebv?u?c*Vhka-wstY*{i}WCXFy{Y%!$2lZC3u>TIDY(9ifxXsn$nItn(_ z{Ouuq8Wc_IiYoZbVm177$BDv@JO>%s^{%VG$f4)%IoLeAgsU$Xpq!NgI{i(+8@C5? z@tp_4*QR}vby-ccXpAcRX(sUJjn{?RL)LiCM*+R+{iQ2^io#-XKa|@F^y=n+EVJq_ zEj5{n?Nk55rTy9jx!HB35pF`=)Sf`$nXUBZ>^Hi#b{p%N8i466U8$~Z0PejV3BPNH zz~HY{ptw4ZRxT(L%BIbu=_@8sVR#5?Hcg^|Tt+r6#=Mjq;a-X%{{9+Gfl(RsqIWI7 z+HB0j@8`ocIbV#p=O>6XgWOy!v3AltDDO;0qn0dAIvztgp<_AZp(WNwiNX~3`Qm{7 zhoR<|Jj8^`NXy3@<#B$WK;g0h*1evOQL-iQX7O2yur)-vDjh!kJptbw%M&$^4;Od4 z)RNlYHxgW)2=8z<{}(b?V&4BGt?hImd;Cgr_8Y|dlJ2~_2Q+mMNQ zhr7g4?E$Pby;2D3t1Xd)8St_WCDe<)!h+#gELA=)#`-Jco8s~G^y?kkH#!jq-M8eA zQx3rGnX2IP?j@*~yE1iS_Hy>Ju^McmfYZ3y_h^ z!+ia3!hE>}FsHqNQhgG!a?n=o#YBgO~l(~g5D$$a~0*!L-368g#+R?Ikt#*NvSQ?*Bo z-1wG!omX<7V*|i<-d_HB?H#plub?sceOP<*JlfQ{6+SP00@K_2LGaohklv>OYHlQx z#VH*O>g6CvN@t+_l4y!Iz69?U9j0HuW5o66(`k>RBHx>{2p)A?#QEPr%npqKt+A!h zU{Niu>m$cK4!r`?*Hb_}x`vi*If0|b?<6Pf8W^i($-A!=i{7TDlE0yz+@bRj_P@|Y z`2t-i_~&#!YcG&j=UwR6rYGJXJdEqz?5Hbd9;_NajYIeB zo~!>0;1m*BmC+y}MU<6>68D^z5+#*Up`jru4W(oxD@2qu5S5h_sVIE!Iijf_?V&{p z?Wv@H|3~+AAALR#&OPt<`^m+VS^4lI={`ktpNFsRMmYRaHjhyahZz4lika{ontHt! zkGpS#cV-@Fo_C6B*WIQ^y+6SH43QivzSHk9J1Hfu0_>$Gf`hZEV>`b$38v$AgMHf9t{rT)H~*) z`&Ki)oVuUxSo_f7zz?MH;jH-Asu&}-)eFn-B?*zO30$(W56D^9LQTtEC>Jq`7awtxWQq^SFtk{7 zu5se%p{>+$sV}O%b0FWIMJSgYEXZd#Lf6Mh94s@My?$5FsMvCPT3}9(8V&L6MFldk zT>!QZF407LZP?~xBkFV)P}{;M;`we9`er^44X@|$4+m3PpD4pB9qK4p^aH6M*X-X# zNTK`gS7PibJ)4LBK{aKjMZZH*XN1i9Q?Gmv# zFpaEtt^(7kvncGvShlH5!hV{Md9sHcZq4aWlC)ExUv9z4eGT~ApD5hgFIFsg7>`z7 z+Wh`ofw(Ch_*3cuD)>7WW}ez=Uuh%YPq_`G^}09OeonFX>NkiN8Ehw|gfdaNG*`$R zlS3Ol5`>`lZy_OeIO}{zKDHrS^cZJ`3;s2b%ji)wx-G*#Z>TD6S+ojL{@uHD_+Iq& zC}PXKU+9*lGrOgIfT|wRVs?WZX(UEr&ihsD_GlDcocNeV_n(G>w-WSC>LD)lECiQ2 zb4b2Y00wO`HT%9lpb=+R;o8Y&xaFuZ<{mvmTAmwlylDZgmQ5$q4PR;fe^;TPtpghd z564(jciNvE$;%x>NLA_#O}_Vw_BPhyxOEw%v;Q8X-E`(p&f^j1+R|;GZCvholD=kl zOUyoo+OO11B^wOr_B<5r5K*)bCPocwuwm>88*F{hspI1 z=toVAV6;*O+m$XuBAf8#{mV4DJbE5<<~@d=OJX@ht&~~>X;#`Y9?e3ZLcXm$PAuv}=i=v* zR$o)D9_7LKyN(LmV#MN(d6=aE*3C}c(^1U$Ht2eXf$pCZM@k7#f@=PMeq=ojU5tj1weCb3=FU@U1) zq&poQuyxbYV)^EcnxVB1CUFMRTfkQ0nDt zSf(q7t_y1Io3rC6Fd~lZN6K)IkGI4V0U0#tv0>{R(Ky(b z3bzVCQqSPcmJ9Tzq=YrfAJaCi&f-zxY9Q^qu3+!G2W>H^2YJCfZM6BgGX?Opj zO#-{L=RkGq4Blo?1MdCjqea40D2*M!^6O>s!h$NhMI$6|Yf%jaUDu^}`HzBKW*SMU zm{D>{4e6e}DTJ+!g0}80@W-iA_~e=)Cg0MA)_akZG<`n&)VjeJt@U_O;4KkfoW`f& zA>yGc*GXIFh@iLL5ihodfY}ju*cXz9Q{-F3-G{!4vO*5|tTqjB9zW1io58;X1Da;~c@_kWa1KFj;Vi$$4Ck3C36DVlF~w?nL?UK|ne4VuS? zqUq}@_)#y5qT5h*ySx_!>v@=T@Ua;9vJcyAcuDh4so^0XQ)tT`%I&{zL-&?J9J*VL zPZ)oZe1Dc^pZ_)+_V_5U>uyBVgmlm@^2aSRkMh$?r)jHq5KX$e8_l1z*e~~+z^Cj} z!1=E-{`YG)1pMpnpr~GWGVmIGE*=OzUr&lAd%xHRE=+(GC(1};RvAmL+seDkPouo9 z8}?OF$3>23Y3_PwxG~fVY0+V2Hv`pLNNsvq3WUVc^cb{8CjS9TQ@?WPWN~p}t0o9Kl;~DD);g!wj1eM)C;8N@pI`w%Nt4P%F zIXYD5=qlUk z+M#!Zg(Wk1MD%q2mVQ{=GygTDp-1#uM{v1waO^eXC>>8|$zkvHJO!?0t1$3G3O`%~%xN+e* zdeQCAuibKmJ@qSS;DnpBb>KK2*B!y!ZABMX-GT1NXgC>fgkZc`Y#3buZr`N1{a_KV zqyzTPwyDzd8E;^7Q9gZLJqBBEj>N)c;gIn&93Q$5r*{K1Yepo*ac4sk98yq3tL!|G z+AfMEd814(40R$oHEOnrP?R)r@`7hTlp1yUbt6m60>l^ z9uv}8w2B_J8nU9yIq|LKb!f=>L9G|RlV8dia%ee=IV&&augdMP=vsIBmQvvH(;YOyS#UU zo2jW37`*{x#^u1>``I+TIEM9hu_shaH5U{w!|C->wG=f zv^^O&_;=&urPAy>aunbF)PrZ=&xYo0fz(qqlb87$ii5p>@S`7>C`)5DUvIeyX=hdJ zA1Nopb_Fl2?tTuQ-eDxQZ7xPU&V&`IU&ZHv`IIp~m)2Bnf{K}HyhS)6o^VS=|LUjo z*6$8>%ig1={+_~C?XUExZ!_7PEQcBwOCDgF%611=vHy;>IJEB?>?|3B1C4sHjHNMz z>R*IUm%^zd%2%k$8pBra19|L;Zi&?064Cw4F|aVoxA*A32Cp5`MfIvJd@wwh)%?vk zTR$6=H)x^|FG5jjZ#3U#h*PKA(g4#4-1w?5UWi=5`jwX`XiY7}f432IwM@AWq)^5~ zSKPI!fZLj6d3Kl_nj5NNSp7^qsHVncp>B9#&Kpsqd8=?;IuwT5`S8WrhWKVsHI?n@ zkKd>4q0WRDI8)>dR!LR#M<?BK0b9 zU>SP_ySz#l4tjWBEWSIOpLCDMrUN6eTzfuFXsm|eiS_h!mJFXhHx0iViNf89JE8nu zAhmb3!~Au3#Qa)QPT1IK-*3JJz6qVhcN67U^4^8dE|9{0fd^ov%w-bfrBLl!2%I`T zieHE2qH(bX{{uEoT4%#9i|#_RsWuF+S;go4ckqGThrysK9A9qdu*(3q zkNkJ1FX5Eon~KNsrU-*`27uw|PqZRB3#QNgLN6Xp;z8eEQ0Dp=h)~d&QgA;FTtX9Z z=fFvveB)c}^kK*eSo@)n`>fRf)4lO@ zv;Q5qyvrG8EgmM=P1uSj9XrY9$^{E}8qgkb~YMyDD(BpnH>GY1S@JJpfsaI*!7<@d|&efweU2X^`e6m|0*hj`O!g=e2~l z2TAdi6B^)iyq2cd%ARTC%0**vlb0QCzndtC`|GLp z5K9zinbNieBY3FecCJ~f2;cJ;a+HGx8+*G^>y^XMGD{7m{)~jZV~}UDw>H|gZBE;^ zr)}G|ZBN^_?Vh%6+qU^@-#O>}&%JNmFK?=Lt(Bc*p?2j%lAY(tk43HZco=2E5?^NY z@F0O8Gd(C~m3FB=ANSs*9ZLQ|>DT)}_Z7IDKK52?SWV}4YA20juBj`S>m}5?VLj3t zKee!vF8zbsD;+fYdPK9j>d0Vj>UTT#=`v0=E~X4C z6VlyK;_&6m^QCaDtNd>z-OE&dlEBh+uk8*-;P^UJ_%ZJxw;8>W`WEQ)CWo*{IZW*J zIA21PDJEV2di%&qs!ossud3lHYtQ=44Ewyi z%%rMB@0Y48SA*bK81XyqHO;DFxbEeG2}XF&kDC@NaJuKf z;_8dV_meQ}Y8KdzYc11+#cBj~YY1#%!2ib{XUAh0IO4y%QB^s;&xJz8%jeA2Y`-!{ z;io;f{zHc0YgJrui}@I$3*LMn&soACi{g4M*VJ1{+?mE2#XOzh(?SG`$AspGez`Bg zz{g2jBw9nf*ymbAQH$l9dh(nuVJ^Q}e_L!?+&KmBg6G;zxsXnR3{K z?QLM057JEdSkikdr@TW-)qi+vR@B z`laD!K&gB}Gxjx!*72LtxXI>j{c8RW@ap*PatUU7Wr_MyCMt5~ ziJEJ~4u=o-vOk^)A=B%nv9`?_yIGy>DH6yPhZFyMr?X~l`T~d?(MB{*ps2pWnm@1W zcsAz|vOZL#9pEkpgh)vcAPRdpr(p#OKTjCcI4z6jt(j+%<^719WvTOe%=SA~|>?^M}&?c{wD31w>C-wKA53S_6ueh|k4~T?iR`5^X3pm85v=PLrnRqb|K93gB zy9e+li|lvB=BqrQjRtBqc{YN%!|4wu+cy{)oo8H>_m=^(z^3}Xx3W7YPZ)hExm1g% zFW{Ds5r^9!*1LMv`Suli1s5`%E9^NbVRI=}A7T5_ zmPmO4aV0;1nb+6Pk5;RN)4UHRZP$;+6FYr4kEz5*A?9I&dWFK@oeXD;kN&CSKp%iL zSWRp+YE#*T@j zWO$69S-rzN;sXa&(ey3~SLZaCbZ>XKZXsbP@`YT811GqCI$0>da#@NHxIpW>} zE1e6iTc62t1=>Ofh`nm_AAAnFe&(0XHgd5bmW4Qn)?&?U1M*qB%g^yiZW#>+YwXS0 zIMFEo(-b|WTFWb_GVy0SBQX=KQrzd0m=(|~LN=?tC?bZZdjWW5@znW|adn3~mC_bM zN26i|iRG1@qz`z>fT9!WwVPY9_s?f`0D8_L1&`6tJH9mF^Ot6JC$lov#v?G;EdU%Q zs)^`%i?wCUDt|-Vw}5C7N1X!`x>G-wWYx^tLun5vjMQ#X@tJa|BB}l|%xLb00_HVy zd4BXG`tE4ZN$$)rxH876?ZTa%CcQU*p_O#Kh8c(;{1Z4v(GqF>1I#SM4#ckm>hksE z@zV&A)Bhdg+P0I}4W=jYxrt{8)gPt)`-E=Ztc4!JE+PKChm`htIgNg(Gom4dhDrM$ zAb54*-bktcR0k8{=!5N*!dC1eSHdiSP3eY}i=gYII{zedvb9^vLho7wE>h`e6Y}N0 zug3elFp77DkDJo-;RHfbmmO7#P56F$n^#YrY}TeHi-bCN;1ayE;ID@E=Y1dk^{yYv zJHlef7zQ+gQsbT@Gc+fi4Jf8mUZ`{}DVMt``t?bH(Z-QY2bDikj(Fx?UqxD#eRZ!C zisIrm_(RM zhpLfdXzb$T5#Jn!Ev@XtlN5{kHd_( z96?h5D~i$D+ptl+H$kBDz+|5cAA!DiTmankpu$0JR8;tih?^?TMTs9uE6=e~xgTOI zVN)XdEq`Ir&R~0Z1_vZsrlM^l2`0E@LD;PjR?Qmt!#%zmx4pUGeP5IUa9)KhGocOn z&GB@a%QxGs+kO9~pT&bx#7Sw|ru!EMbd4L>{<|oo#X$Tdug8$h$FV)qZEa2@e~s4G zlM~F9e@zH3TZ`fC?L%{iFOOSYs=||*yu;_wtW!cG9@AB;fyb@}?*nNDVwuYyPDT83J#iH~>%taDBjuZ)+YL{aIn`&V;2|oqPak+{+PhBrT39uS3A$nC>+UpvhTC} zi(WtUM$i_P7Qsd!eJ>f_TYoBzMni`H-a28S;h-S5gnu7uB|nmMapSOMfeKpZzak}v zkhY)EgmJh(2zeh8N+0^SQ)vv`I`_E&ICZB-Vw@*gbH;_07QZ<3#42PRm=G*9`FABY z(nQtjvjNp(c0>dOgwIPn&1uN*d$|nIa@Q3sadA=QIU2}Z#zE9t_R^wbTh|_S9;hD; zHiJWM!L~rJIyQID4eUkb%8U-Pq_D9!ND+v>BxRg(^)3qTRC(&z)kq# zvHQB*mgrZr^xe=i6X5d{^?}b+aQ-TUAG$1G+LqM+oDE1R)m3sPk7}6Ue*Wo~D55;U z`6PwZH`H>Bzz`P>|JFw&EcNHVd3BBbd7?i{#{*eE=0rn~AXzr@z;{LT(r+xbg5@#| z(dk3deydY@vW#o7pVN=kC72b4hG4MyjJfY1LN6cJCNF;b6l@OfzAwxmkLRgL0`{UG zDQz!#e;H$cUVXw6-FV4FrkOp04d3sx?8mzK#x<}fJ{y|Rs@_yAj7(ogFv5&06N*g= z`tN@e!n40{{q7iz@if)IkFH;wUr)l-GUI4354s=6w?D2W+zZwPIZv`rcasyoNbmK( z$J!l{h0tLEf=u zx1QGR_xmI>-CHwp^j)a3Ag6|LLgX5otk~NS77K@D#OYmK0`ygKg~yxh2kA{MpPnI9 zrdDtV>#&KTBdNm*#z>;)x8YDDBg8IPiHrr+I4`#yH0vyO;1tu!r|{us1L%{$yiLs+ zO(*XM!=<*xPX=5QY}gBv&tFXL%_w1di>9Ob?!Q`%Nt&g?>*xI0Du-W;chf!3ME%SE zHc_0cOYGHmf)0N*4jkC;`{>x>M|1J##K|U!5kjgnZgPX@jc^`L275kz*oEI!Qb&sT z9BF)RQYt><1{}+QABgm}2fgBvea=;cOOLq3r!-N|Y`>*4#4z_4*x|mJ`=iP*jFqN5 zda3lXYRA2`v`X04^7xgro5y&Nc$?a9yEZ1#13GOLM*;CD0Q_KFAye0F@mY-78q zPZ)M0XbgyFZ%kuqmPe4Jgp%^AB8+ZpQQSH`v!kC?#$&Tt)E%Pry z9Gy`#ZiJZdH@ikXmJX8N4f7izg-!YvL{*P&AZCbj`RvvMcK$$L z7~9J6@fvi&sq@FJJZ~<4-Q$-12SeEyE^koBg2VY2>8x{#TmgqCs_dI1sj&_1GuCYV z7IA)fnBqoZvrC@$mnT%a<`A^jZtOu`GnGq^0XqQ>3$pGEp@D~Y@l}$4`&-%#or`qdDTE!Aimm-Q zl2UgogJ>TY@DOF?Ngnx|nc&+t7ms7lPnRaasfh&X% zZBMMfojO}-r4!Q@)}w;2XR~L+0cbpP{H_X4&cblXRRpMwseF51OyFp(`EXgu2abQ; znK^Z|WwKRZc%1!UZrl_!vs6R|bB z@7xC|`kCJHF5y#-)p~;ypW3~zT`0aW%BbMN^ijzjpJccsmI;O@vk)FewodD7PSFjI zb8#8_nnO=w>%uxn%`}KxA*_Q429q#B9*H^l=hx}C*58onpDs&D@KIaRzf~IfESSYT z#2;#th#h`O!E>y-!uqCS$8Qo+v^foe2_RfU+rd)}B&^RG+$D879Ifh%j1EY9`x?tvB5tHJsgnN9)({;Dwb zJWcQ+WcVS)b4_}O6ryfP@Q^lz*u$ezVOT+)pOU?15=81Iy8+rw#pMUB z+C6PY6oIPRK;Ei#4OmfDZ&ONW7;w(ntbAMbuZxf-xxLf6(U z+^dEf2zi`pNW-~4ai1IP({5?B-OZ!pBmy{rs+x4|qp5<~4UP;~2E+L&X+Z#4Omg}b z)a$R)5LbcSx$&Bb@@%rf*)I75nmjGy=1p|A#N#)B56kz_p)jmU%(_QR+Fhp$j$dne zX!L2N%a@h^1z!!O|Mx!ipBoGv#ySL}R>DI`>yy1N_Z}7cwgWyYipZ@Kp@|4Lg?m5V z54bqsijtgzfLdms4mQ-O1MYs4A&s5Y*{sUuED7}jf!(VF5!VAFNi8YTlsc}!!;?J7 zL+erEHoENF7=ICLOl2VnZfUxAGTy6TwEP}O!Y?(bhW>LELhHB!cjG&sSdjEA`a=Fz zgo5=Ds`A}ZaZ6{2dp}N^+#k|#OiX+vRL{_-tv4D)ViFuG0~69W{zwd%khWZ#C9YXiJ|m2j)okB9e7%VG|5O#f*+ zwA`x>p_BVBK#V+umn!A`C)M~JlX`}LH(WtiAh$xfK)Oh9Og)i)Ql8bA(dC|!5~JS$ z6Z>|MVsQeJD>3+2E8I!@P6X1`GLUgeoY28g!dj;0eda32;g zfv7E&SEr|N<5YSct)m76c>n_SE47lj$v7%0S5W7+S4YF_jo1mv0Gv|S5J?HxbrOv%B zp=u3%UpL+2d5sf@6u7xiud%j;Z87rY80SC@8pU`$hVRZ&6GLyVukMvQZA8k$0u%8C zaIAzK$n#*>&k1YpAsoEp+Y4+C%EbERjeRR`9HZ%%O9M{! zD;WDqvi)*n&B_Uf{c-s$MuOezscV%q_V2W}Y|aDOQq%xNx5SL@@WqKP@Ue_I5eExe z<>%M%N=aFkVcn_4#eE>TtY;5<(c238>)_P8Fr51G}ino6p zvA#?}{WEF8TT=;-63Z>>)vYM#I(O%u444SY2`Oo@y-o?!eAZrznOmOj59<^o0nh1Z zvf0<6azDo+<~0xBQZBn;7dWHl=YI}=U(;i6{T#zkLYPV+ z5bE?>Q$(sv0tbzL5g%maG;whjNjW`9GEevH16@xB%{9z&pS5ZIno2(#%F9&Ve^xPm zz|oiBht_s*3uUhzQ$6f=RN^hC3jYK_{)n33-Qr2jz3L+0$#VcROr=LK#gzJJ%Do*= zS>vdQ!32F`pLfC<-tHJ2CQ_#O0MeD;S5;>B=gO4zF4er3*9IOvzi#qhsSSDIBO#tP zLAiC4Jf>kOnR6<|CUENlCjk9{VG+0Pmv`6H+5TXe_SO=@^%^fAt~;C}9lUaTNf-2M z2xjd4fh1P1O60$;3k%<5NbI#~9y0KS>zTr(8uwp{Q-+w@Kb4NA^n5Z*|Jns{bMg_B z&&+(AYq|!|0p5GnvLaUQi-!2*miJKpqT!xcIf@fv*m?ULcN+5utp-&bdvMLrk>ylGHh$?gJv2{YpG?!?Q*PSH=$Wm$8B#$YQHi8!?)`vx5_Z$BPw2Y&KoA zn)yn>{D?8I8V`tU@VW5lD=ZHV3tf}HJCkn3n?(%8k=|aKMSIu7Egpu+plDVM$BS4B z-D`l@6)w=@sgrTRd2b5pO)zh+cjwCpp}4nbmi~=D_pLMoCG_ zIqRc7UataI%zYT=d}$$kwt(ogW-AVVW7yzSOsSoRU#s1|!&AXEbGY2mUscRYQj~3n$;D_$KHl2+ zIrAZi)WiS;M-3@i-eeOxqUO~{5q{uW4io)9yh`+VIH|?&AKevg{G}q;^s)ozwZ0U8 zc9qGEAlOaT2jny2_R5<=Z;Pt~-t1FV?Xjw&2uJmhdgVVPY@Se7)?May??QQSl0bzV>E*2NtC~gaLQpIsg_tG>#psC4Eu5BiYyVV)_YrWo*uD0x4xnK z>x$Q(Rbag38c{kihDE0LE%%fKg5DA4AU(~sqjTaRpxG%TT-$iXrm_Oi2~!WcKk_UO zu>)6@*y1;Dc!mD%I%|DC(hvW*9k)82l()9R)8gk2)W$)cS@eoBP7Q*yIaQr45E%P4 zACTeCW5-_!ow;q+DVV=ypwFdXZzfx3p=8D{3F|$P{@>aZ_%Lw!j4#7OHIu2DX@M;2H z@@60064Zmqgx@JbWylPc>7nfUxabn6c0Z6kuymSs`zABG@Wo6c;Gnom^Mbwz$u(<~ zauI2R6n8V;)*^?jpRG@0KV)55fgROLCbG4%OAi#<@ajny4v{vPEV5kT zHvQnN?~hw-?CaeGU5V8Vu$_skdbAZ+jx<9du#E3httvzD&RJHm)2DY^7AX57-t-X3 z=Hl~4hTLLAIAymCIBl`@I678U990P=EY@y}l)}<)chtILw*GZ_%dn>u(SBs}({6#p zl#=#AeGh35+p(%i>(h*jFszMHZxsm1Ku}13R3MX%)2Q12159TdXBct()dJ9xYr>%)Uiwo}P&h19 zZPNzHgY!JUKj(ABrkLj{Pzrl2MK#bBLcTE9XiiwiY&TDLL@16ZJXA(W$(;^HOdwj^ zc=;PL^LHG*PB`4`c=q0*M4Zu1R00J={=kS*d8bo=UF;hOg%2OoQ3A*< zr@v4(;FWdSQ6`M4yNKx4GZoNphkMoY0A@sk>S^$5)b(JchwKn}k68av5d2(AUas;QLf=DG+7^P+scOv)#uY)Y*{*q?hRos6*T99hr^c|< zZC|+N9wB_fK!@<&lC2-MVGu5;z&#i*p!GK?&>QuDs@Y8$cPozJuAg-aVSBXsM9KW9G^E7wC|0f0)^Nk35#z8O5j8Is!g}eh zM6E`|ipKjPQ3@|klUArP;y1>Pq<)A-yP<*bz3QaBKq(K-h6ai%?Fv1&Nv~wg(EPLa zyti5eCFgh8nie#;eHHK|=2nvHg6AJT36k^jb3-El3ZBS4{zen5wIvrd%8X3ms+_M&v>9~>n#srV zi;6N?O;{kjpxpBVB)xm(km=I(e({8fSIZ4yTk{-oMHj^bvj8epoy;h93#Sb~g~n!= zM%uSG#i&wR-Y?T68dV>~(&d``*hO~b`(m_?*@W>)#Q1n)R}+cv7RipkB<8YpmNe$$ z+ypS4RqM0H5GE71*MTUA3!7}s{V_H-d+;|AEx3V`WfUfh79uilW#nL=Fs}S0jpTED z<9F+)cwyv#oFA7XnA~)>$ceM_zEn?Pn_Uc*_m4B+%BUjK5}Bi~dDYNEp&9RW%U85x z6Lq}JhcH(!5yn@TTu}U&<^6UWaZZ0s1}7}uIZN~_X!z{@69JF^D|e^ue7`Yb_PXxx zU#HKu^UqV@ppi<)v$-C5DAtNnj0g(1O4*T@D9c~wbi?kg#ZC5hti{#aK*0xvM91}@ zTW-qLPFoj|xtO~`R^v!ZQm%cv4b%gdVHgW+4BdE+d*rVA@r9`zMQ>{x-29|Xn7nN4 z4JC5K7o9DNdf7}k?tEb@Cs_vfx^h@;IvLNYfcx{|Fq;LufOA`xkbU`9k=;=kqtm*S z@*Y_To=1$r)RAA+%`6AIdi=aA^O>*JJBSdZMZ>GFvk^^x9R0|cx)0O3Gi3s*jrFo% zhXQeZk56E{6z@%H8MK^vT7mA6+k4OY*>3}@P8ys`u;_TQ^IRIhCh-vR(0UxX%Qyn zTuFpyZiz1hs(Pzi5-^33GvkSUJK02%gAjOg#3T3G zblS~FgPKU<5L-PU{~_TErY9WC35P?EZh0d3z<^XcRf| z{hzCWbH2h^tri!8!!pJ?*;*7b)Rm=YY)Nm&Yj$J!?J!0k8Ioa^0K*1fvTF@IQ+pQ8 z9MIZ23V2Jdf;hCs6JXG2zE@$q91H5U81C6y1QyMbu}1Yc$u$};DArE)-)HHt;@2HJ7UOo7h(O5DMl% zsA#WaQ!(zdMGNoz zwrn<-kFLsdW-1&gl4$ zR46r0^ow~jKMo&o>Mz{w=#aL}2iv8qeUI~sD+65F_}+LvOml$$1>y3ey!Mo$8Gr4zaF)Xzv|l*DZxv3%t~`>WRG*VdlC5M}sLo(=-`+&19nzUJjxBJ-$RhYRS6Y&3 zHF70YEI{j8)1!SOy8i{l*G2N=I%;8_Wv?S2aKbcoD`Qgj2zuXpc+w{Pp!sQlGT|Fz z{^yM!_02ehf1}kO_>CdcgTD-{@;0{^{dL07C<7UBXDN$LgkkVPgo8-#z5c6hfw=1^ zugFG`X<#qz7|D}7kJJqQ=tbMkqL3BT9h@xSYEibhzC7)2gFEYmYwQuz20TV|Ugu3P zw;S@=%r$ioSe@=(O{?up>lymRcR7C(Q%zC51P&L&+$lqZ51o$>g6{dJ%PSMc?qQ|m zB2rU>*@>;vR-w;2&Ub#x6%CURF`O*N^GR@8GkQ}&J`*RE)}I`h^~cp}@H{H$J^Ivz zbx~i#_axHyX%i~5%MU*{aybC>Z^0A$6n>Mkl!JvX^IwSI_#3nthzxFx_PGdcoyg(S zZl!wPRg4zfY2i`#pBXJq$j+H^htX=^WJ6ximg=m2j>zVF*JJJt_d<+edXRRC@cndG z5ZtBe6cx?VMOJd{+aW|hU!lmmly2m!Cl$CfNx*XJpSW>MHyL)S$y!k@|^Tv zENOM#M=<;Uu$j6A=^XyZhAo`2sO;r|U1qy0<^-YbLVJy%>x!MJUIzr;`il%%V>7!g zmJme&eQILL&GMh_KgAz1K9vAhmCzoMs@DbDhI4&$xdptytM6Mfhd%M<9jG~i>bJXb?g0q45%;`+(R4+mRCETzAung*t&twR%^?;9bGMzJos5$x2wVDwHS3{vpRpjH-# z9{YPWd`CiPFs=Z-_^uqkg<%^V3@r9thlfPbuqe(9Fs^YSuZEDd)H^ zWxIpOPfne%xU;p}dsF_!3^Dk+-HgX+&UsDNMYoeGcDP6(eL5Lon(1u@JN>RB`p1LG z1q2EdtHXgYl0)EJtW>*Q{&!{Y@ZrZlPyIm->XDL)!f0J)C$9O1GEP+cvZSGkhbxX= zH16lsRkE~^B#aWrdP9*IrdMAEZ|InI7&QgMvQkq{Q9o)gZr3dK`RungNxfAJG&4W? zeOrfWx>_YVUsvb3urn{;dxHqGy|-}5^SFY?>`cR^NwP*Ng5Ilq(e;T)Im@_a_Xw)~ zM~23H*}-&e?-Za>LY6L%9jLNsx48#=t17I$O**f4OE!h^LB4bX zi&Wt+HjR|Re{&(>aVlzUi!)E#zQWOMn7`m57(^EX9#&YH?+E;tkjpCeids$*99gbK zeY@de)hr`xL0~p1gNT?VTMBseiSv#Z?d9^ocGN>?=HBqu?V~1+>BhJ?g?8w99&aCO zdf$0BuBMvtkfa5XsR%kAl-^`&k5%S=`M{DmH%|5&D6?&Cy3=@G^&uap`<0X)z!567 z;|JVTjd@-6Rnn7;kUQ_CsfP%6W~g~kVMkPkoxWhJ#pXh)6ISRr@aZ%I0%1doa*`#b z3|ou1k4o5S>j~($Zq3p>l@apP&~h)yxzZS9|6*aN>9Qjw9&AzM$TO?b_1N`Kp<(|e zT~H5Iq}Wi1u|}zT4!04UySod_d-WyfFiLEY8Jjz1uIL9(spe)1=ZIJCYU;a@)uVL9 zs39o7oqMXBZzl+OYT#$K#nn9rUL zIQP6G90Am6?zT3dn>l`3nCZ-WMM!&*$d{?|PD_aJTnyWB>lh)MMTcRJkK=)_;?(nF zBcIn&0MfQD;lv-l0>5)vxXy^eczNHbVw*-xsoG)xxk2szGdeDw)tw$+@;vRq8jpzQ zEezoHhI==Dj~bfq@s5~sdUhlV^gl)6KN93W@=W)yy{8wm(7F!X;0f&NGS zkGK=~-ylu?^WGzyg~`&*KoEpn0{|o_1scTpp9YTqZ{UAsjNJGF`S(3$72s|;XIA~)I z`Gz6ZH3aUIWTD>Jf5|rZXQ}o{vS@t z2|HBKfpX9WsV_;v=WKM!EOjT1|Bn}Rq+4mlO(LR)u7}!Y5LKw|Nj^w}+Xr*vG+Pe!1S?aD_0tp=gOIhDZ1YB;j zD@#>SfoMUwY|8AFM98(OSJS1w9D5nmD29n=5G6|ux#})dUjTa;PDbKNw>eY3SwS3w z$}&Ms^1iebLb&!M=e!BVz81KP+w^UDf|Qs!r#zfWeQ5$9(UhQZhMB9EO?Fa(lD|I< z5#|!3{@2^rwLwbGfF1HPqa!mR4kj!LtYy2n?|p8QKtZ2k!x_ zp_BpR?174%*oJz*%2Wd{a{iI{aQe&&7+s)sDC;ja$#q6)t}SzTVCWSN%Q5jP*PD9y zUtR{!B$s^4JHQ%aQBBjvhlxw-VUscYtMn|4iK7{CTI(x_dIm$0fQe8&Bt^?%jHncD}2Ou4af=P2{uK~&Hl@r}bV zDq96iB>pCZOqkcgdBfr$n*`3bGS152VlLvR4Goz+fxVlRBd3(B=M4vhRUdfc&YEVh;u~#Ytz=HK^lFlPcC^$;&XtN+o<~kqLfMPPWOqQDJyI*dFnDIlndp z-76v?m2|H!Sj())ci`tD(3vbM(*+66(acCfiT!sK)-IS5j!#m%yxy zshKIVyrr2rNE{7sr$mwNJ|Zjf%O#J*jH=}Mfnzevg>5HUw<&Dn0*DI;s*{NAk8aRT zM1djF(6FOVkG(Kunz?K^S?o%O#}Tvy#8yvcZ?HZ}O?ypf47IJQ1<)kSDg4BQms`W1W{TeNoe$NFzRDT$Eem@oZB;Y-z&07| z0Z^13b2K1Lj3fK5Q46C8j1-en&&s>O`1qtOvQ4tYZUk)cJr=IkNbcYqUwq4c6tY(= z2YXt73s}L@%EWAtIFV?iO{gNnOZkPL2$&kl5>0-bQJ`q_EsDPhByL~>{1c`*)EF3& zpwU2@$iDH37Xul2+gM*h(DipzR>i*t2ybQ3&x4eJDv1!}%LG|~6*9#>iby*Z#raqT zEAZ-IV~Ae_Vt#SS*YYI#RO!GH@k2w9pBbVif=z%Tb4h43E_)=iszhxTVIqn#5F3uy zz!G1ZO4@z^57Bp!OSl75p0RZ7}O8f1}^VEe)73OmaL;41;;xyk;t(9@H4wWL<&5xNOBpZOez7)HYbPe|`Bky8lA?afT5I(A>_R;xhdG3C1G^Z+e25rtM12UNg|J`3q zP2Jz-Yrq)~G^Z}@CnbzONiNGEKf{p(9Kr*78RzGCc^(G518`ZFSIE-O;#d8{$HwO( zoU{_Cg99G5lS{stfG*}SoM9~593?C;)}tQ|Pb3Os4ju9rh? zH5xkn97X-G$PPig*ay~I6L9Dr`#p<*4#yc}9yLIy=<6V~gB?xQ>)t!!2Xyx^YSJJh zvS*A+xr5ctZ*o?f&tZ};r+yJ#q`zkgd8N@ZLJidA&u=gDXOI&+&V+Uji3K%&Or#W9 zBMsf*Xzc8eE3aMWj#md4>GNtU<^cX7SuB%GjdAtFi7$rkRFalTfj{Y8-J3({EEV== zTNgO0dEB-1X zq4d*F8HhuU%qtjhAoIEtXiKF_!1F zzW+e72Tn?(U*} zw$H*U=0s2c-@{Q)F?d8>ubRwn`w{>d=$1euDkk_oE7fKkMoAz9mU`)7ya|vn^6~27 zLhEzy0FFEYWGCw*=nd2mS^QaGAEbH%=8G#>CBt$I9iT-H5z_#c>A*?~IT!ul6#M%} zjn1?)a&+U|1Ka|FP0|Y6R&kjgO{jnv`BZ~r>7wr!C1_)@ zJvge-M1(^l0i>PC6Ex~XvWcqT8WfhkT0x0kCb&kG?g!P9SaMAewJa3~E7;%4Hb_*I zze)3^r?br|r?09knd!SCyyUJ3$qvYh)$-qCqH4YUT|GHLh?K6RpLLOJP=M*xjkJ9w zTJV{=aCjgB(ndFx90&0jiB8UHzeO77q)Ht!M)y8!ea*A9&joeJ6`b4ByR9N15_I4i z-uj|vz-Wt*D6pKP@&5p+MY4#uCD*MWjIIAECJv-c^Rph$8ct_%<$~yaWew!X>EY5S zWyUB_&Q$9Ai)#dRRu|WN`)@j9h3=J5%JmYMg_Fbzbsd z-r*j8iX@LxnW$xy$Pnx^k`a!|SNxk|n{jpnHwjA+FybE}15_y*Ts+ZMT*qe!Lj ztLClHsOD0>5gS@cx$yAtr9N0Lv{dm9UT8B9jR-0~ZlTHwDI*Z=VmRaqWe$!VAqGFG zIwPizE~%!9Y`u{~CfFcv0)k2PBXA*v!hpVvW)v1sX+0X0Z=i;@ElFYn#UWX%0TMxT z7NcE!BYE(?M4yvjyRRr#7qb?xRrrMHlx2tD>*;~#eoy9?&WOJW1B;c9&WxvIU5fNZ zXU3|XL1Mlcitm$hxKE(w86xiH^kYbFlxfY>Q89*_0i>e%p;=LoK|_-d<7toy@gY=rH3H?;f(T%eH+cF+9(Uw}I(x%KAgb4Nqaagi#^YWP4nLk~EcBw!iScO9y z_dPTm^#gd@-BTHICiOCl?(m)Tphi_-@(u~hkuJw^C}J|RUvj7|fUR7Vf93Pn$hPk0 zmeNZl+tI(P85`)Lw3tFU3B~@HH@t3|j?vC8E>YN*Sfp_I_`bP3UG^96Ny*Z`-_)X> zYBW&SgsW1mC7F{uMDA%rV>zpo0qs4_VGih5Vp0Sho&NcTcubQE3%1n>n-S=HM1*U) zR4~l566z#%k{#gDVs@hhTgcpC@8qNqYT!N!`HR^=HF4V1M|V(gFz8p*7elF`Wo8uN z-twE+X0G&{3n=*w;b;mRSm>-9BA()v@ap^lk@WIRU}G$cAzvXp-T1@M2zx{TP408B zoHu41fMi$x>me1RkKuX}-kT;~X{*oO;mkf|+8UT_q9Pb5*Rpk7Yt6&XY`RnSp8 z`iUsypD|3|c~Rq>1<6|(;;fX1B;9&wk1+LSdSw#?=wr3Bxy>3m9Xi*SwygQZ*auDX zR5P(Wq~JP^vu;^W+F~kNh_Iso(_@IN@1pbUVy2i5o%rt-dQt6 zdx<1VD}Or$&r_V1RX$9@gznl(ND%pJdYGEY*{WXn{bDR+jY`77KW1&r&5|^EQ#^vf zH_LO-92<}kB64vsWAD3P?B~&n1p*?u54uXi^qCjny}!@)-p$JJTu=&IKM|<-#1sn* zxEK1w-v6ERM|`-Tln1X7WNe}zrkg8v!Ks(CNHnq5fhfq)r(jYZZvD?TqEusg^vU)8=ZBEN^>CO-LlE?7Ia|J&qzx1>z6 zjh+W@2ySh{O{6;Zvv5e%YEaQTj8hHbx%{M8g3nq`u7KnO7rDe|>=>*`4OyD1ssG@q z0xLJ7{SSSIOX9DW1jQ~MP?b+lSx>=w5gE9X9KL_(`7VkMu^jc%bEh2|!sLum;523{XjJXPYb~Il@9-4>UUOXk1c3PW`^|12X@P3ZdF>Z@fbKJg1!?e z$yDBh@_IsTFBuC)X5 zjebr1+|r7mHS9t>$<>A@M#Uak3nmTjvc)TUBX-aiq*Dw#vo z2%8Vj@l^{rCQGhhL`o4!VonJWFlYG)j|3nla_!Inxm<%6fIHjvCzqq0>o$1DTW1Qy(2k6yNDl7xm zxxPX(;S_&sv*S&ztTEGz0$-zH_Vxb(KS030cc`$&Rpv#tTUMAL>QEeUgreIn*kdnL z0V1TB=??P$ay@Zkt_+L_joy@2t0cbwMoGasgt#98n^F|8sW>?MV68Yq)h!Begzf3< zrLQ2pIl>zui9x?L4f&PTq6NFfU#fD&HR-eK;5gN{eFy|fFkdAM_z9Vtz)vl*dz%x| zaOp_aN(`CN8cUOw`0P+&E9^{T_|)4ZBb6K{-sU#$DQ=&N9gXEZ23y*gm7!{| z!{d#NWf*35!O|=)T#dE3Y1;u&M=rhr#>pW?Jh8b$8Mdn7un{uG(dB+Fof#3O=(lt-6i7|kNClIE@?uu<*v@S>BB#}u492)WFcuLAu;u5PA!tn6y zUJ$&~wP+NU3#%6Dq_(&*M{$#Er49c@ZW0YD;8b{%2VKnJA}B!#MU<*ZL4p3Mm>c2h z7mabPCU9nrQgSl9EQVeKWrm3jby7vU<1+3(AbBXOqeD#hl{N|-hNyxn+AjgbtXT`O zTApt;bBzD@@p&pxhytq%arz*1r@m4^pgZzVTYa6{E`(J$*y$N%26)msFy;p!NaD`EPP@6??9A|aONcVaZ#FexaSSjt6g@61J;>40oqdu!~GU||_iv-(j|f+;C3 zsnQ{1nf7W`kh~Jg#j^R+u(e(n2JA1618Bi7o{yb(5myzowZC?=Agz9;^!y_8&wi5h zw`lrx6gZ6S>amTk4DJb$I*|0^;gVirkT!po_*x1e2N*)_5I^ZK+g?Xusqvd+m`60u z)+OKv5ykF1>c?&Io3=-8k*X~OtG-VP4Wf9xpR}jXPqm1=kTB9JemR<2Y zHMLEzEt!@8)dV4ez^(RD(8-saupDt)#1VZ>VAbv&R-sG}ZTdxT<4Io)unw+ZqyEVc zpd}jYOBe}~75wqogjAma+BZ7eVrDh7&$HtylXPIr4_r*B%(WF1R%v$lh(^?gCvG8E z+^yh&=FJ@f5>oFSWK&T1~?|LQKZMd13<&|922l{vx%`c}RZ z(0JA&Z(LGk&+IQ0>*TD^hkD~^NHt?Xu>9>Um}l#Qudzp0N2)y~xh)+E=uw5zdoOlY~*6ZfaRMkL+^u%P9Dx zd;%(4{hn>y>HGLorZ~MmkA5-WZ+aL_Blx!>p3d@v5Bn8Pwzvwh_a;v!jR#9jcvD%s z_*8EyW|eVOKvazqZ0CGqOT+=)t1YHZ(4OD6@m^twKg^*nLQfRT4ue?1Kwz!y6iI;f zcnhAGSW|Wy=8vulQV8^?s(g6#m3XtJnA(16MQkv+?KB9l&Y$JXmz;zHTB7U0%MCpIP5~7l>BZpDAV? zcl@z885G7$MrQ3zGw!F~Crlx#X-nh{<{=Ej?ESdSo>t+nBfp?Qj{PySTL>I-PZ~3D z4g9qE?O4oL<~n?ID?Ag#t;bN`-4(Ib(J{^BR;Z?+TrOChW#MVppe^g^V3Nf7HQw~M z%FDXPiq6_pdl~tzjX`AfSykQ7q!%p?A$8}$(7<}4QMRzD{|qe4?SYtz@YtYCh~VtH z;t}s?Y`2m`OcZ=!4T@o^U2R3vIseb}NZJ1!OefM=xS&LeQQcJa>DRg`5-m@-J1in~ zarl2d3uZ68=wWxmUjR4zIDfuVMPyc!acZ?c3-YbQqC&Q3ODC@E|r$A$2uT}4p7c0&f3y+UzHgSG#x32^hN*3I;$FF_3C*>bC z&VLC|e6{k3w^hItzG`RK_F%6(oBq4DNV2X++1%eiCM}C{n3%p_pJ0_OIaaqoO!5ob z`?q~qGYxWhQ>K4SRNE4PUIz;nWM|6X#cBVgD%;ig+j3P-1Y#{Ex%1R5B->a1^jEkI zUxGjVFGkD16sAnwda1K)D1F-SeBTlANT z!28^IjJO0&%r#~9m2M1X>NKR8+5IAZcu+w=fr3>K*3NDrAfq0>n2~v zo)gemZU61TUgcNZ;s=4_lFc6X@0RL1RK=vn*?7=ERM{3V$+55=>(8~7Z)2sA9}+Pn ze)kdVhzA-8jQYUrP*-q9)<54~=B3s1=?RjlrNpM}RO$lz_zbMo$H3-iGqqJ~o&ezH zpna_8d;U5x1JW3f^M`nZ3hlxp=3NYguT9xG?==@ij&&a_iOTt5qA*d$e9P6f-sz03 z90^}dg*2sln^7gngA|@wd@#^N(2$$^O(-e&VZpgh) zQmQW9-S3Q$3HyQLAkj{aG}WuDkpZ^Pr>X-4?ng;?7neZqSyI#^`tlb$mt~C>BR4(d zXh&ekP)dbegAn?ZBNVc44YWF9B5?d0+(~Vy!eo^NI;NEpC_brnDl6bh279!{FdZv# zl2daGOjBNJ);?*P!}8Os{1VPl{F9pf4Fmk)fl!7(C`LT%?_#wIdYWF`T7Rr#;nNP% zkVSbm%jtl$k0ar4d_VNmB{KG&pLJB?-%vBbgPji&jDaL>G(!O}$=g0|CL(6r@4}LY zn%e$`w2ABaCQ1;>Wo^B2(<5G+jGZHW{~j}XF4I002a9lwN)pS2lh)Rf-CMiVBlnjMv)+a6>QUb=>%Dg$z*%nGmTF*b*J9aFSiJh{;xbgy(ax5K zX}~(*czDLou>*=Mm>GT$0XjZqJb)$s|L_&pY(b!fXFE?^v{=WABGX9-FCN!c8#49 zF_JS1ukRwnX6zj*3+v04bzCkniPVHRCr7UVDt;!l`o>qSm)A_JiH)~8TNqVDta*$!xuSfzQ>c4@+(T5!?-CHhtuKxNduy}-{$wEJF&F%`5qp_qfT zAjjDuizpe}b~pVy&FhS<%()ZH%&3j35&)B>auCkD8@ox9fe{o{Pnq2*|(#e6nb&i zNz~~y)+QAPkx5}XY>qZ9{bA(Oj_=U#qVPa!p18Ay!el9{`Kdso8BHObd95Dot(-sL z5!1DCHSO*|Jn75*U|x%Hq>tKpvi56aVMO2|5$EwPbhgd_BOFwlfcDQF2lu(8g@DnR zr&X@ma3a`MuUz$3AB@H98|C%ID6O55ZLeal9fE_OnNqUdaoapb{wIrbRN?JIay_OR$7U`3-6p;uYh8;f$y?&Nd)il)Cd-rHK8{Z=@vRd`oEK) zJCZxXlw_6!$F6P~hzM)Y@$CR=5(cGW9?Ty$g`+xE9boNRw(q#*3ZkI>UaX0~OJiX} zK0wxJF4bWWeqv0TyG0L!UNL?SAOi%{rykhW6AY7N9uKcBM6}UNt01GYC}Ap_zIBFrgijbO`Zns?Y5ETP=p9zkoI z678UK&8OSVE53fsuHIa&{2kLuFBS+j9#LTu_GIA6-?Hi#hOs>3-{Up*pcz&Vi&?5Q zw$6sK5|XZLt)E}GWG$QDc6Dge#_V)>RdMNN@sCD_s~Jjboz5w#GD4}bEXtrUvb z@1-&Iu|I8&!B+IOQ8%yEesZ0|ZE!qxjHT`|b!sfL88UA@FjMu7-&)g$8wd{xy4qtQ zi~0jXm3jJ^zst;31&pPEe!K!jrgm=MPVnOgIQ`iRX!g;wMDFD|{B6fwtX~{TdRYv* zc%Iyd5@-)XA^u7t(H!e}EReXA-#;wCt0R4M6OxiD6Ok zvWzAl7n?ZLy7v)_jvYSh)*n)1QP^H95?WkGgR^Yc+A1#RR%%i|9o!nXKAMu!F94=C zC#GO2UeIc&yWqjCdaqz&x;fWf43D)rR|DTSKm|kb2T0H#u2PQVt2Z+#tGF3leX8XU z-<%X49v92~pj70~HV!7_^k*66i_MD{#KxlpnRXy1Ubcm-%HK+)_lVQh2uBQ7+jn%7 z7tuIx{AlnCM%c4M2xm}p39C=)72cnmiY)pdTQn$hIDEQQ%s4s4&f#0;0_MQuh~g^(0;-oWItRW&R)x+d~mon3_g z^hj+zOJMuv!*Db}9~i!$+G?<3VBEHzmoG2jG&Bypt%WiHV^;b z!(*8RQ;(|HKFVzrkcGNM(OLT6mg#SO@K0Bs%h!_tTbbw)Q_8|R*-Pynpg+?;)n0(w z0&a9=A05a~uLN;Lu&Jn5?u*T19UHJ|EGD{prLx!025XIdQQTvZ_~vfr4O>KX{^M8^ z9OV-$&~zt+7*ou;u>_wn?A*W+PLbjR7stP5a%MwpfxG8g4t~~b_h{3XC*d52yyq|L zr1An4BE#Km5riS3l1sd$`fW7V>~@5uRc_uVfHK{L=gvF**>z)< zHivJDL>+H7L%3K8k~fKH>@#-+nEw_ol<}b`(epByw}skSp}0@&?%~A6Ssz4C z(X%h4H!C1%VdW9L4lfH?0#{VXaECaj4mP#@5c6#b0f{(wEKMutgsfP3CG^wo==J=( z0NJefuk?nk9y3rk#T79J7@<{kG-36z5L>i?ozLwF;BCs-_kT*Ma$rzZsU%!QBOEoZ z!Z6L0w>aAN9l(%!WH81o{NbEHN#95+y#n4fMjSI$SfR*fU`(krQI*|BBty5CgO~$ zeFvf>?VpNQ57s`$-r7LDwJu_K0sTD+qo9vn7e-dJg_uYrY5NZ3WXoF+c5*3jN0p5! z=db4D^g8iUFt0VqLJAKNFQs3UxsN;hZ;6+tlbqRn)>AaDWtN_gMFwwvRD<;Ox(|2K z6lIWSIUlk&AAAQ5-h?{u3WPl2%hA#r@f8_mx6qY1t*wnS+`qfaw`5Rp76V)<^AU!$ zJ$`j|`Xmk)l6`Y{Qx)VoW~>_PKhVSj`wglk2Hg%d2m05K4vDy$`%v~kf>fD2AV z$QdMOFUKJk+xMd!Rk1^OAd2RyaqGQu$CPG){j+{iYCav`X}BkZr_p*g zD2#D2%f@CC$89z~&vg9BW6X@%HBY1Ktk&Jq@f}upKnaZo1dytPmZ(+Ual>P`ntyMG zM?)$8#W^MpTtWQ%pRtuk(cfpwmTXNJvp;DhF()J0m(tiF?MfTH!xQ09>c%}e-se{w zx`53(i+2}flgo% z#FMG;h9>OBxav)o;gIJs>3bgH%!A-=Xb{ai6cMqB=!2XrYh|MQZbZH&<$$l2n;XOk zPuqmaDMfmaet$}c{2741w!#Kn7`Ntos&rfG3!XO^o@HnsWR-^n7*N--XnZD&S+2+9 zkwZ!_CB-GNt!rT4_zKvBy5UT{UPk}M+G@qryzURVcW2VV{ISjn_C|3~!F!E8ZbP5s zxPSX5yQSiGce%_!%dSsHkAyYy$5z;Ykrq&TbD6C#Z#@+)9okd}u%;*udhY`)TVmk3 zr-#cMNk7^Ye(;naZE-C%(N$x&bq^E6{K9nG3=eZyY^2g8UaF;9cXKId+4vZaQJyKX zU&=Fc_pxi@_v91D5O+*iAm%n1!(Dnue1Vw1TTgI0D6K^gC4E(WT`!lOvYp^IsAFg_ zcv8|H^Nr#X?-SU%#u-YA9>_yqd#3i=S!#%#KJEXc(oz*irkODj>6xdEK|R4)rY2XszAULc9@&L}<3C~t`Kp%0 zhCW%u4%4mOUX9PfkEak5>`BsBN@p?7F@X1XI#NF!W%h_R7d<0RY2LuXgf(Z%7I@jN z7|H>C0ALdpu|xCKE#^bj?zZhktYo!_ftsStsVOR3uu`er_7hxrc|W+<5a{gd*yBqV z+Ic$9RX+tr7Y(KQnSZGUr)a2_%l`sbqK#y8>P; z_HL(=_M{rRsVE;mrP^-ZL?E2-#<^bci#=m5XkprF?eVVu4unX?7MWw|(vB@d4%5EC zGgeu5WaZg=T(oo0HPGjz4qw31fNL?w#(VnCKXRQ-7P%S1Ku+dy?sCtQ|L+>fJ`3X+?l+<{ zxB?UQT4k;Ry48vD>CED8zCz@`&O!9H=UMzBzy)=87np=a=R#66Am5peU{CPP)7 zsAvF((2XuCiTMa*=tEG&<;NAzNtC$1w2G|)wimQBb!F;njImH2xndE*fy8kwUa^AS z!d6qIPk(gSWOqRR4|uc-gTbP@1!1FrWyyy+S@N1Mp5Nr8!`2MgqAYfo<;+cEkfVmzqLUmoTaCgQ$i$KVv^3Q6!l zv8mnOBII5quT!8E77jr}nSujzp4gV-j)cMab`pP?In9u@f7>f=~j9^#+krk}002vOe#_!R~Qd zC7}^OJ^OF}J`i>tPe`9DmhkbOA)3#MPLbU7RzVZxUGl*BOU_H72nbd-n^v$4q+{Sx zTR)$JOHayu*YVV8%F?tG7d+7|#F4>usOncqS%SpLqBdMHkL?|(c(7_{8aKuQ!Pz$v zMxI93t4eWa?&WYk9q@ZoIi3H>SOVXcT4w0Z-E{~@e$W737rYUMFfBZcyCJU^3SirX3y4iRqE2zMWo7D*Ge5(Z|ZiFzyPHs zfQA}w6z-O+M)!HfC+w=yKPIm{(-NKbg2*osHL=9~lbZ9*HK0T7KMx=QqszWZ@Wz+%pZ#-z%{WX4EXcj2xD%8qf%cS zkxVJ6+{>l4E}>E{-sNv%Y`(~&-nuff(5|6UI@GrLFb8GjRQ>-qVji4X<|X;N=sF{d z<~C@6Wkm^_Z{xHCo`EqKtAyBgMDV%6U7c$k+B9({WO;qQ`yzHT+@5QqXJ6*8MrZh% zbfI^?I==|mY(~&QnI<+URbVlLwS5ClDSHh4ZKWksOg3^q;fqhH)!roykyY7-_oxZg zM)$MIyRSQ(K$yALvWt)H!Y?cIif={u!{(m$I-qd-&y(z5xxYg?7+63K$zvEvf5P9j^3~HyWBIv`ygy{zp{|&iiaPfP_y{49+lc(+pv6h&4X)h8w z*zM?7Z5`y8pWjV}Ee2jB6Jy?=_E~n8n@*_d^Q^`~2|neYKvn**xLah>*py(VHQy_p zaD--)HgK}sMik5fTU32lIu~u39YBiItCZ8bXuY&fbhd~}&d@(D9>!4}=7^-X;SB+- zroZ0@oOy{dw&Q`-p~_B{E7wh{L5|1k5Rk`e-KO+8x_YT{kcV3cYs;Kul(K)npTC# zg<5?kU_HM!Tn7F+(DfA|sy{ACSQv=OJOiLV%yPT?-X_N;4l|Oz2R#4Jt`z4i8L*B%$ZIW(f{EX>MLds~>Ymj7U{v(75 z8nKq<z`+)%Fo3WNz}CYIiB|_9BJR z;Lk8#VFIvtx8R-cMt5Ly@r<`>QTky?py2aU5;k$Bnk!OLwG$ppw#9rCCsEIv7ha%> zc4IloDb-zHp(B4z38_eHAm|vl5j6jt^uRWKI_(3dTW(O$ zTMiqxL};qpKkc^**Ue-aw7v zzsy|e)Lk^MDU!0_Pja>m10K`G1Z^1IW}prw0W{7!6xzfXU>#98Yck>(&nV6Xju^Er z%C6d2usufeiyrO6n*@>*mEAbYT}3mpO~_KmO{)#|U-6H1*r!w?@(3*{fJO0HTaS=B zUq%@oBt7PuYz7PiA|iQ~ch*+x$gx+6UR8Z@rz9^AR>#0XL`=^dyJMSzc~+HXkkQJN z{Ohb`R#|+;=vvs5@DR)q(^;K9GaG`3(PLJWpkz0(bx@IBm?V*Idl9Ale01c~I1Q~T z_mAJQjYtKufu^&5DyAS+KvH3>n{68-UuWP=<>4wa)CBR>O81}x1eT?!DwJh@8nUHd zEiByBbJTzRVi|g2VM#l_Gx%pF*Tkfh!{cS~CK1QF0H277-bOuq?qa`q_DKfNqe(C+ zUwLRmqNEqdxxJllHU!L!YbBA;9+!-CVF&K~U!?x?TVBCpVdt;r90V~pYhOhT7QY06 zp|a~;OBrS

u9N`PGXgTqpT72`;ex+oyhIlmamdRL5M{P!08T7;c{J#%0BIAoG>Z-jKateke}Ie5kMsk=&U4 z0Tlb7V-?7sTGudOUK7h6FKf;KSg#w|5;uy5rToFW?lcjqx{Liz{ghIOH#X08hlcyq zE@5N_%(5oH<3d>%o>Mr-foL92U8$oY=0K{`;a5CfqM*sh72R}1Q0B}0b~*DR;+OHq zfREk!-_4sDbn4coUUKdGGGyXgcpc-NXSrso(wssT&?s-e?FMuuVFyaqhvc)JZ*})6 zXDOM@{$A3qOY&MD)L^-Zjfd8!tdC!?3ta2DjAjY-kl(vO_T+W~IM}Fty zac6!dsrKG(_FSFtmEFME!XbSf|76SVC4A3~!9m~jc!T;DND4|#fx=>{2Qb(B8DHJJ zW6Q1zg-@Iv69{=}M!}!E3UU0@=A!RVO(9~E_2Q)AUq2i3*9AiFQYGgZnPdf=@=er2 z{frwTC3Lr|^jJ*xIz2APiH}u_!e+9n$#L3nmv>-(xYFa8@ec%+A74_6}F9gS^rzlW zl~#PHUFRozXR1@~R#dEe59W@apteCb3JK?Q`5P#yt|TO;FvY3-uUK#C#BdD=EBN#> zh%{3E!`@8druTcG>RKO7A@PAo%-CjW{~PcW3D_c&OGJx{^DKYmtX(x1G3~udClK?T zD=p`Zs&$dnqKP4SHzbtqLS?v35h&5rZie(I2dy2S$bTS|uO=gTQU`AF@IJf9Ff|Dz z>NLkV%F$SmO0L5$)um0*46=0B3w-xYwS|~d} zvmQ@dCY>(iRvpL1>`VnK90XTuKxux3_i?s|j4Ym83n2^^#qsRQFGDPq8DmEg8zOED zm_aB{T1#$5Hh$m(v~N)=H-nqz0Ac%=3`u57QQxT=hF2DH|9zFBhVi<@SI<>tfeQyZ zm3aRB)VZwcn@{Ov3v@ixl%6>-l_X9K=ULCU zQUfkjn$%oWIL>64Mm4Y>tkRyUJ6`HtukparadEBI%v$BX&N>02z!p|WsIY~|321{* z7X?AS+->&($1E1Pk`un&)=&P4QE^;cmq>-W6}nVpb0YdX{97R`Q;vD~DbT?rn_2?a z++vzqmQBc8aB3rm`M7?&344$Sy=G zBQhLpL<-{A!u>@S$Xu(z;k}O|8jPm@c#z4;j_QRM^X7FfVl#TBVZPaPFq#Us0 zE<%AzPE$s?2tMKx&+YZDqIrK-`BTV>9E+b19dGurMXN^_ZE&8m_SZnfK}-H#JAR05 zXIzyB8dLab)K>i<&qNb{Zi3r|eJ%ou5*mL`+T{?`zPTUs;&l!rv1$ zc5%X3l7dD=A?;20{O_`47IrDbX18;-g_k|pGHWX!Rb|6qFgW#72{#@67~!@GC!Fgp zg=`Jxw6Q(4IHh&;OO?%?O^~4-a=v7hbwU{u5ZP_*1#cJROA$r-s8=ySyRK-bLLUcM zbY}x<$pvwwQ7^M($q~sC9-KQVVmN#~ks&cQ%z�t zEA`tC@fFnnseFa=)rdWJ`VSxjqsnpbCd`XUlNDSF?X5!vu$qp3^jT>(?4(M0gHg;R zkUBK8bVM-As@RfRFs{c68VpuYG_FBdq+7c~lj2eLl_#EUB5&q9bx# z`H<#qXGHao-hCZw8NK>w#YE7J7k6gh_{wGU8C)UD`L-=9H;D#(35yLCNWhRb{nl!e zx6|&XgR`hEd+$?g`EShN)$z@4y~zBKq{+J}vXqrsx}%J0Yy1ncWZpD-!KaQY_I*08 zI=Ld4>2ZQ^9YnTFfNsQV0M#jDzq2w2%m2m^k&()s*7Iomf*FXkV~S*SiKbzcuE1(n znj3Yg7cpLtTLUU~93SBj0-%0G}IujiGKSM_4cL?TNcr~Nh8Fp`gpSs&%3B)d~hD!6JqQIAdFKFJvhU>>23hG`ujEak1&21@#t_t`7#TXN+C~nUtiBeFD&O zK3}UE(k;zUVwKQ^J1yF!0&yqL*n7LjtXr~k;i9c71XOc2fldgx$8f#!`3Hw2|3-P{ zv5(0C`IBuSNL)o&p#@;$R>l)Ozen7qp>uC&bRt_$a)VK%z&H1u309HXJ(9~Ib<(rI zQv&Uh3>DuQ;i1(Bv?V*yN;zMTNeBsrjdyDLLqcm>)?R~fryS{w+sDd1@6t|XD zTpMJuVyT*HfW74Um&vQ$JFqo$B@DA_!6b{N8u&RnRjdILu*C?n@>A@-T|Nz;21W)9 z22Ebeqwd2NOmz8OgT;A*6mgbRjF{5{aX=#tL{E=fMR)Rs3Ly5smJ=v-229_Qn%j7d zbjSO=_IP09W58&M;-@ibD}bbaJi#YbdFpW6bG3`{2EdAXXY%@sxYDCX>xfhKJ>zCh zXO3gtE&(&exx)|CMT?shO~vTp1X|Eir$#y>0G@XiIF_q7(8~^ctmAzQ#D`h{26(Ao zSDNPhY!k3-U^!?nCBULwR8+ENOZRHUScdXvJopbNJ~mDa3X$x0r>u;=b+eOHG`(<9 z=_u!POq+#bhVIPY3x7_lKXUM{=E+sj%fa>b6t1luHYbi9IKz;8=A~6M)7M^6JV*k0 zq5^vb@WCJm%ztcyO|O5{mr8f>X^Ed9*%3Ba>o>)NW@% z$TVxlOnlHp#^huh>2U*KM02MMtNM&iYK#`l+zeI08r9aDTFW7NViRQv-U6R9eQRJ~ zxew*?8OF>fDJ8ZknVW&EcUkilIudl_@p#^;p5Y!MNa91u70$5kXuWA=d&RYQP1}+U zUcaSQ2+n%)%_lXNt=x_7Ev@iC*eUmOKZbA`X(aj~yXsYC4Q$~$%|7Lhb z1io!+0FXg^TRdO48Vdb(mpO>WMx4xengsJ{Egtj(TY1s{6dnrWGu420{Gqbh^lICm zamTZtEm((@F7clZcaCxy8b@FjG0d{rXg+8>Aw9%BzqU0(Mj*ykxFk~3SR|{ETr8uI zE`tEPDYwyduQx0h2m=6xN30iRtFSvO(ElNCXNjbW&wpO-HRv3siZyP3VlSDrre|#B zq>~Gp3c8JVgey@@ONYFQt5fYi0CtAWR@*d@C*h>MIUja5s5ybfQay2)PdS;Na=n_G zWIY&R!WuzM2RI-NeS0#)(txtz-?dZki z9jk>G)&&DcJ`ZFzR!}&NXJ5op04v9p@DDPf1eZ9xfVp7bOXfv-LO9P~sArPF|H~!t zDQ>SA$1!5j=D|VNW#6ajWOjK6zm}GopPK*j^CA2y?dFV!zR%65jW2;6a*bxht#2Z8 zDRiUSaxw0J!UjNw6Qmpe(Ev@DY6t(9pIUZAAw{e>fKgQ}80~NJLEz$M0;RG5XIBGN z*TYn{SVc!Avrprnz6mYuf!R-b>|VH2UbO4{MqVi5{@+h4Pu0dS+-$&3*0@GhF*toW zS+F7slH_4D4su7C#tecY#*-Fe{NR4as9*4x-Am8}g(9JLB-g(gj)-*MCQ4U(jQJ|s zXFcj>G8_wU@r;RooML!u{`53sbB-Gih|RsRNPHQ-*BB{;l9JvJs`&@Blv25s#T0s= z1YU^j+YXxh%FzFIcF`>s+GM0aN|5;H8u?x?kd~Bwgla<^M2zvX=(mP*NdIW&T5mW> z51e}1<~qKF>z3ht;{53WFJ5?PdtbC*v-F16v2K6MGWC0bu#9_kDRso9BOO-x6af#? zL*H|0BG_A+SPffJf8*hs3e?8BE6EJTfj6&jecQFtZ|CDer3vNz$ap|KNJa|N9k)x@ zQVM259-KaPnBIMa1#h}jy^wnkHJJ^hM+CciF@KF-cN)OSkWEdikR|(#rB0&1=8f@+ z+L}zsO?t&6-e|ZO%P%*~rQP|Uk?mz*Z9OT~DH%`G%~^&{4B74%dU8iBdqQD%NGBsH zNjR%NCG2{p3+J)y5a|6LkHK+x4V@9YyUP#nUl{u8_PYSy&}36u|sEsq0b2+Zpw0Cn_)7iYuDmeVI!X^6&mwPM5@AJaZTv zM3wA{0l$Olx{_hF;xm?-#03a=#Y)x(gIspDKDB+>zj=wB%T}|xBuFP-YiB>*hZqnU zcSo8nDbh~L238^Rj`1qhUcy@koTUHyFubA3+x30wk|Fd4|91?0fQHoJg!10%=xjKQ zU8h=sR)7&G2TEw^I*lF|Ys`G^#8a~G^JXB8omi?kKD9uicp0=q+=X~(95 z4{w(09551&nM2@#hl_aE=DX`S+skgQGoS0lcP7GF;vt22h4`z_p&j9^s#rMEcgOAO zTd|h12tv(J@1wdv;TidT8!9aAFr7F%N*o>I-%gA-kTEAai8Pm&b*?jMYb%2d#eVQ7 zL8hB#mmbbN%(K(Xxmqcy5X^>LcCV3Hudij_EcVQCw}roXZCZ$o|R`rojrLlZvkSsY#CYoC#5gnf&gj>J2X;bo)W07frW89 z(ggdkfn8o4+sLh-U`sjTMP$yRX%R;0d7$*Nw=2K9{QO-PGDLf#jMs-*9$S*9##?NoJi zDcugns>EJI9cjUr^WpV!ym(i6y+-p7$lvJ(E*Zq;uG)mUqbTDZB>i>XyNi5j7R%9w zxkj_#U>LQ7m)@aW!?80(&J~W%yGSH}s>Us6mYPIU@b@lds4Y*Es{c+W$)8f#pW^g1 zS(8@?ds6DOzYvsZElMlmQeV`yJa3-)|8lSM?IM@09*)?ICG|qp>W&vw^dh%zzD0!l?5})1+jo1b~I9dDv`DhqJQQn6B z!f_~XU+Jn6hi*qkb|lLA22!oQ{VUE){J%L~avxgL-Q9qFPn+T$Kij*6p&d{BP8hY^ zY49M(McHc4O-d?Gts2szXocy*fq z3}9QhwdXYLipSgD;4h%@I`fmsvQ_s{PNW~v$z{)RhG}z6L0Cm8*AI75#?6QJ0%R@1 z@?%5U`O5C%jTUkX)1SK)uY)Dtd7g&Jk$}s0R4nsK(8nehwcc>$hGt#3<06Mq4toH@ zGz;@s`ilqLpOSW~C!ArvwUIsl)3(66e{hO*Bgm2Jms2 zgrh%zGcV9?IbxMVVG|?U-+&Xxso`XQCLZqSKxCyB^XGPOFx~c5EOx*wV6TfMXdE66 z-e?pK@@hxvl+ayRs}$8-URHRG3|_q%a|+u$r+*Zh2(}$A1vp$E`*A7le)cEF<`$qW zdD%LTwFB~9h+Yhmp0an3R>d(8ISUljQEzIl{)%T??(TF62tw2sT<2irb-ii;UHzWB z)XvIqX*CkGNr^1vym@qH@C$7VZog;Bc+Q)3KVtwq45{Cees;%ydp~)t{OpK@btSUj zC>+@y^D@F5%gbB4oo4C)F9@AvK!K6x0orDOThFnNP{S~)sqtb?mu15uJ2@y7R8WepAFv9*vYGS^gqE7ltRCcRpDJaX;dG#C)#F zghi$(x8y_qge`;NkTCmD2A@qgN#UI$8o?}Y?MwB3?srdhLT2gtl2h6ONIE?@+O z1ZBzQb)k;T*Z7&^t5m z#qaBJrN+lovrT2JuBfuPuMFce4VGP_w_F350_?IZo{Ds!FD5M%#a*Rt+WkA_3*74#%H^9jpObQ|7nABr^Y zcUa6sWR_H1nWi6lljD`wWz?{33`j5?ySOv^9G;kEZlrFNF{SYq>-or8H^tchaUx-( z@OT{DaAc`eyP0$By0z#tl5E}`rN0{)>0SW^Xpb_gC}DlI`7=@gI8?u~tw6+J9cqQu z?<)I#P9>C?0)I)UjmyK8WgcJ6z8ENB&lB#ed_HMMtO6u^wP+sDYqW-k0mN6N?3naz zX#SYC@6+o>daUPM_+}t!5u}HF}%$Gbbf1@!~^YqwL8E(65H4{fa=1 zG5K~+DOpAg;uwxu|0_QB4(P>jTq!8TrXI{|R%2*oXIx*zjK|ZP3nV&~Bty;1M$=g( z+g|Z1PTU8Zw{7(Cvk~u&-Tcdc2aFwr$(C)7ZA{q_J%$jh!@ZnkIcue+U1;xth6LSM!;f^}jEdeiPs zE}ZitCsJKGF4K3%3>@lK%fhX?Oe=GfcxEe+^xea)eq8`lk*y8PZat7G%`ZQ)e8Ozz zRZ5(^+)O|AC&_{(1w=!P*wfNM#2PZ>lg3I7mr{pAZC=y9L(&)L&-x)AsB|CUeRk0>MHnQI#ehPd-bm>cr&r_tTzGz?n z6n>E+%*-6Q!(O5TTO2nwOx_o#h2Xq7;%VWuTzMn{nPuSu(GAx5X>;s`z3nZn=w*IN zxk#!k+Ep=M5oBG>9<&lsxa?U|s}CS?+vChT5C&0pb;&ZkNMUnQc6EDS;OoJ|3_VYc zopNXj2|04?Y;#mcW#n~#WvZ5tR=s$L`dqGo6T^u*FL$U~pi?CAtU+5@ruILh(jdX|)4 z_p(wDyHEiIXL|ZUIkv%C+4PVxs(1_i4^bDRPLB3F5r5tC1X@xOg|WQie}6v{OU_w_ zrv5%(Vm+xB{nPs}~#X&prTlAs=%5erZ_Kk!7p z?%?EU87x_jKNxIC)>f%cf<@RS0?~YxxcqKjB?qW6-3(y2ol_m2w}jlD{XH&^)E<-K zNB$$#a?5GWvkWF_HiIl9%ky4wzc(r4XNtRuHqgM5w9v_t zE9h;R8M;$nsq1Pd%u)*cMF>uXG4NaUXg73kb+ZwIbySU=|L@MQVE)Cim<~bwgw8Mm z#;K0fx|!@~lHxa4PP-&O%zC;Ke&2|bG*O@JHzb;8G#{?Vd{njr?L*Nv$u@_sKV28e zAKFS+!@r4s`kH0rchyC%-P*84H~(3-XZJE2KOX+uQ~+&?!c)TS%A%pqBsxHuw6)uM za|o1QTRbyAmsl(~7LPLVw~Dk!kgPZJAb4hcRQDJ^G);AMEu_#e%kXzTB)~_})5^|6 z)eCiqk!dSLRNFSH^G}(7y7@0A_fuOEuZ!>IjX%up0JQ{6Pa$cVT|g{2u!iR>{olBl z;f9i+soMay>il_;)?2a5VAstLxgqlw8Wsc9DZmW@3iFG(o4AWa`B=VzO;*l54v{bG z!V9Kl+lS{bBU_i%`6nE%jRX!?Xzw>ID}AOddq08#;-7rKd8B6T9Nus|yKXrI0|c}G zz2U%@%5R_r7@k1A$+H-a1uDV;)u~5ow%6yhmr;i2rO&qsXdzcYJ=_lBHOuwu@QLk+ zclW^kKXCi)e{g?cz|VqZO~kav6?G{|F=hXy(l^t>O$)XdIjy3!w>9-^lalWbN2#?M zSPjF5&SzDl2CFoU{`?Gv*d%(xQJ2l}kQ>cRMYey={tvT|uQznhD@$3O{r3fK(D&hQ zW~xNbV}V&Eaf=&>t<)wzoc@HXcIVNE0+>xCAeIqIE3~4vP1LwL8z8RwVs~lKSGn#( zz7zPjH`ykSKbM1jjYrk@4lzpDq3Pc&iDX;_#KO;-4*#we%||!R7n<=9Fdrmcc_~^< zK2maiwRU(|Oiv>YBLUZ>6&u_W_M%+>f!2dEf zS+xrMm#mpmOgi@hM)$j6Pah z9o-Fn4Oh0 z&g>J5byrvljq*WUsb6k-100unaJRQ}0I~W}g?VCu;1YZ|!o}3FjcYhPJGBKeXEmS~ zH~u@1dI~@L)xy*&T5h~>rFQPy>ynuV%U|A}9zi8VyB6>-2|5}tBXHDv6(k-t>A1J% zDKRt6WJ_f%cNdy|EBA1zZ#!j?9n{I0RX2`!QuR7 zuW95vxb{B*`aDhH*}CR(`q>M0Y^eK2a20ot%(1vFdDrbTjA8B5f8(g%=j33#%#QK^ zJ2+znK&yPqiQa{)|5DdXqL9^}_`GJj*KEVEVn!PUq2ag;VGb`fWTA%L+Ys=^4U|oj z9G{Y__-$79De2|@PI3`PcKM6h05y^guno zG1@ED4+Aw`fjs%4(?1V~6}vM3;Q)d?q#o-#7Jlqki8&CqYf)R#dNw$HFI-kTts1;8 zb~2HJPM2^-iGmR`TpKMS-xFt=o4btNFVVwli*-2h41&>1pa3lPOFSUxFShRygizYh zMSmZ6HZQr?NF(Q6Z}-61#eglm0X-DKAj*EyY^^w>>KH7g-7+&<9pIRnDcV|8vnW9; z;PW0VXzy+>SZ$R_Vc{&yjChdLDU+QsX@cP|P?U?yMMqd-iaP&FTeI&*0PKHKHl=?y zVtM?TuUqF@xc`|1?aAl)^<#@;6Mln9LizW9YprL_)KJbyD)QgcXV$zOm6(5-^c=1= z3w!>zqvj-kZ2_VkOp zLZ*G=!U4%{%WiKz_oOlNej}huS7$fKzb-j*5Cq*I&|be_$X}Lx zf8b)?f0LzcP)IRpb3`^L_t${dsI{6!H9@9#7b|}(v<>SAuNR5l1|BN6y`lZ*h!NII z$^4VcjBS<)ak|Q4r?GQ}(Fp!jTXW9#ltX=&uDo|rBqpONc-VU{(0>cP7*}zLUh3%g za_g$diSo|Rm`@Ih`={y5=rT%VEK1jTIs{3k4o1fvgv3mwDE0SQZHSM_{awX&2 zI!9l)hc{5I-~4Ejt?0NyE9kgo@0$;@Aq_3BwVz2?oBw&=hHE0B+QTGcV*q^ue^a5D zdp7nvG%B1~O=pWexBz?dp0s>ZC+d!W9T2dTEAp?O$`qcD90*S$J;Y(Piwj=RTv76 zc$1imMhf!DY{rrtFf%4H8!4uaKBl$uwMv8fMbYzQXhyW;_qP}!C+ad)F8kCUq!Rt3 zPr)miJiWG!?7KSmQs|rBPQvxl)&imDS!STs?>m~WPUb4k#)tcor=cw`ymP?-GrRu+ zJ}eR5Mnq9ZTPXy0Gd6xy&(lZK8IySTG+l1%do2NDnCj1vXEQ}*eEY826w%2p6Kqz| zplYOWiUs~Jb$`$Q|7`w|{Qo!p|220;Tsrh4sgY(01Laem4nK=S_=|6l9> z@&EtFA%O6ItN5Sg|MCBQ|93@O({5j2zp57sZO)nlK<2RlljanQ8p`9jh=_`1uhsGwbm&qAUh$#z1VNBMsT#XXZQnI)fKwZh=5_~sn!`cc3wiSB;VJ zp?0Fsqd7XFlQ)4kK(Lq&!}8HuQpc9^R(iu%&gYsIwpl`rD-EZ+_OUorrXdr|fdGZX zKQKiIK-z6K=qkaHz2b)fag7kZ(UwZp;=&&iD8`Rm$tBTAe2l9e{@7dR6E$EfSx8s} zVk@EH@ge>`?{#u|pe2B-xl?ANPn6*7X0m03O^Mdjp*S;6yipD;7TC+;^<4Z(b}iEM zftS2r5;?27o_2^(p=3qoxvY7vF%kl`&~cW%!Qf!ZV_#ediQg*bvAT*?LYcBSPxou> zlNAjKr{vGmu18UXIib!rWSc*$(6-76ofvojAe_QSeeCzFR(|*?4#FC1*=L)5wL~R( z2@Df``Oi^E7u6O2?4GGfj*VZ+rH8hMVmx*CBGo(Bp6iRBO6)BO{Lh~Ww0}Lx*|3wE zOmj$D!*W-Ja|Ery6e@AORr4$A-54mDmTxVk$U586P|dO$4{kCI%(Lk;b!9yPjVj0z zu@Cge;8toXU9`-|-q?HXN9lYg(j}uQIxcx3%$T{Tk*II2wV_WtDH#}MoEEIpd^>N+d(!YB!cImzO;D8rTC490=# zb))OQ6*UVbJkrxsb{yar2)t!fBgBcBKsoYO9wjzN3}Tg7upXxQre>WVy=hOn=y{{N zE#!1KiYw^wVh{TP>Fp$vDyiQr5ckoR+a056b`BMhS0S!ygPUPH6@8`0!iKbwk>Eke zGa;ZlS%XP~*avpZJ_K0D5gQ5#Eov}+J;>YhQfb%|;iQ)Nb+&LF`*urws91To@2q@`~V80!U!TwF>&;^^oUrQ(8DXeNF-alca%NQqm0>wd;BZ*dGQmXg&!kJj zy$`J8;*fJ3Y*;!VAr=p>bIucbn%JBpyMR%z{U1icet2S#77Qnk%WAj5H(za{XdLP2 zInb$tkuoAmBt4?+1Qp*vnPagZZj`1tn-Q_&W~j-%MKR>MJPmX}2XWdYvdn(Y$V!E( zB>>>n8XfiF%T1|7D;vp*wtA&7cm`yjS_hm63;1+pd?h;Tb|UQzzT%3EipqM_G^XDe zWuUbI61h1f!-o-3|9UsmMrqcqF6X=W>fNpOmUifMF_-6r%t zGNO|6g*C~|p`cRd$S>`vjMMGm_rQ(`IUlwiL-nq*Qfx(rfD@?d7CPasNUgRDupRn> z3@an8JPO19b*o2(C6|?1%C?*Cn!ssa-K+>uwp=sBL|wu*z_18>L2rH1jxvykQBn|9;U*gn`&{9r&R}&P zrzAf8-6NGCPaJVP?{oVb49bw)B)8*cGOW55tePm+38b>M@zJqmTp+&o&55wCg`*;Y z=TKL{cPqPMyJ*(}dQgw{4cwn)md1dTA@+?>{k3OJ4oJjN=4|>RH>+uLizB_rM>*ya~lX0MUKHS8~SCb^o%5lG0%NSPYj2_3q}-(ZfA&<-zj(! z>kG}JOx*%f3kafE*cgc?yDo=m zlrL_J>vR|RNc}pvOiiA}Sq3<}+3u4f^7(t7U>SI5$gPR@QmUa%jz5Jd5F8aO%U0@- zkPfrPCLLR!7}26w_`#eoeyU2;owkG4+v*mGv9lM-%n zG!JXgZRwV#PLz?(A^z+U$x{oQ7{7<%T&Ov^Xn45PPv(OMRK4hE6+9px|@Zo4nli3RMyNCqOPbRw*qpz11C>;8-&9X?L#a5{=jb{fYvXjY%7Dlqq@ zcN~IZw&^u8UUU_eT`Bxjg$rbW^n)4mpl~erNny-{`Bs1z@)&pN9aelb1kA9FK%Be9 zcJd)Hhl@U_^mxKCg_`?;{R}r^m+%*D8KrofNw(5IsglK9o%@p4{R%7l=vbPDlzSXI zAB1QkI#@NqY$h{z7%S$SR+pFE*(}$;c=t7@i{+Y!3K{4yq1^OaD+4Ba?j57+x~t zAPMy6j1P>bVubQg5tt4V1tX6uP7hhp*SAN~E0A#3b1vIS)17L5dCiFts$55#KX#22 zQKT}}lTz))eH6znVV@#9!!kFWRHeYrJ$(lxVL`SAOQ;Z4JeIhGMSGTB^zcMVM~RjV z>A=pY*=53q8Mkmn3|CB?@05uS`fGsWD*VXcc!Bj>p9%DTDUSnXcF+XvW2cbKcaT#G z=MRw~Mmj3#%uT##at5N0*EA$sF2XV)5Y+iCVhoadk_PszGI5c0^Dc@aTyuOoPL9jX;Y(<7Um?*}*3t>T<1s_m#B610 z8lEzRQ2@OLbz!9!b2b{oOSTowafl5v@LCG6%y}9gAq0I#&$6`mt*V8~6CX0SDv{-m z)5mU&0GDQm&%iwZ>Uxo;XD{R8wCR1Leimcbj3*1NMRc60C~7 zkJ0DH;%0>(V8Zc(TOkhScB{)spmNE#XfC9?y%(oW55!Hr2tbYWkYYs<5j zo=bxa#$7EI*1!DSY5Tcruwj4pM0>@TIRPr>qC;ey$L}gX2He#zt{r4Fw&XXi1Xr~d zb4d{!jO@)xeh;UwCdyT=-mW?v`U_IuB%>=R#tSLEjvIB8Jr0P3&`fdGmy=wIf)&Gd z@6UA%+73wli#cSA+y-VK9QG_T5l%CS$}b1RV}PIJ4G0_obg+1_NW$m^Ot_*>5le57 z#}gHr^ylTe1MLJbpXwTYwGu4j?vUMcSoB9)cxn{k79Jfwvry8jDT0viZNLg4g@;}| zz&56`k~R&s%o*?wg$QkhLEPR9UQkiMO-hDuQ^N8kCRPd%U7WCEd72OA@u6}|k$O3H zwzg{J)05yk4li%bEbT?A7cck|ZH-H4;#bb9uqDj76lu6aY&`X#zyu&cQ1mB!?vpp? zpzveuA`&AH@aG)W1UA7c4V{IhNdG_pYG&h{m!@(~#*lsB!y7HVi)C|boo?Y9)Jzds zx6+O6N=!p$k)MgrB7mWwiVY?Dh*;gWC>_$CBNqeYE2~4b2t-T z!)qs5Nf@(^LR9XF*56G`)Nzb6g}6RIh}(HBu}MP1m(b?k7=cylEb{3VqPLoAROGCh z$X1ZkIrOY-nJXDDigIsrDDDlPSC7$m6}_2J02YTyeI7rfZ$$C5d!gfO{LRM|`da$r ziX|W$#nUuEQ4)_~fIKp`Lvu#btzFv>yc(cJ13EJt_V zP&r?<23JRz&Z!fQEz>v4T{$vwb|)y z(b#ruU~at|@*nx?L=?xs6nd>!MRE~SY$U&kiW^a(j1osM<98D00L58Q=Mh)KB4H7&|k|6b;hoDk5i|cRiYX=#yLq2*ht~yrO&B{A6s1$Fa}J2k(qZYY!gWe_uz! zr}BqeQ0S79x1uxYa4_4}GS5OvAaXHRa(s)vKNNR$a7b`mU?rsuYJ+Er7G3PyiaLo4B*`{g@KVA3@WMYo-@{-9h2FsoFNH!uljtondSe%BLLRBERp2)TRZ*2KAyJ~>&^2)e+ z>{EOD-RX{Oe+hBhJmhvCBuGYEpf8%A@uA~J(MRE*@n#keKNCC5GWK8N+X;Vxp$B6~ zo^2ENqcxTjOGb-P1_!EfEyyt70Jp~*Q#@IAL=)ZGy3SKdn}pTMDaw@>SynEEBV3VB z537ntbeMn2f);~Tvg|OnM4e_BI~qo2@e%n^!+=vVS2`A(9HExr8&69pEDjY4ow|#O zh}Z)Brxt30&Uc1XwjXVP@d`0b{-D-JzZ*5hdCWgk>~m`A=ckHLiFM^B+cBOJ*?Ec9 zDS+h2DB0Y0^AU{47S(ldBb(IPrNK$u>oPRvT*LAFl>VQgs(*$6?vo+IOuEQG3AB;< z?Ay2q%ypNUC370DBwMk-qHyc?BN}cgF9>MHprMC5f{H3Uo#wUe;dF=Rq9y6A zMy}x6)C0vS896yPT7(;&sYAQ!T5a*%hPfd_E+e>mAnB>BDFu;auP=?mP9e>1&|)vj zu2`JFZGLy6d@kfL>Dm_X@MFpj;gq)0%%~Am=FslgMN1&;xrAR>?a-#WUm6s^`tYdI zKO+poQuLK&+gUug;295->HY(_v)2nRVTMH4a%oHRE!06ro$V^Rq=U`u!84r%~dc8JFy(qV;_Y5s70`_xc@@_0go}c#`(4-Esdb@zQoUz*x zw(4xYdE!wJk~^V(wrLrp#P6&e_v-x=X*1*q^TQUB28-1ZQ(8`eIFV<9>{bw&j=qatdd_%GL!&7xQa_i}Td*a;I(pc2a=NGk=Bmsm z#y5*iJuhsBONgam8F$Cf5!B#)scT$@UCbZ8>t4M>0o8CtBrkO9=rkU)f;8=E_Efg1 zBgRo%d)XH@UmV@R9)CYCXr!e$HQ-y2ZMc)k4K@)I9husa4Z&94ErDn$2o>+}2v`1$fbW@s_((;+DM6!9inbuHyGOV&knYlh$ zPBt~K)QLUvF?SiiBBl;DXo97B+?vAZKAnjxB9l4tO#TvMGTj9?+7%@DM+$p-^u3LDu~)mS&X;Lx-l`9VYX`44;ik-^#gDE4H*pf9G}Uyhcdpkg0=CyQVw6e z)QFy;i+w6;MdGqHFSdPn8wZ&DYQfWz_ji*pnvHDNL{ao)nB)v({g&Y}$j{iK)^ko` zGj+dE!G(>=$Z3;3H%V%l7Y|u&6X)Luh{qiG$bbp84so}1=N7w5Y+?X1nAzw1vY&VR z;QS=5sa;BrHx{bDuQ5C8(l0(dI^?ApjAE~p?nKHJ9KV!7KuP^p~6SFvTBs4vSU^Ns*k`;Ycc0Ya`yuuQ3- zN;p(IKxNp7{pp~C+<>BB&Rd-;Ag)iH4W{R{R5Bf3bE{FkqQ{*7_v3?Ljn@M%qPgqK z>q2FV+~~35uhPV9ubF+r0*{w8$qcaVn)H&AhN7KGr-zoXg{tadsIp2FZ9o|1Z^)X& zL>XOezGmx6HzMW;-HdJS*^*^W+j!|zNHSI$Hc$NH_^{fqaB%0J&&Ow+AA;-t(D7d7 zdqIchCZ8pSq2li7LcDO#7PLoXs`XX-q*E{h$G&~RAd{>UyZLC_-6({nvhP~e_FUI>l zn~GVJbaX-d%CD8zb7ml69eo2b5j`MSp*=xUSkilfqE)(~M8oV7is@72kt4)MTNH*Y z<5PE<3St|iHYUQUN6X`ivFvL9&D{%yI$fpMDe(4CzND}!@+0-7pO|%>OYK?(=JYIzY&Yp0K&Ij`5Y@@$4lYFpHw>z;gg{R(ZFm- z0KlInHm^dCa{j4vWhDYBIN=?0VKBM4b7O}3P}oW--yYdi9T#}TC>b8t4?<9iQ?nHe z%|M=e@@2XxI%w$etQ+)vd=P@|c;Df~jf0?Z)hJZ_TWF!3O~L6)qtFSUDp#Ry6j{m4 zoh^_bwN-dUPH_wYxH9zpXU& z=$^LWlJd%vbgq%5^0aI45f{UE(&IV-dL|K)t&58@|axmVEKI51i=j@_wg$!%ov@VGl;~QH^GyRUaDX% zeFMMvqusxXL=F-+sASw$%t5s-wqjjuW=^oLnlrr+*w7RYpcY#&DUEz#wK?a>Mk71p zW&ZL<8IQ*rQjt|uvD$X|WTlB`;&Q*P47f5gbB|kI$~`gyg)(M(=O_Vj=QLKlnSq1AUa(hMUJ`un^cXQGSuxioWYr2F9*2gI?OCwT zR|%$2`87D041WerW_yG(WG}0nXyif;O^3io{PaT3O1LZwBbi=OVps5uT!P9LZTG=( z;rPLk$F5Kw)_gxsPQ*}phSf8j1ikMYWzQEOuUftiuSgtCV(4%Td1hmH+wxXzGO9~H zG%MoZ$_pL#*3EqOEDMpcktmhl6o5+a&TkI-hhH75xA2EmKq%P;`iJ!qxkk%cF3Q3^ zbsq9l2-rnhw(E>{|D=%oxzx4tTLWZCgkc7$p-T~NN}tI-&{l9lQ^Lqj##DL~M#z3A zHe5KSPAt3k*J1??GP9ElEp@a49dOXIk_PGY*> ze;IllgWU{Q1?MTvpqa%a`+UbnZ;#%LmttvJ4q$z%EYHrPUU3(Xv9OE+fkfnj)6jZN zk_@9zoEt^fXo>Eh<>3X&rEJLAn|dw$5j#sRj7_q^W;ZRF2nPw3II;?3B{=^lf>?7W zlU5K4ooGCv2l~H2%3?FPeKOCV1Gx7?!1Q(R!jb^F51%rdk@rJf4F%CwQ>rK86pV;# zn1rpQDy3AQhIRyA2LcjjdoXskIPhzG9l!0wkv@~WWWSg#a}(Y}cbUscy=?TtcND)n8+X|QJaLf~Ab4up}{W;Dhtawrl-dD$O_Pv|9h z@z;HM85K;R;;Um5(lbrrU?TRCwTl5U1BFfh?i>2iF}EIQ=pdA;Id^e`3dK zOyj%Ay4d2@f5cBP*r0WDg_cBjIvljCTetSp8te){Ax%!e?w^54x3&~jusfU%tAGZq zsCJ1Qj$}QLJOl=!ZwSJa#BfS~`##E1QuVA`Y%Tv9*a_P=py`)A`d^C6@v_rIA3Zh7 z|MHG4U@m?+3%g-E77Us8PRGQZzQ7c?KH4S+9O9@>aH=F;EoTDp~Sd$xBC;kzDCV65RD5$dt^PEd0rp z_!+PEke>o2dbJ3#Wpgg$IssAa5%bA*c6jUKB9w!E)#cG&6y(2DAdpR<820I_aRgxG zPVEY$9qhg2!A?Q+yfqx}uL{2IuyOfgzfr-1xW};224Q*CKaxa?1hf1tk zBl3*kkxzkF6w@3ZTpK}++d~GCklLI=5i|9(Dzb|WYihEKMpeJO5#wFB*7;{j5U)%# zCJhVv9}$?kB5{^_y#3LUGbTV%fo{{?>-hL5BOK=pc!@s&B8Zdxeyrw7j;BORIbpbi zUomfn$DK-*>1cB{MoCNj4s!F9m{ylfnQ9nh(-c=Bv}l+gNsdoB$)p(uoe`8Ikb6I# zm{f1g2k>tm!HYa$uv}J!tr8-Q8^Z=NHXK-+QLYp-xpNkA$H$<#K#?8 zE52?;U(`moOt(vzPF}=83}3X*jkHf@mwgmNoKj+V$Qb&By4)_>=(N{(t*)$HR*5$k zXc@{cI$$g`s%B*sR_^2GjrXj7O)k24{b^#qGdm!cKlx7E!ghM?7vW^%0~*AVY`RPb z3%tOv(MAIiu0-O_Zl9r`=EC!9Nt~*VN+@h^o0#&BuWEQRYRC!reL#k_IYs+tQf`AVk z7O2XV`bZpyZCsN(aSx9XK?#je5{#4@DegG&`T%bt!g<5h;s*j73QiKL-Yg=v7PCY3 z(7A+xu)~MLwBlC*u^G8Iz~i%S*p5kY@WfEJ!e@&Tf z&I3a^WdY6jn$hBO%SAuOxPa?ZU0?YkKKga36sXnK>garKzpt z-5X5hkWyFobpDcHH`#OE3w2+sjIjPP0KL3(ABp2hn3vNgms|DK=M)neT|d)@lnQQZm1{y_dYLdf?~;gr|HFv**>HKj zI!!1+;k9mBDrdB6%4iVfIDM&)76gsyw4S5mbdST_wRX-(7BP|@-w3712@1cGn&x35thSKu^9IG5(t_n=I)5P$Q|@7ivpY7oFs$&Q8%N8T}RIKy5Z1_7`ne| zeQTlj;QW+25nWUwa+={FlXMI2hZv>yw*<+#+%6nzXt;`5jr-8iDbWy@N`eSO^1mBO zDv+)TWNnEE3L7nHDHjkZZ2#<52k#;~o4`?L$K}tS*R54Dges;=Rmmd7=PnZGQG&1cIsYB>Al!v#e5`=xs z0dPS*5KXBE>K689IKMFV=uibQjpc4$dbZENMD%p!j*d2*b{Q(S_s|Kky->nRi3Ctd z7aa1zB=RK7af;+7tr;I45-LNCuOr}sqJ%e?j@^3JW1Awx%vHMfbzIu<%Lm;70UT^*H6WQbBUkiXh_*a$alV#Sugj zbX()u2s($D)_WYky7I@a2U}sh`_YI9O9R2`g=I;@EbG4qYQ z5E857$j|@EGWDj~s}fXrdevb#lp#*VxuLPMsAOUcRG~Ap50fnmj^y1t{J~9Q`!uJ| z8N-j(fGC=eLh{J-88fNip)rNM9T@#1j?{+$74E@dl9DEo{7rnTT9&E-@HUErx`%4y z=6Mpfwzyd7c_aIVO^K71%fQD7E`NE(eC;oIZ`vl$-PV29Qc|UoUh69VXJzfaVrLTfUwrn9HD+T0fj!JDE zF|M%*2K!F(5@$$}xjCzAxnHhlQ_BSQek6=oKRZOKaj0T8n{Wvp&x0k!xQEbt%txu1%Z~@O#Y}S5*b$o zZ>+-gU7NQ^0anDN}^EYZtZ_exlp?b$q(5mHAaEToW7&-~(nhF9fOUx9EU2Xn=obE1U6t21**z z+6UoF>L;3bqpJ>fv053PEqQih_0Zu9bw!LNB_vbGGkrSlI)9#-j`Rp4s6KMewIg(R z-$**5G{-;vJ==!Rv~dk?dS}4hk%})Ao1#d+IQMB+cd(s(rVQ)q*$%`Y{Q>o?TM;D} zl4bp0cb=MgR1_P(lfZ>*Q)J7Ie8d7`J>@JQM0$^=G!4vHsHgsfWKv8lkMACS&{#c- z8(HI+o40ZRvE<_80{8fsW@U6v88fd$(+|kDa#ABk5`Au4H4h3-o~37;(lV~~Ei^y! z2)UR3uN*0T2&zAF=}nqCUEKm!?XTpKqtQ7YcDgu%0S~ai!uHAt!7bcL=|*gfx`h`e zzl~qeX=4w4$gjzn!KpGm1g%SR&~_k%*6S8Wg30Dl(lQttrVKF|#ob@UfTT78F3)OG zCsKhXOeY4-VPR)QD0@X6M)L{*+vx- zL1tB}JzNv**PW3YBdYPF5CESTEScz*;L?|Z zjV&hwgjU*HbW;vhKFA#pzP_^!_l~;e#EP=;%SgiT#D9o}N^$gl`#UbuGrn&<+#j)~ zT!p!_+QYwbI3^I3VA+BeOn0$jUPntj-;9NCw(Xoz!kP z_x<;b(C@=YlqlA3Dhv$dzLYv%({m9ecSXZQBshy9(#2LGpcGCp0y5qW1Smj}1s|=Y z#vIObq=w^m!YM|}m83#V?U;!f`Yc(V+`c$G(K z)jrlHwlb-v&{)PB3ObbM#I>3xQ|M`*Lldsm@LOn z(9)rFi2Tx$VdOkY_`}!ZmZsZoUL(Q$Q?-meN{=8dsV0G)C28NUyqVY!6*YBWkp|MI zx&{XciWKsM0X8AYi#4C(#%Ih3a_O$rj~z7O_w$%O>zLMyjG%}9L55QS#ti0rjyN*S zh9pAdYWP+;oS)S<4E@;|uq*z)+jcp{wFE#Q8grXuvE)5sHM^2iy;s9usums&ji~%C zu?r6gSqi?yS@T9oDvv!}*Hxmdtcok|!Py)`h5=(35;TrztIDV5L@Nn)svlPuJ&sIZqhpl4{vDg_459=pb30> z@U9HYUq^Rt5RPQRf**7tgW5Zf2uVCbfy>aT8J)r)AdH_tl4F)fVRc*32To7)W-I~v zx6CT~>UlMaZC=Sjs0mx~M1e%%ZK|rdIZikxGOf#!ygy!H(%EF)`sDzgNhaGY&4_ZY zTdBDku951bHRQ>%Y7PrW?pik8<}pA-U6RKJc6)8&3FA`_W@JKBi8GsePUt|4YIH9^L=W-pURq0dCsa@6f!S2$)GH+3 z$HH4-eXGd|LHz?Ch%VZR;SIOi3Rz9|$nE_YF^VqLe6Zq$*D=9K_kk7803YdVB- zA&#F<_&Q1wqtk^-#|n^WG#heNB2613#-Rmej?dMEteI|1%T^oMUujp2338*!mks7O zhVrW@C_s+^=2ApPa*5GmbFS>8$Pg8yXVJa_E$i%lZbMz(jYl zK3t3eX4I6kWTJyNsP9qzvmjUduu_+_49PIi_NHo?I-$y*E~gom6-2Nq(>ab{dnHDu zr9G;Xg9aGRp^3AiL|sj~L!|5jvGX~!JwZ-T81W>B7Tl?~Zx|R%J*ZPAO_(5! z1dw_+ru>pTw?SwNATy=yl|bqdj7e0YFhi`+PDN4@p_-Obbd&6J-ZNcTXNi85kr&o3 zZm6)cL3TatHnuUzqGaMS_9M2iySgMHTLWzb(ermW(-YFhz7Q57-UuU>a}c|*2~YN) zcAGUyF66N0-HiRF@&qfknKX{xgFK}+;j*Bl7EOi%WL2tN{782or8i>WF+~CuVwRfJ z)(GoX^RR-ccQ?Rp2lsjoiwgLXVk^56P&J3JNK2)V2WS$CTXmYGLdBjs4XRYRDyNjK zSIRAC93wxr<_3d0i)^rHN3~8GAe564tt(8@M*d3;8Blr#ophUVx>dLCL@2|@Mj+j<)YGY*OQr1+SQP@b4bE9O{?i-+BAsY8L<$X{gaz1ZsARvv z;y&6Ctt4ddg(3ixiOUDW9YNDP8HxM^!rTXKSjC5JKB;RBG_m9nYG#HKFeIe~Pi-QG zp|RI1vlx?3vL*U}YMbzpu-tfQ1rQE)g2N9ANv~|rs<8qsAuUPx9_!iw?09<67gyvi1(1u{Ore2E4$l0o7GOWBMVS%iQI*I63NbZI zLo>Dzc0mbzqEf9{p_4SMg`)>mM}k)f)^Q7Kr>*m7KIRypE>69z}A=mhbw25zdXRyGC%>CDEa zOYo7+Sx|Gzl2Oe)UTHMh?EZywc?PghXAtN?Dw*XSz4FJ(hQieh#NH~UIy||=9{~jj z^0A&zi>BBSS4Ht13(k(C-|It_XPdlYa=(efDNwq?c-^arSfb#xSWFpT{KdfELec}l zS+6PO*)LIEM9s8+NdCqfo8dg}n? zN|FmN7!b7|CK(@?+678Z8jOoyh4vYC2p&{Fitf?;0`O5CTX!^A%@ecXeaIVL9UU>oMCoD$U^Xz5fw8i^u(;KhQs{}5CH_!WJ5{=E7)Ml z2MOqaH9b&qkC2=;P1pstBNN2Ns4e`q^L0~l3uMYehBV)FT#hRrIkmwM`u*9WFoR(O z7}!T-c8jMEUoxvg_)6PeOmQ=48N#B>*$?bc#wN&HXe>7PreDnl(9{y_(pUjF6mYw2 z3A2@8<7mPJqcudmSX~T?v6QhCMWA1d2^Al75>NIKq2lMsuYBcVW^pi zWio#WV=bj!7P+vBOkM^M-4T!SIxDL1#k)C4JVvfocm{$=!UE);wo2Q?@l1WOg->c# z2FZOGFV#`tVJNjsE;0dxowAp@MsXy9w}uraA8H8F=42*LaGB7~#l>hU5Z8dVOZbyX z)T$|12ldc*O%Kh<=`lNX7`Kr)!E_+qcQ zqYCD!Vr?Tf5k+St0=5i?LO<`D&q7n7- zxRiKEyd?bWI|0Rg%o|%(A=!#Cb9>_(6t~%!aDt(3xYauyhnOpHyqC$w zn3bY~tMb=o(20~`bf^J$aag>Bt!pB>*+mS;72X#ftzhK|X4tnT4PjVE-C-2Mls2?K zWM*0_58B8|kA%kt#(64nC{Q^&qU2FKk^7;Ja=1jMW5K+EEZv)6qQevoGvQ)SYb4*) z4Wa?DGL>9KBn{O#nL(L(VC?3l9o1z!r8t<{2pRyYu>3y^Lxy$(g~zT5#`W~j(4D`9 zTxeQdYcW`{)yTF{l82;P))C&vG1iq@Y>Q5O%~MQdt+2K6ynvu6Z$v<$^8o3El$uHi zxl3-zSsZDxr}!hLo>K(d$kV2j>l87DLV19mi?UzYEb)ICa&f^1gIXBq$@+?G7yUvl zAqlQl`c`U%CS`R+VW1@$wD>Cu9u&7KusK`ksroAebexFaVc81ip;SlxNxgm2A|$Z; zg5?(m3MC5CJ$Z7%!yTw>VQ!OE?lZ`X(hOi?)FEYm7esS(Bc<+`FkwiifB<_MSLR%S;AB-zkNmtI~=Vk<}2;~Ah}j!y3^O%u}4wb71D zHo<4$QV>c<^&tJCtPk)nM8P8*+7{<7kruj3{ymC>BwuED{m+-6+(U}+5mr;XNjM8Z zTp>1A875W4&v%uUv`vPlC)LB&8wH>}lp3#jt&|@zvSf;vXbB)56}ntp($bS)2@z(v zXVeX7t;M%M6bh9CddISa9Grb>X>E1;?F2XY{K?CFu1QiOwAYn(~7WH8P zPbxr6x(ca+mGg{xZzTd+PJ!;t8dC&_NvgPrO7bZnFPu5rTT_&S>tS)hR6ij=gD^ACre&p`EIfSw}50WFv? z$(80f#S4-It?nC)sP*{YS-c!(5wmOA0-V% z>m!&zhu?tqbA(+k&G7HqKqd{7+*&Vja$8gD!-Hs|!7c+GUl~+|Qu|)=E-`L<(+m=sI>h z0aa*Z0uF9q7SY;?oS9N4qAg@`xH=PNIf5yjZJFaFXY&^{+AAoQ;exz)4_a2%xNwX^ zTQeYB2=$+m(`Gu>>T1*%VGxg8AO#*eA`PsnZfI3V>Ou&kQ8VTa4of**F-cD2@Lf{ z=tCes7d;&eV!Ag{jVQpB?+EDG7}}O5u!grq7z;RxD4e8yL^cwDVn`Bc^o0URXm~|l zOfiiQXE0VCh6B)?%SQ&ZHO(M2Zv%iHi7v2|6x^spXpXg)<;XRh5jD zSpJ`~B--Z$fga1*%SOCwC)iEM;2GhcMzx7K#f_jh^{j;v zeBf!JIF~qNW%!KVWsmADoBltvEL^ilSJg4}F-NGqD2T#nqS9R9HEcyEezl;Xho;I{ zNu*wPb5q0eSzI)QEyWc=AkB6*Mob}DK+1)z6=A;HB*#=MbuWTO56(4-)IrbSzw=#s`5} z8#Fw(&-PGi7sEiXyfKtXdt6TAAe7%AWOV^_e;UCD1Q1noc=Hg7G#%XgllsfT&k0I@i7niU*zHZm9+iEkvB7%~>natPo@=0k;Xn@AMsD~CukIC&Nq3qwXX zt<7~*K%%*I$?^$lPm2Vwv_uTIJ#XrwGF6_~i?It*RcS(^7W}ioGfhkdDWYWL{6mZA z?&BXX&mPF8PwZHf{?S4uI@~K71NW5CW*r2?!;N7OtsnoTNj-<{4ObhNk6l;s)BRVHS^N6w$~fshD?&8=5AJv;1vp|z)ern2LZ4g z#!00CRu=>9#}Al&H)hDFh(ZK~`m~wDcr|7kM+G5@wQ?<&sUk2Sadp>c7Gwq(expr$ zNyF+`6*V`InlXpOSP{`Keygc1%m$CNxOuU&|AOh^p-mz0T;YA^V>s_|K$N;p@KY1r zHwq^Z*JPF_0tDT?#@R(-fVBgHZ#$vb66$dUsD!$lgzXjsVRX9$M4B}AC5AE}$+WBK zY1o(Ih>%OxUGS9I{6rZ*7{DBplolbI1N>q_1TvxkWWVRLF?jq8J8wdt53doPQe8AB zTVDb#fS?8KDs#7}Cyw<}Dcvs1aSTyXOiG$0nD3 z`rXYGIX4!cqLx?3nncN-n(L0fmFQz5L2nM0jT3Y=BhB?iBs59WYe=vxG#y+_k#i#y z^byzdfFX@iGjt;8Bh^bAc6SoP77J=k1Cy|P=Yy&MLC8v&?pdlhxAman7fF;(O?}1ZXq>ZiHYHtF)RG_S{aFkhyXS(xp_Q#={jW-~-hM#k)|H?f?HU`j2Jq=3WAOv|_N zP1xG(>XCBb!$9N|CRQsOdT+FXq8jKhcMT`>T>%#wd7*#rQ;2!^pI$5eKO1EA1*VyV5}VQ=#wjHi^CiviY^`>}<&aepSco{nekQL127s7L zC}HC)FV{cD3IfQU0+p}>#**Poxb`B$(LfH#s2PH85G+dY%4rOSY6M{()imo>1jP|P zw$4xsp!bFZ5pD#S^(g-~a^4k!XVx?tpgb0R&jW{x%mm_0^v6InDbsG3VfzAp&6}(y zF^;E6h5>hq&iy}^JW-&E?I>H2) z58bVfz(b2CY--VIbkNW-bLqOWa7#Iyve9cAQs~Vin}PW+Tu*^&s!bL7c|*;rp1@{` zp>AmzB`n8uA%@c)X9n380FHM?^^CDa59s8%ItB{9~ zRdJ=3ihBlUJD?5=O%fom#cwRN(>;owP=Q6Uje}*EW&dsA$*WFt6i8NMBt%m#%yNrU z2`51r5rKZO%6$G+)O0kB?f6C9hvCWTY4rG@L~~@*JO~n4a}^LK7C$R8pE==m`Q~ag zrHYCBI;5`(q_-Phm25Gdki9W0dKKY1q7qByfKvBi%pgMa6%b`01r}VCa|!2FQ;-kI z7fBso_r&P>jLb-*qZKe#t)>c=IT*E|V*kgE8R5yC3v~E9;|F z*Ud29h-!&x@zP8Ewu@lWlM)q|7r3m#z6N%Jn8UH)pzc3ea)dE5RB}8h2%cLIT3OPvxg0L!~+8|oGcwuP4 zuq$qi-$o-m~72bANGIQ%VMX25f65+2HI5 z%Z=h6OL4-0CaZ8#Mf7~fWnE343?Q#fCBz0@UUd?mp4MGRx-luNnPEUf{VPWVFgqxUpgh>DB%CvOBLK8KREo1>F z0RGMV>cLdfBBlYEQ=v+DM2p8u0%d&I|8t60F5R$KeSu0v~7cz1xV%?A{JKI)fEc1O$aS05X_V`uJ#3c<#&7+H={%@+WbpZHLW$W^vW1`5cXEI22alhBD&AvD96hl<1taHQU) z+V5J(vn+}ya}N)wicIff{dpGt^|G!Rr)ym1l)2C#8+cU-{})cUbmA}HfB%+sk!M05f(0}urpQOQam0$R3n#N=!M^uS_wd@ zbi}Yp)hia!gk_r<-Fg6w!CEdMRxqwg8}445I$BWXHQK?zLdv$VU1uc3w>@>~-wkW$ zE}N(A~$peSY$z!ae#u7ImFKLN+K>5LDs zPBKOogNHKh`q+DH0xe-vX{@bRNfH&SSI2JJe@7vkjH{6UQ211nZ<90YBz}oNNC$8t zU_|F9r0hwJ;BUR6n>0I7#hsk{ckg;$#%6W|GnoNNw~$S_D-DLeCf@yII8 zQ((OW_&uOlac7`BX-L9~NytZV++5l#?oXXxo4u?jI{<4@OUtuYyqfzV%p`zJ3x^MI z(vs~I6md!21!!^O8}ayI&x;X^sX+rD_G++UrG=h=wG_$}JYC&w41;0rx<@%rB z%N<5p62j%kwYDe3cWdE1c&22B5NXM_WATvY?BsW8eV&fKGYYN?0rl4&Wk= zmmzJ+Pds!b*t{NxNjOAqEsw9IC7{26!Uh#ekks}F3f;O2LQL$AR5+22a9h{~LX`X+ z30&fkWv}7{w*l%2R8R(!%#S;!l^_xFVDH5Pt}JDh2@kF8k>=IrVX_w-h2*f%J!@-d ztLm+48D*}~VJV=zAS|3S~PimVsfIirxUN1GITNvm1yUR|e?I zO1c1#1sru>Rvb@e$udDWxt{E*UucSI$rL1oBhCz2!D-YS&g zf8$!6nGG-K8Xu87&>c8!?yW5#@PLe1E%Tohp|M!%p%7Wt7O(VIF98Tzr0{rTLKlUjnLCe*I2lPpxoC(Wi3zf`d@@Zb!Kd2T6lSdP0x!%q;w z<$}V4WPH5O(#iM+$`+FpM)MzoZ&4bq8+Nx)1jC#M;)S#+jgnRT1OV_BoE%Wy0Nk_-jW#q` zz%Y!)23~3<)1mx)3P0&p4o#Wznw-o%%}#9U4ze__8M|)SV(s=f(d`O6Y2LVrm&2?F z#s4kyz(teG8z*}?bylIl8exGa#Z%Y>CI=Z8G;z=E0B~yd`f29P1!l2(3umfFkP$f4 z;PXU})rqLz2u{w~AYV+>l@f&QDn5*0%0NnAGz4f&-}p$>dXC%qU>e|)snl~}5OxT# zf6R$xHry%()At6_0CZcGx+GU%v5o#OY3Bimp`fNlI0w1SvpktrhQS1j2@gA~ONN;6 zKfv=U4GOx~8R9A$&4&U;D}xTeS+-sfoz_&4kR5{zGm2(zK z_8$h=pC{~)KuDC5b0es4B{1B0ZS@4V+Kzy_N@sSWV--{Y2^<0JTLfyNWN_dwS^G}B z^*v!4flw77${`>LV@6#XtRoxh+jx*kwZXkJj0%0t>S(sM@Z44z@WHs!tQ ze&N$BwJ}YSld;4=7CDbNDba8KhEwzfW#-_c-XI2d1$=6>0**Vd=WWb1V8zZ55S@^5 z3_WP)A(-U8(WfYb7El3kJc4^LD2V6bf{hjuO=9I2rr4mZxyL$9L=uJ-wt#?SnP}eu z^k$nVRa!4p0yds#ue~C*a(L+jWSb=zN+zyKRwJ>Kw63*h)GYoGG@68gE#~6ePnj}H znTH30__a9O%e*Yrkuj>as4Qp<@j(Sy9{7xYQ^s*5)@u++8wU!iOc%;SWxURBDb1`8 z8bj|R>^~(cf|VmQh~^kYTuY;PO(legv*V82i&Spb)8;ii*P!MpH4={x!L7_?#SFf7 zM+)hiEq!sOB+zRb9Ank%mSTr2KbzW z4?DAn!^BTX1pipM7S!L6YvhiIH-;r5t|1kdJO&`P?|_xTHcBheQ%TG`rbT)nYECmA&^s2xtW4#a=MSL^;QNi!Kz?ucz*I6vnfCBkf2rO7pEv&Xw$i{=<* zY}^$@p@^`{mf>-gpnc~3tY}&Sz$BQipCU^fB8X8Njn#(O=pf$H-`k+X-r&aoDGhJI zv_RZO(7Hy2g;^7+BEp-LQ)+^05yS=kVK$zK=`YH%wn!3$wD0l)n;YgZDvZmts~V$` zdyIj%qTNxHWC4Q9_VwVBqIhAgpRkT$z}ee=Qv5!p_)TUn5f+=K1qGZ_B_*7dv~p5{ zXnUp-m3qn3#6KD464Lk1i)j}e$EjCr)gQ?2ipd8Ah+vDY@D>A*Y$X-+jOk%Djyp+Sktk?hx~ zc+nMrC@xy}B{ic_^+n2L)!sl6!XO;zGV0%^N};6jtYYmS0MOR6vjfTMtr$a_R-B_Y z_>v2hudattqj?^&Snr=3SBqZYvg&HWdUSV})RpfYCTMj_lLVsDwzWn&3mXF%`t^AL zeg{0)7s6qhB1~-6FE{jKaonIFR8K{W!kt#EK@~)JbFY~!OE&A8(0_VpJ%GpwGAZ!$ zxRMc%tyu$(ao-9M)tQVdZ&BT~ncv9`NgC%PA>B~rN?XdlAVfwhuqt>YIcMkqkP zsKgAxL~o_OJV+fH8GsL#=GDiGEbcHw)ZJreOZ}+_rbgXg+%4f&z*-D`7~mg5w|6DmWr z4?(vTeuY!27*Kvo#agSVL9}G^3i~1p43zVSLm*D6>EeE`ybN&-27k;LR*XSa(iAQv zVkSufdZGu`jyebYlG!3^E!Z6V7OWXu-vHj1o5v?vsgsJLv{k#hid77ve-3R-;*K%z z0O3uPEu(o+!SZF6{A_$-yuOv^k!TQ(Slzape|34Yexu$$K*Iv_2H{-{+JN)@gV#wd2HTL+u|Z zYl(wLEzD(wE$+oKzoQ_Rw`s&oNPKU6IwK_%o-*7#UDDMk6fRlHx<({}D49)g>=8Nu z<{p62+Hq^Aa4bUArbMoa%EX`OxvDa{o$SG9h3oYSy2;cEo?(fLI5n-@0)}}a6WlA= zPWd@SR@I-#7-*3Ry)3Wl$1YBMH)xUt_>*D8*Fw_|q@s^kTp9B-x|*WU(N9wJ6%s@r zfSawxA(|*b1E~)SHxKuaUc9$#HsLOS#8-TZG4nlwyfyJO(p6~i1A1&0gQHt~n8%T2 zQ6+N#U<{-}jLZ_MPauk;?)kz90T3L?s$^`N9()o6Dx>!{3m-{4?O4-#KHNQN-zy

vW815szm77blAug$C-j-*w;;}~AM#fk@Tcr_MLH%y5-^#)|ez%L%7 zr2cscWu)1eEBKIR@y!bM_$gp+hhT-wNEDz+dK<(}4vLoTu7uY*H);E(N9n4h1XO8! zJWB(P$RReJxKS$F&4(Hh!X0srpyJuEx=16$v<$8xG*ot~G%H9%bLvt6Tmm>~&e|*b zi|Lq?G$Mwt5Sn1sJ%&|5&~O6(~mDjardi*8PT^kD>mZ5B(=HgT$D#W>TPoP-bz zgA6BtRS=e!!GeS;rm8nX4TSdg1VpJbnk;&GncBgb8dpMO3JV_qZWqeT%n~CYy8!hD zav^A9JMifzlc)r-eT>KPU0Dbfn7UTu-tQEtzd78gCE#whsuTtne<0M*+p7R5D5XY4 zffO6<4NayQN`WJQu$lgah}nArKk!5tS+SD1X7j=2QGJU9M1^HMSNV;(!c!4yh4eKj zc~afd8@5byGiaM4;|wjJr__9t5N*&ij`Z*k z`>Q@LMiH&+8N!++15_2mF<=O@NNFKVq6$6eI24%SsYs+XS_AMCy*rkq=qweF^tC_5 zJtUo=xg@1kqNuDy4rfUMhgGhV)`Q#`;p8Qzce=_F{ffo-SL}RAM97msz`RRXpe?&p zO28jOxd_sO7TLU^!iE=;p<@!!RDPTfTS35DRC*CB5gXAJA%uP_sbw|MWJCiJfKw&o zg^{-~yYA4nL;aCNL|DkvifHw0R0iwP$x1Pj!9NY&(5KGw((atn~DV1ZEC0Y1>sO9{}HoC2x(e$xgIjWI5|o$d<1;c- zDlZVkHpBg1sK?A6v`vDRM-|>9Y0%~awp#crLNv1~9MgsLj|fsZafw9)raA9e4%GvY zgzMIb=(Sd~&ZTsYm|`eiB})aYqVo+pu}@J27&bWB{RK4efEgAOB3SDM&Hr`M9kpR8 zheA-3_CtyoMUk7hSgP|$se30{;}Qg5qLf_B3@MojN=|}C1QY`MMoTKCtwW#Vgb?3J znZuP%K?0X9FCIWkDFn|z0`k>kC(06RAtb=>33d z{G^!EX2k#nCH*uI^+f4qkYWH7AXL^nj%ZN=B@p~>k0EEH$9_@v|YnBQ}DvM6s zRQ))>LWm8!zfK8|d$>ZxP@(F`Ag)C~Q;Ec}TnbDwflr@EMMAS{y8~D>XEsG5Sz4h4-c%D$ zY(%tFlZx9&#lWp7(iDWYz|$)%O%-9L!<>AO6kEHsfcz#=px6OxkBBdwYa*PH@r#AG zWN@?;?{`5LYvEH1(6)@@4)zG;n+8=->T7GwOhffEiUdShvf!NisbCW|GJ*_?bOI?6 zW>EIM55&SF(nDmXXE`D7>++jrQn8566NI2x26xmcOS3Z;tYu_eVCHKbL_odz43ejB z_fBfY3H*PUdgtLBTA`By@`!}KYznv#^-wn+vz>P`$qSlDWPp;hO%@)qoAlNs_Ed$7 zpH3-?hGlc)f*tW1iWE<@APrc26>!FoEg$3D1&T5pEpI7+gd{zXn1JPcpyF3WbqkgG z36ro!5?MqPtOt%-A7YZ=?!Hj8gxKUKyOZIcfY*uT8>P^cgCbmt5ppq@#>ayO0SX21 zf!Ow`d^zBF70G&^)y)KR3oI4txu3u0%pMiy9F}HKfrAFeun3fLH5=0afa&UGc~cc> z&*@-_f(H;+=}(N$^Q(z3FUHa3Ql9jPyRq@ha2dlLL9f74Wi1UzdtBKe;o$9E%PnvV z;x-vH2rnBvB36597=jbvw7~HN$h`*#50qmA+u|VuLo-U>I;`z~%2z|kzlBGOa(8ef zuEs4bfi=SP_&_!bU82$SOv)-~6j~3#Y44a2i@0){Z=x)Vuw(E+-5!-A7O=~;HXMd(O4;pT`N22`*bCzlz>1W08GMPJn}h2zUn2%_oI%Wx2cW$<+>SjfFZ0M0<67u~0ot}i(X zj1#7s9Aua)55KIlb;0!NMh`rrQp!lue(7;1I{68zmYc$qqK*%*ZigCey@JKTEbUN>l|ZF1ks!Rm8#7 zlL(32T%}%;u!9Zf4u@)NC{&2bs93C4lbbvlx?SUgxn=6_#!tJh)n^5OX#{@iX*<+{ z8T`!DfRwxK+c*d=^*sRgb)a*Xk?sO1xAie#r>a4M+jClfWb%T<`dOGl)*e#jcU?@p zCFO3)9ux$#sZahAD3T8#?Jcn+7aKONZ00X>$6fy8(oaLKo zCbeD!I%~2ngr1Jc&FZp#?;SwAc=zC{`MXN{LPk3vioe*OWZK765pxNP7yI z534~|jPs`&$Ztw&=r#o=UH4^)4K!o#Sqsp-lS$FwkV-6-gSMIAU!5MWfR9{pm~+3z}kDVFycF3mY++C}heFsi|XFH7^IBqvi!b_-jvtY~7zKSckW; z*H=Q9bSFk$*aX>wG+S!7YC@+*!R;m+m&aIHkUEH|aN&Z>{H7(DcCXYSp;n5cWUmd6 z2dGWdLzM7=Cku-}g;GlgjS~z?3qaQ5<*s6@AIfct&pFrAf`A{!sq0T=_y>WeJ}O6j zHi&%Js&I4ZnZdB2|93TDzR;CiQ}oG4mFGGVjC7u08ycyMiH=KL4i7C2QDo*v#?Hf9 zX+o8Vnjv`q!u2MWNHd@dr?8n*&|{}ZXJ_9#9LuOWsz|37Ij3g9Vpe^P&K}MeC&kWnfKlD>jCm%sp`7y?92qO*%kGDIw*SNW)iExkslSqr; zPMe&-92&9Xc!TD(GY9a8%jwR5C03PfxVNo=AbCwlW{6g(&}S}Y2*g(s^2LGfSvrKe zyqs16M6AGs&gr3Vd^mO%NMK*3x`LuP1SICLoE(Jusz#;ykhe@vf##S(vY9ipOGB?t z!+T}yB8w^xK<8>n=|!+q$4W?s;ISK%_z?8-k*(3f-gsx+EY0#^dtAQ5kaMf z8V~e~6zmWS_I7F^)25i{NwP5k8MCc)(oYF-0j5F=WrBT6HZ4dTU-%2MomYt zG2dsDn(60J@hxEj9w~T7RIGwWs7J@sPmO21Z>;wzw8X(4>!6(m; z?iaE!2yUlD#ZXzG7-8U&fQ>p+2=(5|+(s{SU{K&?aNFc44Q?hzllJdGL?v7Cr^rR1)Y)GF7XtZwyea|THr*=n$R5` zk%n|aU8fUE2EsAml-zOKP-u;P%FfcIi5ErHx#ZBBS~{hUv>)2``iNYh52q8^h5Be~ zz7BcD3QvTf!8bY%T7b6H4aX5$bxkd@=FIT^c3Y=JzkC$Vc5PRe9%g3>6u$0U!s+8*FKz zEV2g6kOV}j3J3+OSTIOa_1CHtE+j1j=Y0MIbcas|hBLJrSE&}yEM`cmS{GT3xR{KI z7$#7-S;+$FlNH`1%GqQw8O01wXhmw_=aL>6GNTtmecXp!pj~zc={YS12HjuwAq93X zpopVCMQXC95S^fj0HF_Hl2(ZurR6L^EKx&M&`v5yNgbx4`0PYMm!u5`;<*`gP{?A(kZP1%lh(Y^W52LII{aZ{g3}ctK0?8L;)w%2 z%vv#A6iUH}9thHMZwt^Hx6^?rs@0QDPjOWhs~lXoT4cPoU2EM6=>mT7I0H0a*#SJ~ zjVEEX-B?OtVW&;u|!^UO2U>fU6jybe(K&F`{JfIxrGWE zAt=`7*+Ek)b?Zkp7nK{!ss;*TufV0mBWCdcaUc-MIIdI$lm-z((x)6&<5E!^ElKUN z1|Ce&s{nk1khR67o9YJ>HArpFY+%U@KBdMMc^*jaigUaH$q*;p5I)W#dJ1J=5tZ__ zsy73w&z8g#bq=UAa9ADT3?#va!ix4eq#cjt1kKbqEC*>N6^t~`Hd^hZavQlb?xVfAE3&Bj5V-M9BJhQAqfE0WD~T>y6tbB|xSiC)kF?{jvN0+?qV6Nh0)w8W1~ zwl1XXFx9s*oKjMgx~3|=f9~*DgoPfC1XxTj7RvD0lYW|GsckCOe3F;K5>)i$xI7|| z7NMq*dke_!9`O-@AuVQTCX#F3gCw2Ilw1(8zDZy)sWQcrOk`MtQaNYiD{wr%#RWv* zJCs-sOcJ2=FHEE%R+%g`Q^${q+8~RI1Q{OT5kRqF`Eoh~wN58d9Bg6@ju@ydA_5V} z`Nh6W6hHU2uSU-L^LCi;AwubKbYuD!x3NXLyz(P4_{L{su`bLu%#<;C2mA zV?fK(2Fx&6)rk_6f1x@Qu*-$m!r;^sEc^OvP$E7~OOnSx38PiM!{i}EN*K`QH`;?x zQdPyg=C|lwi>%?I>M@W_Q2|;@(Wo(H+G>Or;?5yj9bU6Jb-DLu8)pRaQ1YRfp|Wk- zDgk0h{F$|B?xH0+GG)LN9{C@EWg`;vCI*2UYGQDe z8eql*5e2x6lghRd(aZsU785l3L)66|B<+$MqNy|{rxi|Wv%cfTVv)19vVq;)%{9Sj z$9H95F(jr}%At{($D8C|Kd5_RW}!a>iFK@YV)#h6Jp zRl$P)B!(11A_Y(|Fr1gHsQ?#JIoFj^XdTvh1W=C_IIDaHnQ&TS5ekRl0HaE$Gt-G1 z@xefdVNuwh_>tl@Rg^0TICBPxsY5t}TWv}J@2OIz4b^~d)MO9G6iw7(i6~8>8kHf5 zM8zWZdfzgl8Jw&_JCaOp5-+&BuB1x{Q4POyMdXI!@`4Fi_f{(+0fGD7MhwJ7sqZ%W zc5bPSQB94q?I=T_w*ED^f`#HK(-2AFd<3HZXOqnwc7~CW=rAWu@@e>bpXR*XRDVaU zG2taIP^P)8`KB_Rn+RC=)YBk)$R#FUw3uLoPr`9jnTC8436=YUVDBof6AT`a;L^jZ zoyX-(Q_i%SqNw$=cxI7U)HUp{>lqUC6lk#%3U*N2N*(IL5WpB9lR}@=uv0Qc7_fy7 zA;4#{O_Ew_8%dHJ>{=FXSwBa1s@2=ErI~A=rXKK9@WW}Z5cExl#0HdxnIVFR(7->t zOm{>f0m@(&;1m4UFt4c&8X2eMEGTQzjrxP8RT5J`el+n;w7i~{5X0`UD?SMk3avhf z=pqdKYSYOQ`=?CdXp6i@M6Cu?f{<%N$mT|PR938f8{}yXP&q}_JF`KttCo&4pF0q1 zYX7*=?-3Eu^_=2@nIX@XGoVRBwv!GX}Ty zV2Rny#s=)nYZy)d5Yw1&0{)Q;_UK z&|!nxlyN5U9c7#g08`MRT8wyVwk-XeaILF}U_e1sr6Enc&dYbMwCdO#2%P*4REjpx zw&h6#vd2_Ms<26{1W$>o?9#Jh(r%RrK1R9ex`!Mp%Pmj)>Co#8bb1%}FnV+alo`tC zHycH&d2&CgZ*nObu5g6L-N6H{C9>2EAU2Pw@C2nkGm_K~FcxkN_{oeSTO~5oUg^eE zq$$X7!YDZRkKUop1j&Zv`*TYv>JEAv6uxw^16PyLbRm z{edz(ki`s!FjY*rxLZL55d0=JK%!D<$Rz+QTu0-_eL=FlBs5H_0WJacaCx(@rv(NNvH3}34hMAU)aA6@wx&zq86d{T%>|ujr(=`-4Z{xixCl?)r zVE)P8Z$dc=a7E0~}<*Hp&zf6T0*HxcMVxJDWQ_sRMtYeYzVNER#f5_^AHJlXE% z!QH%OtwkCj>G}--YlC!Ul|8#f%$Jrexyr~V}^n3$I87O|l=OGL5 z^1?L5GsB{Y48Uka*D9~zwjgQaCp~P?)dv$i&9#k_&RA>p8bxTFa&Vj@O~nbKOho_{ zI3RcZ&f*`}=t(=3k&Y6AP-YIzzf#~o*7tS@!;gTLtVeRv#WCJZ7#`{LP6U`r=}CdW zP(3W{8PQ?aeL9iw>d+YV??r;r*aLQ)kdE`bGYKuA z>}8dgH$+KvFWdc~i9sN?l|9)QBOo*cLPOw`2Ud+d$k?-VzZ*F07h>uajAo6X`Sf50 z%EpWps`kgVOrkjf(@RRK&5Xq00000000020|5g70000000093000000000000000@IRYJI&q(X|2NTiHVNAwWw;&n0L&wNyy z_D9gTl_x4blv44RN}*t{I=j|>MuRiad|OcplUqEg#O#K&NTNckUiK1SADb&mgJU30 z;Si4s6!G4`H+0iS6Y3Ag(c1+t@XV7>{5*3nNX9PWBl;SAS3v`Jp1wv=PW$QQSY__I zJ(ylyU5DR(bcew)>>a)#UhG0Wo@E!sDmu8drRw<21^j9w<_^Po+rnI#Lk zFJdJ6gYS{kpIRaOS{MyGH4XE7UzRTFw+XuczD>@Te^UMU49=!Q5O0wHg1ikb99RPj z1DtWp&OW#{WHj|nu!lK{_aXX#BNzSI$$EZSylJjB27NBV>ewCl_GgjU^*md&_PGNK zb{V6QiUNl&3S`TVfx_o4`(TOec%k>+6#g~-wJ6iFmb9cNq3vFnIN_2EJo4O$V^uQv zj)f{~-n~HUXVt*Z2~E;tvvas&fDu$y4MUTYO%R%N2ENLhQ))>XC*3+Md~N(76b-+F zua0aXpDWY(QNtV<`(l`IY}^I@zU?k*E9EGquRTSYl#qwJt!R%o zA>SzqzV1+tS@)M|=_LLGI9OR(2>Cg~3S^ByCbVc??O^mj@W*(lAT+)~Z+ei{k<^R=7np6h9Fx^^BM^c&2}TTEPwQ~C?K zI$GzOBVUVWoP!}|QW$KSc1wKv;sX@?H(4At`4E3H`48pB$ikK*It zRF&70GrA18Nii99r;nxq>fK#m9ll5QL*GmK>~AFh`TN-~Ud>+0->@C&6o->W0bdV1>+>a7fjF~jY z424xP_k}r*@i6gr2W;scAhzxG(DhC?|Wa2j+BLaQNv+7$pIBqW8a(|qQqwr zeNTvkpll7v$xV6U#1jtS{lgm5JCyOs;zM-rp$?~a%HR|Qb^bP`T4GnQ3#Mx3k*Cc~ zv~WKS?vrYGz1B?@$QSl3ACJ8bU4r*l4C&NgAHMr{G97eiC(Gb`LGqx0V7h=u{@af? zEmwfc!KT_hawow1SQ_@VGQik#v%qB3f7Iw@EHsb%PR-W4!L{Z-9nnsq3mC<q6B&Msn9#@Ep+u- z3xg(@fqmdm>Xw;IGCSPZ$F>9}w!9VF_2gVrpB93pswX^Fr$T2%v2a6N&K zZ>^)z%8k-Qr*pLYQLykb`4ObQC;*@Jnp~>%p5iuok$qG%%;?$6RXr?`JJjal9ovcA zd;FerYe(3Ta`-}CIv3&b&{)x~-T;>?o)EXR4#rRS4cTMwdvSF9Q5fCj!YZTYfWzM+ zF6wX>6H6+|{)WS1r8f9?<4FTBt310&^RCa{Z6<@IH7WFIqB%FW3AKJ4?D@kN!Vk zc*zA}s-7>5SwB;__FIo`xX&hh;lRpGHm*Y#rb=utUV~nKt(5s(DyG=vfsgNU;v3_z z!sQu_Te*_g<~xx}%p!Q#-A^1eES5Lq=bo+S~!f;uQY&f??kY6ND~daRik-YBir8FFGg%P5*4a^;8^!m7_+5F665b(v<<%tj3wv8xG;N^N296*-bz-OX(y-Jqk^R{ach%gYt$5cZatjU-Q;nX#zacmz8z*~nUMRpMDc;L zBN)^!gd-O|Q4fQsY}2$4>_)T;ax&I5$jpK^RCMDO}#j7pe86M=?NDWJcYwE zRdL+9;Zzw~OJ0-f=~U1N9=W!g>qOH-n615+E-(B;mm_t~w<*m;KeZp+e?bVgpYox> zHBpc-(ORk*;wYG3KLmr{caX62C#x@*$q2D{`*{}Ll_`g0ksMXV4U4& zSomQm&RKWVC1)#PR;ekQ#>7D%{Y+l_{+p0eC=84v&Vf(*JMLHf1ZEGJ0Q;JqvEDsj)P6V!Tfa=l_wMTS z``8(J5-}W?XQtx(?RGqFMJ&e*ETgb9qL4bUNeK3Hy9FHu05_o=9x zm`K5+ljs$hqImBII6Rt(J4T)*^Cw|=uD%zx)~uwJd;HkLSW!%W*%vKcYorrzekF@F zeMs-eFA(Rh#&vJ9#f%3-DAsc-8-&b*;87oFQ;#@$>NFfr-^&5Jg>yMANs;%P_2zp| zEzx2vQO^n`EIc^^a@>fvtA?|UQ6avbSV?7nmkG*#$lAfG=-xaQZ^g9JYTsb~tT>WC zXVkLn+$bE9mjk8wS7DsTK}q=2S8yXK1;+-2qn7#%RxS014MC&%xULqusYX+o-T=O9 zc?Q1Ec7ctmza{qVk8s+oL#%tIm?qbS@f=qJY#P=Z_pBT!s$RYf`lX}!?9+4nahW>b z?z89LTRy_+zP~}f_Am6wpMaw;nhTPVGvM9aHMn*55#G4IU33#fhfkfB}!XtI>c~nhzZk_ywqN3O1 zrrkf`a{Y6Vt>298{SxS|+8wbbph)bOJ%LZW4CnN!ZFI}61d^`5feWT{pk{~?zSO!5 zO6Pa+(eTJ=3B4wV^mN&=O^rIMS=+XpVodiC=25RA+@g9*bLr zx{4BM|DTGe=^HQUFiH@9?z=_{_MalMABAQ+x&*rlFSyq%;eJ7vAYi#Hw&s1L{`Q-p zYaM}4`+Rnsu0#Gczv(SN-Z^@e(z`t#Q3dMpz(2L0XdLD%4`bbWogDC%B?)=x$Fy|*#n zT7l#eY{v8QuLG5LXM>SHD1S5w8EvC+>?;-5vak!ngP@80=tc{DZybbPJ8B`-teSrx zsh~$Cmtk-9JX998VAj0fu+V%E52>F-at+!rK0}TDTG#PPM?JQhr~=3LPQuOS7IDJ2 z-4xQJCpkpU!7YEYAWYewKlGmr&|MWxi>6^rf)~sGcTOCBeWLg}Knp+3E~W?DcJiL_ zmxR1i^5~UVz#eOline_Yz(zq0mmKvG`)!%bx}ExXEom(X*Gu@QLkZvhewKBQxBtub z06bi`4}1{zat!W-8 zj+pL)ktq?lPWlvl>LaOpT_v^Ybfed?zv$vJb5<%`0o`2&@yZK++)&#}VdHDXs(VVP zSFqP5+Ep7THakI%#%mtzDB&^jvv}Ct98|q75lp@>fSQ+2glW@U@aDC9V7k1Ks!Vr* z#ebz}(tiM)f*;U6NR_|nXb2j|)Op(AB^>&FF$OvJ=ccml>~^Z0t_-uoiEoyJrp6h{ zU3QIr#~R}0St~?$`Em?h?j)|CYEB8K+vw!{pY*CTQ@Uk#7_a)sFll!HJl9vI4{h3* zzRrmS&5=bHH_$C~=m?Fl^>cu^0)Pb|~DH=zsphd6m(&ULdIsI{gbd=63syv!X zRyUH!td|=HcH4z*n|xsVd?Rqx%%D5JuF{3;#+Vxt&mJZY(i>NTuqo>VMc?tFq!%V+ zS3V5pj_84Xs@L)tPh%Y4e1hU?YG|%uJSODa2RUIFw5#^vs4inJ?X?qj&Kts)7idD& zsP4R-Utz>uJE}f>k<7-2^R#deIH75X$9jA7!>ZNvW`zPOZ?_YFRR;3M(cLIhXCOQK z8ezfWBx=02A3Pu1;~J0Vy7{vP@xWe%957@U-1>41tY>c#YHR#xj^SyLSrdf8S7go` z`|qP(hcp?-7UG+cuPD)Luf!g|f}-zbnBRIt?Chn%<1`((^+Gu$Z+Zg5%)0-}SDRq= zCbKjfL`;w7tm)9MX~0#i?(y zV3Vs78X1qpYyHOv-OeS#g{kGRMnQ$0yAIIB+T#euV|r&RBt&=|o{f%HEDSe!By1E!afQVxJP{eorxkKVXUqQVQZxk>kMzWdraAnIR)btv4Muf% z(V<(hDB0!1{X@P9?rOjm7kcou0edL#lNyXyABr=zvnlw?3@#q2&NIDCF+$ECRvCMd zr&&5F6`zDp4mIR_{Q)liYR7kKpA(M!;ZB%{E2@mH5(Nn)4pl^B~u6y1TE{pZSH{9;A)(=@`S!xzM)AH8{cvn6hRxtB)njv$kt z2l?c>ozzQj53P!IM7fdkp?S6nekgng*sMtdU;i`7p0l}YZ4E3a7>4y<)$yg~K2qP3 z2#NjD;c;~|t*VcqhngGV#hDv?+~X)+%G(9O8i!ERU?Zf1E~|W*iZ>Tb#h4*G*=hI) zoM-x2oIk1)-syYs@a6WrdASXqzWCWiZ{H#O(M_Mrmp&)8qph_3D2b`v|M}FGA^bvA z$HYaeq47#N{@nQx>^x#Ndhn=XWiXInxH3>5sVxcoW10UT+Qor9SmA^5S zS9WEPV@ruJWaACWYuf;EfiV*M;c@uv%TBDw(BvhmZk#6i@Vs7DIQi-sy7|h2T92qx zQ`rs(n!g=yO_t+{TL!ZE-X3fYaYFgHw~%N4ke*1}V3pnmPBos-!(5Y5Hv0ispUn}c zKGNVT#eGrsNH zlMVOKZU0J8#S@?rV#QGv^?c2yZ z(|mDgn;>Rg+K6k^)VX)QE`=zW!np=n-V$~aIz~kB&zUjQIX_BL=A8sxi5k$S_a-u$ zhPd;cgCuFlDKXt*2dmF5p~(-FrDMJf#m{?o&>w{!l=HU`nkOmZw@H1trpE)k6&p#9 zb9TXTw+yOtkwDg&Il`}qIKFx35SZVnr{q(;1*f_780HcH7j8_WOfKMZzYx)4%q@vk zzh{({YlGW{oWSUP8?e?&mS?UbT3II2^`>Ri=$y*46u!`kTMqOzuLX9rPQ-;rodoxg z49athktQE}D!^a^>f`3bjgZ1KT9*i=rXR$H>fR_>`BP{cWya0}hv4B;iL`Qv26imS z$4^>0sOL}w!8MD?&u|)d`Wti30za<%Tto-_qTpz^P-qd2n!bZWYZ6>YABn!pGO*;#Mar_tq*F`R@XM~Z!taLbG|y`lZ66oFoh@@9 zrS&kywA_K1&HZ3vSTE|@;ewhE?z*HNKM%JaNy%WvC+NJs9sS11lG>nyVtm|jD$9>S z*@sD_;`CLhE{Wle5e{57oS;;r2mUa*4hKaw>gZ&cK7Bhl9f%g`L^dnuF2x^_C%CtN zJeo{>CWPc10@r_8E>4f(&bB#tY+PS%*?k}5el*dweKSxdvqD9#(HXsJc;QK)L@HaPiif_N^_s~ z5lwd9gR`!|thGT-Xw0t`XUdF+)o&Bwz@-ALxBW=no_k0}=Q?mf(mc5LbSd>HoXLFP z4E=hM!owHNz&)+SqE_833~VvxBiICog0jxpt9FpA-*@;p*c)H1+XPpiouP=lXY{h? zH=!)u03vFai$Y!#z0)t@Gp@0?bcGG~+ZT*F%`-UYZ6P$=F@>YW=jr9!a^d+=Mc2zW zq_C!A0?G}^A!r=h|~v_wYLntSur*-zj`UG77yv zO=H=HmAvBRTH3Ggg)`*7LZj~{R;%328}@v4Q837qzOh6({GC$%w^RI7`5* z2Hu>SP(l|q+J!g4C-6#^9i4gc3N&Ue=Jtt&f?iAuy&Y`IZd2|G8Qo*}`s;IOy=pCo zeEbbXj<4v0LKHn&V}TV#^LfksFr4TSOn2vuqx#KfaIn2K9DBVV0yi1(`x&#va~_w( ztFgn`@>3){tqbJ(17lIKYKypeVH3RVI4({}+%J4_FvPdE@_bG<15F&HdM*CMkkJ`WK2WD}!G3v261}nVZ|!zybB%NYUAXxV4DB-)V;`7Zcq6 zavXlU6M?uYg90vH6dQfj_(|X^Xipo*Y3+q{<%)-J_R1gls$R!)qJyC2q8gmf*oT49 zJ7JH)4T>|H0{djz>5H8owAKyb!D^N46;Tb6JQcj~eF=88_TomrnegdK1YCMtNX-{^ zqwSPwkTF4xyR1IaIGjYeoRi!R6Ih3j8zIaL|~ zxvy7qXJiHUubNNliPLbj+ZI7jHi66x$AQtZjd<&l2-3i`CS)GuTW-<&r>l$y8)IjFW|GeN<7u(8P(tPK>JWjF{@ezwyM^{%YMdK9UToy zn>Eiz$gky57mKBj+oJJgQ5FVw!a656NCMZCz*29fUghzas?$O52SmX9 ze=PlVNN>#Y)ucRI31|0SNGo%Ymidmt7gK-I<*}K#b6o)U?!6i2ck97Jw(1HiJ5s^k zFM&JGzr&6zoz!>y4O%>CE)TpYhfdp+VN7Kr-?|z_HRit{`eBlEz4}#lA_XqWHbJE# zEBrmk9V~PQ^SzVisP)wiUO4>gp5gMWpBsja`X^kj1UJIXf>Ts*HdPc7$_1<#!VX#mB*C_xT+4U%S}RmM&a;5P)(< zD&m`-T{Qb~7EG@25;VO%_`P}@FPlCYpW9iA?gJ*`N2Pc%Il~hjn^!^n32Uy7zmK!! zmgDVFnUH5VmnY}v&=_BVy*CVHZC5j{GL%K@8ME+_%scQORfFAqqG{0|8)39%BwzQA zp)Kz|kYoOKVOnP%P5$S9ZOaDnlt)Rz-U(Wmzo`K>nzc)Z|C|lDSr#wcci`<-r^R!( z{^MTC51{|@YoM!F57Bb}W>icljr*`0#@`9V{wv$zTEj6oqn}8@S1oDk_aJ_r9?x5x z)TE<|qM+G(0Ddz{0Ktbl$5{YL=UxCYx zr-dJ(2^{DA5Y8{UME)g}@TQkOyZ0*;KARe&hoKxT@Tr1vUOTbyhz&c&oTJsnMx2#V zDQ=Uy4{*AZw7ump!DTB&f9#?v+bGbI*@?XaP4M=cSfQ!UcFKKm9IBSc^6=@)IDU^S z?=MSd$?22Wq!bOM2@jxdQ<%%8t~7YP%o%6QT+Qy|HV}SP$M3CPAhbonFV7R?TfyKl z;G8IZ@tyRicjGxHWAL4Uwcz#s49_WwqO0c@kdkB-I;>P+v%&)SP`d#9lWJh(@CxpH zc8niXjN|?XrlNDcDR@kXhxh;3Z@J@cEZu8`^D8z$uuU;~yjSL%ZiD&vGNu-%beeYE z3$R}zvw8rYd2Egv7LP$PVmw{!^5GemX3)=&|M=yb5JA58SYD@^iPzqLpuAb9NU7Tl zE~*QoENmC8%{xfpqCEO*{1GZXmB8C#TO8Fh3}qG>NQ0I*aq>6=`ZRqs|9n~_HC`3K z>wIV7bf2q`R=*5>Twg{SGcSpCi(9BRbUgR&2oP>q-4HyKevsGxw@|F;#jOUKq_ruR z!up`J?V1{>7vt6HRdAjE&-hmIw|^P7}h8KNAn0-HdPDTv&1EH))5w2CO{T zov)^M(&qB5_|wNlv|gtOhnIdJ&!4^UPxy6cd#}f{e$D13K~+M!njX%J(}SoUo>ae4 zk5BFzhHLu>)HyI&w2v5tJ0iadmp6%=Sj>cZT z%2h+-c<&S!@ZaGk7@Dczmx)K}y6=j_CvVzeWtS6==-tQ}hwgw_cupuCl!lYOd=-~$ zF~a8)wo1%9twpVoYcOA{K)mHF6}^Y&k=9;+;nKgETI!?5CTHJDG;U^4+4nOvq_z~d zxmA+th3+W(xDRh}=!@G|+!P=CN_geaN{aJq0_ngl)Dh&2GXw5Xj9dkj7o=0S8TP=5 zPiTIRKU9=5nx~0@eESen6!O|EtpCpLBGh2myInD6Kaul8_2!=U5b-8S-8F!uQ z#^(hqxXLyt+nGpLzG>t4`VvX0c{U5iN6CGEI11h8;*3-Wsi(p+exoag-uDLM)`JHn z)^>il{_S1r<`ard>bktt_XFrYc}Ghtv}pJ8W8$Uzid>W=;U6jGbaYiHj?lX=lxjZ~ zYQoI<^>PQatn`Jbk4wmKgFd@WUm>pUmV-0)hQpMCB3hn)nD%+e;lz$Gh@Ni6Q<4q1 zCbN)px8=dG?*bIvmluns59Kf|QvpkS@Iyp4xM=p`)@QlgzkCLjc|L)?meHWF={j^g z$$*@M9CR~0CVHqRv&)$7nC@XtZr=m3*EV&C`d|RhzgoaZ%?4V&F&VChWQxP+1Grl* z!UfJU|9G)TvMWxNQzwsx=20bdtMxDS_Nif~-A3dP63q`IeX#T4FW8cj46D0Z!25O` zeb)0vqq-#AvoxNa+tsk~PzkkIMdKpDffnBM=C3=pK(5gTa&kR~ct1vBxK+U0t#Uj# z^&mYT|AW%@hV!NSbKt`833NL@iIwI%fb;7t(t8z%r)+i#cGFAY{ai(?iQY|*FZm1Q z{(qoyQYc47+~l~?eZcsH2l~8m5sIBsX?@AR+&Cm-@{S!Gw{-&7O=WQXxG6VziiebYo5yDbFLdI58cv?9UMTdSk z$;by&w=_|D?tR+iDzHz`>3^>AnAR>?B`#4mWfPNJ{?qThs8=q7t;&DEHZYouew-In zPEJRI(XCLFFM)agY14$DbzH8kT^~pxg+1xuwp>V(Efnce0D0@~ z!rXDs*|hSfDD&ijvyabh$h^COdY*m;liv8?lCWH@1LSHmtau+@D1KKUZLjg0m6r*j}p(R zikN>ojIJ8oAW63xI@`5C*d%X&A7)Lb54tvBwnRc&h3>E{rW@y1$)2D2Lyoy&s9LZ`L9T)*%tJ_t;di0iLl6{i8@;Bd1LoP zuF#Jc1|LX=ms59ue3iGb;Au77h?<5gIv)rIv%7Qexi|33gD8F!R|dv?lUY7p9zXRc z0_PWN$!yUsSToU%3!G15(Uk-Id1WBxxoh!(iNE2m-zDmh4&uc#zJtP~bn*R^x9rz6 z7asX`qqupiur;iK{QB>QShus_JGvf>#}#pM@>oco7lL7H(ohd|#h7M89=9|QTo>!H zyW&V%Uv>gVH>qLr=Xz);_(%;EL``VJ!5MAz<6<%l8FB=adR(UgJI$C;JqCMv@+r) ze7U%tHrsuGcX|WGwsp@@agrGh=>8j$s}nh|L6*<2HsoJUJz2xLQmC(Pg_r>+Fv?C1 zr|dpWtA}T?G{2!4b*^QDQEgd3(wX3b3GYUkb< z{`Dwj+Z-d)icmhJ5{Cvl8ImCX0oc>FoU(Lxg01RjcoR66{V!}2RsCFfR(DghH0~+B zHngTsF?~5#`-qTu&JjKJ&xq{};r&MkjRt^@7(S?qYq zHa^GxDd+gwzI$N4BMl0b!tqA#DKhb0jG@!xV8Cljnmw`>&lmJ%qv1{DH{P5tc9+5Y zCjqq4MTH~sCDNWTh}}2$hW6|XRviA1VXnLv8uMo3^vI>cGGhnI9C009oqGWKUj8iS zxd1nn=;O3XMRe9tV6Ay^;xyGu!i3gRnl8$W}E&BUz#A`FPP%&Bc{0W<1bZ+uicrE`Iv=t<%?V3U} zrN{8mvMpkD)Cit%Lgl<)?^n>`cvx7r;TkO2znjyZ=%8731?na)6h6<-=3Q+f^>&#| z!<3`2ZzqH4k`fr&y9A#142Ps?Rbs>LIefzIfYAIX8E^O;7FC1#g4MMCw8P&NQ>~-v z@dAMlPq+h%7N5p`lLkU&A37dbpcpPUrzJ43%ZWec9aM7L8Vyb)bF4X;>X%!TDALQQ@mQ#-(M` z^&c07nf)!mcKRu{waA7Cv$lYa+8;O{v74q}?4(ND1vvF@K9|ZIqUIi+sQ36NwG=lgHcQ|nE%aNs~(fD_pB(GYz7 z?~e9szrcAwCf$9$guKiApnQ}(A2z6>mmzcT)YGkebECZ&I!C*iwdr|{lxJbpM5Lb=m#3wI9pMzb;Dl-{Dn!P>J)&u%4#eCme} zKnu@2`$Gr+j-g3vo9S2mEOKzw=a=)fG5TyjvV7JLOOglE#7o-r``Zj|x7y`#)k?VdpE(Bf8pK1R zTWReOC9>>2gNHQCrjYud)b3S?N7d)@#pUYwti^!O4-6&WoMKAZug8T49C5sE6`jp3 zMrFw}ioUgzFLYbR;uv?KV!A0-FN<|?opcw5VhJql^dy~Mainhef~_Jv=q?&S;Mhqh zjOmB<8z#e$JsZ$+MGRhBa{*W{5XU}?C*T8c1_OBKU?n~s`JN`NRiTn;i}1JNVZL=S z02d_{k!|Ey{CIEycSv3MasIZv^q-%Vw&qdo+fYaw7KH*XI zvULqG*zyPMjF`mD8*)jzyDjJ)j(|ZAuhRU;?uh-P#m!U8)JzEzw%5$%RYEvE{<9l9zHEltS(8|&(~;*@9v6zX z)JmT<-Vl2Q9HFdV{@|~h$dls_;_l7>`Vlo8Gjvz*>#PH?s6q`s`B&4ui!~hE)*l9k zDneyY40iOmBW}K;3ZHYVU_c!KjZrT% z$xa#v6Z2%aZr3Vk8+1za*3jb6vT+!dA@AC6Rsc+>RN+jWe4e}70*t=e(yhxKbmGZt z^5~(7g@eLSC2l-6e~|;1oN^l3Zpc$4CR`tC#wTvPp&!$0vFqzT8v5!08vjz})hB+y zF{vl-GK=Klx{55n$&CV|-qL6H|9Ixx-+aR9?zvxwRzrtvE~d>t2T$r$u++X*y4-U< z%vhyK)h+R`>eoctepEx)zDbj;B~vMqzQO#zlgM*U0#@~S01x|`z4p z7;@Qw-W-a=+Av=}b9fgR9&tpg#crgja6l~mQqGH>Ogv}&F(1CA>_C|lcEYYR8(>6I zJ*e#p7lkwf{yKd>YHs^0c0GF|hMXD7!tkAf@%mzz{P8peJ|77M$M#S|Wi(xX>qL3& znyivu4j0zU60RB!Lc4v^y5|dvVVi6}kQBV)POocZ)#obYJ$J)(V{D<@N>6^#F9x%8 zo(Y;~!l9JrVBNHE*m&3ruAiSn-jfdrp0z*euDT=39tfk6@#DZ^&IQ;bTgX-REn>H4 z{i#8_H?Ge*3}X!LQ2e>^I5)|NdMzJ-njTL<`=^X(H)kJNWLR)e^jA??YR$v$n+fHi zF2b=|35KjAOwdinmEP}ZcS;EFKBdZy8l^5tX{|!aWetA+q!69K5AD)2T<$is)2tOo z$$Y_G3U(8?YTH3dc)kmQB5q>9xGb1$o&zR-y?ISwWpupI z*rtfg9-bGB?A54eNC6~_+yHk6Ea1dB=`ej_F4cR;X&vwB+}^EYWnYRvXDFc7)pO!gJTbjxKO@|-q-IEvtbO*-93wo z?(ZXaoI){iS~xP^g*uD(K;~~FZfqGv^1n*p`%SxLPpx#(8#}&o)r6O5Jm$VJF*s}La&#Ve z2aGE1IrYULI@Ea>gZ~>Z*1pIQ8@f)==s8U+?RJptk7?oQ9(JgvSOU`4dQr_}AI|A< znxDNZhw-D&(4>_P*pPGxUXQXtPr(aY^+vF%bCqBxBj9S=NIVp5$pienc}H?4tu_8A zMt8jstL0sI)M#t;nQ)J_RN^rMi+K8mFnkkj&Al%N1MxeRzZb7`!1yy_6=+dxxEU648lYw%$=hakPIweT@F3VXQ zuUiCVKIfr#Xf3Ywzbqd4(T#2o(`6{u$8AZCqO;s0cDsL_vZq7~^D`!MXmcdKk^M=U zT6#Ekf)CNryTak6ji3X|*}^^p^tNq68Jl;)jys`f8j(WDxdTbioysHDOIXe_RS15T zN>gPESgkRQO-B1+j1Y<;N=hgfYRSLemcaf~Zus!}0_wYC8*08-2OqT#ipre_sE7X_ zsqM!>6hBCwv;B(buKodtdvDJvaT3&c0MA0YogJ0vTe zggYZg&;%PV%#C^|v_IVow(kz%f?g)V=&5R4_I?0Y%>PV>5A7GtgZlBTToo)ZUV?JD zk>F~+9mo3mQs-x@e@-`?Kld8VBW65;pSMp?RAmugl+?kq^m@4AJrQTUW172Lq+trV zpyTNUJ-to|y-q6OjT%+%V{nASEjnp&kPG!P9gYvqR7ee;3_?wn9vIdb#ygd*gzdNV zsCu9}=1dBO=Fn7O^M8ODE0>8;xjLYpup5RY=7U1ROq?Szsf#y#E_x0;Or`6`NCnMf z^i$uGn{Gv7SKS)2=*Xkyr-@Yldz8@GD-7a_=J5U>abovrgXlrQEDVTz2p?;#_*kYA z{d%%hu-H)!qjnspBqw9ORHTRRN+WP*a4}nsE2qLZHx5<53VYKEp|0|%_+3MCppqN8SbeB zaZvdrH2P$Rmisn<+XNMqb&Nzy)Sz!FOR+YxMNE`mLT&-&BrcrD=9ycd-SZ_`PpKwD z+ji8NF-~yQP(XVhV_G%YiMNy_2zzS}vR&n6I2Yo{EAAwN%eY#sI8+Ybmz)ybO`6VE z8mv+8Wa;)vHKJcOi|Ka(g|l`pt*6pdFU44`qB43bQ8S)iK;X~ur!-sS3EGZg< zHUAvwch3RXSbYnuUiibB=KVsj`!dv=q=dFFPf)F2DNT?&PA{x$!8<9R%-*zC%cs9m=?xpM>Yjw@fA&zVK?u~JcV%0h z7-)y;GpTU$1iw37}{N!mrYw=YL1^jBC@l+oGvpIp(4`)Ui7bc8`LW!=*y8l>yGL+)AcT*20Y?tMPbk zKUS@DqQ-`veC^9NYSsvcv2~4ftP3URCWnH>BbB2HyAG`w7KRVd&rz|_={}vMJ z3s_G(2=|#EQd7YSyS1KOR{C>tf{huG1Uhu;1CdGoi zIZ9>ABE-QI1Jic&;sB{T_*gU$=w9P4?IVKr)?6@|dJGIs9D-T~LI!^OAbMK<3m zhBQ{-vfbC=Nk9lFzg)$GFCU=@nNI1ncdNO`(2d;p@0I@9=1xfw`$2Q7Gigt@#!s{E zNQcUo(*7|%tNvBDEAy`v#w_-uOV)&X{Vb6uVszQgq=2Jx7Na58hT$CjiAkT$9w&JUf0 zK4H30V7Zc?IHtkXHVqsrdj*1a8Hv^B)%k|M8_K5~rbU)A!i>8k>CN0yUhp>oO{*`s z*sayZ1w(eh%%g@d?~fx6eLj!JtUQL=e)+We7S zw+_+p06jp$za?_%-y7YFfe_(4&-&lURn)Pl?R`@zu{ zz4+BF#Lwr~!)1>UoD#EuJNNw+G>*&iq4(c}_XUT@Ik+FMy7ZOf23x~_Z!2)P+Gad* z?Tmo7V|nzpX863=3G{!*iwnKSa>j~Gx)_m7dT%{(un#8k`(a1t(uTB`z}OwQEY~a(xf#7pa4H&*WiEWe?OD96$-OlgX?1 zDj`jVDY+$*m))wS-4Wg#v%Z8EpOQbn;hZcMeF0oBF%jjvjer$(Z^iKPaAsJQzMer_Slxd-OC6lI(N&z(j%e9iHHXM%9;>bDZ#4Xe3z@inqb zO$OERm*BLb4J|os2N`|4V8)ZLV7vDqX}<|){iSpHT=6#E@>oIeE}e}#?Kk}6;7QoG ze;Q>ZSYgA(JG^`67pfWQEG8dKfQBQbP-_qbxBKK_MbAA@eSJ`!-kuy>8aEOX&cwpW zo4HgvNS!rjxN`QuZJbrLNIHJ_8OZz^O9LKhalxh_n0@aq6x=@n#nV;`8q33l#1;Es zu5}sRKXeaUO@i2aS0%Wx~Gez+|+oWEXn#+M%| z;7#RzRx&;UJHBd?-Ff7I!mpL~JR+{N#uB!>@skKtww_(_L z@j3;{l|on2D_Yfh6wdghlkurm3hOonl^*)x-UmkX&Zr;kc-%!vj}76I%pa0TOClwu zU6Ap2Gv7G89iw);Q`_NH@J!spUCmqJwC*^ZYG_CEzW$G6^Zw`RfB!f_5)vtuRQ4!| zN+G{{2#l90XnMDu$HfRN^s8_?-dBb?q#r`~?^*Q8t9TH{ER**&dG&Bh_1`f36aW1o^ zLdr<`HZC4oJ^guSRv~iO=;KLKo7C;F5NZxUn;ue7)jvdDSOD=THk-$CR(~od(a= z!);T~!(i)|^rp>^jry%a*{^}ZrB)rR>6;)-H&etp&SUU*dI0}0J<3z+HN-`(bGXxU z0P31_!fn}6IBwy6@Tw-7vULm`xu3wLD+195((rAY1XZMcczlTl%g&C6Oyyb$4YKBi z`gOv&W))10IKvGsCqUL{98dMJK&$&nPR?e3%g2p~h{ZKAe-5!WezicqGyN>un zwnLOYya|D8*zYt~YkZVGIE+fEh@ z99)Q3@3V7 z@flYWY)zHnqU-%pSU-jhRF4T8MLQ}eN(CjO7;1U;hx+V)00n_NB}=pAoX3$ROq+z% z@;sI&tshQ0xu1pQqi%^0|Emz+>y3n8XKc`BToVmlG9Fi+Fya9?5~CHCNopRJ(@>2D zf$Fw#ubeVIQ7g-)YKz(6N>9+UV`+nn66kIA!qZyaaNntB$X*eJcE2*ftuYB~-$ZcE z_fAo-?2jjMm)-;-N5E>>1=ld+YY`>K=vS%b#)J zR9^|Spc~&99U>geGsjyQTlt7Vf828JDwwREjE|RVbKOXJdZhggems3C?UFf7*-lr5 zd#eYdGkl=n+;Zu(A&GQrO&naFmMzXNBTB8=4=(>UBS?IL>6#H3xjz`T{@uZ=PdyO! zeKh6g4~S%z1@R=4iKxqRd&P^!Sg9II83-7)odGvWkhgbLCbz7nCbF7w=+! z_XBvRTox~U?SW&eHCZ9!4D}vz1FCj)knf0eJd&P+7bfnYdCF^OZ$J!%ZSIMeuA1`J zv9s7=>UPSWuEd-F6w#R5Lm(>i1l(>$yx8LvD4VO|TGcH2`T7SXtoP=aEiEGS4W+C5 zC*#zwv0!j2T)3RyE=i<8aCv$I#FYL54@x12k;Qmz^n7t*N<92MIF!c8IFW*;6FqF+ z&Y#r%O0-_=;;yV5Y710A&)U9R*5HW~|G8H| ztsVIObf@;g4lH2=pZBi1he|r@t49_Het5_~Q7eMI>=OmBz{ie1J zq5Q^65o}}`3@ak|uF`V+lxo29lcwXj`9!-K_2Js?3iw&Hns=1fp~6xe|-4< z41S#Y7QD|0_+Eb!|7|r8Hk)aS?&Z5EW@kC+4s_&EA>sIDupAyZ8%_LsIKTFMMMp~H z@I~trT3ORUCv4lqHCxuw;+kbVv;H)XG~F*5xa%I>TelsbPHPp)vv;84qN7l)oF;z1 zbrWTCWN~w!6c{?8nl6oxa`gR^Ae30{Itm!P?D zmOSnu!jR4QZMGSFKKq5jyo;&%t2=DkrHki14hsf({V3?k6G^{!Q=!2<06zXnX8nC{ zskOn3jSm>2jER0(aQk39plgo?nxBQLl?$s3HLr7VQzWUs%M*|2Mqr5FGLjiLfR_48 z;r=NT+*9U>+JS2^`&=B2xhZgz`xE+7*P9k`qeL(11}W@GgF{F6;Ma+fY^9M)YVXt} z%d#!-=Kg-@856=;8-75@lLbPHRspOm+ksf|l4T2)kl&sWT$^5lcV5TQkG~(Fv`h(B zsnvtVs%c~q9mASY553JR$=BeBSl6#uT#;VLnpN}Z_x36hW+b9q9}RJT zUXxh#s1;W9l0{WFRh%9k%dsmjh$i(zaP-mx(B88Tr3-h+Bik8!Jgo-XQzN9BcX#lu zzZGb#QwDpr>_NG?lfG*Se8;H^stjXUSvndlb`Rqf$}{m{O*vDk=D+jbONLs>Sl{zJ zOzts}&p9yI-rI?OeH^ zGye;R58M`ZUQPPvr_I!VNd)xsFy^Q!1>^)Tsq20?4cyiNFE=Ri46C6i-krqOrTdjpd6*9OzeIzDK-AL1V9FrskL~(BJTH(#{B50h|1e4sOzyY_> zxW=LAK3zq46Ec&2#@`Z#tvA8}EmEQG)dR|ZsLT`hMpBP+9-y}4DEX#3GhR36Jy#6b zYd{5Dh?<3mPp5+IpJE97)hOyNO@~d90hIef0|yP6&PR$IVb-%*G|uKEyl`1Ad_Pc2 zZGVk$qFtR3e{?*$9sDMApEj1@z6u|;FB53wd~oWLONEv@(ctbis(LU03f;$W>P>H9Qq**K+OLab4DM83 z=E35Zl6p2CSP!-J&tZ|9CaQQVan0XukB-j$aI&#UXcg2ufFj;nO}l{5(Gv%}<|z^U4O`mQu_H(<8_x z@et4YGX{qh-J@?;y5nGPdGzU%4wEmK;SSlIoWCHMpMKTjan<4QO+O8-xAee-n`U^# zby3yj_%p(!_;#nd4bwUE_huY8UxE+!8^hyA4(ytu&wER(1f@1JUNm+ny6L}>SPx$L zuM1-7%LHY%HSQoKD_K5qq#K6hy{7D;DYUdC6ZgMP;DTT+>R2?8tsI_!_e(uo=%>!D ztG~iC4xlS1KZB$+m7BZvz%R{P;_${nc%*)jkl*=&X1Um*`pqT0Sy;l^vZahEI+T4e z2Krmff^+*#@SZ{gyuUdCZPb;pD!)up+oI@M6{55MTMD&-eF@ z;lF(!z=~)a4)3@NSq~g2!1TJLBUIgmaUJ64~SEbk2EI;kdy zt;+_*Q$2Ca;u~UoY#QY(xeilij6~0XbPDaBDz;gvaqQ)(d^P1Xy^s9o^cAmReY+BN z%Ul2}$pAk;>MN$_rN9aYKg^Ym1Ur|h6!DR%HGG%ovou3AI?;{eR!7kR#~$SJcp{hd zsiZZ#rh#T(8{C?HA4Xq)D*V#uj{g0x)7f<;xb2iXcK4hrdR%hkwPkl{!?ma2&{{z& zFa99+wg|MHGYw~6(161;N71dd3+a4y8r@lF%3(w6C~nJ4A?NEEl9UX=OM!*#cIlY7 zFl!VK%z6%OEqjH}a*i;1!Eh`L(D?uRVWXCGNUY^Q!Odx=qS9=4$?AqBlCw{T^3H*B z;;0wOs4+B(U9Zf+Iuca9I{9DPj-SB~P74d)>(JBC)R(4b3R^+JJ)9{-$vUZ`+m zI2>{rW^ZetnFk@MQc-_ke zyXxm-o_Q(WR`1K}t)gk#(1~0=qZjnq+(_l|x>R}o0CuyA#ZRw~il^7r(a%U5zMkR- z_iB7OA^AAnlpLg0Md4ikpp@Fi>Q#N*qk+A$m!q6U02JC>h8JmhbY`4{w0GBVfk}7r z)4qsnMz6w{EPLHqG~leVc&@DM&M%JKrfO$746ZR|MSoz&p#9*x&w@$ z8veDp)Lym}Yt_OzeR3Y$UUh=}2K(ZdG3hjE*dm4}gJIF&Hc~E>keRtUhOU|C+P#-+4&LoNp@N3rvfF20qp2`K{ch|hSswyYSUJ2T)%RXIAIGULnN zFTtI)Qqa6!E7siJOO5w6sVYc<($J&A^?P~Z;|V{6;q)U!s5*W4IG$}0OL^UmmE+bws_6r@7m zjr#anEsopwrJ+{9ARH&gfB}u?z2XqYoY{Ev$8%C2Fi%j=d_%XdE2F_hc}!W~8&65U zllFsL(I9?=q@Zjlbqm-^&mvoBtNcfj-CDrM^X^KP*7?x;t=n<(pdqNWayU8`Wxpz$X_c zi^CQFb=4LP966>xd~%JXD>o0q{Ym>N^ywHlv$YMBi{De$3uB(y&`ns@S^!JuT!+`L zmh91Ij4-KbD0ax)M6(+nnB-uJ`3L>@sJkaSUkHPPrSn+48vy$}M)TZjst{GL$TC+N z@#5z>+6%Hd_O%(|VLoLiuz;4|#1%jR)6J#M&WCaO3PP?DH@S zJ_TH$=^6!4@IuzfPUSUSd~Jkv2L15xnl=0S^jZRz;#%)(?#0BoyUt&RyvrSHbmC$mB58 z#}4KJ@}t04OBSBmpCefXJ=k(_0ITM@;iwrus88K}AyUDS(vmjArf@4ftT&y9j+zL+ zD<lfmi8$%a4N2Mm|SvH_neABX#vZE&+PT>7Ny6FpHp2di{+__UD;xji|HBg)KK zV}G*nc_y+(wIY69(+O)sE|7R&nK&e%M6x!2tx!@j83*sxrGDF2gXP45+~5DR_}{B^ z>VBw@-mIU%{pJ**akC|xt+PS32fbPD;swZ-#)@t2L%HpX8DzWV6aRXHeJ>3~hxYZN z&7vrNIBO>jh-Hv$wk2u*0&*C+hHOqtaG=I>inYHDBOInd*|Q{g`S}<)wz=}DFsYz@ za4r76G@Z9(EQX#&0>7IvLmc6JS6c952DRRqhhYo9(9{o8G5Bx>T^Js~rVo}<57RKT z85joz;}=tG!#uc8gRtkAT~M_)5IY{b;*9_HQPwL%?tO9sN2$oud=o!9_&yUAji;Q%(O|kr7Y(aU3Im&>*kb-he68St{ z9>U^c;Ci<;qHI7OPcpXQG2XePQr`z1mkdCIkt5NmeF(-!3=`IzGlPJkmoTKqO|l(+ zhIHLlu+BLFZ~Tpip!%i!b66^sFNzc2Eo(-*@WXVfNCBD~wz2#$S@L}}iCib%4TK+Vfx)zt!+KF%6$+$Jsyb77BVc~AbqKM-}PVb=^zZuqy8mLdJIcH{;2E@>85e=-->`7g(* zZdSZugeu$S9)Siu7535Djp|)VqMiRj;V(X>W3>i&Ht_+hjqJl&X{qEEe}FH?#`F2G zyDWL%3O5cfMCHeb6Ru6g_lrHnbx-6_Y1=Ne9=(glWS3*hkkRx`V=mlQInG`CKM?Ne zjZLFx!o*>L7%aC#_%LlB!|7`3IrJWgiMH4|Y7onG+@hP2y>R@cUA%bhQQrD`GJfmr z3ol#Sz`{&jT>4x<8688kuCUtN-h>IIJ@DSl1>$j!fA8_S8-+bK!-@ZmV}Gwj z;;%Vt>DAc%RDRb69=z1#L4Q8cjJx-6^0g&6M{yDsnU&IRe=XMg(N2M%)Of~(9nxtA zV+330Wb}UFDpuZ8hdJX#v( zgLXI$qZ*ZX&_fq`D|4J&Dw=r9t=<@Ioe3|{9j7Qn!`<>f(#+XwFrl9_$8_5-F1Fr+ zlcF<7@$*rkDq$;y8Z^Tgl7~B1f9T~_e{wx93nvTD^O~qL7;xB@&goUak)Atw%C5sS zeMKD3JblZlp(hUw-O~KNl3~>DwL;5ni1&vqVXw#rUd?GYU z_~DodXPe^|9%{^D4$1+*mcw9}?x?V-g75akq;_ejLwt!FX zS&ea@)2U(QJFwHV;giuD>1pUoQK^qS*%er$^%-kQjY+|n*c%e>hrM}ttvv_tOA+rC zHbYRn2HU(;2Tjd#v1DJS!#OC5` zE}K{`jCY*Do+oY4drdVQ*m@dV?1tm8Kczx}ZbX%ze-p0_&6b|NxC26luE9OC3x&1s zFVTP04L8TVf^})`c%^YQd$+lB@9&H0S$m1VZvtSN?jD*v1~5HrFAsC?l-9ruICE+l zrq+ZDmfs2mZ`MKoQq7EU?~c&czEn(J62*R+aut7@pK zM1f>w3MoGQJE?8#E^2?AjV3#iSWbNugnhPS^!^M(AV|=fsU~bP`S-k$jYK`|@aBTW zcuOIh&UIu+N6RJgh1LC`=iQx5Gk4H!VR$tn_ub!qUxnt-kJlu1V!amnf;HG+$52y6}NtWa6VNd1`n*XVd64ed3 zEaW&|uiqe8HhS~w`EqQba){h|Z3NS5Ri1fCRXA8O60dw2%fEiaW6Y>PY_)nQ?bN1o=1qX!2r76O*hpzl%WV+A? zw55x0z9iZA1>_v@k1aWSdCQi4Fgty+(4eV`*{T;QhApx4SUjBAkS|`C=!^kZbcBOS zufTHff7IkL1KyX%k*(Q4{ywmY&W7%#0F%)|`79NT8)(GczipNTr5wzVR5`>^iCLCIvgjjx*+abT8`ou z71;SQKwO`{nb)QI^GnH7!SMN2+Oq2!<8?naD_AYmAKL-Xre=Z91Z}(=n1r>ilc8IR zHS719j_a?vQqReiRJ7HYGBRuhdwnA`Tq46Ox?&s-*IvagYl;f$pJJ?{TRCKUQ z;0WEq@|+1RF!ml?EX#bsP47dLq%r)_F^C3ETbvRrPcgN4uR*~B`7m69z z0+TJWvABO28DBy=>TJ&$(fh&a(Wgq4{k_;`swe*a8h|cg^YF~iaXi8318I7xORVll zsII#l|NU=JkAcL-OS9U#)kk^8lM zgJpHcx&6m;Y@b$04YP;fSnF*po>IgIFYmwoZK%St5xO}It1E9Q>a-{U=xpU)_+mT zUAAM;$X0>(jPl29e^GdzsgJXkXy7EzQG7M|jaX5tO(!jru`aNN3+ocVeW8T6{cVCh z-_j}W^DIhQw-c8i3a4dFWgHbV3f6udi&vs;F!k?xs=oD?tbY1poNcB+=Tq_SR8!uC zJJ{Ix1^twnkLRvt;KZ#lJXL=$$jn_{@U!p1EdNM9pIgTEt zcfzuei)65JBkU~*msWK1;r^9VBnmdCNjc#p+}xdt6)%n9{OprdI4p|449);OpGZ&* zF`_CzUoKw#K`1`Ao?Tv)fU#vNeQ+?ss)Ncntt$e4zuO6ar!)$iqY~Inu@o-$)22OV z$|S)JIxKUe%wcPh4XP;Rz{RX1v~Kqh?4`Df`#S?FEm%*Ls1461UZ9cnk7>(1J)DO_ zseOq)&r;ZeGrL>D>lIqKQ|>)|n|)Q9w&IVImz^Q+YpkQL+bdy+dyi_3aDRv@(j{v? zh?a4_66NSIu)4MlCYh;F$K8v#N18}W-ykgVQRfKLWRQ1_B*n~Np7(D%KTQdeRz2B^ z<|;+p7MuFH*J(_ta(pzg*sUfr<%T@}r4 z>JsL<-hzl;^Eh&R0?s+U8V`HVMw_XIY-8|_*5>~bbk^GEgda&6j;cZNPBKr^2ye3 z;IXS#@D{#M?c|eU*V-UxADzeg%Pi4OHy>mKM+~YMOB>=kXuOjw#*ivo8K_CSu0H{p zZ|kwoDGglW|CppOniae+(D%Q7;E=n6l>C?sV}2v&-x61uDWON-^;|y50o;G<^Yi|? zyzjCn&3#`1M?dOA!gK{T@wMS2Ht8_+coZzx55o7`BqE;G#L|LYqQB~E+MMRe3lfaj zaafz^cFP%a2FAg}7&{QOOkkay8BFM&3;CgnlEsgGu+ev|X!o&?m>C;R+h6UWXD_cx zZQiJJve1KzA05IJLk)4W&>K?+ny~e!G+KEuS@?2ajaO~D4mzW5!V>NCqHJ;kclh>V z!_)y#amWDewYm#Uf3JxLedfXJ^D}Yd5jP&P;iB+*-2(nkxgNw7;iB{HT0v0K#UuHP zD7BXhEqx0ZdUh`a+-rb(JWkU#=}OH+HF`381gpxtqW+sQP%rxyq^L}U;)+K!SN9zK zbyr}I-$v}26HJ?1dt%bu>8$Z82`vwA!7s+!L90N47hjsq$(!S#_Et}}aWtjcHQlgq ziy>})n?b9aTg1D6N7DH1v9RKb5$7x$$nCXfLESQ$%M}q@?j&HB<2g8#sYOG*!}#)~ z#W-x28IK&~E*!hI3=+=5w7R|qWPmup{uZ)c(3FO6|X!aTt2xIPfUFRf0QTjmnEKj`|SqNyK@XG2<3F; zRyY3Cx*j}wK10VzK{()kKN@;hq`Bvn#Njhu(;7`*Zu&5VM|uRprkRo0&D9^xL)L+1 z(;w=J-$J3QM{{>!Gr86_)Ac@5;c#6qPJSNGmZzuliQA6ww#fsNZj8gag;}8f!wamX z2IAf;iMZyO5=x7bu;9TEUi|epN$!O3YL(vnW4d2b^OH#ddq z8Uw7e>`Bw@p3~!V-Yl1^&cCdO3U$}M3Mpn&sA9|qFut*kWwtGF(8^DP9S4Wvl8H%@ zxSO^-V0;wFbSR=#vcAOa^DVqq=1l`fX~DqxNxZf)i9+qwc!_qjsL*E~D^9o#Drp&b zV8l@{iR{Kxnxe#?^Z&rOPId5CUB~4iC3suCkf2*n{NsLsb~N~+h4p6YKHQ%ZHhv-B z58l%G`+acG;$k{!Y=b8cDRAa@OB|5Wlf6#1)4n}lXy!hBe*LLOwbGR#oW9qMLqEmf z#1)S~=04)&p^K1Z4Ja$XmcIR2$z#;QG39X~m>WBy=eZeN_(2(?Lux>N`)3O8^5GWi zIIPlWp#@#TPo5MCVVkuB+l%qg}DWbWnE4;O|7u@E4 zM^JF$UOq2i&LkK9<1`2phYsXZq9u>3&4TfLD!JFZ)i^dGpWozu5wf0H(z_?&*!!>z zX6yCi2MY~h+rxvDVQo@9(9MzW`t}kFEKZ~6-b`@!8IEU`XrWq2Ask4F!O(GvJic`& z{YuNG0rpB zPtMYj9?p0rB!iTj_t3~$y>UKAp{;`|TEAA|yIl@K%ga345^Rd+?Iv@|gwy0XL0z&f z^cjcTd@c=~+zjU+0uQ8U;1`n-d};S^+_In_H@TjH7qe4^@`&ICD@k?)=ByQ7?CkwR7FMHt8!BMo;Jd!}VA(WCj+v zb|d*|E7_?fn^x-F5Y_2Eq`7Kw@nsoI-ct#^l8@rDZ{9p8X#$USkl`;^yFtFY2PIi( zb3t^e;Gvld&&o&Oi{fDLY0JXdX-4$ z`JIFKKg*#wHEak!J|05ZLw-|A(m`_cl2S&1Qng>eXq?gS3HYf+qH&of4{W_GrYz0^ z|JD}*=dR%Sf$OTgKWpQE?(tYIBM0_>8>suLk+4Bx%qza0qtYu=@Vn_AIH-M|EaU|? zY99oThP@N@t5;FjQldf6<=99y#vPY2tO=FJ!w zqPd^nx3mfy<{!nee@}zF?PKw2-ZJ*-y%+ya7=F{6-Y5?sY1&wLJ#ztWTC$al8~spObt-p!^MTx$OQiAro9Hs)5NOs6*U-r%j5ywo&Af2al4E@daVk&t5n; z;UOAU>Y=dyD~+kx%KwEerdiVy;D>h`^|ErIC%JRc-n1BkmPKM}+Z8JJ%$2M^HJjVp z{3tfOgw)o)6uu0~fY!mgu<^iMkcn*+##g#=wB}e?l+}x!>TgrdgY)#dWfSIU=c2k! zJt*Jq&+P$$thT*E(*9x*U2{Jpj<_^{vp4P~eJDWZ@=|=)(+N+jE#$meDpYEBjn1uH zOqsSj*fYcq_dkCuEQs`B?S^Xd+8Yo5S?NGdZZXa4I89akTY)CN1*`0AhN)ShOGh>Of1*Yd|bJeyY?!Dw2+1W3m;79M^l(joe+^CJ|U%hZ=SRAGdOM-!2 z196MoRm$mi4$e0&p*AfOewx^y1FvqP5jwfNst)N|{zZ1wcR)}(0TY)E$0?rIK-*27 zQ@wg(VsJ2Dn*Li-`)vV5`M!tF(bL2%Cj()DBoIbjQ;=@?p#$b~=HR>M2f0{c5ADlt zl1zCxbe+Bl6VKJqsV5__aP3eYH$M^6CniFE<{13Z=R5^zy$6}~HB@Hp$`#<9pLeWJR#0Y9k-fhkj79FGp?#|gw{2faatZ) z7hV-MozfS!Q7|b_`qz7=I&Avk2LEb4K_=o@4BCX~gn!}E3v+sUcLk0;`d*AKEf8#a z&Bf2Ds(kErjP$&J1lI;Nisy7s(WgZ_Y0i^TD7SeM4~$#DsGAOrljOye#G&Y_GMfgd zjm8D#-yz~do#bgy4`<&9XTEo4moVYtJRW&nK!Y)!=ve2$FWe$%Y3D3%PpQUVjhDsq zqa>oT)P|2eZKmBVS1IM_G?o+kV;(M`*eiRW)Afa!C;#XU1^YyVugS-}HHuc0CNRs1=JOQLx~>6|NW(F9aU$ zf)`_=@$=KGXe)H%jv^HvJ2r|>Z%KfPuBUX)bSXLN)ClVe{IUF7f4;e@n%Z+>*!GAT ze6TtJ-zFa=_1Dkf$gvc`s#h$p@;Qbt|Lx!4x9Q;j(~G4A|3ST$8YYDIW2>QKXhi&R zu-Uni6FpVvmKq5Odj_MK_Z9Nb)uAE!rjFSe_24x)njhtufmwDvyr^!1mWyx6GUJXI zJM%V-jh+v>btQD|W`$O`wtA}3y}k{tzbXgU8RpU%WL6dO(&&4iiM6;Gu*A4#4G>1EvD|6PivQ~ zN6U3%>H4lz${rsGR%cd2;6YVhVZRvVJIt})!6MN8ew0GXJ_?^U?grt52TS+Zu=vQA zO(nb0t^6#mIWQTIELl#bL$z5b6C@MXyrSaC-Ff%x9Py;GAx`N+oIl--esz=5-?uuv z`NL(XP;DS<`x;U@w~#MP{EI7(o}#wU8oHP(@DAsEiXF8D+xtcFg|(G%y{L{Z-YLdK z$9o_StD(%(M=9oh4jGz^LXTe_Ty*mhRTdnjtzogkgW_mI_eZdOKVvj3 z9)_b7lSSh)3r==-!Cl^=*s^MosI%f8J-c)YKlEBd$9qd)-*Q*pxak6wuD%YAxYGnu{4o;@!I$c!X@`tugo5BZ7htp+A6;@kx zid9*s*m{2$|LJ)KwtjcOQ}YbD=++@B`|l!jCF-JK#R85T(g4S*uF(?nPI!1Z5mY+< zb+g_{cwrdK`Admk^;`?7HVW0#cK5(Vfnzy8Y!?o}0XU~|Jo?El1iOHrwIx$Od8UoJd@;_&CgKJ0Z&KoXr`_p9w8}T%p3ii$=$# z()kO4lq0839bP|R=710(^?ZTkX2m0Vw*evfUQhCK+Ce&fB5C8uGMwft%hgk5x%;*` ztT#ak3MN@%sQpg*I`4|mh)F18yc1k%yQ8o7WOlptulv48>5t13O5L(jNLnrjdv|{% zMeTInS}+CITo{Q?4TkuOccmM?YIEm)bj=c8Sb`D5iFAf`LAufO39}5b0i{3?+_&V=7c=V_P|8>b| zG~J%V#_NE>`9GAu-iz$sI@6>THhk9I1fRXvq=evSa9BPFdmn#GjiGk`c+!{k3XXtf zdoR|VqsJ9S!=S??8rQkx3zgFwNPdbRFS@)zGRG=BGpY$m`1J8lajg1yy4SKEOJt{D%-{yryC^60ysyE7dMv?c>2^+e*CGDm zwYagjGaekbl!s(m;U=dg{J4)F>b;g@#hT-AYVsEdI95p}Jyg(Rj3zExFaci{-=%Ih z)Hx^0o60-d#TOo{VX2B6s}#yP@49^lE^NL>_xFWz%dQC6Abf#mC+9N$@?wXq0--rt zinD|g-r#r|isDXD_McD;ZG9;!21oGJM-~`Ky7cHDYhEi&Lz9?d%9*GIEtSLh$U}2+ zYgroXh!YxUI`NPxOJZ{bt$e6#JZ+<8O@A7A)S1MX!$h-X3kFs`G9r&-0{5lsPQI9Puf#LMkuY89|ewspHXSP11oqI z(2&!*RnzL`;Onh^lH!R{cC2ae4(uyk67!c@a>eqEF+r zR@0p33L4j5iCRZ?v){>n80d4D=G#e7Lun0t`5ex{KR!wuA7yj%qnY@7;7%?NE)<%D z@%+wK9_=&*eDQH-#xx}|rQtfTVr(6DxCS?^fr@A8b+t%(G=iG78I_mD5j ztfu+*EIaFlrQy{oue&d*XP}@%e(%qh%O$ zN=tHTQh{LPdQq(ZFaryBJ)+uG`*~f*6UrJUz=14%y!W3G?l3q6&u!yiR=718i3xl) zB$Eb@cjw^qBHX-N0e|}G;3Laf*mk2x2+MmQS$Jg=E?mD=IMBWg!wo)@=hIshKiP%s zUytRTH!lj~k2~>WpBdb>B~I8iCkH*Vt+8oxKRET?hF(S97Ch2kis3gV@wV|h@Ri1N zx~RN@wF=xIq)!IydHD^_Zj9!xz7lcLl&kQybQ(MEK7x~EHo~W%{#YY(SF)_3RhTuq z4KAK?`pvLf+W20zimFg+lv~(Ar3A+I^8+xFQ z#T`~UxdAWT{~tx?{nzu?#_>v$ibC4EloDxCNPXVdC8T9XsgxBW;~TQl5S11Unv|Kc ziDF)ju&Uu{2^?IG>^OtkVAX2I?`fl4o-+CCZcWWfRTcO39rS)0C z#GReK$3fT0dg0}hwHSC_5I>(Ci}|W8;I*h8-kda|7xBG$%93^1Ca;KBo34Vo`$Kws zjHt}P2?qQ-PHTRfKvTCzzwuavOJ(y&>ueVktQo?$2Zll5pJCXeD~AI2m~i;-Lp=Sm z8?N4HhNc19C}=D3rlh};(We|yrOS(+e^bG?mo0JT;UVI$)0S)@xkny}z0lNlCB-HW zU^%IEWPSK7J{-1-3cky*q3l@p*_QxKK(fC@i(=nHS9>=vT(U*+(Qct_Q6bNiv&I~w z8uB<)3{O8<(88g1*!0#MYq#H^fN$67Yfn~VzkvaPI(&6KCmT>=~0bnoX zDx7?Dj(S=QMz?|%aqHey ze+ctEH9;$V0x6~>QL*(~GAqlZ$a4W$7CMS26=Yy|prd%d)fZ1@d?kA~T@I=^OP=v2 ztgtDG7M3-k{WV!U)8Pk$Hpj8@r&E&QeV)NdQI~0y1E)*<1@Dzc*r~sTlRC=i*MF0Q zp^u6oJbf2^%bLV}hb_djDqT?HJ{Eq@W$>NTNZU_ji56SVi8t=2(XmZOD8~FOHP(*h zk5a3#aNYwk$kYvsMjxi0KVM0d+>g-@cuUVe^@A@4-Av{@4ErXev-u7+nDWPqdyZGf z25S+H+b2Lm*cf(jlXz|)rwD4k%OY0I%E~|Mh?0Dk{yb+g_uBEN#q%rhwA@8aifbU)uVef>C_@+&h3m^C8G>h*11k2(Y zFK5m#xJ5gozQKzkwabp%GHLb)2b%FA3rikfqhR$3qVDCluzhtnO2zD=Pd^vp^(&X) z{jo=|>b5?wtUW@b&*oC&vHZfEnuS3jk+s(Plx8Slwb)4AE;15@a z(SYQiw5CW6QEmc1{P2d(>gZzC#z*|sYB`jd6ocas3CeC%s$M$#6y5we6Lqre=NQK@0=JGra z_LN6sKz;?R4UVLXD+<_eg%w6WzX-Ljq;Ynp9jpuK0~u2W;+PX|JTa%4zVuAx`|G8J z%AbRHhUqsr?a&J#bgabogTqaPjg5;Fa$z}oq^=XwUXiIjIcO65c55Q zvETe7ES3Q#U%lF*7n4Z+wFT-ot>tAOYv^F)5RP*n$@~9$f`Z8~4k}9Hl+TwS zYF9akTeWb|<{tb;=qpL?sf$^+3edK>gnQO~;RhLk;5SANpR_9AlAOu>e6l@`-WG{g zzf&+&(GQHGUO<=JaMqt=Dt5^=33W-|N#?JCC@(oqE+GxD@8bl#re}bCl-1dXoyca_ zC9%JrKFm;lMNg{UllJOsSU=4NU*I#kH9d)|ziZJ@<6+%&?ZL>d~cRaA*p3h``u5XY&;zMw^cxN(?S0IIDt5R1=hCxhv;op<*%>6!GCsx z_bzE1^-X~rTwl%h3IRQ{mvGL@w3c0?NY_c!3$Gopq8e<%{ zv>3O#nxd`acR@FIGe;ivth(KPPT=kD=tHRzdk37QkO5KbBVP{lAKQrzPvlW;$6H!y zvWT8Xy5PgIfMw(scpYdZ>Z|RhmQD+h?`KVibq`ekcd`%9 z8rB2bzNX>W^Y?r2#8T@!sgyq#j(uLxvyYQIAjKzHYCcGEG^KE$w#4 z8!9kZHUj-w zsRuFEISIzb9we!>F+9EbKZ)O>PjDfjjn)pT1nGo3cw_4fikT;&uk$)+(p3x8I=+r- zHs*2Z!N+vFWEf2=li_*3R(w(Y9sDTBhpf?#P^K`Fu63$GyS*1aN@|3AQ4hpEdormY zq}^l!?mhFuxBdHBZIZeR@1}RU|9>ZKcL?O=vt@ z4))iti_63NrM|D`paPx!pPpqBY4yJKVG^2ba+glHW-lK<8&62F@OqVw5Q+q)2CnOXl$?Nfn zQw*6^+w+lz!K7h(7B;6Zq4|Z#`1Ura`nckiM=`wExerZ>G2={E0}%5(snd5RP1@p% z6XQODU7tfVPn^i5>elpU#QEyI9TjkOZZ3^jkpeX|9c*>$FlvE0B-zeq>CgRm+0Fi_ z5IP96uW#YB!$oB9_Y6F6H-o!tCSaZY08$vbiLA$*p+OVu;L;dhSlITPHZI8(S63Vo z6V~lx&6!Ei=lc|~_s0w{$Ws)*HJ%Y3Q9pblJCp{mY2^jBd-3^`Sk~2;haRiFIj;3U zb-uF%qkpB-2!9WJvFe>!{p1^tdUVe(%;9j zqD3fMxXcqG^ZN)zg=^8uK^k|R>F%ym`y_%@J6;Ma7aW`?v)g<{UUxnj%#JG1<8>ii zmHM!9(k^whY}Z1|o4!2J(HN6G9eC~2ad@cOT(JE-OW1qH3&S>iqQqu_+md9^uI3gl z^wGlMOGe zN&4Z@K|8Qm(8OiUrBv~I4ktYcqLiLTg@yL&ye1-=zGVIZi%1`ye{lrYdKcn3JtdMk zx<%OUwuko*PQuo_^^~`JJDKlH;j%(k{=RY_S}kvaV-C$Qr7@MSC{Drhrb=iH0?9vB zLkc$iE{OdP;k8Ox!K2r4s`{@Vzr65K=vba!UH@?|5B~B?Ox0DRX~VB#n*Ua4U3n3t zw|uAR0mAHcbIXj?dzg(t)HP+bNpJ8DPxetK$2x z>-0_cm9T9_zL-<6L(uoz&6AwZ(~%mYEA2zkd9fK>A8#qtH_M{Wh{e?_3o?0WrXikI zwx+H$OMH2!H-A`|AsEXqMAbR3#PQdpE@w_Lq%X<4S>M?UMz_fzL+_}Z`D6A8lHmU8$I5o z;DIy74Wi%+hXu8WDZH}Z4I%xF3cOLxpt2{kMUNl)6jb3xkLQ;2th2AtbaXBqsRR5r zej)!{=ZGW13~_6711XFj$){|}(DvJW-gaCWe|c`AC!eQdNiYkucBk+ww;W+;S-hZe zC5_w5VtH$8E$pE!IO}K-X8KQ{XJ#9!hJ>r3*OnptT4x#0e`CS!b?SJ-QiPBt)|fPE zI`oj!#pmDKL{G=Zf>L`Hl}iTT+v0HXj=w%;C>E3DYHJ!6aa*ia9K;?M!g1A_q4-l)=8z;( zJhv3wuD{^GYo^#_xkp%-?T&4=t6AfHBP~}8!HAMeV$5h;Op&$`D#pt5(-$|`ZH*1I zX4t^w{Aj#dZb`RCJcK85he76}i;#SC7(2fR;I(lxDb?~K#EzYWF0JyoNiJJ-bkM?Z zl*QA#uA=Pq6xws|Fzp*3!fhYpY4cWja=C5JExTke?D;P6n9zq6ZeD=3K3B!|+;0Gu zzlAT_DkQ7uDab#_q7#E$_=~J5=V%0?`{Z5XZoh4CB{PbAZ!U%VZ>)TtfQ*{SN6w0H8g)^I-GRC4&*8EfRG!2mnrpzz4ocqU)OWZoe z$G&z#d{!*9F27YdSz#14DUY&+ZrcQ=bG90x^*b5j+lgHgOm7MFIjHZslfjEuUrzo>7eo@30I6njQ;UJ zjBlL7xM&zYTx-sDGfSbX<|8HjG!lgAr>hOu7;@ZZW7Jx3g>Fu2hmR8;ad?~@t}(P_ zy{zH**Vmf1PV0rUPA|k^%hRe0S7zaxkTWoQzC5nacu7BmyEN7yihid$vfTbF)uZ>` zr7HnjaGlmsiXLEywm)k~`S*T^3R%IenhRN`Jg2(&$rNGCwXH&7(KeiTrJJ8jMha3^ zOZZXr9dLa(pH}&$l0}Ciw4Vz>JktvQbtzF`tvSan^d^Z?JT)HsB$h3oO-(0DKuIZx zFGbq%ABBO`I@|-(lLq5j&G(XlgFE0*pGwFLyhz*iwYbh9N>G_@!CDvR!Y?wTGefF@ z$LT}xqytqOiXtFCN}8OnuLA??;dHmp0%4ubS!!7r2YGY0iHmC%YH3~ zDQd&es``cCo-(+4){Shkm>-4#V~^6Y`$^Q#Jp%_kU&i}l)6vf>g614;hEdvX9PT-S zS9jhAFYkwR;r&@`GxKFNYT)Q!A4#_N0F?i;t6KV&6SHZJuxs-&{BgYkkFI#?Vp9Hs zdyFvR2M1L6vfXa1xpaXphyI6^hi^c8Uj_28*o7%Rt6(B_g2fDXe&MwhWHOnK1^uDY zYdmRz zfG`NRO`=U7G|0_sr=T9_%sUEl@LJpl`kuE9>+6GAdrvmpHZ^9C04*-naG=qPr|{>5 zD%5*zk7mL0*mLo6ZYj{_uQ{eXeu6Kn$KMysek4G}^vyWlb35mb*MZpw$5XBBTVczw zCgGLbFz)fh8(*5f7W)nCg=-Cc(YWiBpx4xkTd&_ECG}-u^#1-Z+vqgi@mfKd3B~w5 z$6TELDYv??hY5GgJ_TlJpQ{&+dQH3Uogw>PhEN#4hW)m!#wWQCDZ*nd4%Mus`AUsK zV|KQ%>fc!IZE1|zasy%H#dbJsa*Y<-gtAOs58Uw9T2Lz6iMpm~Sn%?>nD(NQrgg=$&huR^ zFQ$2Nef=p|D%~jF`R7MJ(vGnhD$VH;awzfDMnk=HP~F*|P7c(J8xG z$&<*mED|<7xl1;6hu}u-P1qG(NXJ}OanlN2ywa>WF7cxyxVUd+`}kOndbR_0Dow<> zE9|*4eG%65d*SltgCU!=oASSO9dU!^Bv4&n;?nY0l@8{%fxUDkzdrSz&XhP)mFH`y zwci9MW6qQA-7VNOeIUM5ixwu&u|%Ek!|~y^U*NMuiQ8MWSgCrlSd+4uE`RhEZobPR zpB>Cs_RHhw+DBsaSAQJnIt~uUucadAd1zB=!3)>#f^xSOaZ2T6+7mU8@7!K1d~LOc zn8ukPZT|@R$$5yW9&<5RN)=<={Dm>%O`e$Ci&gbzP;Ou(w%WXc`JXkY`1LOck5m(H z1a|47!iGw+>{)JeU_fm9N z-XeLugMn{z5^|LcU*c^6P~E;ggh5}Fj;mA z(!6uI#W9)Q)-S=JF)|nws6a0o9@F}qa=6=19iu)>6leENp_kXavEbAq#*yQ|IARDi zb_~Ow$17ppyh$uZcfgMm)ikW25UXDtp{RH@G@JjOEUeWr%uAcL!Aid5IGKJ9zl=4z z?5ILL02HQgVxQ}&^z*_w^1t<(&Q5pqvY8Ch5sMe4@gi{) zPwQbSZa6Xy?X;V4k z8f~|NX-@-{O|)fU36tx&dBWidb%X=H;=Iwvcw2g%aM8(`ei!88jGpz9-#IDlbvTl8 z@&|H!pHTeKLrG}x?}I1*{G+J09#U#=q*CL+|DfC_%BPzsf7jiq}F}_!Un4%qm zCnhzK-B#e<{Rh!}^#sTYRmJ)W8$RfuC?4FnTWE~RR!N<=NgxId1kQ^$@7beex zA;SjYSd0hN(ML$Pcr9*Bk;1b_RB&0REFW~9Q~jUaNEkBn2Ca+LrG?&F>~MNHuE_7l zF|)34kDGIO<W=u<~Yq z$a(Bc}O%mNTc93r405qGZJ8mO&R&`KPZms-Ji<;?V_5M zk632gN+{M+;Vt(Qu;i{Uyj|@H>2G@A9Cf0LIRnA_wiCN6y3*ueGd!94PuydwLKO{D zdDYrUm_BkLoJp)C?T4qR=So*hNH=8V;p!04Zx(M4?1hgiPk_I<7QD|p3tJaY6-zQT zSiyP=N|kJf-FG}-jQT8gl+aZ;W2;7LCl8B1$V`xPCZ!ay(x>Q{rT|A zbGSkM1bMei!!qY%h} z%_p1qos|0KHeA%24(CG)aBTWGer)87b9gepjq^d3^W*vEl>+j9Jd~_FUs2()Cn$be z3&Xnl;j-RJY;@`^6)4N$ksuj%>{9}5M)oY(wv27{)3D`z9@k0r#{{dnTq#!u^`X0< zCE~d#xitlk3x7y&*(uyQ_bbKsRYTcDwyfnOi>vt+t$8lTvgLMU7qCTgV!3!5ScO|x#Bld%gKVZYM=jbQNFRAh9bqSEMPxZn(MkZ4+eHJX`16eu z{oueXWnp5c5(ikXB?;NX>3`uo|J_O03Y8RSKoUF0N8N1m3CdK$(B@vM7;m^9-e&Bg z>FJA6dsQr~^y^dIsVL9kAstXv_79qirt{#RUnwd2Gt_+ChWE@>c+~u*w9ngyZd-|v zrn7*;+iloC*GrUY9LEdn(h(+FW8bi?FkUa5uUkndBTWZi`w!u%u%AA`0 zfR0YOLlrW;s9~l6wwJSM(Bx_OdHQvTy|f+;-d4b<_c6G8^)ebRsL;*FvpBa}f!pU7 z2}UMk=+TIIFu*tfLyY?1568az-b9Mk4t2MwLLGQ-@59N#?c(vN?KG?X0%!P0SfR2A zK92LkTd(_JuL8yHb;^a|s;c6vV?)4GFBjv!tr837ZFF(EIgD?qSJKv6Lppx^8*RMM z3|C7JpvRTDoSc4|ryn1{Q=OToNtrUAO$RZ9}M>W#=|Mk zW8ht}p3OHusy=$1!OL_Y`u%QVm-W4QPH-i?o;V3*=U*1wvNa?NSOqPHNWs0pO}y#k zWBNC413AZ;;UDWk^tNy#jF*pt-+Kn5=7R{XeBgkc4Ri2bSQng3R%9)&K`e9E4x`3r zP~JRKajJVEFZk38O@@pUp6?HX*YE#Q=By-9K5aYZ6}bu?(;Fl&8^1!o5%ciA!$fwH zcjt-5U9_kwA2g1{Lewo=_6|M^Uy}iKLMy2K72*>MO-`H{NA8bVTxA(Y?@qc;aah*-111GGwB13jXgx8P5yz@k5(Fc?Gjv= z`nEd2WIYz#eM%NfJ;;|jDRQhKxmfprsXG1~9T>r9w09xuB8iEoLCr3ZU-UTz!c8FrH>T_1+WC)&84*iETNyf^1Ve5Wx`V-xY{R2Nz%!&{i z9ohvgp*lG7#aOuUk4saRV$LkHH1MOgR32k^$<}cY zr~Dr#MSX%hO2bjLN}6p3?S)XTlWcsT$FG8RP|$Ky=D%jx%WonpkR0FkJ1ERrmIH2D z_K-MVk3X%ef~@^s*t^4mHD-Q8DJyM!H()5bmLFudie2LDEgjk6B@$S8c)&CN5*-q0B`^Amo3-vl^Uf~YDy%yqx z8w2qtEaN?ceh77sZ_~=e>6~4Yz@>XV#Yr_rxP7~)xFL8J*y{9yU;BMADdQbrPSB+jwmy|lp;$mkd6jmHJXODduH2?5B`fQLJv-dzz=(g|XA_D4upj8@<&W@tcM#^+@)?pqgirw_BQzn>%8Xixo`dOaG8WJuQcWxA9_;K$Ml~{eln9AF?_jU(dW_6^L65GOvSsNrT4t*OHQQ{3H5z@m?1@hGkdeBaW%-PM z>dOmdD5^9$AMvaesFvTzwKTeBcl^=iUrXAAVTTj6( zY9wjAjfcG1L-Bs&UC{dAB6c++TAnmyDc9F@ZixopDP9GK!yRdFK&`kjYcGuHaTOwi z9XL27iw|k1Qr}0LB-PtyVtW27;o4D6{BP4eP_&o;0S6s;QAip`A69@5KPq5X@HkxI zi*SEs15A3506`nO-QlCpsoVGvQ^rA_88o7)5C)VgVOwe_ z-po=Gb!F8s&Eyjrr1xd{xR>x??NZ*bR3F1fpMd2nboq9L54F^F(8SFJcy!HnHu~HT zf5@&Smotc6jfNcWxPntx7K2^o8p-7!i?~D*htZn-_=wzF;n3L~^u|D5oM5ek+hf() z%t;z04B#|nE%b}l!HD=`XefFIFE&l4vv+g3VSWHrv{?yT!whlO z(R;$r*%zt)yg9yflR(Dc(_mfa1_lk!`M7oh-*-?#5DJBp%Y%>?w~)$^(>Q(K3%Gp# zG!*K&VTzPFmbQKu9t^xi2M-^kiUsNP&hx1#=3CO6Q6-qSAq!hmw?eeuI$o?1MTQ1h z6rK@Zz0kst?M4T{mMm+UIdUXFT2cr3RadDqSb}fNk5=E!J_2LoWN_}HD)C=8FIYaQ z5XOxy;<#NERPxU%|&VNTGb|>M_!b;)Q>P#x!)N`DMP6qA1tjsG*T)8%b zgtOAY)oyFWX#G0QH@WP`H^xto(| z*~hQ2)8#sy35gTW;ac2Kze`y2!438V_TZ*cHS}tTVd36Ta-GyBHa*itwOO*bR{t0+ zymTHOZ4TiTg(rm4exqnh(?Go1TMM?9ghJ={EJ^1tCliFzJ9Keg?h(oRkWHXgJOR!JB;mCsIrulKH%0Wd1ldJ_V5f=>&JEMYoVUKzQ8x?2Ci#&; z&oi`fw=Q2_e}ili<*I8Y4I_ope=v5WAN1U3E#{?2L#^+TZfEYK_csO$17jAg9!Rq5 z?t{tkXVlvd;r#bjQDKJ?H~m{c+B>wczVI-#lur{oBoD|dU<3>|j1v_H2hsYb%T%Ot zOSopVm!s51@{rfS6HPt{)3<3*?Xr<@X0QPs+IkN@jrPKGGe+RTLvwI~qa0rERHo!Q z6V~ZSq;<*0@2^nz$4Abb&&a!Nfs~(E`wYKw=m21VyfH!pb(GKJdRpf3s zigo&DNc$Gvj&M2suJ{WfdUO>Lk4z+=% z(By2&js48oaH7E9y?&B>V=U}d>&=5^H$z5|E4Qw$h2|aSs;zQU&|Ll0XdA{&naVSwZ<1xzBEEOC6w12l;h=f~X_!R7FQpMQ zD#nwi%KGxlS1IItRu}hW+hNy6Gw9Vi7Mqis!SszA7UxN`tACl0=k=FNCgebx+ZmX& zOq*WrIwhF59j45^o3SmUA3l2b6`mBy@U9i!r2X)$WW(1kdgT>Ml_ONRy~+_!7T3bk zP#vD*(kUMAQ6e^mq(S=i7e^z;+8Zk&Xvo9FNFaZe!c{D9!Ws!RZfr{CIg4ojNq&<`@mLm2``vF z5?{BoAnl~bv}QDZ8)ZsA#|N_CIbBj7xm8eJv<{c=>xY`VrqS@Z&q>AKoqk+;D_*tx zNy(e%CyE+o~9~$ z@V2O*)m$4(CB`{)s4g3VUglA?LjoO-ibCh1_aQWN4V?bvPt#;H=#JMqaz62%{G&_)m5wQ9v6}A>iV2dYmcuKss|#rEZ!L8G z|63Bv)gdKEhSyvB^4?5aai!`(!a1tgS1rFv=h#26I2;E(^9m)y_SH%@2>Nj7i5q9A zJw?Z1`t1394SfDRhF{27z;v}<_-|z(Pq8!So?HGCCS;`0%ZM5nFuIKbhfQ+XQ?wtJ zf7O*#9(V}Dv#P#gOBXa5TD^554k^Qk&f$m^Xe4dmn41;nGWJko+5V zx6p&Ot5P&?#!0Mw`dtv-ABF#3HbI&;W9|94s&$uD;oSW=cA^V3<=92hW5zx@_-{G1 zF0q%G1}K(eVR1RI9-z&E>h2pgAdyb#QaIaY58M3yKo&hdP}tgN9ICLL;$NSkgAEMn zrQ6U(?gTED?~mFGbUAae6L+nU!Tkv(bnv1R_mi8zeQG|y{(*DRcV{E($)1IQU$lkJ zb=5G+PM?QtYM=-Eolt4i7B2FQ2b0<9^zdNo? zJm5EsH?DgJmwi2HjLjf+o8iUV6fo|j1$ zX?x(%oZ~S2)Fbl$u1Q64#o+bmG~Bwk2pV#eg!G3RuqoICBKu6GW62)uJM%pDYqqAu zaxHATaEw&4ZRys$XjrVglC2_(z%2eJ`A|AvufGS4A1z?OfH_dUQ-@^-%HhHdEAc_Z zVtDj2g+uNAXprhvsCs%I+;5z#&guF=>CA^Z@ zErnid6v0(S6E*(b5Nayi`D(fXr$k?;`sLjor#hd<>zxwc7B}F8olVuf4(+7)CGTiV zZn7ACB_DjpZ{tUrPGJ1_HRNCGqSJofyl-5KQ1~qj`o&j6SFtl|PCEpzr(cGX>gUn; zf+zP(-wq#p+H=P>Z8R}F40|7YvCQm@D#yBJ+IqDgKK`7IRq`8Hd*&v3^FfZIg8ZR< zbTHMVexwRA$5Dm1_{il4R9Wyww7IYjRZecDXZ>Ua%Z%RLt~m;inHhnN)&QK)u$D7N z$x!Rbmoz2#FYMZz4`~uxQZ&8?4hs&D-7gd~hBrXCa{%u$>n(UpGiJTZ^0*U~#1+kl z;OG@+OuM;#Lfe?_!j>)@9WrbQ(?6 z+6{UUO(2_npSJN6kY26Hj{~K~xhd~qmBn+oa#I}l-TzcFZDJNobT~>k4X5M8`txA@ z!kATx365l!3w&b&I_#CATaB+_f66T|yy8Pj;WiYrJc;D`gMe2K;%1C4O>R&-oEil$08W13Ysn#c4IC z`81&4S}RPFdkZ6f4dneJ{it={ImnK(;ziRlabkoFmPVz(bdST76cR$6KR44MIaU5s z^jrM4bgm$CxB#-8;_$6Y8B>QR1zNdsPNxKA*RG?Ub*hA z;vakuj^65&7VSxTCaclGOP^ZguClXfFFsYARh{Io59S~A;fu)?nryTJ<8PmUkDhVR z;d+}#84t(B5~fkddSFt;2?*c!8Rl$A!OB(xeqi4s+= z<_a0XZ-u`bRM}Ay#2Y-c#UKCwuWmrK*je&kToj|qYu9Dcz8+OVK%yc~@Xdm+%hGsb z!(sd{G=K|6Xya_HS^VmS7drdwhmaQJ1=Igk7kLdL)zKfsiT_G*;v99d3Q+*Zu63*+ zdt4}Pn@nkW7fJcwVm@27p~`ZAJq~&-gSxI?Azl4L~ zMReOPSh#nmmd1=fO`oP`VBpa267I0VK}G)T`R*SmbdUU(#6f)E(tb8pj}q=KkHt?1 z*5Q@n{OX9Os&P+F71)|XP|;*r&34>t(S_8Yl!#St9)b_?GBq>CHD zoaQ*M@y_-ha~y4s5%}sjF*1?Q;X)(n0~-(X0c4%KXus_uYe! zh3I2>#WphTqeC)^rxCTk!{*2YKB(i&etm8D!mDVAFBr*NEcrEr zl9sAMg#9?YAGi*UpJd}uRVk2IgI7_zOP{26O2FDXw`taczhdoX2adjz zM3)=};&0E<{Cme~Vdf(zEFYtZ8_pRKcV}XJc>v{@kASfCd&Na|136&XIJj1K9J6+7 z^N8su$o**yRV+UV`_(R0mB;z<>?b{7>Twg?X0r;1Tn}OE$bp<57ROV+i-Kj}Itr_q zE6g!-#+}zTaKG2Omlqez7q9ei7KXnw#R#dF5PjJm?>>&lg5HI+&mxwJx1U10l|5L= z;Ks@m>XZh;jbWBNLgyoXo0cuCHHw6%WqV2f;XqPe;|02N zkMNlCd-%CL4T|HO;aA2QmOZx}ZmG75M-|fO-%e}(-7eA>wIq5rVj>2Gnc^&;{bI1k zHkR8V#b?rWF)=3x6ek`PT^Aq5lt4LjowY-pxv`kG{#Akd^171VG>ShOedzAb6hUFe zGjvs36DW~Ob%NWRKc66vbf;2Ev`(xApE#8R7^f#fTOb0 z=!~Nt?>A|{g#&{Gxa@)Y%SQ2;AMYsL<_dY27EolX6D}LNp3EON)Asu(c&N)R#Gl`w zW6Cy+*3PEL4rdCJZ5Ml(nep@TrL59%fa*F9;E1+mP^$S$xckA0fBlq2bhW2k&z>CA zPnW&6X3=?*8#uWA3oNhs1E;HIvFCxd>X@OssoeV=g~mqU+^IP%+1>>@cLuZ8aUIl_ zBf;%fU+}J31@q2+reEJ=F-$6sn+!CtXI3IvZq5{bSxdNFdo{^sd0^AD*OJ|XPxIUp z+T6DI1h^V#VTrv8?fhiVw-=kBj%P0%Q-2PgjSWMygR$IGZzL{J*-P>JPr_CE^>j>n z7LD_`1V)W-$S6b$PuC^m=^N_g**SpEJ(84%?--s8(|vmjdxOd#BlIDpTFv03T}^O*xxn_e@~eQO@Ko80P0sYL-n__zlUhT0Zm*53wOASo!edaocO+vm> z`HwnWzFQG*{Eq_bj_dL5!lj`tiBu#dCA3f?)%Q6^k&%%odqsqhowQ3^C6xw>s3>Gc z^?l9>8KJC~m3*jys*D8RqAxx?l@W zm~;#sz3$s`t}H zY!}T=)x#Cz8FXQGDcG0ogpmz$_|CmZShsO3KDrvpH3N5ITFoyCin#@=N~?wU4>!~9 z`?7fDy%n2EC*jtOr(kJe3-N*O{AG>_crH(bAMILn#m9tIhn%4t85Rp7_CQo0~^V3*i5!`Ql_!v z``~nqF|44R!5aValtJ=$`2J`**7l!^gI0J6@~2KfVOl@hc0UMRheXqY_R$=8;3jGJ ze*h1&X2Dw1ca(ePm^iNmq9wMCOrkH-RbYYO$zkbv(CitBLdanBtT*Cq{vA~L z?FKv?=MA}0hOB9M2Axmd2c6mB+;FrPFIp`pct?1m>Y=;TJ0gNc-xI+xFAA>5eS?WJ zFL3bUAfa}OA}<`sVErR5aIoqcKG)Ub zi3vK;k!{QO`sxc$?*5|Z#aSFy^BQjDt5M;cS-kVo4%(v>0{22I!6Bi6;^sz>W!*pA z-`$|$dinHrXCkJDpO)^MYKzm)IPxW*JW!MIpaa7zsAWbuoPBB70A5nM2u+TJ7 zuXZDsMb}YB=M$)!-6b|{`bFxhNsyFSMxj%uNe4Y>pc_k4K@xNgniWTpp7nI$^DJb& z)e_9FUx0uAjzinDi&VE%jn^$YC3QTgzy_jQ)quA?JiKfU-1g1mKTAEaBgdUmVLHzB zb%3eA2I6~Z3oLs2i`LwEO0hXfSh!XW3>Vu0InCgozqW#(R|FWkw2518c;mNS0?KUH zqQ_NAta0|Ard3^~D?%+P+pU0TlLz96qJ=#C^hHd$vxLXok%7S3(VRJblr(EcGJDy#o_{|*otoU-HEG$=0J^Z4i3LKhqGq+ z!s@mOT=%6+(6B0?PRnO>Ox*`H@2PQ0!V`GtG7f)dYT~sV6Mj9~iu=igf_6;_1h*|A zl~W?DT5uC*oe#j%OIGo*qZ>JYZx!iF2co)H4}RO}z^^8x^QpGOFuJEVt@4w{r~hTq z)ADa1Ei^%I^Qkm&wgXut%U}<2FRGvFOVuH=Fuijgug~lSi%zO=N##RQxRWWd)-*=F z&Yoy6`Jr&nBT-y8q=?oWs3yZQVCNqDoMd$!>GPI#ICYMc)`rC4E!`N-4VVBW$6r(5 z88t%doD!HeX);@sEMyIJc^H_Yg;#ZzQTTC=ijQ6r6jkpDlaCe(4;n0aovW5`E^QmH zeUJ?ACXax{(|z%Te+re!ekF&i-9^Lo7sT#K(LB^K6qM)Pp{Tql{95KE_#SJKE-ukS z9TgKU`I$iK^S{%)rQP_z)xPYLlMgOKkAUykd}uUY0@wO1ckT>*48d#SX;(rNuI;P@ zYnL+kTQQ9jm34W`Vjp4kn`_ipHv)Dq_rQnaeYs`&XYo+ybkR&=j>~=)SB?+Bhg#Y}X;WXX|QD=g8-hgvgT zoE`Wc!goH9=qHTeV>EC) z0{-;-;JBI3jr!K3r|f5qDxZL{FXDo)5zj z1Ll!OsuIjK(m+4$A`A=&gQCCX;#+GMetu*Ts5Mm4swbT^d_fO3eS9C*J(z<2`?qn$ zMs-+vdOklsqb+!?zZ<3iWC&I=R!Qc{pmR>wPK#t?g#(!-*2bE)u zu;}D89+znhPvT$G&pYAVzp5A8_}L2!%>6O!^&FmTcwHQ;MD!@t2g!LZ=)AIIMF$7b zJhDHmdKLpoQg?{heuxLUWQeB~xeAbL46G*{>TeDNL6f z(fuyi``F;kKhwpu#PK*|TaqYmt^`&oava_N8uUJRjd*o+_V>b{ zFa8K#(=6z03W3grwP>57#7>XT|Xl& zd@*K5E3@#tOLS{0qGb82VBJ(tn?*VP5~>bb%@U|nwq}>wz4%D=B4y=R!SjNwnB5g%&a3d2vGrIl;%NFD!aak9;4@yMLT*lM+d&uH#PuOAg? z^l*fryr5F_IBLv;=W5|zEgL?$Q$am`kzHW-Ldx8@34F z>}0S{&Oy#9&lZi_G1! zoc=BvuV3ztBhOvIX5$ICR$HH68#?jv%o?&9xCGZ}nDMTIZ%Hx3ks`MQLe{7T>g%`w z1K}_oU6>*4?y-v!G#5%%U2=h@oAos2(Kc3B+lwjPbHM(XI+kQR)4kUNAlc?Jcy)|n z)94p;_e=pA6eL4Odnuoj-z$C{Q!lo+24Ka_%`B5qC{AA76Zgp9fLTQcI9z2Al}-IB zPN;Omr#elvBkd%GZn*{h_a}f%PVu-sW2GEi{|7$LzAMC!iiWk$8lr5?G~t29r5{{#h^Gi~zoyv#z zouEf^&x%(LpM%!R6WC>jKi=NiA^ut61KwX0`17h1Nbg)L9I-WG+Yoo+dId4(aI-kB z^bhWhOrdi80|ozu^G%-+vc9Lno7^>dNmFkee6|U?J)FQgDf`(xR++Yb+XK-hw)lB$ zE*;$c8g?~n8hH@`mfZ$MTI^-@zk)x47zXmZ1BvP52TV%DLzJ z!t1(WWIpRH40TvfJ|`bZvn@XZuiwE|hvFbxU1q#Y#B6l0%Oh76HL|eDgq9;?U~NV` ze|mXQq9K%%>73yhI#V5ou8|HVFAA6 z$g=Y}k#tqNL#5GhwzJ!f<$l93Xu}=wd-jMfgnRKB&lDQ}#f}^E9!a*8me46hAMRsN zh3(>NNGR`vZJU-;X-PR4Tug%no(a6{%M&VHY=>GZQ9S@P{#cEzOaa4{_sK?{Vm?WCFh7zNFXVi!doP3I6o;!@d#w zU~IyF@MD86#!5emh6eWB(yfhb2414Yb$djcvzKUY-(9%bV-VdlDQ3feKIYTVgVg3) zr_}aC}619LOY`N8n z%{+9ua=aYYpV7qL>4w-`Jpvz}jDc#KG~w25B~E_ghu{2?aNj+ByfnO?zMb#Qc9|Ap z`|c3$b3ah~!rf#Kn_h#N4rWDQ>477LPkem1})*rqUQx z?bQg~?Y+3cGMGkt^c4zQRmY%9|aBu^wr_ckaOmzb(?6{gUw2 z(j3aw%;1oXAL!&%C6q1hjk+tZ3QZs7C7OE_@L7`|1b*+wr`~^{(c2=>^Ik0W+}jTF zM?cW#J_~tOuh*i=X$`(|Y9*y6Z^j9O^!RvWU)&5mVpo&T_zw_pVjwRGT7t)&YeD;T4agKr*k-;l$7mJ{3qDuU7d{i3`ei%ve(|_{Cj#hU0PlbU$*Q8ar0q`Cq4m4?2e0qe?s7H3;g*f4A)#f z$anqJd5rc-{`gc0EzbTF7w8vM4KA?5CXE!lZQir zlemXb4J>=*f{TA!aY6MSG0}HApHQCz!EH*y^_Q~+gJc7g%sVZ;niD~VhMHnyYc}@K zNr1J!zGB0|*R=d~Z>l}{NZ4^W_#Yk}w0hTmyl^F+lACpf(~W)k?dLXdwUEW=iNIeS zBb=ILE=k%mW{ASjHGI+YAS`hkM0#68Fx0()KDtkV z#|+D|9XaL239&HwFb%AF18y?6V0ZR+Qvc`4cXoXuvjzR>chVjaSLLGWb|2Bt(Uq6) zG3OQa{b=GkYh2OLMiZ4!aQD96Q1z*iB7csBw$-J=vr*o7&2S#(PEn_9weysC#1q@o z-oVA2U*ea{DZDT3CB^xCgO)d$WG>$*&Qgt``8Q;%Lv7zeW_vH@KIP!&I*1SU9fgP9 zWMFyK2SF)7m+Y+i@oGJRSB@}b@0b)g6ygmNf;`~h&}4PxOL$3Pzo@8`1Uc@BoIFt${5HhF z!>%KA_jU}QIeMDzry8NA=Xjhx?=e*0J4<6`7DJQsY|$cU45fNs#aHV9okP}v%wI*m zqCSlJ_Oar|sHObsNj1qO924?ZHPe`Ty>NowX0%G_PCKtn6JB15W9-HGy z9%piBpK2~YS^b&*#y7#fG&MZk{0nA;hS45s5}qIrT|93pb-4P)xZs&s@5TI;+l$=Xb26 z17)EYbmlyTZODb8?E_fhrzVaXmnT}C9?mB&<_lvp1oqt)j$I!|q1>zS2>)G{?lbr( zDppN|)ypUG2bEE*s3ycqr1@D6zv`FR(JU#A0b&o2z ztM0utIN$)JxG%(4pT-NDj#bfts-Mv6+#*=59?F9n53|F45JJ9M;arDNSo7&8y!t#+ z_%Ed&*550q4#%79ng0wrd$o{a%_I2Ikx22*t?%TF?^chEj?a54Ru~W68lT_Q6;$t zdh}_g%FYGUZ}vvvhV~PDeEt<&+51$mP+i6cjy|Q-<;uJ}Pmzi(cH-YFZeZZvjic=2 zNj%{zzHY7n>%sOM$}(hp@TuUDbC$oB{^59OBq-fgfguBnv9WC~cv!^X)RQUjM|&3? z_?nDqnM}WWoF^^k3EWh+SXzB=C3W*cx^Z0}%j`yCjawgH_2)6FXlkO~c^~LhNaPj| zQ??km4IB;QX;rwVWa;SLXcjsG|GxN1g>S0G8Cxgt`d6wr^7$BkrjR4F-qohy!#Wt< z%LlSc6!AfFnwZcMAqE8JlFEa=yz|vWp(d|RnpXW4Dt51@_|6cF%*_`)BjxbkE+$`< z8^i}EP*iUlc38hxm>wFB*|L#*al1L0mwHO+oG!|zTf!$xZ?@2Gfu5eJ9OGz9)3?46 zWO8%h(bEoLl3}!PR&EsD`|?uKs;^I(vwQO9?IE@nd_^x)Y@w5^VfWJr+XS%4xXAW)SvO2I!c2Ks0<{DC)vnHviyDch?=Jxwajk z_)!txtvUkZeX=mF@u;|>@)q@#%8CyQ=VJ>>#bv@SsGstd?jB!=HB-;g$dOfqw|29{ zxQ5P6jY9J|0;tyvhm|+S@t#6N3{!xUzmq6;L^j+09*!4O()evq5lqlF;C=rxQQS>u z%w4{W2Ko;WevLi=zm$p8?RWClm{3}0brVh{N5W_~UApSBl`i*pK!mITSJ1d%Gn%8rk}&E>^8dW)rVuJ8t@p0rEn*|8?1in z%8o0K!q4gdCLe~6y*%Y$Af9$pA*8G_;D=hoWRR$ZlSSnF7|(vNZPL6 zJhRJ$*KVkw3iE!vUfY~Cvby15(<4x{_$=;B)D=TnllyAS;MUx4LbZ4b`sFX<1yWVm zc4nwBWY;lNyBaCtOMPK))JVQJN*)%CPZm|}o#%ecfI7j+_S? z%R15M^CQT4bhzW^o`L*YvjpWoJ*CmtXY%m-v)JLk02**x3GYS>;L>(e4A6NCC+e?? zzB4j`l^%+RmYY${HWO;O`x!oKhX@Ic`^mZccBr--gwwPAF}!}L@Ndpk89j$jd`%O* ziu-f$!w+JW=}l?u{5>d>n#yrSSu~^n2$m`-U~biUYMEO@9oh=mFkuqr^f%$$zuPgV zLT7yG*lw&>IFXA+nQ;51(KxbZ4}Erx<`07x(3i(rFzMVz4n4XJHmAw+0O>Gb(+#vN zc0B3rTY$@ldx7c32->f0%O{r9Q-el3tW$*!0~FGt8=Mo|mgIx$ib=~&DI zQit%;->+y)f;_5t&7j_gia_dYg^i1*^A2egx|jbIZmbxD)7D-k+_Hw&y>S7#EB4&y zcrWqVAVB5iSMX`rGqUg-&fgja@at)I(&JzHL;L)G?B07InnmT(SDBeOP(FkHbLokV zpY(ZdrwOhb_+Cg2`ar>}GDW$a(Kyy-4A%sV6b`RANq?6B+=PK*;sZlgS~*c1aajbH zNuzjtxdACv+!6EY@?iP8eN{b_WNC@dcZl=r110HNa05njz2P#py=zW)W+-CioF%CH zs6ToyGXp1+QW#!zRN`#cOqu;f^lu)+e4q!GZwu#cFM8ni%0d$N?GUD|z6%%ny#|O~ zjx**J(;QtFHfTIX9e1X}u&psdR+R|PKEKq`A zo2&tuc@`)wdr0A>$!NU!8l=qs3eZ4!&m)KyjMQR1%kBKhTN%$xS}g1e8^qBk_tLT3 zSD;0?63wn0=F~3(*=zeqRt`P@O*59l=A&wS8=|nr^P6<;LJgXmTFd^uZ@~H&Vf4g9 z7uCEjIxU};47oqOaoGrWEZU~Z7k|XCmgQI4ZPZ;N?K1|=f1D%Fn{Ifj^%lIToI*Dm z7vV=!bDI8O0KT3(j3bY0)2R816s)j{%d=_w{Nwm>w+Fi%uaLw@RCr<8 zP)Lu|gzdwoaHHc4Jh|})Oh45F6AZN3_F5yA#K{XUekV}Ft~%-MH`c6pnZ$#AAMiC{ z0v8@Z-n>I=RDudaQW_{1R z8m3H5-*Tu!X#lOAWX>0#N+hHDG?ItkEM9#74&9Cn7QZi0L6dV+u~sKjuvZ_73z9dG z>&^mtduBDyukeRub8^|-Cs=rIwU^TJZo(V;Z{VK3k{({j!i}Gj(KN1_e3nk2lP_F3 zJS>xL9LaFDIgm*$19foQ%OrT}WQe2cW?)gj8e!?CnS9XW7kR8~qo3vdBo}U)@{~_cr&%r!#lb%)JND&!~cKxUR*1!13Gcvpd#-dBF2$FT13K|#p37YQyTmg2at(ipg zzRGaL_ze2JS{c)3*+I~pcg}OG&3LfFc(|5aUR80u2c=zoNr8T=MT6kA=zYNm6E^hZ zGXYL)p?{BdCGQgAf)%z3mA@dz^;%=I6LQ+xaq-iIMpYF zdZd3OIrU;#xTIeC=FVW=_vkhW0Tm$pHyHH?f01ha8b|9&GQgjkAW=1q2=#${17n|qaBjbVBcYI?Q2Yz4>|DY znoL;JqRmT$KQu$8jy8?|Lg^b#u|3FA%u7|o`yW?Pb?6J>!HN{&Thc@>tsf-*HJ0Lt z?oOOnsmm63W4WZHKjv+e#{r@&o8D8S%u8;tQobfjutP^ADuyYQ!1T7b=M;(B?=@&RXJ%W#!4QKNct6=N%ZBRV#nou;- z2RBn+H1arzrT5a%YK{Rvzp2Z^E?=Us53by*S4X;A75Qf3ddyjIU;O6W7xiYILEmj9 zVDv{WRc-oDlm8{UO+>F`JpyB!kbp8Wu6 ztrH*4P847Kw*kynX3*9-Yxw2IXl~iz2R`GPK{In5o@=cWx@r<(T6LO4f9O_zUtcMH z_fy4!>OU|vV>e7y%McH~J^(5KR&->rEVu7Uz_Ty(&}DT9uc(vdRaNguEEKtT{%Mw+zVs>F zY>%bYbGmckC8mQqG7 zCf3-)!=JRfZsDP;%jxa3=c3}*U>GGN+y1Bj3C8LTj8LKA#aPQ5+1Ga#Z7L1X~{`-sBfxZ$DkS5 zInslJd+o-1w|>*3_Xk0-e*UEu>IVX?u zJT5}BOFg}E%7)b4_2_Lf0_#rXNj|L!<3Z;t=&|cFk`Mn)P44Z~biah2FZc-x6>5Au zKmi;T-AMZR1t?~|gN-w~aqS*0u#$DdvoDXb*2YD6vml#pd>V-ZR{x-qK2kbiZ78_? zcLol$W=nUJb_b0^Uby7$E$TS7oc3QB!SdC4(06}=*gfDIagrjaK@6DD2cZ_MpORQPf5SX2%;!o9q7uys~!~#?UK>%(;r)7kPoLu?t84>&?sSHCXcBZDG<$BMzB91e?YV zqiZHbLg8}_{{6dAY?*bKoPv)M?+yclg|$Lw%_*ENHNe`g1|DCx&VJiX>W$X^^QB>#N|9ruBHSh<4w zQeRx)poBvXwZus#3uDWPYdpm>25# z(!u5t=-Yi5rajQ+J7ecbuiFIT#WGi1Vc0^`9IV-K-9uis^%ia#(+l@2g=58rP!8b+ zQhb~RgACr&%qZFF7ta@*2vvCY32Vqz z9!RO})7XF2UpO3BC))3jMdMM{Vp>K&n%%V*=9`X&j5V@wDPt;biZW-tHVgb+tta}Y zPQ*XGb;+2YAu+IlOz59LBnu^2=>!g!`HQL0rLNe484I+yAG- zS4vXmNZ9x3X}D$FE+m_GkrJIIopTD}+#fEu_U#YQP+HEF7>{? z?B5(ezy_mKRNcLj(@)ppr4_#^&9xh!^0-5CugCJRuC3Um*Fht-zVfQDHBh-Nowec& zu{p3CC_q0P!rO3`+Iw2nBm>@`cCy(+6Sgz%1h-gS@=ooIH}@1%$n4$dV%;eC4o@bN zfJDB9o1x#5I}}#f18?98xU}CIqE$x2*=PE^Tk|L6UHu5ZS9#!-umalbaGzR~9fh*E zFc_j8EqWf;<8e+$p=D1$e$|l2i!bKFOYaC_c~2)iv}YD1um1rVH~XP+*(ko4m_h^g z>SCaMDi#h57GEAhT6TFH&yK7Gqa$I5mE%CK38C4rjTO2HY>Y4#r%{=YDT> zr9XO(q=P3ff=P8e{kHL<84DL;U62k2X@;}eOf!s~DDdszrLe-zo{ZFFapA^b3`qD) z?vG;~62sruB%slqP}sJvOPsxbGv8dl0e!}8!TiPc zbUZqo-%HbkKU%$cNuoKv$kO9C%8_Dkw#IMko8WqvHj24xap?IY7$bjK82&2{@*3Uv z@4QYrT5rUu%SQ8H-(m>8eqR_mHV)o@pN(S|{t)ywJ)<2BPGp?eLu^jnCQjV!#(~%K zsK=Nfbe}j7i?{C)*FTy^Cw88vrC$n!%iVzULPY5#X$f0?HW4q{rt;=@^>B2IJmw__ z<9mq4w{MpSJM~78lA0$E8RCoG+g{MSavjw9`-x7I9 zqXp^~R6&lcFMbWm5swW{0`9qhJMTY(PrH}FFBYhWv=APdYjV=P=bZoW6s<8g6b-f* zqxx1Ywk&OyoSU{92g~%wcY7nmoN;Hx)5uuHrg{!hyftKedr z*(9HuOrsn1QN?$?)NJXys)^cf>D;_tINAIQ{8F>x=cVbiF8@3%^&Nvg&dR)!J!!Fn z^S?XKLPl9U&3Lq&oVJ{V@l(B6RyCe?oY_IgPi#TIN*i=}m?+&g{sk1omV;*20NmF# z3f~)6QOi;#hD?jJwhgQ{(OUTSpDlLm(`flp?gv$-{KHvm{$E0Q-i%C6ytL zFt2YLQLHDQ^3noh)li&kx>)=!4#N9dA@pczZ(KFA4=eZ8W1F%>%H0q2Xr?6|%af6`e~$ywC3WeY56?uWg{DsXbE0oBEyg&k)aC^cv|Dj#&Gn2L3x|Kmo=?Q;mUCZ2_f zV?yabJ&1n&o9KZ-fBcmYhjM-ILs-rjI2JmKzg|{DztqnZytRwkI*)V5-7503T!TZp zqVP;FRrKrTK{Yd#aBSxQ;bGuR)){gHD~`J}W>|Cl)PK!&-0RC)+uwk&dK-DpQ^P0L z8o07mB02oi6ja`=LG|qOwE2cUe|jk4IlaF_h{+oGU~!F7bLZfw%tq2sdW6G9-X`<) zX;3ds;A-7z)aLV!LKWsv^V-oYmtBgx;umt;?dLEd>?O%s|E7^kx4=AAciu7B0&5KG zX`|9POzl~Yx=R}2^5^JeS7%7NnBiP+69lvz{wl1=_VYRs4KyB*vE& z!qICJaeeMl$V~~QEs59pUgJM2S{y89%{&Hc)K$1^+6yv>PDQh(5V)gy8FT^@gtpS2 z__BBg=bgxd)TRBT?@p>B=02x+XKs+z*EMLqFN~kJ`}0QCv0R{NhZc4w*zdtfv2d~` zT|F8KpAJ~zrs78Oem((Jt{&pVzr%5S-37tUwGaNBD@%TRC-AK7#rU&l0(xoKbBmuF z7snyX1!O@)tO71*$`|EE^hW#69)e@rX8aSjjW_jG<3UrSBx}xRLA4CxaqDPqeXt+a zG#S#Au9MtkyaKP+Yx9`$wP-6QQRbX_=v`SWEO|Ja$Nl~VdWSF3J=ly-PFtUgYi{fC@N9FDh3j$-|(` zKJ0dMHFvi6~IFuuAxuy z*}{Q`gQT$W8g&%R;!PU^af4teO3qy5PxH*qtMC}mn zCrQNEb(=PJxj$ek^uS$zrg7(I?SME0g#g4d6+^c!^8Wz9S3=UKV%r0y3?u@l96cBdpV2en{qyDv&NYf^D6 ziHp|+a~K|TKJI&z>Y8`5#b_I_xzPbu>!#B75%YL!VU2jc&<{**$>O#5{cwM^E*f6b z!H0K)=uy-mH2Gb`6Md$j=4NY7_|ctke>N?zsU};aL)dB6kNltir5n#IagVkfUJ8sA z#-DRw_x3|{cAviF^*bM-$2$);l6>KszZHr0UBMG}8g1 zbBDs!jIr2#dpZ}~iV`%>b`wWfHo}5p8%j2J;2#yeanYNDl>BWBV$VkuzUU<=AMMY> zmX!!wweJYiUXG`N(P!XiNIdM@u?-8|4`bVzFwvqx!oMb0QTzA9aISidAUCf+J8THy zAazxe`+X263P;4|JE!Q=BpIGsJpwbUEBCkr{(9hGJw>7IL=i2IZUpZg#=Q1)tMI+3oKs0n z*lc$lTDK0v{Ejr}_Mw>KuLq%5A8V{lbY)++&FEt_p2yzNz!Wm(^G&(pY5&=f`mUU| z{_9oL-=E{%w{YOb&te~`EVO4Qz`~(gp!|A1&Yot6r#%m%{sR+^`1^!)dZ>v@T9;vJ z+$4N{W*X;}UZb!c|1#LPtzoFDL2KzAV9}>e5wNLE4x`{VkPvPx{A}PLh3ZB2G2$GOE z(6LwoZ+f|*?2k6;l%K`NN3I};^jO%m{0AIr{0L@!bDj5o4}jZyu9CHu8CzcbNFSe0 z=fusKFynLxnDw*7y)#;&TD3s1PmzaFrgx0nvz>;Q8UV;sdBe{4=PoA{v0^GU%S`1jN!;Xcm>^LM| zT(vF-~Mm_vJa#%{St3 znNP6t&w37f^_dp`-bVrENuU%on8vL>f@^|5(w@RSAgHub+O={x`eJ~1eaS%X5%&z# zEaKT&?ga17*$Rulnd03M{@^~c2alW*M2+FL*p+L>l~4U~;E*Tq^5Sc7e5uCnDT;7( zbKigapF`&-JN@H~HvhL|DDH4r$@z=M;g*o&LM*p{$L;w-!`t;Nx?O4a+}*XOL@Bs&ZCTX6=;UF6~SzA_jWr-ZxgC*iAc=h3=PqorbJd~Z>5AY0|H268VKhE2zi}r^LX#JFYp>v!ZE_khj zdv~3t0G&&)c4h(X+-!*3BU2&$qz=!?uZ1$pzqGw5iJz4s+J<$&qe)?CVxh#3sziFV z!WG8fK213#GpV!dHFe99!Nc#vac%Adlnf3RRLv#)Oy5E*jt-;0CoYrO*jE^?Q zbu*xjqJ>zn!5n9eaK>|QOmUIVE*N7F&e+`whkKqEUtInRldP4YSuqpr_DscJ8KXJz z=q%DWUx2oLP13sCuDrJ@j%$h@k;USkaL(o=xjcOU4cE@V=|{G_bX69L+cKzV&_Ku= zR!(K(1Z)jeLixTUc*B6rU69_4+q;9$?cbfIn>Kl}C{>3si8_Tgos>BJbgcH=A6-BQMs1yT56P$y`Nv z0uVQ(F2dNJ6+*01J0)j&u^uTqz4>#V6u5q z2Omw9;YxvE7xfVuvZ@4wvR?dgI+EI9SUo#jz>5i5U18_%e zKbW+$md3ryqM(wgQcojC_$Di$=+Owf5xs;eENQtetB54P&1x!*TtZ-WdK&74=mu zSzqZq{hi=V2}ye5m-o?Pii-kw`<;ucEU#0T+(Gco9>$ZG9Ru7`2&6XWe-xUBJJydE zh7m;}*-6*l_g=nALkOm+n+R)oaE4UxXH}74s?Xf|2laye7-VN7B)2$+*1HNHEr{ zgY`Wx!Nj>0k{8N7xu?o8a$l4Ni)22Eo!6g|LP`cD4v^C8^JQGJyipjjyM$DlWw7z{ z0I*v%09|^y;o584=&hl@PZatRoIJ-2d*K9YwPgMm20p*r<|Vt@?pus zTCl8CfIYWbK<)Z^IP)eHrj$R0AZZ=7o(!i0$4c;s$}Nc5(;?bE*5u3iT99#632J}D zaMt}Vw8movEZUiZCzF@6pXX3cJ!{Who)I|0em2bAIFIA4Ln-uXGh9DBhz-ok(QDoZ zaxUnPeVF84Nk4UfU}87;uoeL?AiK08=M;rJaH zR5g9CFelQRJG+$W^_i*oxu`#v4qZd*H}=DH{|0zE`!VdvtrO?;xImhgt+2T30VRxF zM;kQDS#`?`vGP(TDJbtkeXpD1l|S`Bk1F9_a{}~}O(t_CD^i&-n$@EOZeAY^GrRJj zG4(PGu$U}H&G-PRtwvDrEfO8P9*JWY4dzKsszT3E+0sw1B5_)*KTmkF06Och!Rbp2 zd1=vC@#fFoQlrbkI6&{CP@1YZ60McB(rXQfaKPM zPh#_68GJv%3KAcWqDrUFH1XXoxTZ7+3O{?1&Z|Xe^T`fZoW3B~k2dE^ZEDo2_LwcjikNKkzvvCY8br=QfIc zZI55Fp3wHTSh!i1Ptv9~LGxKWXg#vw38~3cXP?j8i$yF9$cBE~mZHviSDu|dmwGO3 z5`L;praOU#d};g#nr&W3V&6e{b@+D3>32!&nKljjjJpl~y5FIy)SewymhrMBmoU;< z1LwH?^PR9G;*7>MAX_yC*Oe6T`w6#%oy!{{$>S#Q~O_;fmo8jm{SGtc7`=ro&E>ek|z|9m)X^gX_CLYY^5Sp-kx z{BduPHqH}z;>5p>sF!!0RQ~y_qwt7W?E)SRy$TMaa^S0sGuM2+M}Kt%nBgeTi=W@b z0f8>u1OCIEe%@U8y&76~uVbgyC45s-4$Ha^0@X`iEFb5>chZlbp>r^<8h#jD`@8U? zZvaWc6VP7l&h9bQSTUctgX6{Pm47H=ZUCMf9R(JZf9cVyVKCeJ6d8ZbWOq#!ZaC)1 zyMJin$hS)HM=}AIP8Q*#uo1S8YNUH-^sqBD&na)$4D3;1&1c4a5#;B~a6o*!p6T1VEpN$9n7 zEsu~bgx9^dkg{Jtj_sa8q1{&TKjg%7EkA@YlO@=0J%F_(;V=o}dBwU!{*l&6(`9ra z?iUop?ws1jl0&jgcLJKeVg4U&ca8IXP0K z8H+Jw_6vBKJB@RDcgKAVyC5Oc2KVmz0QDM?Wb<-9$5!MBGL=c>t56^gS}I}H#nVwa z%mI}=tU!O-d2l>$#0Jevs60ZAw>%8z$9dh*;lEq7wBR$1pS2TH?!AO>-`@RW_{%iS zHky`B@SqOw1w7JKj@^X8yhr}3z$Akn2f`(Tw@!n3>xNP8u|60#!T`oLM@shQF5&C_ zKGBnh0+n}shA(DbBLA=v!z^4uT{r=u=947LC#SOhmaXE#3(=6MR0MOD+K`X_VQNzi z!kla4VV9dN)3_O*7!L-s~TJw6XIOER_E{Hbgy+z%*Hf<4}ng1O={Vk-z{^f#nZiKk#n+hI? zn+NFj3~snYpx4v|ye54+HS`$CpH^z)>c#c2;))r!Ne|$HnI2TG@Q88`>+sR=x6;%( zsnp>X&$sKF!Ru!$JWXB64H4s5b=?V03~qt%CM)sUGZn1u(#HqS3~8r>4;JQKWGxjb z_~*2;_L^9HuAVFmO##eXE(yA`lxfc3PDaAN*ka)4IHy$;i-brOMY`QlK$q1Iz}9ox?3CJ<2PpdR-_MD3 zeZ)B@Z@YGQ_p1wT{oA*X=0<3e>Q2w2Mo`(@?Y!!TJShcO(M9)I*iy9&)P6R>lJ)NR z{=BoaF3JOg0xO_MI{{}~H<5H;Z|J#jBH#VkL`mK~xvgOUh2G7@2l`Xsz=}2OeAke5 zhd9A08*}U(&_Nnrvixb*6Lw1x`-EEJr>HZ+$*glA?>Gk<~e2>-LUwowZ#AVN$PXkhTrcQ zM=RFo@Ph37qW*#ye$Z$Oe8H&3UYw zA`a;Do)&*j;3J|7=`46I)U~{&tEF9H-WWq+bZa6{3E9RbJqB>k`|fA}hH!J|Coq_B z5q>HT#fIDGxu0n&YftzKeo<+tGJPsk>>WVsA`9tvcwf|5kxrjvc1c&&pTc7ar$A;- zn3L1WmsByfRY!*qUJ8xpVXOBEwBAt*guP>sCPB9~+P0_dp0>NE zZB5&@ZQFd>p0;hcU^6h^{#u-~YIQ=w2t8wc+>q+JF-0_{J!;{MzUl68TVoUH;G! z_D#*o3(sT}{JznKxxS4bl1|Nc+IF0uo&lTX&^~*gjfy2x zGHW1E&7}{5&20!VeT~s@tBxs|K9el={9ctpBb}mA&zEWJE-L*39kEkC8S3-CE#8r{ zy5B-RuQ?buoDzglx&~#?car#S!VkHL8wvYtHE=t0^1J1bUw`A3MAI@0y|5+Kc>hAj zP8V@^Npp2k=z6wr=g4Ed2#!;Po3jTN`|2ThxFU!J~^u_uJyz>Ryy)!Y- zKRR(MNGoj;a>IV$=MQ+)?vc2{{h=r@gJXt!eT3zlfY$>Z-|5V;8SkxXmG32|!M2Gn zYmT)0)c#X9qb-Uw6M>v#lQnN;N?XB34dzR=P|!1i@Or^65R|B7FIuy--PWd%sb?{3 zhX_A}GAK8GqhIYj-6rad(Qht3b%eKX7et?$K!!yCj6eMgx{C75sDHY2U~7rZfzFhp zv4L|Ep1fy5Rly6f^tnfu&38ntjb#!wo$h*ri^&pNfVXa zp?X`GZo-5aXl~{ZgeRUcC;QJPnO4MjRAs>T{7EQ2ZF8jK#V}||19^;0;QUf#T*Xq6 zf806-c1zYuI+o&4;q>MOn6kAgbHPTSY!iN)(Mg?_0r^!-~0d^(r@wgE)3st4xptCf0V|zC=5T# zCKpvQ#^0q>9LB?(Zj+t|;+;EqKfB34b2^~jL-CVqwDM-xakOu@7Gyk{NKu27**qe1 zfAD3M#0+rgZa2PRKeH+9(wq^qPiO>Sag@v%2&hI^@q>{sP#V>FQMoMt7H&vnN9MPM zTlTaxx~-wSB^Ity-L#hUwx-=ZQ`f)S)ni+Rf$1yg^n6*P6V>QGN=4DG8b9KAxLa9c z?h=~^0JLiJq|SIAmd*;!q3?=R_>=6D`GX=XJNG13IN2kjAfoKkyEe#vxK03s^ZU&` z6ca!copa|?gv4HyxFS`f4nml-SH^xZr6KFy9kjkR4*7}e%yAsBvJ%b!WUrP7I#Dn- z7g|BwwKN=M*PWRx!%M#Jtw`v%QYd6+P6quK3^c`lsxtP3O}?YzRPBITv6wY{g+ws< zMWN{k=>CQWw}UCQu1z5B4o`9CfDyeSDmxNIs;nptl=XGjShSjolK;*tl(yZAtR@in zdJR98m3cXtR61qCjfix7M8~az+}0zMLQN9Cy~+9=>k@z9_RRlM-U_Pr%?D38FdP4@ zFW9Y5z8@7@qH;nYj@r4H# zD%w6zl#gRCAqIZ9hoUi0>VS^yy{f;G-`5jvHs3*A_N;02?S--%M2kUvfp3RqPcZ)A z<$4BE=hl~C?3t>NI>LBPY82iCL2S4Gw;<611h*Y~a!`T&z~EhG`;jLo9Wu9|ZRY^9 zlYC6uumh*YEdS5tMMy=PVv3eK|AAKENZZ2{=sBh}Tv|`G@V&F;9m2j z$?akH6Lp2P)D?%z95{wt_u^%hk?5|KGlTJYkCzu~aJj9tXwwBJ=9?_2T=?uEUsb?u zoSy$MXz(=ERSQmUf^zBW%=LpuppEYCM!(Oeyt-|?H!HiZ7wE~gZrDw+n#Y+rg}H5m zaW%cN1PIP5t^ls;zt`Z7+&#y))aMBC6e#Jg5^C^@#!!wuz74>IG&kgCNYRH-53`Pt zPMS0veiq_vslZn?v&EWds+|+Dgkx09fSFDyA6OoL+U&Z#HkC;@5>8~d1BqIwR!NEjs%2~F1cd8|qz^4#0b-F;#k4unyi7cwErcgv!6 zxJv9Q7vf@>K9z*&QV1_q`V)}mBCV;;?eCxe)cX@u@Z1@t;$}yb_H9did54IA4(>2m zk9x{ViRA8ccVtDWPspwid?Sw?*pT2<2HfQs&V7UTvf?glJO;^*5SWmDyw9rfQy0r5 zM(jG~3|&d?LRIlkFKDwOcjueTuPuavoAW*~PLrx%O*^Hz!gB!GRPE{$W=y!xdEOQG zeR8N>Sz1l26jXonFe(nFes1SS=uD?U$ruBUynS=7ifwbvGozUEvkvjZc_kXA&Aj4d zBOAQl>0aLDg?@#p!Gf2gJ=L}j6A)b|6socK;D3gfkYn^&var->_~z2x95u*$Wal}b z(wRIg4ZQiLO4L@W=+v9h&Dco=TGPtM%b3aQv0gK$HEF{=p83|PpYhMH?+YL4D-kna z2D#)Mn4UIdj-IRao@#1i_pYr`u&Q7PN^E+M@zUgZ6x1$Ado-+6|gS9_G_a-Bk+h1@Q|N&P#-CwbAPjgi|7M-6tF%cDvOn z{feG1Hb2Yf#JxdG7q88<+cl32vPXFd_+bP==B9~{*$M-9$^2Hp|+38f4q@(bbph%<{?3L z0{bN)%RqGgAtohP!w-V>%s7hC`W)fa*;BagZfwV{Mhgs$b|eRdjUZFW)ph)wBHXX^Rxka|65Kx7vPM6!$iuL!Z^Ho@Xj$(W%fS1 zRUPJ3(T#L$tJ3!}s9#*)(P3nzjY^K4VQ6ti9UqHL=fia>R+AmEpV#2v5T|5vQJpKn zloJlz;C9%Uj%acV=2!RF$@jz%RRA)?37^=WOk6A(8Ttt1WVy;ez{~+i6G365TNU#b zjQ0)?mu~m=d|oi+ zd-Rx=hk;!Z-#MRn+I9A`J+Zi8rVmx-mgk)j5z6X*{6Csk|kZhMm3Kj>ChkU5-~?-XYwc4(}-3N zi1nQ{Qnd&ki?KgsV@NuaG;-Z_E*8J6i&u?ayLkqZN})Kt!k~1WpATbLs&22Mt(@R} zXl1`zWd3H5-L7Q~4m8}^Te@CTE%qw>Tb&Dypr9tUgG0+{dd*(yDgT&ftdH}dM?lg} zl;8hp^|s%ypMGmC17*>vRsWi<8~@3g*{EXcQ1Wg_a`s3|rH)4Z{pJw)-VG7=1aJpK;bZJ%JnhEi)Y76AJ`TES$CdF09dU8 zP{OAcrq0>LXQxXX)SM`0Ub6dDScrGpkBg)-=3V4<6JzZ};qu>%u&D_Q1>2wJzY;i@ zyT}{v4LPkFFA*1Q%c1OK0e>(+`UT}%>TwQRak^p4gizOrhXe~jWqE#JZ!N+dXWha- znDpWjZ8fB<@TLvfoQLq0tnc2$HE6h+vD;|YM8MOy^#QTI@DKkYGqi}!JwzJFeN!o1 zK^f17vkxAM<|Mn0n>eGlg@=V-hGiyJNjgdxrmmV~vG?l0t6WVk1`p-I zB%EZ*tG}?UdA+#%oCQYUeH(R}RQD_g-=$pM^f!?XqE{#@Qdyb z4WiMS52DVa298)(If#HjQ6=qhz-3cTe9co3p((*(#-F#Bw_?mna{588f6}5~^Pv6o zb=a4PM3Ksb(Sx?sit!ywF{!g_(RocO`1oCNPUUME`aTb2Nn1Uu4$f(RO>eW#GZ+U8 ze{4CV_SP@DmT_#I>I%b;^Z>rb4IlK0Aic;MqjQ@djxk%U9PJnU9meIM7^@J;aus;! zeEcyE)oMU5!u);IaFJ7m-3(Pr_?{v*WJg-9ET!`qOf=ExT60FlhU=UBy>Qd2Y5G=O zk;$N)eTG^qd*?;y?H4+=InVcSG_mYZMM zF8Q2Lb}r<%zmRcq_*OEYr#GTC8G+0K;;O411`Le13@C@SyrJPbt~2j-*%xsgdt<40 z14gq7YG-@n$Rz?{ZzI$w*Sid#z?H167Fy#i28<@_^&t6)5lKwV8}bz}-;|Z+{*TUQ z$rd1oFAMJAniBo#Ehp&*Z%)j_J3Pe7j9iA_bkr#I#zILe(cXTr!(1UL{wN&}tmx!{ z#q_921@E&WFU}H@oRYU47J50cQm$5$bLhkbPgzw?;1&7k-dd5N%XK}x|JJ@lE3}Lm zPqq9a-$%X2`CqY#p4|`}yq`kMKS6Ohx?R@`)WLbGs)cTVob0EskpCoV4P8$(p2of9 z@PaFMn`Z^P))Icg0HpVx|I%^3QzhM4%OCL6m$zLyGQ|$A7*%S~OmU(7OdEL~z<7l9 zaT{m3ELR9)aNHPo$wHoWN)67wn+}qBLLhAC3IpiO2meal?&5yM<-zVb7V1IXE2yN8 zPH!io)J_$t)F!ORsSFSe<8qj|;FOo^6=iISr1n^}O2$b6uaL$Xq)ewkSw5BKH77g3 zIZ)vhN)=Q!Cq22@l;@r-$e($PAY0Jh4U{&kf82DcO6(1P#v}|FJ8A#9wPLt{R~!_2 zjKsglpH7r5kspOh;WNR4DZ_1ku-0ZFF{_wA`+bF}{uLgCM_H;cyTD%MITjtesS$-F z*1vmFr_jK`k$a8MD`qy`J4_UnF>Whr&y?IQbkms{5b8#w|EUF9FBEK0dEZO8fP=&w z9Ie5n220Pt5q!O}GLRi^RP_zioVrjt)R<=DRi+J5fsz4$i|8w>Zy4^?da{($%^Y&Y zWH2@LNBU%5)fI83eUbl=n^hW^y2mx#*nnZU=YwO6S(KPIgs8&H6bE`!3LT2LSJnB^ z`Z;)$Bk@A&xJv$rVdDsx2S7+@&S&GPUc+E@m=AI^yD&3+!L0#~jno?HYon7=t8#u! z6>6pKZ~6YHf8RqmtM#40KF6F{3JaWS{U$B{$QWh@Tie;w@WYLFVi_Dh3)wig6Et{Pgd0O{x3+i^RcE!x)u2!1O7TztC`8ZT+Q=6bi! zVutZ}y|obiV^Cit&vi4ljVs!883}ZdZOwsh7!TR*pxnz4`#q|^m;^Q>8wqXlr(oGP zNyk-n?&l)`MbRZ=)73#MpP6l5;S68yI+Ap{9jU!oEptib2bNjqG8vHxZCd2fvtEq< z{^(XVPm+Yr7)ZgAe;BK&BLVblkyX!g=sLeX9oM#;yGXntxv1XnZx`6HPcf;NC$zc# z@sP(NyKYzrcTqpqIGEXDaB1am;^s`V5289>+qofSTeb%b@=(OIqrv?42Qym=qj!Y;z87DAH zgwq<{Er=ZE(2H&e{Yhv2mRPHuH-2FNB)_KwkW`+&m7Nqxo5<5NU4r~x|BsJy*Q26#LbUzvTJysI6 zd0e7)ywi&SydCR4J$WP+QU-5OG}#^b0erdiXl@?ZPOBwfm!{8u?5+|+c~reE_xhp~ zc6M;d;dq#o_b@KEOz5l_7*i;qZb&Li=>PhQkcrpa6?h^)ExcXAUaGdns^0XTu*H<_ zJ!?>&HKK}oig4HXiZFiSha1Py!JdA)*~O&Y$`{odA)Y-d;C zm9l+>9|E|`7MsbR$BYopYG!>@gBd!m4k-#k<8EffYNqT36F8#BcXT$Sx}bZHEMj59X2tZ@1~vSIo+ z7^ffmM*Y_fTu;$6qw9b#k6#G4S*3V!9^6pdV=f0y!`GYZ%{eRh(r!-r^ODBbO~9|U z%zn9Nc8%WfQ9bz4xsh{T=0^>Z2N-V(Lbu72!qLz6{7mW|0e%Q)_m1!xT?QRKZTQ@p zYydd8R`I(}kSE|%!F)K8D%{C|44hQn?(u2&_@3XQlL-*_Sc%3!!Lov0HLAJ&69$>Z z!9*1sXX7}*7NjdaKZ0-IxbbPfyi3zdjdyzsX0fM8@m9=R zjst<@H7Mg|I zLxlzkv{8kAc=e2ja8@htz}KtNkOju1vY&oKSEzkCM9LPQ#40}tjA>*#%u z+UhY!O;4k+7DklShvFTXZu=31pP=_|4sr{-_xy-XUok6-~-(U3W%y9IrZN z=21 zvdnlO zu^|OcLiAycBG;JIo|lIzLrV&BJ@G7F&G*_7)g{ka;rwfx^M&Nf4a$#4e0yqs44eyx z8h5MB_XJrpZN9Qjy2b1=v$5+qJK*Htazt1W4DN{;pdVt#4Ch7(55q9R(w$pUsn~M| z&Gb`}oc{sY)*gKQJr4a#^>08$+`ozM%jt4S@7JlT3nRyN_^%aygiv#LK{mhi)vAFy zS98>}&0fiWv-6(w+wC4DR>TvSWk!9?{OC@d0g}2LtqS%X>?wi;! zckgbE_6xQ}t%>}HF+c2<{0Ls!iJ{NYWQPr8^0})oa4SXn{lsL(pn-Z7HwMiJ?{7LCvq0id<6P6GaWfBB-}q!lXF!8YcTw*4Xj6gGt_`Tzp`Fg(Vg~qseWq0t3En zk`(l;ng~#z&86oz4cvGi|BN%&s5||V-15j1%V_@bge;8YHMNWG8`8oBxaV^5?+5lt zR6EEF<3S17E;c;m$)sRITT|S3zh0_kHJ{@4SW3sBe9W6OOW}!|oB1tl0WHr%Kf)Q1~0NVM%IzULHdF2Wueub{$#0N-OTrT1Uro_1D+(-RBSa^ z{JBQ*NT{9Vg{?dl(*{B24Q=ej-nyYm2y0nw5mDptE3&z8@2S^c)2n;BdaDwtW*D6^rI|st4z3N>S0lMRxNAb+5Rx`L zWSyE2E;ynxGn1YNJwGZUhm060Jc`{A3Y@M@-0@blZcBd!#0O_vuuu37UUn8_+OK3- zT-1~{Q(tssnhSUakGLKr^-|HD7Db=_pKqTYQ0LS01xd0C4k@E3egcKLc`Pq!D4hAK z53ec+CBARKe^O0*UWIJjvk{~9%HC1%QauY{T^{poz~h}e(+FrC^MBlpL{5Is30Eyv zjy~d~n{QenqH)lDi{OaySD!*KpNR;)^7KD-XN_IHiji$*azd)jW0QrBu%G~ z^D76V^;f3`bMw7Cj;z_1Og4W$>nRt#x7wq;+bZwB_N4d>{=`D-*a_Ha%moey{%m@P z4bleHc07=kefzbPg~9GVYImMF+(mlVd{FBPQDbF*N9rwGl`%EgP@9c?x19u zZlISHPU8O-f5pbB3V|BAzZcVLW z!#>5$Ps?O&)$JccdHJ>e>EexvXFvtVJhsPazfCkE7SPfQE<3l zSxFrd>!XujQX};t%Y+1LrnhykFXDhJ?~=-wOBMRb+-L7(%4r_|Ar@Z+{noYvB3qni zZbTJO_a+WDo5r0w`3vneJ^@Lk`x~Kk#x%S%6G8F#lm3?QI?nBMl)6xL)iW8|8rmjg zQan!BpHH-`mJ9k73@RX(DG6`J7-$ZGvB<9xofhouSO>QjR zG^Qu6dN0J90)e0=7HA`P*RfZg=k7o}?d}P0mgM$#01zk1?+p1Q&5yWp>EiJ9tXB8% z&M?OntE0;mU5gxB^Vn!lQfu!k^w^S~mX{vV5Xi&n-;9d>8n-)*)!VoB;=O2{ErE2w zR_}K%QI~x`yCU5RjwuilFSOA2;en9N$}K9z@4t7A$H;6l&p9EWJPM@YaL!)SYMJSw z*_}}fOmeAzpS$98%S13k6hKO}VvD_)6aBh5^l%wdC0Y5P4mX0tN0k@s)8R9W_9RR$ zr@db?qK*Y}!g2Rj4a0h#f2iBCRsQA$jhs99^!GB%I3c)e$R-sUwy9Tc8An5ruMpvEnnF?*RRXw-~7!s2=ECw!ltXcA5IdMbOgcVxAs;uwwWX(%zn2bEoPpUusI z7@pgx`gjya@ozU5dgmyKJr1H(dXREv@)KUvj{JS4F&A~%|-4@9iA9ic2^%-ZEH4>dL|=kaKAmEcefZEsTZEDgePlmwCj8HMs1EF zC%t>*MYQ_*EADfW6efSayq_A{Y3b&MGh8CNkbH5U#$&=vbmt?zVhj-8eu(&9WyUS6 z(vskGz~YuFxd-pGb5IxsTiJZV!bj3J+`mft*hvcf$o+%MxHX5^{A)kJy*b<(u~4DL z9pfQVn(~7G$DAJkgWHuquvgK`Xe5(+&SKG%yXrAMmdxrd@fZeQb(f<1nIWa8rZ%6z zS00w91tHkhR=w=uNxS?4(0%Luj(+<%6M98z2CVE*`5VtqoXej}LiYhqZC8PMbNVze zO&Oc_kyWhYn3qghwu!R&{JtBToob-{fR=MF40+hiZQy(2IP;zb+dZbpf0 zVYLhM((yueTWGlHGYoj{Q5dG=3p>cPTX48r-74xXffi6d%_{(%J|yIk_F|(?`IRe+ zX)ii{SGd+Vw!f|LSHch6kL@k-OW^%)6K(fi^fTGmwLXm5y<}Aad*TjGtD^HT_9hhv z9D+SvSZ-{$gVh0-M~!t9NrUvNxfuRCy4ze-ng2%HG)S#ySD^@+^whH!guOQ&a8bQS zaLF!~!r7GmQ@tnPyi3i?o$^Og zucX8@UF1OaR@*@qJGm8tXalQhC-Wn#lOuS>$L(Q)dGW*DAefa4YyS&!oI!tpt&i&? z=qgr9WPSJa9Ifq7?Zp^_(##PP1-dvtA(BOO_O$NrcRB=^UwfbDEt?-K2t=3MFl;0> z1+C&NXE8EhYqj~SlLu6MTip=)i1C%)cZKNk{;y(kSo^n0ue{g(SF|zdDWDlM0!5)q zozx{wxX^JkBnX$GGt1zfi<$+mrCMb^!xUd_lMwFc6uT?K!0&bu>SQX*e^RTZMZ33H zUOtjBy>_^h;9}T8Hy^rX&y^Yujj4`3@A)BefRF&Q1HJ8gte3Mk4;scCu`lgKW-C2` zo^Eftl(x3H1Toc*yQ_$#YY2C4A}5)#&x?r_zzvF?x0l0G%+A0M%RmG7e_S`S3c;~9 zM2S>7VH~w_3cjt^K2DoII*gex5ywHgrBo$&mi3wvzf)za0e_i$pf7OA`*sF4u(ORr zk;O;CzkuG3?Sm3}Nxq5bM54ESR&3!*tDtZCjdh&+rGGiQb$LLZB8u>tE@Qae3ePSWkQTnLO-({QGZ9yK2mIp-u@ zUPKgj2G9z>jsjd<_Y|epHEE-*ssbt`3tyT=OVcnG802Qh$X3F@sSe8d^qLPDc^@}q z|8ZsvKmeJP=CdXY?7l7s@IWGt~vIgZ6miSg;s}dgGjjL6SJJ3w!`Q#T|+gjEq^%WXY52Z2Ll# z((4XfSa8U8NB4DnLE07=zn8rKT34FhPAC&@ZB>&7FrJb5Y?`3?txU(9}3vYkLd}p{cBD&lRe64PTlAlPPn3X z5mEdEop0Aq&8(^h`pilvRA3`D8)f{SQGdzCg!siv4M>@#PVSuvIA%->eC?=tk-`OK z<;8f;O`Cm_+}@8;b=G`Vu5tOMBVA@VCC*Aj?vG*N^tdHv)qU3vcXtEf8~?HXRhK5G z%3XM95pde;#@1V-y6gOfW0FkOk2VcG&@Lv5ZH@xlLTf_q=a$9&iYXZ!%yZ!?o?%47S;3GOX5&hLgJ@P-lN~S7I2# zN%K2c?};bQ7ilMiDp=zM?MC`Uy;S)%No3cFI{4XKAn!C@almtpsYOC>d=IZj;-d%N zgTK?oCCd?1}3FEq4Y(gf$4?sW3(APsB9 zVzK$x7k6~|#+IGK?|KX*_tgG*3zpmVq<^AimA@auD_uTaD@+z+_)eRu5R>hrL;B{t zU)Gk<;_W%15SNOJ-YIf6M<92*zfH>QWDA*$vLyu~io8jT@5-jXLGYG}Z{wr4d{6eRH{W7?i&}k5kJeef^E>{lh@0jz_)JU$iu-orE`u$XRC*emy?j^TV4yqX=m`NDTgS0v!jxTO%M*?;1j!-CdI1YLbCbBc zkKTsUj3HOEIn$2~;OMH`+JU#zVel3+S65Doks3zpWQHg#$kyj0&`kOQV709mutbo=l*O6Al5OLTJgl_8m zn~a5tIGC0|ZBWAmuKxvF0+ZTo^6pAp_K&Di56jP?BaW@Rs~*-GOWe3)T6;`;3k163 zx}U<6ew)b>^a7e8Y4xnU!AKW@vA02zX|6o9fW(~G{FJ-@@~Dg`c~_72)3cuy>6xlgD8N8r&w4I!P9`)z7ZobNqg zGf(w_ZW7X*;%Z35w8f$PQUIHO;P=amBeAVda!fBNh%h@Q!m@P-1t23+`WP=y-%aX6s9 zQCp;b+zs^h5bALg;9uS-ZLQn!CS;B8xBt|)oE%ctj9ayNRp|m&g+r|@1%Icjym_i7 zXt9_6R%FwT#J%n+x z)8y&@4tD7uSACFUL;S~~S5%tW`*-Ea-O#kpX!{TYsr1SHWJen>Prnv}sbC42Y7?KO z^9X1JK+j?GB%7cf&;MM+ER#K(9oD9Ev{pj?sC$LqWklxBPYIQu9W8hxg0)jlxwRQx zvgzCwx>Zdyb{rv&Y+qr3;_Vb1gl5|v!doy@w1IQg(7rEw`ln~+dd1{#1=0FSG?>~l z&SYGUkB{_ttb&D?W6mAOA4am%#W--T*nQ@5^4q6w9SKkWL|9Udc55~~;Qp$_<#ZdQ zXPz{zviDDT{j2!*ibD3c5y2=Zh`2<7Y^*7l)Dx4~u|x{e&NH4fLs$x_D7kiw7yC2W ziiqMoTPVstsuM5wOa2Y;i#3LeW`c{_G=X$ZB>4lrR$tG9`GvFRo;C0pP1enZJD{sl zKt#cep^}KhkbYu~P z*qx^m*Eo}GWC&Gq)ZqoiVSOV#9xkD$1NLFGlMzSNKZZT22n?N5JyoarRd^an%qoSV zsjjCO$9**UuBvyC^BwL6_3PHx?Izrw8*40!me2;$;4p}mUkr6Se`L=br))mKS5Wc5 z+ZlKI{*1U;z9e&X{O;L}!yFmR|49l%pkNR>X&2lv%_1b^Hf*rc= zS2}oZnvGX?UZi_w;hpF^@2Bp*CG&jXjUDR%4{pvXsdcF&p8WlK3r)5H(A1GoI`1bC zpeIS1+)kz-UmwzeTiKt_m~gG@H4VGQ{bSZLz_SEN0~6;!h`?Oqi6H<*2r&n%DWPJ* zI1%@#-g!nbt+!*)(o_su{%L7JP!l9N^DSSb679#6+23$+%o0Wc@b5Vz6$zMpVNr0Y zaJ+)R3v=wLrg+~FUhQRegX%NF%d;EhHg6Sh+KWfW>o6L4=jDQ%Cv8IpqYOLQqJ$-B z#z?=_X_J)c#hnuAhyvE+n-($cR;D@_#Zl)#!?N_GsgG}T!Cr%m!dQ#b13n(GbTrg1Y1{N{w$C>}Iz{)D+5H(mkD zADoAygIbwtnhaSyMeXpr-Efyg`1@<}JuS=ie!BNS8yo_lUNO|?{k?E*q(wpgCn@{~ z!Ty7BUul7CxHTu+X7yL~6}XZrN(EnU7 z*&_Y7#i;@J-}wE1Ne=LMXGDH~`7qQ@a%#c%dAa}Nhxb4D4^aNgR+bP_5dD8^0tN~S`=3JK|H1!(TY>+rq{)Bodt}i{Si2brf`#2~mBJL)!5sp{MWD*h*6chYp zV%vfirZ*E+2hGL+$5U)RaT8-cT@-Py4xz(B1!poztE}?zI*djwpEmEspd*oOXd zT}d8P%^yD`5QRaS-iy=|APbgE=#fxiudTT zVU5j3G8BP>sp}Ng#H|$j8{8%{#*tAV^5_(j89XGFP;k; zJkq$9$wf@r+$miIF2(2~2zca;EJ%lK-Qs&%12)~PQPiaKu9H`$)a;&Rmz_jv!vCXt z#gvYeDn=oSl>mKPXLl|IStSFC*ul1{Ujsy@JRFpbgis#hsuo(+wwSOp%;G0v9CRwh z^lx(Gz6J6QV_^{uq&BpvdsT-eDa`0CA%AM z0yy7ld?G0WmI>^*4(7>4gHrmQ>`CP6QpW1|ih{V02K!lCfrJlV{?7(lUie%-$J&LI z_JO5AZS5-393}ursX-CcQdvKES^sVNMoJ7#XM&zfdRUVG^%n)j+F_{*`#Hl zayw+nqparnUqH66LJH|3T=PAl*y1J+RT+5$(-b1f*q%t!55XL^ej`-7R0MQPI-tqp z&C(AW3u794TN$5Usr?l`b1U?qgow?HxIVkAvM@pMoc=Ux;Pk(dWR8N887Q>Hgc;cv zug=S08=>Nrw9a?(^vBJKlfn9099rDVQ*$6vGXJRZ3jH~s! zDyft7-?`$|^w$GN*I}jqk`6iPIc-NJ5mz8v8}RgD?@`B8Cf|Wd88#9L0lbvL45Q7? zWA{RSr@~n1WWs#~;YQy>w`Yho(2_Z3OIj?)57tL8w^}4X({yqcfVlPfQUzgnWOTw9 z0G1%SdBMH+$;HEc?;EH4#^GciN51fz{8`T-{Xt*$IXKOV)tBcESN=y>MOLk=IKfPeh086dpxr&56@HahI6#U> z_TVqg!bPOiTx*5{dxasGns0B?Rp9f9E`%urxuAz z(kd7;;U0*XUvH~HzMBXbv8|ps>8KFcoR!K8MEADcI#JhCgWz}f5PA#J$)KT<42{W_ zvYl1^VHtaL{N;J29mAt1%TOL&oe27FKSc`zPdD=-h85rke?pK9;nh>BI`C#B)auar8eR5fMBv_H4rZ=1gbz1oQN{YQ$0e^$p66zK`wFF&P942JY{~ zmuf1o3e1n!2maY>i*S4j{5)}PS+CByX61xRm zQN8U0WAb%v*fC`_s`ku<1<_8nV4zy@M=q}rspKKfyvhc?)T!XdL{jZ-jws1;Ncx~C zk#M*d*&{d?$9Uha@!X(eh!sWx%eK%Z*)Pn#v>>D}r40SBW`(&arC7WvTsrgp2&#e(dno2}wC-&6uZ>E@Yyn3^v3JvsS+Ta)@C^~WEXqe2k<56noQYXf;X`;F= zp{DVAU*1@u?VoTIm#*L&V`$e3nk)TUZr!6`V?UuCM#;qXiaP_CLgiY~O^u^7CoeL> zR&S@~11nu6L0q}#|F~y>Ok@o>YUY{++Isx%}1vNVEb! z%W6#W8@`aSGSa<(QpE6mMM-!ib6%f1?tP_<38q~lSn3%$oF1>EqxbSB&88|brD-Be zBa}9zChp4al@2?aG}X>Rv&%uz8|uK1Ap3^YN*_gk(&zD$AJ_BzBu=cLNJYKW`N22& z?qVaH;h1KUMYOlq%%)UP*bbPR3>p9#puV!LcYmX9m^n(LFU;_Bh71a94QeXEfm10u zAet)O^N8c95O3_tXgZhYd-u3_k@Ur1>5sWlDd{(iC&C)x8gArnr11tWP3~MH*stPC z0VYVfsVe0z7U(HFExbL6lWyD{sOV}rJR(f@-#?%y_TOvhtt_1potEY#|phWM=L`Aj}Oa?<1u?zGab00 zWAG0Z3IgqK%@#ksYDy}6OV_r z5r|nt``N#xtpSU}I3?PzO`%5wwAWM+@)wsWYG~`7L_)(N7`OL}qeFZyK1g7?;C%vN ziWrm6u;TBX&_hgbL^$HIAW+5sReyHjM1}%rWxyv+X#?wigv)Q_%SQwj_)4;hU-ES5 z*6`EIEGClLXiZi8(L|p$(%JcwVpHB$y6NwvXEv+koem#(sL&?!x@*#n6-YoEh#nWW zUS>)YCDxaw$@Q(D&$WGpN-0vZ-naD_K|@5Kp|3^}zRD+nh;ncLS5!ZRYk=!WzxV|A zS#&AGf$higP=?YrSa+v&xu_S70b>+T`)JVE4|gnK31r`hXK)1cX`;tP9YQSJ9S6N} zh97ahyg?`T2>5^*^-G^Mlck?Jt#xqs<$Bv0YCKaMlcPsOF<_NW^jZ!Qxs`hH0%CeF z<+h|5^Zp3w8j4?u-5>-N&5Wz8=Ps<6HXNfh-}AI0txU|bw$yvl`gIZ@dyHKbyQKLA zTK-!Y9E_35vce_V{GyMZ?}AJX%O(?3-mtcg5!1N;4*)Yj%)csDb!nm>o5Sn7 zA6EC=nb;Z3k~C~r#s9w-O-5^O&h1RRvW{kvdernVbmeAr{D@@!i7fByIa!v@RG659 z18}o_3nX}dAuRfma244*tYtyd8f9Fg^mT6Qc00$ye&zFNdbq*m-c>WwpTY>y{X4g3 zaTQh+a)Jay?d6=h%V%}|QO2UAg`|ifUSTyZ8j=HH*0;m_stprk0+KntM8;a@hSN)rUL{Ni1!Tqkxm7`I@cZ2$QFGS;<;)~0~ zuhJB{wiVfVoQ$k#m)?sGkYu+a*|%?eS89vVIisQ()RWRy^cbviZTk9Ik@D6D_0$y> z!FzGw1`vBtpb#u%i_5EokF8nhWS*pNjR{s9Uhq^a42oij z##Np_7Cl2DJzRD|BzYQK^p%b1rCej^MNRBII==#e$~C6WL9ls3v^wJ1E7TK@lM+6( z>N&*I;rz-TYG8}Ou)ILO-Suy8UUQRnR#==>@fha33=i~e;{F-UtBuEbG1^<*uF%lX zIJ3+iAkWVYE*2#pD=TyZ`Ue&G(|AZBNhl>8gWA10xLim?#|<9;AJoK&KwHms1-qu_ z0N@EngVSpgFlcdtw`hiyCwHkpzQC7Mczf)V8P}Zv-ry47_>B}Tp|-3rF}XM42CkFa z>D+~DpzbTGmr9gIBZD<5rscu7Q-&dv$7NXdb=~<*HsUibj@FZ^Qis%T@h4(!PtH@e zkL?Gd_MU(69NPd9*+W9XIa&_&HDkk2FNNKOh^ac*_W9K%v|RaWL4FYl)(tv={NO{E zUc(7`s*LqjE`@GHfU-^H(0;~|7T9=W5+ARY1oYMtMsN%3!PMIi~>k7kdeBS=T)zcT56E~|x9&Ej5s;+GX z`5m*1-tuVD3as==iS`A}xw#kGb1~Rfl$l|R4?)Mwfp6^APDM#l<-s%B|9vV{txFW+ zJ2@aR9ZMeGnl`6uTW*P8`aIs}Y6>~BwnL+ds(A(%fV}5VNd<4AWHqUEEW375zX-5p z17Q$}9}tn6Vw@4jHO1gk91!Dqv{47%6e4IM?eL{RtA_>fqr%H7<|EbJTxNH~^V%Y? z-#YU?c6T|X$Y^kGQoJZwR&0PBAyEpQYvEGJ5C>gd)ZOkUimKzr;V15H3*Sa``pG|2th-J*j<;{5qJ z7PU6an3bQ5(W1Jgn_4XQ?PJZ4W*qyUWUwAt%A(+NkTbcNAvF`F;F3WaSX0f2S7l&K z1-7>M7|OfQrNbb#`5?pbm%l{O(!!f%6MMBe!buY~Az(fE`B6ARA*WL;bG@pt?*$4q4)^Wfi}r-w;q za~{WN@v_)5nZa`f`2C7}$a76oC08Rd$;GS9-W&zvA?Ag#RJ!uD2J6-M2jW&GYI+hZ zeTHyN)4LQ}DIvr2WxoBrY6ax_ofTCqr6W#B|95IhnChPSl;fO91G9graVvUh%S1gDxj@wJev`!-HsRaX=qT`60BekXvu zgJP{S^0TZkLJeECgQCxT6k*|zUYs+p;=!f=Rc?WlwhzmGRe0tZgt1<<t{dV2;^E;q0P<|-4T;T4Qv zIl2kjqDZhJX40S0&r#@V`l8+Q!}QLEoEsZ*A%z)V0vU^SIWou#phdGdFFnfY4es2XJ(_q~;T|FF#0V=?n+XajUaaFBeYm@-alXmB5uBwawV_0Tk1QSjXHyI%r1B$HF`n%D1 zqXAY(etwtW%$lzd)+pZsm}}(8kT|8`v#ta?9Y(LveD=IO`T?Xfwgx)kF09%_Hv;Wx zXta?mQePo~q*>$Wqw@{DRuf3nl9}xg7v#Cnn)T7|d7CE_H4Q)5K)Fl*I#x8=`=Ud9 zUu-k3f?lR{HKO#7BQ}qF!BkRw>*E4tP~G_Hg2KI-BS1Zgo_IUx)cC;-*MMVMSs2@> zL@w==Fp*se5sgm&C0*<6)6hSjy(DOcxtfYEfC1A*VFOKEw2Da?r(f{OgA~LoPe?@U z3@Lj7TO@Kn5^6wSE`#}!uY}cGb%q2m1$*ZdgoNZeSRWMg*M(9NFp+kDXkYpaU7kst zvw*%XyPa}6C1V6UZ@qJ)lXv~b9W2rT4R=G@9$M>$Q`*o$K5x}$;1F`u*JlDFTw*-w8O(DOMSFu> zb)D!hMu&Ky&DE{wu)N|KUrcli7&>sGd?RPINj>30jXU6PR9+Rmm?xRI7{{~0I)-Kt zI7rC&xyjM&$K-)4hdtUVRmR5`6ibnGY!$$6;iauf?0ivTCeeI^&8 zvn!?&1?GnjLw1f#9`a&bU@-V7Z>N>wu5M&Wu)N!MYk}*+OV1!RaTAnNfRZQfOULXKxlI*SC*i@a?>WhZh8Ye;C9VC=UC{K= zyV?2htLd^$EfYw@bkcBMe3n)9N~E#hBqzePfwwax?m&|tn0H(=@7M(b$x{AK)={L5 zxe*|Hko}|IxTIP3ydIIM0f(b4md2(=Yp!LAB%APzLFR))lAF4n!Lh)LDj32`9ZTMp z_&~edE@JJ{1#QP`GgGOvNnDc_?7INO56~I&k0md{zVI*;u-UoN_dTJJxEJ+JI&t|F zvjX%^jqb8WbUN6(UXpNX!kTh?J_zp1Hw_~_fCnQibe5e%RagtB1u zFbug7kwrve3hjK27`y?)QL}ZMUf@|0wH|Zvm@<>3h{oI{GzA_9TDTY6cee_cp$#dk zsnHY>5ef^5vL=6nN(}j#)Gjj&w_*_;Uru8~1wjE2FYF8kSCYdcHQl@$)WXH-0$-Q; zTpt80F+q-v@vx6SjKILV{kI(5V?R5s#S<$#wAiBg6IdOkIv4y&?x6YcEoYd6YnV7D zM+0q;(_C3AtR-5JZ=2*Z6UB?Nc<&V3gwcs$<8Bl>HfrN-{O>-Ma&A>nqvYIl!&2n} z@mu0-&;~D#}_V~V^$iRYfaIN27x+l#R?u2))A1$pTP zGgN2o8U$W^ahVXfBxeD}2+-D9@;II%elfb1{$a7C4i%UAryqSxW-AdDHoB4?>8$^c z(>XfQrhJE?)7l%;2w&{0qkd(p)pR}Id5xDkL-CcUsc%x7N7;7F_+AE_LdTLYMXAU+ zAS&LQJNBOfJs!lN8X$L&!wy7jJ$Z5uyDA~LXlASO6jq^Wb52vBbZyNdVEp7!uVvP; z%)vz7U<=nzaNo7LAmAft<|W7H*gFZGZg7{XAiYv?)j~s)7+UN>gz`dFrakY{RL+=w zjR#TUGWpIX%M_6D#MIJI?&dilch6OD%KAHYDH^vGXi&tyq^^buZEAC^sEMTDl(A?v z28NGUE<76yA8KRX_)I~z#|sNLhqdgvK_g@oRV8cn1w4r=OF=-?qRnG5t6|3_dU^+U z$jLFxix#aErOXU?tGwk^*NOa0TVr3dy3~Qy7d$c7$39__>}CNyQ&)9M6{Z#wi`D^5 zUj$mbpv0y^?aEN~Xt~1D_nk>}>W={C63Eqt1%bBnV?8+n$J=#t-UCEKVD8zNtP#ih z)leUj0?YEqVZ1^WbA(wouw9TeT`&7!3bXAt4VldarhWzu^3zy1{R~RRh z^9_gZ_;CLIoaP6MBkBbnage5YSMzG)Bm*DBsasM zQ3>X^5=Kb*n71o_c0$T729PE}+gc?3L!N|{}L69bI>c^-A;z~fV{nCMLo!-@Hgb%3k8y#-W~ zj;nZV6=#D~P5%V_+n*0jZLy_GQJb%1Aj^+G! z89}H$*?*<%uWqD1YTDyK2}IWc>8NoxCJF76O?qbzs6}4bu>Oy=mTyN4!(0(StBM@?#AXlcCkXoQ!*=>=3mvr81?D|VZNbnKLJop~yqcwS{`LRt_Kc$tmF-RH8C z@rjCxC4Vz?h1|ECZ?@E(0c+AkS!+34S99^^^y-=hV2k&$SA{@kt^*;H{NBYw9@c$d znW#*6N8HzlCy+=5wVvVg*-hu<+FK>WCP9bL^@z-gWQ8j?nnoDg2Cymkwzr$a%)~JP zHfF-yK*aW4HC;kBSr(u59rVz+p2wl}XU(N%uUICj;+QjCg9fLkHaxSsgXT$#T-M;z zQ*qu@(+O2DvbS{6yfWnOi{XbWY8>itwBR5=xOZHfnK4*-VWDxC8OQLarkqW+Y~yqX z#m?r5{%J(#Skx-&+N!qwfd&{Uqgq9^L?yC*TT&<<3K}RDN61yHQakx0Jv5EM0ma^b zw$VTr{-O;9k|x2B=OI=8ted6P4A*YL*NNM?32=;zC|l(q zZI4nTpShY_oK^|;*q}5J8iF!eLeLE_jIu@{Tuyzd$t3DDH6qfl^Xf|VEWQ9JiJ|SJ z>ZysK7?DjPHc|#CXp&7)%nL=2kOfTXEE%`oKJM8#4I`x1*Q>Dt?zchsIio1O)f2DS z>9wjZfseanc-Fi14s`IF|F?xgc+*`*7-QV_z~?pUmplA3U5#}5zH9B^UY)KNDcxm^ z-u&0Dw#!g{IL7{03qOlKU|40eKnun zPh;$V2*&g`z6>o+wMDidR~a{BJ9lanxUZ6P{X(H-WfxF&EcySt;b{xbmS6M&%%(z+ zo=*9kifn#%J-5vq+i1w@1j_tt`%GpuX%d*i_1n9IsO_HMoW(Ojhq(X5&>P4)dL(b& zaTm>fqi&5Z`%*?HrFk3TzMQN?)Yj?dzHz-A0OE$_JzqvHW)S1Sk1MD-Lx$!kM6})S zN60mpxYO(-_uR`;Yh*2}uZ#Ikm$ZdFk2h*$U_2eEZ4iS$kQ ztw=~}>mOxe#YiL|l%@eGon7%psve=z>-x~5Z9cnc#Ed^jO-Cx5<7oB2g<;^1l zbREIC-cuT1R&1kK04vTIcF;LpW4C2M`9z_8_+enRlm9D8{kvU%L`Wsq0WXCQ!G3MXOt zjaIg%p=OoVDrTF8X6jP|9YH%w}MEZFL##57k-o!-5g=PmYZ+h{bFUaq#8m zOm&7aWXbC_&|<0_(^A-=Q89LgdUxz5kIP?SpE*VNvBuSy{T0wl?g&xmyh09LcF%C+ zYP%yOf!RYB*sKxo@D`pfQ#IxE-+M5oStP-0{mthKbf<+kPQ5A?!)3vWCDBHi*QZ1- zG(!%*GqdFXhz{HH%k`hE);O6QZ%V)uCA+MV7t+~!qC&3drw5j6pp{|$tl>``Eck&6 z!H4wzr2<58jcq+N8(*?`m!N~hA5{MJ*0EamBMJKSZWEtqz&JL1iZf5&b3lVn()){V zts%frdMegEaM^z3XF6U@u`t3uW$&(Bib{+t3=(15;CTm5P_c5Z7E^|P7JUZ;XEerE zB=#-%34-P<>&pWjNXx`k@I(FBjOp-T$bxYsO2wGBZLgsxP{eg~^UPpkT6J>ZCpW!Z z^r9>dpOIpG|x9MJ%dF1Fm^2x7o24@)_@P69sgg+3}x$9^k z5)@0-aQQs$-^31#{(LH5HoD|?V@@H5X%ARiL5OSnoUH9Ry@6rp*+}FkU780F2 z6aF6m-z${pa3{NU#6{q7w};X9WhC2a)}w?+VZg7%3j~Oo(SPC|n^=PA3*3@l(lYt4!5Bae$aPbmx^zXPeAaFRDdYo!*^ zhG;k-Va-uvXSm{Uq1$UwWu>18#v?$6peA=TQICeZfheHZMd_%*p2T~XjdJSL2gw@% zPCEe;;9KcEN{Gq_oQsYXwf_6F(Cc|JhG%WZ|5__-YTeKf1H2Wdn1MVfey8`UanFOp z&rz3WiF0O@u|S&OAsi^8r&&>^b9*H>@HaG{6#FDy>a_k&bYoN^$q_f7Q| z!4nehUV(=-?6}ct4W=IdMS5E{r@M#8CAeWGHMnq<@VR~aACaG~GmPQzLJi;!AI9snH7=2)9l~Iab7LY~LB}Mo!uO@C}8Z#cq*b1LmG| zb5?q?!|6x*gK3pJRIlQIr**|1Barii@Sm@wUa)oNf60aedV0{#aXJqR;676a1a~ufa=qux0 z(WarG+~M;vN}cPGQRvG+lSac@WF z>AC4sFiu)O;FCwF;>Gan#Xh|ylSo=XsUZ;Ss6!0A&UGTsHe|L`sR%;{0%Flu3ZE}n zg#NGw1cyAj>`gI2k4#vihsFhmhga@u$|2R{?3UN?T!%}|3>B4nc|Tp2+UZRYfc*c( zuhDHgDuE9q$ivwGXE-7WOxGzbYMbM|Z`V+9KAAn(9rlX1Y2o8XlEr0b8vyfQQw;?6 z{AQ{r;XOvk>(o886UPcbccUDmz(~O$8P&wModv45K ztF%|VgaDj)Xy2p5HPr;-%GOJ8kHfCglW3W;PrLJ7eH6dj!1%|1lqOSDc<7;G%Nns; zA_&I&U8+otIdW^Wp;shmD$2Q+tlfO=@6x+om#-b^np^VzmMwto>ie&)DM;Y z5KM7KbUY4K|NMRG6^vA8`YL9*D6GNfSRl{I*0NL)hpq%GhA}TbHiG&16MdQGW0JT# z@YpjZuj_KC;A=!6L3a|WXef3BqwlrTSDzTdpq(;@X&;19dS@5=)lR{Re^pSG z|9$vB&NxGdkb-mKs9rW#!zrKckHxW^y&XN~rh3Is#}(-q=;ddaPqI6pE3JN?eNajS zDoltqCrqdamPHx@cqQRx+zWsHOyy8gm?HYmRBiy|7x3>W1`KBx*vK2D@QYy71Pt9$ z?`}{DyDwMy;(Bv7`0C-7+NMoZ4^d}t4*N8@j3ja$@&vmSOxQVF!*VXKq1rtTPqlFI zPb?`d0`*S$NY9BO?&}6bR)YeC4uj~})q9stwDPku$}{s`4wh$|DT>3@B>3LqUJd@d zE2%aO6w1^bda_FB!rgoP2l&X{3st{cb+T)Abq0VpIs`6~w!dcuS>PP1nFx2>PtEh1 zY}XzU?vCx`fp&1lmUz>E@17iKG4ar&^yw&~$w0m$!eRv25oy*7ya0Z93|~VdBkW-H zej+BgcT}}*cZYq_%VFLG^z6*9!id#6z-rKOJ=3a3h-R8Gwl<6GQ~l`++_^2QoIMqe zM~EFI22Br_(AQ5i38^252uB^@Uq?_`llzP$>U|jq0PX2Yr(bd}wf}ZrN`3$`HZp5W z!f~GpIxMu$rhJD7WPr^)*S>JU?OpuZF_nI$S8ni`AFOPumfA@#W~!=gN}tGV7Y(OX zZ=Qv-wi&MhQ_kW@HpT;fyuxdxtFmCj7B=6Fg|PEP(v1k0XJl_$}7t&{1!0kI`G4cR3|ij z+-H_k*`7U$tRfa3lblS5zNO|s1l2fxfX1OW;HKgoYfOApmxj|9tomDxErE-i_9QN@ zexbhgiFB3lj(z*kwdYof>u1){3*^zfoPf39HAjJcTeAp|5)4VvSsMlxx2{|-D0#=z znN9PCK%LL4XJGP7h4t!jdVz3t>EK|rGTM{R7$o)=At>D zw3MV4Sz%`6Ga`?@DM0W39_kzTYFQZ8@%B!%o=jE5SMSvYYHVLb3JUTaEu(=tENQ^R zBc91_D+u0b5?l56@!ZiRI~`J~FO{Q1#J4oA&ZJ9@xH+xS!oD9jqYuS=0&ZY~`I+!8 zXrO>iGl~!$WGGWS^*HyQ=9(}v>5JXtMK<$m{B}M===P{w69H%}Lxih#eVvr7T+c!z zOyk~c?29}^G)A10yT{}flPKI^F7)?BYIZGU<59;c(uEsj{p<@=4C|*w5y9H*>pRp4 zH|wcDBxyvw#h$wIpPGhoEQV4OR{o`&ZdDl(oJB{_^Ho4q(U@kmPYG)``|P%dDxeWZ zu~;YvVDS01?aSY2j2@G{#AX@ArYCn>1rBD4(vwv(X(#wZ<#Ybi3c@?4dQu*4#K;t3 zSB{YVN>?d+{JpxQWg*_>!MKUq#6X$8HeL=Zg{dw`ck#X#R$DCIyCd`dr#@^{;~Mpf zKr=u|t4~7u=w2y6;>05GU8S54d>E}oAQ+j`{z?Bm$~G-6E6Azg1a)M$o>f`n+g?OgYRE1<@8X{cKxO(5xyf)vM_kVh)-=_TMFb}!ZAz4OqBhDgo-oJ3}V3jo8 z+Hghie0Ey&!a9MkB%Jf7#C{C{3{CCsL&2S+uG6TJm!?@D&=*|yhg=}Ncl`Y~gLBJ( zFZ)~{N6GUz)c@{Fsp8Q^FBsTj5L!1_N8m2)pcFBkh1x{Eh|maQ-)JDQtI`pW1kfDC zV{%LsG{vr1M8wnXIxeaG$Zj;AU!=H-iYR7=H3aY27U&OuQAU;mj6au z;+-k69e!j>Oq`u_+lQ{&AZy-Q_jO0#*BgB7rvgjvCcw=@BNEbn^4rzWY<@>JtZ)0w zE#qmw=qGl!g=Fx`KXctsUd>g4aZfjEmKsJENh*XF_YatBpDMn+HafkIsmrm5{yX!x z*iE}*#?trv#KSj664?v6RZl-24lvs}QhtQS+cr&4-Gz4kdFrfNdK#m31A~rSeL>bD zYJ@Yjs43%Ss|OK{$X>EcfDgrC268y1!5@yD}&O=DxKd5GE>XA-pqXGUgGvi*5K?-x9=|DD8WD{AZ5Q`UjAkHI5V%z+libb&cjP> z+GU*Bn)4gMkyba9qkiF$tn4U8__Q3*s;PZLMSEth{1=++9Pv<%AAbW{9A<;k zh$%T=CukqIF@Fiv0(IC#=COw`85Y6B1;Z^mz93^wU}dn_t;hIcY5_?~hR+|B1!ixt zxH5n+PU7I{F+CCU-{0MNvOGRT;J17bYDvWA4e% zrVY3y78B!ma$fZVF?m{C+LjvLxN^H8*sZhuUg|UP5IIBU;IQ&s(uW(6ml`gD_ZM;O zRo?m1+h*%CqUiz`g%MVz>IC&NJzMe;r<{CvS@!7s8IZduHRvQq(rDl^yqd+ps=UT= z0;=m272TiELS7E5b^wLbe_s&Bm?py9wmbE%urt>!=oZ9z=4qn7HdxZqFRR4HcFVen zs#Nu3IPu-ry@@K{<%}HI&w@zr#cJf6tAZzMQ<8L;`J<4hg)9OQoB#^7_O51=_yZ-5 z<^Ah>hj#@8g~otOETdSMY0!Wq;1#^jItUa`M_bcl74`yE6P8Q_bLH4em3g5}mv{HO z3H=XP(}@<>vt?Nh-Dku89{wq(Op881%!l8R%y})Xj)x7#R%yQaM?0FsiXoeJfYln{ zGb9f}`PNT_?5ve^2hSXQQl>U7K6+nz? zOA{9zORdA)M$3t3n2tkm>U+0LEdmW9s;JN(RPk7P+sd8&UVOy;&VRGY-HljH4{dIktiB<$%$S5emvAqo8o!)|l!oga?;AMtHw7zBPK*n9`cU`MNXyDiW+PJ33o z6(fpaV`F>%uE1_AOB0EQvz9jwPwYKqsb6x+WlmS#dhh_?1aya|GLCcmZyJ{(qYcRC z(qxi1;4TWvW>d3Z*F!Bwv9_DV0((9yj@b>EN z24r13?3uII$vTX#NUF>c;|mN|M@?Kxla-xqMY1l?l#<;~dJ6~0a{Fg~NxK+=RT`6H zo$cQU6g`DIv^$>pbUIsl=f&B%UXM-EG;JQPb%SoC3jCxfK*p$xmOkw?qiVVqv8c9+ zk#J&z9mRFRoIYhL?bptIp3R#P1h zaUc!+`)@Snle4&E8ivBhkJ5&>E0ZC;Lt#HQF;4XC=M;`6Lt5xrT^mE3dt(L}0FFya zS)+75*J2IQ|&CQ0U><&?X9|{_0?MuB^emh&d29)*rQRQ7>BP=>T zyr9Z?dV6*sq$u>*Ytoqx)Ubh$5lg+T^2Xg6`^FQGkGC$$7%!knpujUvL*7wtW_cN$5 z-mj#qJ)O^{&f8!^JeJ06q~4#Kz;QyC09ZbaxQje6n_}9wEIV9x80M-`+U%WgU(GTU zy%Fq16|sCbaP zSrKxptD$h8K4zZ8uqI~}x%Ww9^{nD+M#}?MxGq9YKA^!2xj^lK@dmTROH{9#!F!qTyqKSTQK?_-LA)L?YYBMsx-TVJ3^{fFl( z*&Q>+i;!a&mBtFj6}cQt2l90EqD+?C;}cA4Y)?&nLb`*SmeK#k&;><7RTN0mj(Y`o z@$-6ko&F7LRBo5fbZXh-6)Sbj-=^&%vQ1hMX4+GYRG z1S$bl_D;b@N^cpcS@c18{+lT~&9sF;RRe?JudgO`<7zR)F;UNAzhB2&O1*bI zd|ctXu6j;H+m8N5Gv**GETa(tOve#ue-LR(f#A*eaaZ9w!zQ@%J2_xT|D%p5QH?_a zHk&4t7}p`I`z;kh*M1abihpIG{S4%dk3k=)>-M&rQ+vYt4jTd#YYN={M)H~4EAQIo zRPIJKUXpE>v(>^kcjN4#f#An>qI&x5kP9X2+r^Mq2f01lb@gvt2w2+8Pp!e&FBJ1L z)CVS&of;^bj8#<3V)56jDvX+a&0ZC5R(Bl>fv$OhE^81_kqMgs__IvRk=#5#n;%m-4xB?L9)DpTXU#h&N1AG1^aQ;7VsM$75Knc5)cQPtr%gljRv zdwA-`Mbn0HWuA}}A4*E$K-LWU3Lc$`ltY2D8l57I+SS`z{}vM*AL_qjBvh=jSsqY7 zOQcf>cs9-NlQ)pT4$MPe-hMuk17nR+p}`UU3;LH$4Aafy)*B`n1-HfH zvO^2Fc3qmveRU~zlaJ~Tb%$`r?gI6o0b-n6lti}HauW(`h($e$8FHxM;FhmM0({z9 zX}6)gIqXoUeUsC}YWwWC?hP;j$Va3#vywhs^5hC@Q4J7c?DZbLn2H2@qSvhm)+(Q= zKsb__RLUls55i*jTveRgq;Cz9O(H)msvUHV;$$XJ}})Pc#In4;phP zwzLw)M-K|rDOHDMFdEtQEskQ$Joh9qDm+`j@=TGwoZ8cxrGP!H#=!PuG<=F9OMS3U zETGSW+vKOV{q}RlVKPrsSP65U#f&C)@CWv)lwP{GazjqHbFFxM4Te-iKa3ek$0x(D zeE}5DY}Z6TSLhhY4Xm3IE6sEfY$$e}Xk(OV;l=wgxTAP>9orYaIr4BRm~!lDqGVJ> zMUdJnbbRr}C7GNg9p%-8>I|6XI(QpJIC2ltdnR6vq8is` zXiyt6q6h$;1UJswg-J2FD z_I?7SMK^C=Jwv`ReX!t(e(VKDxzc^6i>%5e&6WEd(Q0Pie@qJC$#v4OQ$ZW8R@Jz> zq}nF&WjSK)mK5h?kgM(*R>-<2LLZwI1WHv3uU0wG!8Cj&h>QsGurPJeW8dgK7hmEJ z-v1VhBWq>2tcvoFKwto6F6V96#e>My08QpjQ0Xd4WKK9N1QMz4OY8M-94;7b>)!yj zQlv1eZTAFSjb(eT>Ag)K=9{6i!cL@O5`boP?OI!TNIDFvC|fY9TH@?Rr5`z2GkaVZeR)5{HKrMxy~lQaqk z+2bvTiu@G`2LexUj5;j_;scH$My`^%N|;(+$UNy z+JBP(5k3~@mDoD&%^md4#!)!Dp^NWb!U%mCCmuiz@#2R1Q^a&FirL3fc1>@F8-CMy zqw)8e8y-tiR7rxupF8M5rxsw=&au*)C%Dz+4W^cutxuL+I!)nFfv}rvy(uNac^1_1 zS{rN2a)8D$#ceiGqAac34#d}F5nO-1o2D8@rGjcLcsyCE7hzs2e~#RtB~G*vWgauY z#GuS>KXJEzx6|b&13;&egXU<_lJHeE4})XLNod2@Otp&J)ZH(J0>C|Tw-38W2uYCBMMyg4pehNSy%=uPP_6M+rP&bOGMk;$syPZ8v_ zmbMKy^hrgoX3h_=I>yapZVvyjLry>*ieUs)o8D zY(VLBROh@_5!1EhZl}ihsN$Si%=FY8pH%UMh3&IvN>JG0ocT1iT2D?f^+9JiLf^0v zZ&01!ESRoe<*J(FJOK(TWZkS0iSH@h?Hod#c@#-%QxRVgh18NIe2sQhAxFX(q-5+g zap*PG{>h4FjAgF==-@iVtwbUSiEaMVb&7-}BtEPVcc=%zKH`nht?L5Am>%0Hd&Ns> zqn3hV<@9CF704(&OP!uL!6nCfel!effwLF{PoXjdi(2L54rZqrb>Ug0iJdbd!p}BR zf}30*a58WoNCq&~^+NM@HWv?0`g7al7l40bjjH3VKrB$~;~chRe<(RJe^^GeQ0Wb@`3$v(*&upfOkz;Eghe(7<>LRc zTn3u|v^xpyPsFq9`wQrb4%*r}Fbz*qcAGZ~osSut2clbkSRs0!0)7C;f~|(eV79U+ zNnNU^*QP==@mG6J1x`$r(xrfz0A8NX{AZ^j@ZC3hs*oyA=O$tfP~(2Y%AN1eW<-{! zHsSBFZ6j9Uu4ihiOkOEQ!aJXBATpi5F(*9L*2a#zoyX0N_5@lp05X7xl4Mj7t1E60 zt3T+*1NtH~cVoYN?<1OL99FC$-d#CMUK+)SSbeRzkTj#51Vx4I&6mzn5|;kH!55olKFjn<{+dF&Cynbb!q&=B zzhBRQU3*=u9@gM)r-i5gHtfduiE}`h3{S2=u&U{VDc%qTto_+HilTCg;jY=*YG^E# z&xfZOF-060!BJBW?narh++7L(4&V*O7{F45|mzVL>qUVWn(_J~UPZ1g?u?IVh;2i98v z@fA%oYG+T^UD$SY1R9A+@bAVB>KY`acrJZ;a9^l95RO;ApS=40Gz^^$uDdOpk9F?0 zGt!;kGND1!+%7-S2yYz}xjraMT5PhMo-A4tY-HxAXtuus(!;BOdB#?Jv)`#l&ZivB z7ty6Bh?0(F?fl{G-dUq{QXN5!tz3F;3dCC(Y>2^{UN5edgPD=R4U%cG#FYM2zaCc3 z)R>+#?W#;UHU&u*LmDf!g3=*a>7%Kjhl>E4I;zFh-p5X3^KTY*n`e$_p^@*IRSz|c zFKx^@rU^{g_h55 zP)!)uWee7zM9tKXzwb6}%uOh?G*&NF5g~Lm4y@)}XLw7ou-P?7C0zGp6H}wxJ*gg> zmQ3QLt1Z5{#@`fdlSIs42UtxRRQ7~9#Iq4Mn_~i+-zP=5EMk@6Q6av!XQ-TsZjpT3 znf>iDDi>^hdCv|tX9HsON{a}QW8vM3K`LlxljC*KBvL#J5r=3ZmE0CXBuX_$@F?xk z7PNYktANIMi-Y)yM4bT{qQtyGn|6HuCPldvXCDH^M^i#czk|xS^zZv+QK){bu&Tx; zeBO6>uQAWvl+ROS7tb#&38I}0yF^ggD-0IQ8w`cG7ab*Nv0mrow3MDjMYj41@sAKM znxJJV8|-3uxeqRMsZ6o?Q)*viHMHP_wjj#PM%a9}Ci+;x!mOirA?84MSAOVV*>LI2 zJcO5b2e`VId2f_z-xq|SnmULUUJmOW{1bDiaoeBqe;l1OU!ckP%RBI#&*dQv-sBcivviu9CnOy^)m845`xtu10N~ z9Koce*SI&Rrk!*)b-H<22^+WrXNukeBV?iex3L#)Hq3`NO~Cy=;nDw=Qc9Jw|M=Kp>**GaNk zKa&0evb=1qBzYI9SEfUsc%t@tma!aUSsg##ckhVPuFtDR3;7kt# zNuxGLg>)s?{W|~jyg0J}T)uPtbL^%=FyHE?WylR-dJ`={)aY5*UxJ9=CR@L3nALmS zb;g6ZC0k`V&A~YarBMStdRXOYlriFZDyy8TIZb71A)eQ#rrsS!+{!aHmjRI$hS_r6 zky9%tX=lZsZssy{z2m-hxv$V=c|W+zvVi1)xSTpIo>dBxk?edWb-!j1s)mYfzAHc4 z3Zt!HS#_n5p+UKMQlO~&Xm43}`S_RKPpZe!d0x8W8y9#T&OVXz^CKYkqDuhEv+QKGk0 z&Tfx3(Cs|SEoRhNwKMRYUR#8hZ(c!2b`)yuags#hBN(UR?#9?b9Hg>7n$$9MMGh%P zPyoqg-7$D^aL@GAWIiy%2;ae~NLw)mFcs>LznlICY-Z&81$uIfPPz472f2$n+3#l_ zrlqfErk9)8KhB=))z{nV00W#_fRQI@QMDB?$7W(}pk2na6Q(}SsKjpe*yuRjb(d}SQ=wo^j4g$>+2k^J zmr&qYMqu9LAaLq$W-15+LcV_6%Il2j5}EoOLN$4q=kKbSmc{(-mG=A&_c&7zf@?v? zi!`h*HF_r@^&eaH7EX5(+F6UQSYyuin{(#ztL`!OvGm4a4aQT)OQ2)+WN70u(T=}0 ztpVujSkhA)V#*?Sk~gi-PY@zIrdvf0S5sY~GrzLJ!ZTD^b$bqk#eVSKCE7j;q;h+A z*+JPQWbx{Q7NAJ1)b_}jQClcdxBJ50eh;J0CGy_;NSgQbRsEWvC%^+UKs0#e=Dy>+ z;sb&8N(@i^)3rR`0uBV-VEeU6bg|xOhH#&IVkdrveLat!KBHi^xnaD{QP6b?_|mGP zHX&EN1Q3azrZqGift?-QrfA|XlY>GY>Sp*}SYC6|_k9l*$5Ac%0j!->Qyjpyg>jd` z-Q8_)hZ$sWcXtgC+=9DXaCi6M?he5N1P|^IG`YFw)cptdtsi$)@9OSaz1O#-5yZR4 zfP0<@SE^rv(7&4>7I)RMQykY#R`ib&7q|X#ZM&1GHi#%9W)18+`3XB>s7!!jB#No8 zm?MorD@bRW9w4L3XW(nYD)_j3=|p`ic%cq%Ls7|U`-QT0RBHHZxW^7fxeWKYQgp~S z{%=A~pkKQYOJ+-gt@24+JJ-A_VfRMd!o;rfTgRvVHfGr@5!Gpp3sfv?CA5e-_s6so zqx!ACL>)~8JN^=*o;^HV*_*39(`FSSeibhR^7x_BhNJNV@3+hqPcO6bAM0dHp;cxF zKBsyjy>dM?h#wTyu8;$e;WhoA3`H(z+EUK1muB{RaCS^jM{sJ)M;4E(gRK&6klv*> z0dZ%A3otHW>F7wt;gzF$cO}fF5AM;foHr4FSIxIT8fC##5j&U@`W zIa2#*URm>z+`sLo8s1lPG)wr`MFlIRT#+V9*>$d6MoKt}Fo9&>2Acx?A)}uCP4c@P zp;b4`6RkHDwS{@rQp5fJ#$b(;?IEwSzQ(}8vm@*u?9;zpLV5`92+i6kn+Uz_7GJj{ z>Fy{c%}$I0jE7Btjv%2y4jQ{PDuzUssaR<1a=oXht%y0pB`ef3rPcuz`q!`{P(X!cY>Q*a$L5~B||_+5B@mYKUeseAbb_F^1W za9==6b!xjSl(?GrGfORRveXePRr->=K9=-?;?q}k+f71iici5Ig!(~Vp zb8mm=|GD&9h{}&;ZTw=PQ8%g^6sd-le5o4B4V8VEn-RV%zoZYKQBq+@GifStm$hWI zZ1fc3eFfF4uL)OjR*~B1hF=P5eYyh+3Ye(Qn3^4BQfi{jbB#VDpSi;?O4qZ3kLdSQwT7s4My zVeg?y-L)r%@gpbE!}26V7!tRuRk`rgn%nJeEcQYR!7!jhABIT*r0JdL0?dEl~vD0 zNWaAUH?~YeV4HtRasuC38Ge+gyC8|1>}!WwwTrK~a+{OY)hB$7T2J>1(~ zP)%t3vkKTN=uC@+i(3jpRBY(2{?)JFzwjM?B)8QSZ}cm@gny7>a_3y=csMXshK1wf%yR*S1OGUY7Z}JZbS$-s=s>{nKn%FIj@i6z7byVyc^Cvq? zOW{ftN7rAT8%Uapu!WDIi+4`G=PY7x9qG4lNEHn1AjF6v9$r?ax8#E9Yd*DD_lVHG4v}=NP3npPs@M z{O7in(Wp6`9gQ{I)OAwdWxoZUr+=QpwQ+?cV%UQl>>KKxR<<}vZAFpLYg;XfW*04w zY>4UK@>%rf#-_=f$!n{JcvY@_qM#zLc@0f=m2Ir(^^zHMU!IyNC*>^@%|3as>+6_| zc#@n|7xpuKtFsL6o~P`~Uv5RKxDjfP7Icm)5`Fr>!C`jFeC}D`|J^qD-GYYqS!9;L z$DiF4$}^_C0o<=Ad6l9c+vUvUy&*4zKSxcZJCJ}8SRO#@du^!cn!RB9 z2GO0DL9QDc)VG$-UR5n0Rl|M5`!eJiQbE`GF61Qh=@o7{$Es#Z2}0*tQF#Oz`m?OW zbId_D!ucz=vJBPp!*^M1jb0}~Ve$7)yLNU~zhegnU5jj()ayP5wG905h|W&l8D@K! zc}C?i62@=ezptLqb40%l;Z(Q?@EH}Ap^9A;m$nuT6`w1UQG{L6K}~f;!AsY*)%+jht&>99ScOj=^FwM_C(}gCF5On zPomC`hZ%B=v>e#!S-LBgOx;Nb|DANz`otIMr{oD<-t!!pxOVX(uc%8Q8V_Ky`Hjk+ zT*ulz`{(zyTBQY%J2l2VAn%_a*sCs9En}tQ&5K)cQWrjGKLTgHDtkto5Sn*phOX@s z+s3i1+*t}KTVfrTAc4EmFjLS;^w=l6CRmvuhdYGh^Lgl_c4!K83(@X*we!dCDHqv? ze3()Fr(ff1#^W(L#~Pzu97HC&iO57!5v{NDmj>ZPt<^8GncM-FR``eydZrus>!}4d zgaHxcoy6Qy_jHl=e@)eP9p2XiumNAGe7S=BtAE%vqiT-IDG;%vwTB?3OJ?rq4c?0{ zxxyz15J*)3=(ny!tWqg@mX~+F-}OO;Y3}tLp>lBF4v|zJeo3)CGgxm6@sGnZaXLm8 zAkl1pXG{(s+G>t9@XbqV_0 z2)jGayh=fz$W3q0pG9;+Sr`r`IdWoW`Tos%af%7Q16QNXipQH`j&)dlW=EvN+cDc| zyfgCEgsyMHKi^ihxBP_IZK-<8>bKA5IcDdS#Ad(Zk*i>pj%oenx4O`Q!ziUJ$mQwl zn-)f42*vu4CGK;0k9zWM63pm5bFRP&MARc|DtiCm(q|6xM*Rc|rPYzGfNy|CC0b-> z*;d0vKNJW|;^MWArDQBNAaa|h?9a*Q{XRsC-=Wqc6Y8qt2%T{wXqgZUJU9J~;COP@`G%wS2 zM)#@)vy{z`;!e($1M2fR;UxTVHhwSz?SjtDSpK8G5UZC64h=?7k?8_1IlQjSsJHv_ zqZ}OX!R!Z}s@CtyYg6(Q^Q==WeWNH2N*6!a(@!9JJL)CY|M%xzyx>qKh0T{*I8G}JjSIdESh?76fI3J(iH{@%zIESCH9nnf7Sue{InZhK@o^DCBI%9jCgO!|BM-ABPOfk3Z>b~iJ^M|kwyy2yjE#y z-yl-dCgy?Y&@=0+=CzTLQ_70K!UeTssv_|qw0hE6KvU4sRiTvZN}%s2K;#Amr*&2u z-T^h;q!}44>saSgc`n07dW$>S3LTYm7i7bU{EUBQG1Fe@b^X!<8+wd~<8HK=-=}** z_9N$Cy5zq+eCd)Tzc&gQ7Ib|v4D6jx0*eEn9>_i4Vl}Vpm&y-@XWS{{YPS*$YGAm8 zoQk%}yLNDy8E#jt--j^nvesq&iA9oJ?YIK`&$g!m9;wA0=oy-f@T=D}#&^K99EUh{ zC-Y>vYRvG<&;2#A=-54{rNpAM^%{CRK6-)AY)+(Yj_=uYRu)X&Bw~$`;)tAD+fXtF ztMZ{b(88A`Z;t~9Z8Qn@90KiBFVf%#wYy<#m)bqe2boYkli98M?sqcRGgy|e^@gT- zvixpqPIocg#I88bSp*IROLi83{e!KJ~!31S&pv4DY($QRx%?iC*UwEHL~-m z`vRsCU%{dK{^4hTO{kaITK_}yF)fGr;4|KJDt=8S9(lBA#40wm^-28mtDd7!x8WZc zdic&QE{S;rZ{39*M5eefdZD;bzlReZ3T>#7v*qziy|fzmk}WHLC%okk^~^^gux=A51ik=@379w7RkHPN_QmBX2PPA;4CV(+51E** zvsAvsOnLzZWp-T8)+$GsD^3OCcXZh#C=uP}SUBa9CRK?l=<%df+XC&GNLg^fAi zibuJBw)Vz8fMU!S2v!MDn29^^zPkizFMeS-bDf^04q+-@^-5l?b$;h?tU*>vKgx~$ zw%(Qv_h6#2!!$Kp7$4m<9@VMHaNW8PE1A61M7B)R!SAMJP~DV$C7;st18rYBg)C?F zpB>##<2Sy1WL=XSR9MM!ayA2zp7ZVZ)tVM|Q_~tssJAs(o#nM!1L&o*y;WSgM$`N4 zVbLYY3V+fe6~xyr@3<4Uje?ipMD&93lKzKwDW>{equJ_(HrN5&-z8L~lSM_-&1@frU{D^QQ zUM9cZxI3?C|8)OtDfRbNCDdY6B^L=rf-T?dAsWQ|W_|dAL~+z1{2%%~6x5jCe;5A{ z`~Ttco7TxD#5ttQQ$0Drm|1SYYl9V4r2mom!T(=ie(nDQ^Zzg0|G&Wr|E=Kv!2A~f zsfcx&F2Yf_1);8SSVqw;MbM?6C<{IeMYeb}O&P~DCMVD^@g$0$dPq2&@^O?~qK>}W znk@)71?>}~9DI+usFr^&Y}COvviaY93N+Fp{LQ{7aps#DD?L#6-(?_TD5LXW#^%*6 zCp3lpKh_~eq(;caI;oEy27cEqgD^YL#B~asFph!M;VhMiag~fFdm{_kM_5)O^jN@!svt&*Jp2_+;Zo<%$kj*uUU zACx7$SG9Y1rW`E)?&kRp!QRE8lKi`VsiwbN;eI4mw32bw7B+fK@`TZ~MLdaf>7TDd z&9LTG)lc#K@+B|+v&_4 zpY;MX-myCgH53;^a)8LapN237mtEL$Ix0ahQDrKDFw1OsGsRW({7%reWQxXN#+0Ac zo&*`mkg$5mh$q1Ce#|CqwV;jGD0rl$Mums7&Sd+6^JAIdogGr2Zfq-slZ+65j?w0q zI~nhnMKB&+K8BBpWD$Fd?&q_&JIbsGHZs0o_%V~91*(`{Ss^Vrn-8%cz^ zf;JeQ)3dl@DfH?aUV;w8m>?)dsU$USm+N%y*(MaTY_qzC_0pzAO8+8>O4tr8Tw1sQ z>&(eIaH>GT(VHZb3Zr`L{DGXvN5=gxvQCwWL?3CUF%&iFX4PYX(_^_Zp}8+-KP^2j z+`rqK_y5gEhO6d{f!mC0i|#~=@_pA_K2HQ9<#q(7q-|B;mQO;i=wPdx*b!0hWjUu{&*MJ#VS&t#yeK98x_-r+r}XAF zI`X(POO6lQPySvPIk;btPPS5-Dg=r2^f znv4b3JrSeOBeU)4eO63GSixqz8$_{(FO1uNu^(^HgJ1FvM?L>*Y(F4btN`i55OKep zOx92_^#h2JFvie9URu;2jf#3Vs3;Axh> z43Imf1#SLRx%^cry^J+4lq}5rDjQfNz*e2IkB^2@qHl)z%}08n-Sp)shNft%d1kc= z{U%*%*A=`^G@&hRKSN%Lh_;I2SVFC$)+UK8rWm7yzcR0Vqel*7HQmrm1xFmLrN+QU zsy0|>HYq};4PQ+XVwPS3kzdH-&MG!uCO0oTU>Uo#I(KVsa|CL103E4wWMhF{eVNon=g_JnV=%juslLkgfOm=_0xp)5J>5Es8lDQ9Z{+&ncFg?;`qkKyrXK|NPGW&u7W%@Jf+_yc_UV@`<+>%5_?2M&7 ziW4e7{BtT07@h@(b8qe2o)saCv9AZ;aQ(+PYN4NJz| zA@(&>u?OugpHPG35Zpt$V2s5Ii{&%vu1f4hl|=TCI(EN{Q96BUjxPDG9l;kl9j?&? zENTa8A+d~EjY^?1nEFlYQV`xz`>#qXbE7rs>fC)B(r^m}gEo>-08z&YXVc$$?a#B253Mlg;D??9k_j3vy zsSxswn(c28Pdo?8TF4rsaI$~10bQKPHqBY7Ln6TYfY2F|jbVf4;2MZMUlEQgOj`QG z&JXv-D(vJ=V_4Z$4SQj77~eJc&h9w0uPLepQ@IYVn>t&*ZPccgDS=q%M>vdJE`I6D zC>+XmzDj9wDHK+xyAC&3&1^99FdRit z?*+o^2<1ccz%!fR&~Lc>2w)Hs<4LXog99CYmt_x$+z!e3kosX-73+q1nCe-jEuI1v zwsZPK4oN11(Ebp#T7Gfq4`^gf{68$o&XPaA`IiXfRw({J9j&g{->z(LowI*7AY`4y z9OYZ^?}o->n+Y+6v>=de7mm?Fm1=t064w8V+kB9UEb#eZ5p5%nq1DXU$W?;D-A!$_ zp-bMmfwmIgRstX&K)OJJv5B+%9*Te|uc&EtOI;h*I53Dz#YORnGeQhelEl(c(L94| zK^f8dp+v6z7->~-KI|gDFN_M-_BBNaBkC}r9B$E-=nyTIqGx*G>q)Mha^h+zM=fI6 zW@r{h*Hn%2?B$ebp8f z-Q}2xY}?H*SHGkqknF|~T^=tva<`DojDK5naf+6rNvAMaC`E>1ACAse#xX%U_GFMg zIQ9iNbXE44MCz8U3u9-hbGf4W>+y8&5(+Bt#Ua0V0|cBG3xaG8@Sj+zcdsC)oR@SxtJFGd}iYCu0EN+B=| z6iK`am8$sCHo4O4xWdpRS8R@iOA?_%hvhK?x%NGXHxQ%T(WH~BS&0KC0(XL5hCZ)l zXugHQ4sm}1|G+wTbbMqm>!}B?HZNWDDjbxftsh4u7Zs0*q`N&P_n|r*JZ7QmE3)AAd$aal8Ao2qbH!|^$7OM zGbhnZ+4@16o%LiL7YA$>z;}}To6>I3ayx_Yd>g85n32xg7i4S%TY01fk<3jjAy`)e zIuHG+yE0}~&$;0He4IM;k%qPg`&J4!L;$`lcTh3<#_xkJqrgU|@Jz@;dmOf-U?6Y! zNn0I|Myv%^Rv=F)4P&@dQT)DT)(H?SD?oq%N<~z)1xVtcnq!wugv=rXv^)I9EpQlX z=&cmcnF+5JBE_JzM9}zY=Wt>>728_ z%Sqx9EZB2d7Ij;wrdoLueE`l?ADFmcv#`Lru!WQadnrHsgrKDA<-m z@ZYnH^D>fhB1itkpj~lS{d=%)Gs8#{{@ltG|To@1yi zH+Dprgq&T<7rOWR#giM#YII!pO@qu?a zKSW}}$HRo#HCt{EH2HxhOMO~p5eXxz3tfUg-3yp}y2Pu9-Iz6y-s&?QPrbhRq%fJ3 ze4+>csu<2koPjh(#u6>cyMAIAzDv(kI>OF2uXZu-hSx83;}HJUI&8z3>N(|14*Tz= zRbwBr(!1>6ztTuXloWb$pP9<`;OgL;CHCar5_M8`7Yyarg*sk0GczI(yCUKlGocZ8 zI|@^DtPqAZ>mS1+0a*5F@KUrAzCE06^f08dWfQNR8uZBdk46p_ zq`~vG5bG-slu&kIzO&fVF{lp;a^*?DsDY^u0enaVtJWe$JdkkQk7|f`8h?#&Qpv!L z%SO8v{xLWm%_qZ^FDu)xu27B!y$&7jLzLG2&mYiN^bp>eBWg7Sw*5FB_49+gJchTPx%sB`ychLRK)?X|zHV_}PMe+@RdXQ^)tl2lSM-Yhht zPY#+Hyb4=h0I{cdwN#Li)p=H9Hw?KxBauikXm5$)QjI@hMPd5@o8K&IGBFI+Q^rZW=hrrSOWZt>ELp1@8q$_D+|q$jMOa7+j9{5^e955;;JWcH zqC3~bU%qt(Bm)#nH6q|>)eIF>+^cBtJ3>CT63>ALShr)?Wx46^P4UB7 zhzUDiga<@VH8e%EZB`(fG(+&{l;IT=P$4{nh)I1up7>r#9;GpA)3LFwZ*{f zD>sXQj^jQ>RQqCC^&JKXtc9uFl@}15NEb>nms%^hy=8*du>4r;Typ1kS*^UFV6-2_-3@Xn0hX%Z1vPg6lnyJ=T5Qt_;C>x}PhRhDN->$-XuOY`L z@<-M0!G~GF33f9GwD9$4{^^gf|{4<->Q|Hz2sk{+8O*wKYfrgQ$|B zvU-T4TF^5cDTUah5$^~|1qC@HST=L{6t>kCXF_1&MT#IDX|qFIelkwdD;^M@tWA^A zrih*vB_r8=JwwuG*@6mMo&r@aED%`W?R>G-5@eeTBy>e+Dn{A{?~|21Guc&#PzsuH z0u(Z_XRSq<;*Qg8U}vq?%|UqM1$uWluDr|u7T^YZ#>bf5_`@~I>^lL4t2u%J2wymG zcmc+aBFViCZHBtkTunX#Plj5fg>o%l&5cg-Ya$oagi{-w8*N$z9*J80mC1-ZqG!o_sz_vQJEHp(@c-4rS*PEevXO`|n;_UqHDE zbP9yT9LYPRbX#mfrHB9D0rFK~gnbW7>f#1c24R9NEwe!NHFf;?nOhLUR&Qj7*$>6M%m|%VLaWS>a`JjBldLmIb4J;(cjDFGyWt3qB(QNc}~+kd8r(!|VEGu?CIi zs7^+n9tpe8$~7P$<1iik)Q5D`XMvY4Im_esH*r}9)&}8 z_=sUH$cPhER%z%|EPS|RHlpd$Bax$%~KaUJ1e zPG=fRX05UstHM2<@}^{K=e8)L6`-g0W19*!HdG2VegFPs82&qtFsX7x^=>vDmcKq9 zUHY#)2D+jbsQ3*yrw!5=6hZ126bVPiJx74pQVq6`Rat0pY%Dk{FRdHxA48Q}S8jPQ z6XNdWU-c-wG>LzA5s?9lpC}HYELuW~&j+VbPiF8#{vnkrpysP1P$noD_R?no}3r=@1Rc&Pq`U1B4WHL^=GnuxnBal=W6pS0GiOEq%4t^X3>s zLKav_dS3m$6W3wre8(laUnd{j(Iyh52jE9UYxTiQ#~{bSh24t6!QhA;yc}NGx$Gw4 zAK_Emnf!{|FjclLzH(Zm=sdNaa8B!*G9_^L1)iiTuh^5z4DNLNhx?F7A5eIkvQ zxvw*^RuUi#bMhpnikG361ud0F#bR`Ax%u_(ma_lgp14G1hNcX$gxwy!^sKhaW~J#y1ZzNvrl^c~4KJhbRGnA1pzY#*jum3Jp zQ2bLdhZI@7(=f@mSIrA2TgfqeZo|Hlq7RzvO92`A&PykPAo?yL;B#3$w5T19L^g4l z*#=%*lKFw_4el53H1`8Hz?ckl0Ve+A9#qQ zO9s0+6)}`s{ZhsBD9JPdFXT^^nyt6xa8^xRhyWe5YAE@c624O=vcxubGYa#vm~#<; zQ3cB;7!x^=-W8pBk@q;0;!TL8bl<{~nNVn61X!}Ll0^rbDXlIV>UgC^S)ZB6sqz@3 zs83p8K2NrqhjKd<($?U;2SBShm4BigQ5_Y5!KIy5f=l^nVLHmV^-HLzA5DH3h7ozC z^}+h!99M^_G|#Q2z3yLpVx}T2?fy9@N#x$L@>ghsB88U)1^T*{Kl+sTc~V94%jY3q zf8hcv<&jyE;HgbQ#AZ}9eUU-ytr`fB`n+gKv|i35Rmn1HPqB$j^G;8)l8C-VS-!|+ z1F+VpVO>m8ouo-aIoxg|vol*9D~lRUnUYv9U&tnffRRfnIljd4AsFoBZzA+N{qU6` zO#*(x&K4=nURE6nBbPgE;_;5gz5xEnb>|;>zKDpj}m-{*&fCbdXMd_#uM7D{xKHkWaUMw$JUs+ zk+C)D$qPDzLAy!(xa3G6#qp#=7H;G3@Hv&=nXPk=un~Vp|3=-J6&mjHN{R^OV6_tE z=G;c_tU}AjZq=SE%czT>sVDZEWFB8)O`$9EW>$pNd`p*fjqBVSUHK|MFAJm>PPhb) zcyhXLk=wF5PeNr9$SbAOYQTdFrahRL9^jIm3s>+NyUCZsR4vLmtGqH-kH{s8vdV0A zVGL-e6JKethl0);YA8Ld7qUsPwg)SvDx%`0!)A=*vU^hK<8X)ZQ=6#LwPBkJw_=p0 zs3Xc9k?J$hndpY`0JAtlrQ$(#YE%?3IEy59tnqh`N_CUtn$+I+7^8=vup@yJ{2syj zh?tDiI`3SAuVnph^bL3`Ffo#@)92tgV{sIvQ@MaUkT$&ksurr_Z*0@FS#7>dW7~m>};XKC3 zr{p(+Qni0yk@A5r;kTx!IK56)iZ7w(w9BLq-W~fy$Nk_zl8M61CKUPnq9fwKW73;G&`{~9FXI$0 zw2uy*mZ1qeS4PQvM?&3~f`_Yt1o~!Q2IR;Ix_?XUN@XpJSyUt*k;7PuEH34f-+=-K zs_MuElgYU>M$ysjvn%jpCHl_}KHJ?3By4619FXQX#KlgZ(8|-@LkBw4hAJzh`72f3 z9t?);JR<0&ikJk#Dg5-M2D7mJal*;$h*Qvq&HO7aAdR`BhXqY=vx`o4ZyLhH7? z76OPJbhLge_fUsB|gWCki}bo4>YF9L&}Q< zE_&ULKCd#CmIU@->_>T^2AA>?9*Bni!g2&XaphDLP0{MHDeclpjM1pVWz-Re7>rgE z!=P(5HCd?{NL^42O%F7^-FiIC=^ zs^qI>$y@9<$9Ef9`f#$a5SO?bJ-&?608(?qAQb6=QJ}lc7k(>7;~TNC?TW=Ooz8+V_F#0V#J#y=QEW^eOpp#^-7Aiw{Mu1S}w0JMiV4sgVdrOKOW3H!soA?V%qoef-;GA31Tx2 zeZwL!ZcKxv(L1h(r)ty^iIHBBD$O#>aFAIMwP=CGgHKSZ(nC2p6c;dbmoyL1UGkP8 zU7`(lg_lfMM9%3bB~?^Pc2o!CWwZ&Najk(8I@0RZkkmbmw=MiG!T_o0wuC*3&=C zi01c&J%H5F-=k9K6X83kT^QZQqg{F(2FxL|wh#|&R5lTGsT!???2+H3loDfwOayxl zX|hjO8yfhMSR*K~u`M{Ha9Q1yNPnC#JPIWwGwZ`c4GdQtWiS82U$XdSYnTfy#%-zSV?T*hC;y?0LsRgW@r*g7 zQPB#h$+g;pqkig)-bFw|!RUs&%hpX{s~9ejmuc>)Q~9Ewh4oFCb0R(u#;ghijuqa1 zhjWz28mWDzhd$!(F7%e0q$rczjF{Zk)2SziZatv+v48PgJB6>*s65!MJy6#6%Z-Ok z^Ek^Oc0XN_kr`=2H}*$;+)_+kXBy6(BQQ`iUKSHm6Q7id1a2Zw3_|l5bEAaN!W=CSsl z?38vmAlD2jvZz7X!|Uowx_e`yvHpZMv}oCe{u`aAp256T3B zj0**-PdIvsM+SCS3HEj^HEZ>`La->U3YwXk~(8 z&8S3QTUx}2pU-uaiCTLGVW@yvQONc1*j7B27PDgCAgm8mn_sU`sjSiaQ@@2pd^M97 z_*ChRozG+kwqmoeRQgOFN`5L8_AAfT?8XI^7Nd|~tHOeQC@Us$T}!JIO`xRYF+KlO zlLp;_FdK0G=j1VsDSOyFJlZ=2={qGrlp2Z>G%KYbGn={(Di}ek==o&Dw}7y&S_%G< zWkEVxEtjkaXKE;3fWhgMM%_vqCM$dqmVJ;_v}#&@PcgR{+t>r6GzB{l3Svpnd! z6mQ)l3zB{;b?^7|HEEded8x&@asTQVe3Nm<84_a_V#7>^t#3OBMAxwSM0liIcr1ad zp?v!ZY0!#fMaK9@rtA^cGSJ=w-`HYCm9-k_%}d*rPbw7$ z{ncOqzEB;~=^JC!xPfwhvw?%V4S?Ze6SP61nc}V4t36pR_tU+M_4P~hZ@1DcvdhIz zmcP>Ym+0nuGWA(edb3@WMput8zB0iK6#r@0DT1Dklt>Ym0zt?KS(m&r7d%Hh*xW!^ zQft%E?fovtuxH4}BjA8QTWnSAhB2Uwu>Ok`aiJ3*3}(`SyT9VN>6WS&P;l~aO>t%l zWB(P*3uRMLJV**;kQ(fxu{f@zsm$Q5&7&03F#Uei4S=KZ0PsN>+(*f{G*o%aQDTYG z6Ohc*%iK^W5fST8Rds^xr;r1cM_}|T_33@1l5*pTl2e&Dn1GVBUkmAal|&S3q>z+` zqj4()cG+`Jv1wRN6$^D4Nl{ve6A~1hgNjw;rHI$nQYFm}QEWAjB z%u>wPf)RxrfFn-Io&7=1@+s!=#~|ir4D`vuY?g?flthwNK4zGpO?WTtgX~JIgpw2% zrk}*D5oxGF5)31SA`#h!#rN2}Hk3*eWMYO722v)dLJOwEy{_?OA^zNlIPkM}@aETw ziZbWat6m-`23?3-MBv|cZ}uuV1Oaw0wGo339MMhQG;JYes&8|9^!I3Z=nIu1Dd%Kx zl8!SFZG>eG7U*5CP9}N6U(@OIu0GG%n=ob4$c9MeQBo+%CA_J4QQeFr>M~5Ql9g;0 zN0GW`O{2xaQX^knS5}D1DqoMa%_r00)llMBxJPJ{4&4TAR?%)*v3qLuD@Ux{AHI@*^ zsT2%{Z!yEgY@0j1b^RFEM~UlLJGE}L&&i|FDJ%wJP%(~lud6alw2pI#!8l}$MRwRh zPJg%{$*OQX&S>*lMy3MzJla7$#MRMl>QN;>-VyL*AaZrJ*u)hMl2ywUXo_8qprMaK z`iM@!S1P!9M7h{?NR#aeeHxA?sfO;ZFt$A2Oz33xvIK>7AE0CDTAEq20t-g>UVxKp z9ACVdyJTVoN9QVG{+adKIQx}VDE^lxuZEgh&@2?1(?IWeMkdOAf^Mq*bytyVa>Oxn z8(H(vb0V!dkMN71GGRcbMva17){6OkS6Ix1HwRCthA}jiU39w>qxCph^q*Fg6eIfQ ztbM@wxnn>VBX%>I9&r?Vo}5(VnHtKELNVF_8#6gF#VPK!(VpR+-y2&M{-LY z25SeRCix6@_5{EbRcd?+PbQ|qVQ>N(MoFz3q{duZqCGu9a?9>g^BW{B4kBd zn%LZ?@>Ca@5taBasgbCGDQ#;?Hx7I_Pw5J5TyR(ovWqo@5o?HDatwT^{{i%lFh0O3 zfZ0%tvV26#T0eG6;f9>XK%VwOgIKE>!pp9`e~kZP8c3mYd6%dgY?1b4K&!MYPhn2e z4NCV7q@$2=i&wX6ub{!G?9r^jn;wfe;g7^=PFdg>>LvQ3zf-Vav;-C+&u-;B_{5Ai zbf-F#5VOd!7aB2C#$?eoW{v^2reqTS%%L|Rh^e_NFo_CGrmiARjUXWbqzpO_O%m^# zxB2u<(PwFd>I8tJ$lcxNq>(0}C%#V=MTrd&#h7P6G1f8MycU*mt4rkqDu~-pX2aVe zD?-dWFvMkE}=BD~>+)hb2 zi9BE8ScNyPxeQsFJSP@22xE!I0@LJa5NqM87O$;wpWSFX+`H zruJ~>T$z6c_)8qu8si)o6T9$qqW2R~j|w2}O=kV95)AeKwyu!9w(kY2x_e)b-jsaI z=^F`FZM%|NOI0gtC?y(lK4m0w9o?4sF6Fz^3szh8FmhxUs_uJjOn3xq8CPpTua%4k zPzl@7W$+mMcks7L2M0w_U>_;C7we$ZcDid(lvzd!wKCYipWd9)TqevXRUs{%-4%R~ zxTYeB9h`6~+1ZLQ`r!qO|05kpfG6uuhM&5DKMa%K!-jb55<^*3hd&UpLb;cldDAkw z5;+&Y?GZtSSG(A-j$RnLiC@eY8df>U%Kf!Y1trx=DoK$uVn!m~BIiQAu<$Qvzg(Kx zQ9}zJ3LMLBYZ0V6Df#D0TL4>E?N!TcrttI)80XrnA-(6t&#Io_i zIHIgl?gK&I_QiN92z(tb_v zWwhqyx}sXiMOXgCkx}1HNB|e~q_@y0AJH+Z zp}SJEjVVDRP5+ZFb0nHIOa%1E!It42W%^kYSB;H@@;DTHq9dX0`ab|mK(xQ76OJPC zRdV~Wu~{ZwSgJ)aMYY{TX~lA>U*BV)1_L@szw}Fufw&Gu2#YXutn^`We1Gij+eZ9xO5x?rWqO| zGN$M&NvL~YQ(A(5IHW5mQWj2Cfp@=irP7&;LOdktv5 zg*s7WA{~D^Y~CEkxm*Yzl1hhH6&xq0a&+F4U<_!bT!S$x5w5bBz7c zA=0~Ax(x|4mVUxq7uUEZMyw#!YEZerI|eI@J%mEjF+TuVE>e5K=)OB}RM6!u$6hRg zA#mBqhv!mSYl}>v>*Pe74Ti04_r?}eXa^ChG%(6gpd9syVIb&Z!?p=NEq3csBaZQF zqEwd(QHRmDSh!M&u4pBM%mm;pt#2VdgADV7Yh6hpQl_M_ zu#*78FnL{&U71KJB__47xyYkn)FApn0~y)RlX@Fh%kb$2UW%v9ZBNp(m|S+BC2o$I zz^_tkn`9DBQygU)DD;;G)$gN?n$~YW22uyMPjwW5JxMcLTU$~&1MCW>Nj71b9e~og zgfrL&Xu$;Dkmxc*5i=D;lBL0UQ*=zUElWLo2}ff%#86&FDGFOl+z!%Y&PLjw%IMD# z(y=H(PG_hUS7o+~CF|-+q-rgsT3nz{x<`S=jjq!t?6xr!7n~+rGhsFms}MWGiDo+h zduRvc)TU?@=|R$fvv1YmP#bXn+)zb05!J=`)qA0{Lm04iFY!E0L^J`UnA6_;{zrx!gwFxvSPe7>uqkJft`AKC!C9t*4IVMd|>GmU9 zAJWJk4tOhUoaIwt!`zXJmCrQCCV5kb#518{43{yDe0|hxCh>-mTyA3wwTKCf-$6oNI!k)cFX&*_Gs0<)bA8O}_GF6;+r1!&= zKQ*$qHj^^pN*)+e1fB&*L%=DCXtj#*?gpoW(BMXrQj|O$HT22{K zQmj{r^!!r(0iSMMC57&5CYoWzQ5rL?q4ZX0m>((}xZj0Rt}ob!DV^I6ud_Y}=QG`> z%yaiZGZJm!+|)JMhrM5OOR zlOonqL5XQ88e*gag$F`CuB$SzQlMapv4j#yfU2{08DLyEz&X^3ZMwfLY&O^ZL`I|u z#4hOPzCH>ZTzU}(l-ib2K9psc)XQd>CQK;`2#M5bMi3!Oh`X?&it8?oCh)@?MNB2> zKO_L=lS?p<{V2dn8+FLmpxB7|(i=t&A-!~iiuoN`%Dhj;5dmKaYG5EBmMkJUAkv;< zRB*z<;9UM;n>Ha?1LmqQ$664})UXX^rfd&~H{-AxZ2x5?i3wBGI5Ewlo4XCcP*l?( zXr{hpB;i^(D&!p`1F*=vjBwX&f5y1P<&4(g`-`Wjy$u`ZjhO^UH_Vi6} zfkv4b*4bmlYrgg-e0l+Z6eRP-ZXsEt(J(pHSL2kS@C5FpP>f_8f)1D$!N^WCpM(}= z<0WKBzC-SaKaNaJH|G6p3(CsIz%IPshFFSnb3qz%dFpNpl7lC-wWQPmfb#kx{4q{k z8pYqi3A~I{eJf+vP*Ru1RW26;GglWfdnQjE=yL8a1|mBLD??& z#Xq{cs48UmSB_eSFoC&mAsZ>JL8#ag9U~=%E)+tP{0@LLpvf*Gc|03BO11D9=qg3b z$RcCU(LtkB5T!v+z=m6Xn{2^5%wd)lRg3(HC$s*v2s{-qps)eUB=uFxEs`!+Iw8iD z2g_DX+KDafYQUm`2~L8T2^a%=U3^l+#Y(^!m=h1}55og7@WTN`0cDpA3D29kqK90a zl**9xeP-f3BuXL40t~4yFq^6!Hu8H0O8`WbdFpxTGZ9vm8sV}NOUcSJRWF`pcgNK< zoI08a8sfFxaS!25Z7udjaYC*_gZKe&0TIoH1ck61phFQ=aOG+u+fET4;*drR8WPHq zAjv2)VAEGN-l53W^aAWP9T4;-OGYX<=ALBg$1+w?=1`KM7T}W!_5?x_@Bxb3NZ6gr z(o(S`KI6oeE_{v|(>ccg_rnM~Lsyw%PXuB^QJXI9^C$^WQI=#PK=J~xmy2z|%ncce z!PS(ZkoBs}pCPbJ^+)kV#TuW$-lo)#@G|OupA>LT+I1C(vXthnB?ecC?cdi^@U7BR+j<+X~yPO;%*no^A>1zzCO$jP0gmG<1P=B z%v5lc!c(+=;enb^u8N3&x5N^%t-~DsM}Wm-MtbS$RAh(M5sm`*9wg_{K- z5UqqmbO-J08nw9b&BGTMRRG}6=;lQ%eK3S5>7tEYYZ%fT``NPx_KUT%L?G4mX(?{a z!v5@|C6OJ8d;oz3jwVu0dWv$qO-m7mtYX-fc@)+_xWdSZ(g`@Xcu+Hpvwu1whD?!1 zXAdY*&#cnWaHh#=)mt7Cn6p3uqTZ`hPNMZ#1#B&6K8Hc94MoYPt}l4~4HyZaZs0B| zOU?KS{J4p&wHgnjQ`b#H=+X&b+ou)ili9roDyA^R?XqYvXW2X6>ZumYRk5jFd#xk- zlF`_*h|{-{iY0kF4}+Ai(T;?&qZUnMzIdQcW7!s=9HQV1iX|;VA~!BA7|I4%Y0trA zDf*3EoNH|Z3L_z+(S#(k`eiX%1%f@7P9$Z4QEv`On$9VByNNs}Z~({pSy7}ZkoowT zSX}gdt|!o+%GT;DiJBVgJfc8HWl&<%a?{nCt_cWsgV}swU=2`8k_Y%p28xA{2B{L5 zYfJlvMAFbMc4^rk7hy?FY;dC^VDcK4Ns5qA91QRzB~MX}l-erV3D*KO^p>D_LP%W& zp|wPpx=gBM99mK9!pEEdtV|KXqtVt;7#gRVGvJ|sHu)0dfdl9u7$_-hAp_jvWDI@- zW@Y^9B;3zq5hb?u2sp^0y#SW#f>s-Pn+psb(duh=0peSfEQ~WS%#$cWzE`n!p`3&C zNkRZa^$Z6(bD~BA9O&=B=tS!%?Xe~mDlH}T)15g3o5sJL3GU^@Zyc^fJ}Mogc>&!8 zp@L0FW1}GxKpGh0@UQ(+>8wCVQyU=UuJ`>Untecb2x^1(=SnfqS?dFnDTt#q0i$n- zhLM2Z!X7TR810otCn$K4PA&R^BPBkdA$A~L4H!HGY#_~)&~0is?E)$dp17C67Fl}s z+MCg9VvOvAx;R$Sn?H%4m9rXQ5`U=2%8tH6f6QdGBk{C?-P*$JcAG!z&>UhK7(kFBd%8)BH9;{wB zO}8R8Yl@T*DkT9O!6-6%GPFuI^LO#`I3G01zEx6*E8=J5I$7Cjl$8*mxnoKJ4Nd^q zX5$btN)h2E@zD_uZXs}uM+aYy!sf^=Un&p?OS4r=;Fl3f!aAGj?Db9rK4Mg{%tMvn z#_$xx;!%)jMljY+@uBOrjLm@$s6+uUR=UixOCm0yY$BDccle{E z?5~vxUvcZ3#4x?GBz>NpZOAv?180ivLO_jFR)`6T!kB_P- z-V6e1h*~*AOo(kgl0@ets(B#U;VHEGhTZ}p@JeXzY6Y0#(3Tq5Xr(1~mk*H%vMqs?`k(4ocyNs(>}R=o>XF@lB4>h*fa-=zXj z@>4q-4YEaOKyy}Z^x0r^qPm|holzqMq}|kKx;`BF}l!7c3~A#;iQ0W$uD<|esak$C2UN6{vjq(mamz61<*As zp%$Dh3?itmp_ut8Q%{1U#N!zyS8S|ODAA)G$)`C-Oyx~2gr6~j4M7TU|$|R$T<{Dw+)tefhrs*mb&O0D}r|@KC zHtBzhXer7hMTG^>B^aC`tp!kF$j<`7F8CZ`0@y*e5aHWSA?1Lr5N=>CXyL%vyKELALYiaj zBXPge_l@dx%Z6q=Xd@>m1RB<4j2ox3Yez2g3uVet?nofn+6ppiOwJu%Hc7(YRq%l1e&N zlbd>Z0wg8JJ-aQFPVJ)kKdvXTqGZwoVV|-MnV2D4EzT=R-fxF$6O-V~EPm*?9!q6A zXZ&c;jp=9S0246)SX*&o;4IH1MTH?Cw(zjd9~4CQrYtYWDUT)Yi8K@(ok&%=BgkxpFqv_a1y$G> zFYYs%Cq+^VQXc&z^xQctHHR69gd&#ekOUUlUB)Xeh>drv$HvGzrcP zCWI0Z%V3+60*JXJxTODvMmS=BA~a_AE!+@}*SfVKKikpfbgv?E^c2k3?f`cJ85D{< zZHxfq<8C}nHN>8mcKiLPugNcDBgk?GB0q_2UtTD6Y8GY zGt_$@d~YH2Q*XTO8`1a=IcbIm#O{aOD>es%p-pW&K(pyLob%*Ws0Il*F9zHD1l$P@HFB%An{yYFsYReHe zD0U0PK%mvNFk+)Zy)S*d)ZrxXk z8e>?IFk4%WVz-?~&Zev5LcR<2aiQ9Qbm#{5m*Tkz7@4^lq?$f6o3?1_!eFql{x9m# zo3|EFV9pcb{kt&=6c8!R#+8_XKbSY_PzbhS5QiCXd?{|j0*nt4Z3c&G!e^+y=#tOT z5;68gbRr2QcswK+tr!dxs=Z;nrpc8mzbj0HEZh%wS~k?FQWEK`pu@qeN+v>>(%4=W zXnKGVWAjJ_t7}r1^m-AbC~J{m)cuVf<$^dEj9;OF*?K@C7McL_9jTd(A?>%YzX04> zYKu|IOjNR~8J7YdKraGQ*UfEAgusxHyoa42S(s;n#QOo%UoC_t)YiRB)sbl)l>s1Z z2dEw?#*u-IfZ8IGY7rVPK!X9I9KAwiTe?rT8t4JYp%G!I;*XPd7LX^YCWegSb~+?f z;u`0lO%!4aL<+2}KAKz_R#h%Qs?03efAe>QnJzE`o-=A6ffQ*w2rxtCAcRl~@jlg} z%|S0G$H5j%4Jk$Ntne#0>%-9)jdFO0OLc+#1zI%qJb^{HB)pJEI~L4U96Bf{xw-;_ zXWfW|s?G6K19lQOGU!50B-L!SFjAgG(SYZzff&P$N8SvY!f=y@DxIM1?jZS>9nx&& z&kS9%8r0UgIx;Bzn?QI>*QjHLfmqvnxcYRNr59Q1PPJ=bhtQm9fSQ`FwGSU9olU2} zVE!`V|JR6zot~aCV;Ly2xUecHjDcBPNOqy%Pv8n8gVgpQQ6YX}X(4MLaoHip15wV} zSju4GyPC%J4AG!HJijX*p(WCajBQ|n5Otsofx#<)RU_rWIg>tu80shh3y{jF_}(xL zJ%EnOCIW;^zMlvc_CeQSV+w@tW5!VeQb$vfz~~VH0&huVu&0CcAfR4&4-{NPu!|l_ zYv|4DuuV#a=-FA;KZe;ivdH@>;LZWR91C(lR?ouURk#Y3DOSe8DL+3(RNAmcM+?bl z`kO-x8dWbbnAw60g%C09oIg*wsz3>MyP<^8r5uF>Gl&}84GXMdQqh+->>1W+fhoaK zON9!M(YaYVIaSs<>Ni!_WH|*!FN9sbR%(XfmjwmGeD&( zHq8;egwF9K5kWvEInxv)C&H> zrsCHX5*R}(B41?vh4QcMaq1NDE*Yd=Ira?sp4Ezm+mu1m&w72bNJR7-Kb!4_}qV4*_N*xVy#`6}ECLtRxWRCAleP39(9W_Jh`L%m)jm z5)7b(B_UjF8*^Q6Na_~+g4>w12C)ewrIKZ$?j(Xa?^bGwl-dLCqhqVNi^i>0cvQS8 zREvObJ`nH|QNxLfm<^;CpyFyM0ON!tnE;=35u5#l|YB3TL#1*exuxk~=SJ>im zBzI{UlBxz05{~uVDv|$bF*eI6^6OQ2Spve~P$VF-l@}H^g40A9Q_SmcsBTN<;#URm zZjmj&RfxN=7#XjFPnh%!baU`t zohI&}6+2R1l09f8rf@Npk*X{X%%iC1O%a^AXsB5cYSY>qLxFBp8;eMLas`51-iyr1 zKRuz2kdbDeSp#WMPRH;O29*Vc03HF6Vkxg4=BI5ziCh>FR^d>*=@Dzcp${h#= z4AP~vyg-OW4vr%T4u_;O!F{MOdU&d-_NfV87j_8a8U|DmJdB_snuH@q5?+mJA7Vei z#H^DA>+IPKtM1367b~DV4T71{qob{AIbO3Vp+8|gzZqQ1GPevLU4 zVfUQ3P>K1eXILgcLk@{?MI#bvXDp=uIKl-bD1?MI9f_cN%{atVIJyCeIjXZGo2k%B z4{%llO>r>jv+C9a?K%qK2Vvm!O?X#8oubW2ZM5IZ$Ok|idjIrP(~qgO<(}2`hEfy9 z2k)SwMVPrXb&D7f+@43W0YcgW3aU*k!vkB_*tw}-rwKg$LBVf2_)hhxD6<%-x(L>h zvR)hOhYHQ3yGll+-hx?ZE?PpUA|h0;FA)Mz+Ep9HP0FLn1b5lAo&{YC>P%jA^}{r) zj|3`vvHa0Y$x5>XlL7r^YAYFnfT3;mC6xl9tsN;oZE^btK>$Ki(D-2JE&(_y=o`ge z0^6vVXe$p=&LuZq3VO()X$zuSK%@8?W2u}2<5PhqSdVI1br=vzC?dK-&WU&Sl--fl z*YO(3;EQ2lO&Ngv0do$GobD)osDW`BPMB@^<%B&(HbQ=;V`obmy_)cL%FTbq@WmKB zAHuEkA3#)}N>w_@ep~4dFq-CmkMZirVpijxF`cVn{ z$Z>eh!)1E?3}CN`;Vnw>-6SRVH&BY*4RDT{7U&kzAmC=QL(bZVVG-wFKUy)N8Anb_cMYSx6Hq zOFcLl$Br1-vMQMXVVB}mTuK>a9CE~?f9`w1DL0OKuU&V-)!mZ$swx)Ig4(G3boVDh zk>C?!%#5wNgrG;8XIQ#ND5|Ekk&=>?5oAImx*$X2S%GT}MmrS$kjxQKuO+*Ovn#jO zSuQv_+#972#-co_H(%3m4lQiB-;1l&+X9%5y{PNVI@HUFF!Z%_^;VpV@J6)~*OTqk9^c%B!U6iE!Ol2M(5FqW72rB4#Po5JMz^gQMWTz6ia9bi@I$ zJhxD>-&D(_Gag8rK+4#g=`0?b1=uELTMp!I7}Nw7%6}=^*yJ*eWh8Qn^q+I;xj99f zu<;SfWXZ-L0Scs!kzfn9O(30LZn|7z!9ozoATU={TnD3qVX0{bfJXKh-&g}Ru35CG zTjlsMSu(~9!T7bSV-4JhW7DS=3{?3fmx9#M8)%sh6{DTdU- z>k3mKYN3(HM1VNFBhj;2WbSStKdyRfoD%UT|*a9Cj!fg-|vtGuu%iBqdhOQ)FdxCxq=;4NC{u<5zTs~^#I4Rs}Vi2{xU#T zCLw`5#RVnc0sai&&Pg&4Hy)llNF4HoArebs#Bj1j+N2tC?I>zO@Sr?H`h~q z>cB9{fK+$3g+!P;`&oo!#O+C`q39OHgnFDV1sc_?GF5?j;KL zQR2P2eK|2ug?A{)iPUTAP6aZHP*L3tlpwTVo-9a7C_5@}kgbNeW}$ig!2?&2;S*M& z>E1^&%U+Wj89@NLGm|hZMnJ2b3kx_AAi=F`HS}=D9h3#8?!q@XrBnVQUrz3DV3^(of;0 zR&(pchtMN)7(_9N6NgoHG@-RA3&XjFu3QQ>5SjWLZ}d5aTO8TxO%hekbI8W;jgd8Su!?(<+ zGAI+9WC!CuSQ%o#>^xt`1`|mv3GFi>yT|AVDI^L@bfwI!YD4u62gm+UD>e92TAfL; ztq8fNSGcCn{H6CdYzbf!-ZDRW~Tv(x$LTaxc0~3Ee?M&IhpsLS9f(F=>GC zNIHuM+?=* z3BgEuMk8^^V09=_g@Bh|3HoCSeL15hPfQ0BZhIn<@yTfnDHCQKuTJLn*N=MLst&fg zN7V%2OIAwt63Pvio1xxwiD}75Ge|=3>xn&{6wioFfA0I195Ia zS3;1NqDntmBq5PuHo6r~AKX_d_lCt`tXg<2VsNhmN#)FN!3FMYRmkdfDx?i+O$ZPR zYH#*mglbQTL_redX{(O<9VU>7zoLRPoa(Gvc}gwFBO{Y@@l=foE^zEkNl-+uCj#J6 zs1QFbW^9G+5=6*_PKH3;ngTMdjq9!u%C>;|$$xM|lAjS)vv#xM7x{#v`||9M4AXSv^E6g4X&Akg(p?+sF+tZtb>qT zfl(D~X1b2HN%8IY0fmtIE)*K-YBbE9XR8)h!On*e{vNQ#QJq3cXruU@q5sE-i2NA} zHPKCHY!K=-^4(=4&g!+V56uxSXkNpbg1z|_a&U`VKw(8yAnfD^AyQjTlA!Bj#Rf+k z4`cTao{(G`n!5%`wZKE#S(_*UdjF=q3P!tEZu)j+uPl1A}il{%Gk_sgDO}b@6M~;X^z|d&gV&}ma zJMkpRu3Ebj6!=Z_Am$7~Uom65#X%{f^64^?_q1InEsR7f8((}3h3iz>W3{;wBbtk6EqIu7lM<#7I{mLh!GIf2X7kt|0IszD5*`} z1o3n`u;dmg&S2-vvV>Q`^s7=79uH!u=V^gxQKJEw)?;@eBRi%mOMqB{RJ|+{#!sXE z#wnpsBhBduBT)@MbM1sW#Y>Zxe}{<`74ei$nGXlk6a^j7;3~2%wa^Y!?0(moLP5OR zRQiW`L)9rRQIzD%Zba8oGB~m}I{?>PCiWS)vF2%Jk@b{;bt<0q;gq13iLta$pf^%X zLc|}VQ~z4ANW<~{JE!v?h}=n`W3{?DU|WY%M~q%20py=N%Q9x-F28vJrnaDhES4ofotXV4flw`mYdH~=0|hrRcF(}z zGS`T_h`OpDi^)i{1W=y{PQXSYH1|RY3ndOyJ%Bg5&Nt|~fwF>&!^Y*W1E_|m*{}-S zK0xifii{jJBtRoXBCm-+4?#w8+_ts*yH&=L@EsxE5m>I)G%`r$egPe&1z>2nfE3DE zT+!!EW)$&VKnI1k;3XwwS|&-mg(!!SVRdG*+X)6kn4O_%VM@E5slnP)_Xx-pz)41n zs}KA4kkyeB1|K?z)~QeId7MKL>VBL~K&K^q$Ctjx?!~}M1)lX4c$R}x4ZTnQtZ$kg z`*cXXH&K@Y36=udJ7sl2-ZW7b#AZf$vPRPLJi7?#31Okwb0yOpTSyz4)59ZXs-g)q z{yOLvc|c?d56P5EsrAegd>J*y%v+$uhC*WSXIzn8-#*;1L}Cp9^-fT!T`^O19+X)E z2E`(SmoAN|krF6sGK?mwMwfg=v~!6-)HDlFFK{|M0f;TAQnDmlp9dfSbsiZhdY1*2 z;Zdz&Gq6`MN+BnY7o=(!N;XGA?Y0pV^sMN=+|;$!ZW6>Q>4mh@SHTMATT=^Qs-}?y zpo&Dp{NS}f&5{YEa!}y87#9d7n_|Y6nw~C5#ryiFbZ)?a5#036rtaYLmCcIvfL@5} zz{)_ghK`tQG#2_4FgtE|AdYq4tA}hQRR%%=i*QdV9|LNqh88QVW4OeZLZ74(cS$RE z*x{_7=b}cowe2D+%rl~5&H$xD0tY=R-5WHqjJ+1Fe-VKPqo+V}Kte5zSXRiY#-9p_ zzDry(%D`jU3rXOat-3^)j8;k|7n&GBYSDyTAJfcbp_n;Qx6BL$5c#_CQ&G(7ezlXK zqF7QC$#TQgqHzHV*M=L@at;zixJ7}OsyN^{P$otAti<`krH)E@GVkR2jZdt3=|blem)xCjxC9SiAJ+GLsEEiKuQe^&_LFi zZ)GwFTfD|wEVqLxg3wcD4ot1FsCiVjVEI{sxLI?lz~A(T8kH$xU%kIkp;}Iu1T$A0 zJX4K4_gp0S@cT!l=vl-(B;>6qzt#hC*wHld2U|m;VEDvH38s4x?KYFea#Lh2;x%xt z2cFTQ7U?_LuWCA#7ak!Lb2=c+)r3iLGp=7zR!xZ4sCuUcc;c}}y9FlPjg?Z)qucQ(aZNFl(C&bg{Gq(i8F1QCv1w9gC^XwW7fxP~aQuniAwysCkBncET>{HwZxy&_jRF6?8fg?#~HhX-dvb{Q5OetH1 z?g*{UeRSllE6;%GJ?64X=x`PEEq)zXjH<=B>{`0|{#rS^AH@gR*v%CJoIAQ>J(mZl zXdy7cz)ZTgoJ6;^Nq|8XJYqjD_-{qJWs{LjFw4XV|{)#R}lrk06UC@l-iAgQfV&`O#>lCR5v z26oqy#n6gN@cYzbyz%mdcl2#uk;N6U%Fhdji_Q`S( zWGZ~ePSBi#BS>|!`bfFN(emCBV;5F_>LFWDPcYU6$bUndlq8%$+hS>RwJ;(PY(>z;PO|;EoPx(4@^C#^i?|K#;f>nr%WE!37tiT{V=TM$h9`)k_dU z851SWjE4+TexMdS>t5V$1z1<%#V*%adw&E^?#V>vuLW4`iAFuVQR-OLJ5fZ^Txwza z8DxP@RC9qN4!hY2KsAX&n#9W9jTGV17o6uWH8_bYB{ zd}dJk-ooKgNgkJTBE|Lh9ar4#4CexE>{Xt^)1T-UkluY$0+0zO#7_l5w_GnGrxgQS z?6n1s3971@0#v7Ug|H%m0u9YBP0_E4!ot;T{`9E<7!hrSMk+~ym<=DBfcKm;8iJpxv7qitp|E2YV zd|h@jD@lDGVdTMdfB|J+V+VI>l8;r?P*_;$NT3`j#>Yc@6*lZK8s;nws!r;Ld%$y! zmC#Y}mZ3O~DW!{@*TiWwMD2r-3NE;=0+u8Xa@=4gAVYKL{+J*$$5XKDXAIR#%;J|} z?j?ZLGrQbfO|lY7nydTK1zJ`fTen6y3yxvi7Ktsdk{m1u7bF`PV_ zJQ{>*JPzvcv2%0QguGD4jEcCqwz>fU9~DqQ%felSoVc(%wu_vS{s&6xV@E866|{r! zH#rpOXt5j$vi2a?{RZphwz)e9I*Xb`*mJnj6ipCLlrrA*1|Jxy-VII65ZotS5ZT-ig;k&` ziBrg)1Daf1XYCKSPAPe@nAX@Dd2oiV5-WhETN|6qfDUVaTI&MdxKE5 zAyMYnZs(IUfJ_VNLBLRxG-g@?C5E9}B3dbuiVbP~slly=4t*qnY%c>PP$<&!>URgk zC`3z*h#vfSZHz7-R+BYJ!;o|2TS$5*T~m}kJ)^p*gIvqJa8!|1l%U~|1H?AfWC<$f zDb^T}QpgAn^L^JsX%c~Xguyr&sl(EQK-6bNrJq-oxe$ylu9_hCZo&+vC6Ysd8o{n_ zNErX((g#Ai=0S3DP|i1f=@S4%d1a`}AS$h8NihRe$D&-*xPBn4c;b-X8SvK*8%I%5 zI&BKQzqHPFd4u2vb=vTRimu^EQIrOw;&)LmJ^;hvqM=rcQ-jR9E-ZJpiCW{?h_!%vl6O$KCELXP*Mzk0rr zlHoCx#@|g;Ky}oa%dcecP(kVzL7TV8TyCI-k;k=0y_;7ee!Py18n)pSa)smlS9Z;Z z1!108BFaxO_}bOlSg^nqdJr&>BRCm!&)x&PjidKrrztl$>mRDuoq-Zlsx(n$Rgq4l zf|WG5qrw2=hMz6HrBlhyW&|i?UVs$ShEghCHirXK8W6x+r@%vJLBx4wM-W^uTm+8! zn*9^agxv|vPU9ZC2n7a{Q~E=#3?tIuKL7HSYbGsNDKZ0OE}C^R0UnVoQ-WiZ6~N_V z5gatGQ&9S`XJ~oGDU%b{sShh@mH!gI0g1s$c5Txz2O5RuKN-gKCzJ!CBpM0qgaz8q!jx03 zxMd+~qTaCmjR)K@)tOdy5DZ8aGveybmSbR5RfhV*>0>ib>JuL>WNcXrJ7kQIKpM^{ z(Zwx8;u$?_m%$8E#bh8;0A>1L1XO~dxL~dcN|3mOu?k$mR?~GS8w)qBPJo-!0s*pa%Ldfb5xOl8!;L`H#E+zrjq?T%D?RJSpa>ln}c{ zZbD1q`4S<>SJ43tB=k0r0S6FI2xk){BODY~1#h7qgek>i2IRi1qQ6?$v}O?<%!W`6 zjPf%)Ob=C}MX8XRr<*OPAPpFtgO)u){iQ*DT-C>CK1Z)iazV)HR;EJg^ze`#3{&C* z&}$OwebmYzP6XlEjc}u}jRpUWX*)oPS;PccD37$M1gT4lXc*i7GR9k&-U-0Squ0kH z10Mm%^}w@{+khv;%t`zzOr)j54rELiexGOrl!JxNsGX^iO8;9_f)B*Efoz3%AEslg zHK-Jm1ICEcAk+{X92tmDV&H;biOY$Um&6ASG6_Zhb74y}P6I0&-5LFbF2hyYBa&gi zRxcdUXGeh>r6eyV$0?-D!i$w;bA=4g!8^$Catt7h?&5H+-**yL5;;rM3d3^&i6{+a zFpSZP56VW&m)D@h);Hotie*ql=?vl2+BRT)E*K;arc7kYnH5cI$Bm)(4qhRI^Qsm) zcyP?O3@c342}K(eK#k=G^VU;vAhCwv*!aZjQkhj3lZ{{4%RwTU_F0WBLo=SlEnl-H z_Bj~@8c^BU9dWeUg5|wSM+Glj=CaaDsl#%Js6H(sp+dNzM+v>5-$t!jC`Ga6wn~VF zzhm<@L|C+8mj{yPGA*1&Fql@CXoD7E6Chg+AWamsr~p$1M?$z0LAx7NvxYkex$`1v z^-N6ciAO7Psmv_{ivoRUjZs%rhW(1!^xXO-;x`1!giUOerL2_UJ#FUfOKD^}5Kbj| zxn&r^sG-6@+f6tm7RE`ZM=U}AOuB~`@*qkISxOfJNr)9h735s)75|^dAV#^yC2Y8{ zc!)*oG;CQ=Bv#G_)PS8MFJm}je##6B?l_>VVe{Fb@a~Nzj(G-JeG=F(WKO1o_hMPN zL4z(WvYJi@-HTpo6ByB$3SR277Gz)&m!K}|2#tl50l*uN+FyeBXR}5Iax>)3#;oVm zUe{xR?B^Hx`jweyVE$!v(al6)QpzSk(QOebn=FF{tdShQr-GBEqqIO}GJ!g;*%{{Y z0E+-XCCY0^zwB6wA~!U4wb2j-&?&Te^XS#6&hm<2nTiEBN8YPlD+y&fJg~i|w~4DP zj^p+0cSkD)rBTM^3mr7-4&Vw!lwFj7G-k5g1h$P=I3Xo}PpZkn=PWX!txovQ!kTg0ieZ`pJZjAG)Agd3oTFrKxKH01hf~V2pFW4W%1(>Nm(FX zNBZGAS;V2>v=7j_Zz9+;QVhYzhMPt>7r=agLpOUy(?#4T_wx1}L((*+>oh*!)&ntt zp)?j3I#mj;1_NalGp^65V2WrSDt{mxS{mPWQb?r{$aK9{TLE!OQnC`J464F9HHDCM z@_ySF9QBIii0;%-;LFt?gW=t2o}zbEmjsx)_q?s!$|R$!42UtLiz_s90iY3;Oc1ob zs#)>Qbxf&`?2P~maIiYd;75WLQ+TXqWjOtHh^{$;4%G`251XUckvrS`;`?V{B!hcg zA0XHY!R|p!gB+%$!`(t0n`LqRK@|NS6IX*iZWUja>yk#i3-Poe7S-d2YrU(n+tL2e{b{KSG^?%b&QN8 za$*mtCKOTFOAg%I5KPPD0u3(|pqV(KOI7yXb4dL62?#AlmaBZTl?$Ar3i^fG z04nrH6MHK%^dJn7g#f&Xu^i4bpHkE?02+coX(a-s2H@Dm08o({LcR6K^wAo2lb_q1 z;B8t)q*Ky{^7V0Md&N1Exul&6*tczKp%Hf7Il4m2BdCWH(kOpKdCKtidD05^KD&E9J>wD4-64{UefXqde3XZm{5F#6}r2(2u0V3mBKE`rLc{dTY z7(GTJWwG$%H1e>9Cj2IGq0&1m%7;T*A)y~G5~EU&@X=N3v17@^*vSv$?o%V`v9{B3 zX-fby+6Dx9-y^d~0tl3hS(LgGqIA+mR?sZB+)dD$(R*ojqc^-fe^+t#$$Bn?j<2hw zFfn;yu_}nvG&H_GFeHaPy1*SkwSgTN;LTJJZVQskU1!WZp!S3fmGw8uqf!&u2=eVs zQ}k{H*$A-VSZDIIhBUC)0=cVw073O$Q;Y>B9yHn5sJIZGi!H=|9~?Fos#xpFQSw*Z^qb=-H2&4JaXa($r=T7t;18 zI7QSX^s7;dXTp-mE%!VIv}*p75zYXUKy1ID!z+U;ag;Ie8>|n6*1w>$C_>;v2h^G= zzXGyx{Q(MUUm+G054vJ2an<0)S`*|}1K@|5%rsZ)9zZNfcRazXf`U@6C+$OYT_o}} zPV`RPryI+p*K%^RP3$Oun6OVQsTFR@vCCGoEejGIArLAG!0E>qfD=!phR8-XbhwMwZn1P{ezV3L+`MGP_?58!DvkNSmknh>>T;Hz}H zvQN6`VtVb+_;SupBv}crB0cm&z^E{ZYUo2Ot=y3QR``hYK4AwE5u<8UFbg#}A$bS~ zh${Xpa+`l>1uivWh%Mxxs6{%C*t9@;UL3|Fyt)uFD8|ZFAaO+oSg=#*C{vqCL*7o` zq`5zbl-l<{1J+sohKOY|pkbmeN}$jaL=2V;0UBtQPPw@K{{rV41!?a*<8C67Odw{< zETCD|tV~V{X!Toxr?cS4kx7GKNmgDoB`dRl#Bh=X1ZGfU^w|TWh+(myY83%KVvySV zmb5uv;1h&uiRhS4Al3Y?QWQmlWK=omXQrp28+acQUd8d2L zI`Mz6ST8Az1~NvZ_`;Yd*;=#6LP<}MzjP!KJkUtfI9I7Jp-!{m3)|`k7O@%=LXkki#h(z)NKW zOOp(r%t4T2W=G647!#QyJ{y)DkdTJIItx+_A5C_#xeA~JX)~ShGqH_(t*l|hBP!ZA zL>vv4MQUli7-^2fYQI#ha~Ofnqfz8piJ}A%u|>ouajqI_CxDs+OjJ1d_L9ZKqadcr zH#TlLgo7z1tv231eHrg4zMueSTZ;Aeny#>;$9Y*mCmXIt_??A9gCsve6nOS=mb{jtlIvuF5ohNI+U`2=6){T^Urf z$ey>Gtx@wB4aC~|Ff8$0XBs?$c~x!6rtj3db`(Dwu|?bQ{k9{u3DcpuJSjSkCkCsJ zSIIpft+j$I6eVGCe;7Gp^VbV3ey3JJg3U+a8O1f!@e+vDl`)0s3XToCv28sXQ8-|H z8adEdL5X@+`pk+ti#01s^Gu2aK$3v~)@)!TgAbD-mXJe~dMwc{8(ycY`=y&cgj1cM zw{y;I1cJJRFlAIypfU4DzT9PGzrcTo;NUe-Go0}DXu14BCtDshI4rK__g_46HgtHN z-3cl%DYt2vA(9kR6{Yb`P$A+N)-y(^e`ZF|c@)anAUX>g@&52M zubmHP%t8!B5ult%R$#awQWHTP{9BYX)3sqZBp^wv2)1HpIPYA-VPK3Rjm*Gw2K-tw zsJOJ)tlbuWomxAU^b%e?(bZ~;7>j|$RzIMRJ#)xc%AY}*z$=D=4oBQ@Y2dsaV8Wz4 zqAYyU%Q^v`)WSy~IghcC#5{Q2AVUBH)%BgX9W19=107VpiRP_UdC0bCWu3JYL*38* ziCum|*!qBul9_l_Mf4kTPf_XZgDjlFxX&hs2uL&8mfAjiK~AHOY!43{a66D+K;;Zu1u$U=GJ&}&D;PnRG`@FQN z5!?7rY$5E}J>z@^p*0omZPS;EP z@@ujfqF%lk>O>%j**V6t{tQxy_x;c=(H$$JzD1b_={womUe6MherR-Uc61<1$D2|J zLKMKA3VNh=QG;eyg!8vEbY1k0e9 z@yrNCec8NUmC6mXsm;I#;zk%DsO0z^iu<`m%E-bI*5;^%G&w?)M_lBD@CQ;m=1fp} z_OfY97h_S?t0oKxgBgOt1ZLV4{@3JyOPFR;yi~{&_TLu}($mGJoKi_8ZnIu|%a-uX zpUf<@u@R%p8RSO6K(EXugbcuXl1Y+cyr|KhP*f~ntOKQ$_<;~Fj}rK-@Y1QnIu_}7 z3cW@{#DRh=Xz95uNV;`E9nKf*fi?~U6uAPREg0qyN?8$poYghLB-NCTgKA#T{A0!) zWtRQcn->ajVE}FD>%dkF#S}}Q*Q{B?_e`Vo1dyU%!EPf5ZO9qL=*-GrqU2p&gcUDMttlaa@<3IV3=ovJdqw4GHARK;MvL=0#x_pq4vls) zTI4`fwM)4f>1|VyD{Pz7s}7i&T9w#+FCDrAc!ot+6-w{gd8drgMhoqO8Zx4$0C=Do zwowwG<0KY?@m>MU;VlEExicuu^KQ#@C{1u%aMiOM7APCwBJUq|-mzfK5y;S_S@T9x~MZ9|tb}4mIFmlP&tSN}6RMhRpY5E()bMO@)D94*L zDv}^FnlRj9Fd-6#N*pCbaA?8n=0Ho!3yiP#PK(%rLBj154@1r2O9}|PbI>@W{0P(m z^_0$`UqS%20)Q7qu0^X>dZr7juSHJpTh)6mFoy&Diq{1v zzrmsdU-BjK%UD6sSZ0X9e%m;dcxaQhI5NhQAWbYrf4xv=PNlX2eJ%^ay&$G$8#2kk z^d(A;!`JeZa5V%gFQ5dXz=0tZ93epshczKqwe2FfO3P>r41t8&GqDBu?7#x8^b@lz zd^W{-NW_-oHJXs0+6y}v66c+YOID0a3K>ql!if?H(_yB9gdd<`U}>Uk)6i-u?3Dwo z9y07JG4bzM> zdE*rzROc{P>4CDJ0S)9KrjiD0kTF0^QWH16J@L+(*WDQuPecLxAKd{C&>t(Hkz(^D z1Y~qt;c2Q7vl(ed9#^upflCdOETCbjcG6`N0@f+mV->H_KQdh$IP#W}^2OG2E`}kB zSkYR5;SmwEEE}*ab!Qn;sjvMr<`!b|hCnd?!l#qPl$y_}R=`H3D>O1d#|V;0dmSF) z8OZ^d_Ge{o-2ES?_+N!lhDTFju(P9dkX8hu%VPOUa_>(yA3P$%X2Yx0a&SQ7ZR1uI zh{MPP{5$p6Gy$55fckBHGYs;%MWrv1YzOaiazIP~&K3eAK!T~sp#{NCxR6|nDx-q% zDOgaHt`d570)~v+J-px+qEY~~)23MGn5z|3RRjeB3~ZXP$xJdr(;oyb1cD3SO-AwI z(+UDgFh(_xTFznT*-?Hi$WK-4~M zbFXO^F()+61RjXgfjQe|>=qt_ie2{+ znoDX|!w3TiYb@fo6|bayrG$^+((Ibl@x~aKPgXB?Sj&QDTO<@{Z*+8Xg&nC~tSRCY z#Pps_dNl6M_Y?;(x}(U2siQA=cm(B&y?YW@ua0wI!r8pa;P)<#xB;+$tjwM;(sbi0 zVRHb6fHQXk>I;bk_vog5;D(HKZbcy)psU)x>>ebN<%E3^eRPfNU}`xde%1p00000002=f0RR910009301yBG z008^YfsSN~axY1*J3koTAEQQ3QbR>k00;m80000000IL60{{R3000000{{R300000 z00000008hmFm(U`00000WB>pF0000000000000002^#>t`vacO z=Nb2N?(3>we+N!_zM=TAP0~({9iqR^Tj9p$`M~dG1Y^U6LJt)dEn2g{@1{P?Ua}m9 zI{pX2eRhbNdc9CN!$ur3&mQ)E)1^D^b|i6|fOpROu**ngkb0+*?PYbk+gM0#&IVkQ zriqR|&tY-+9=LU{jWT0zQJZcs*(Q#`*FU<1v4@v)-}XwbD4a(X9go1Jb39)7@b#nzYWDPGVJ!4W zA1P^lH;~2d9#s0N9~OU?2h}iy_Rev^l=?ELo}u%}8G*!5JfnVAIr4~^p5KQs8%kddepmjgEfGa>x?HZeud z0*C$Cftypac!k9gX@cx!a^0Q`f!<1dJ)j>tEb8V~2Rr%V;zTa}Ao7wi%2c9R0VncK zLf{V>_g<(>dkC89v9RfG0Ixdf zkB?lkIIo~plzndnmH{io)pzFM^59>>&B_zP^RZqWr1?Y)TK!iH|J)OL%=}C@GbY0$ zF$u1j&k_FiI4_2G<T-VI+y~EU1l6u zx{pI7Z_%_OO5AZ_3AHUZqbAG;@3|?$RqF&v!une{yEPC-41Gt|yQ5k5sWn?*2$_dw zyI%j7nXT)-inX7%(s@yhAE?A~w`dD-&AAGydF(9CO8+bbrK)39Neign|3xznr1H!& zoB85hfG3I}qIa|gJh46}{yuq`H70FC+u{%4_g{&mVrmfOlsXd{>$qKSHO1v!mtf%9 zN_w6;QyO6O02ZA)1iE+gSpVV`8Yg>92yU>28yB>BgVugjjXH`aUUzqMza2x>CnwNk z|5%QL|7hRp2!2+q+&J^sVsV!Em-1&l6#Rxx0O=iqrNM(S!Yms%$vvc-FSZE_Jfmr4 zP`z-$GKcSoS7@@=N_-pA5B@mpqEnjFgd3mCg|SD&N$9}X34r88gPu7KkKrJ;vH%ppDq*z9>X6Aar~Z6 zf`0cYc+0;^EPwb>`m-aDYPQI5S^Q9`g7GA!{1%shyU^Ijbi-cX}88qCb7s_^>6?GHZgk=RM z_^jMo?igezbAqIy^3Xzq4GpqO=WvwBDtiGH>93st+G@nMvC-|I*mp zDC#nd|RF-7fxP+#i2rO~=u96fm~H zk!_Wm#DTGDbl77QL@Yl-MKR;~!k8DQ2e9z8fgXPvfT!julWP41kWJSTk34%KESPgk z2uqtz9T%fShay9$s8E3KNfIa-GMSGhyYTdSD=01bB^Fn=Nfwz`3k!$&prHH=MrUml zmp(m2jSrWQy_YJk+qM&jd2bYtrj4K%o(Ew0ED5eN@MfhL)y7Ka*VJ=ort7v0Lo_KF zA>7KmAe^n<4VgtJ8}?oBgo}L&L2rYmq*$R^FgNNhwtpH7!?rAff|yjQS#^pFRSw}} zdnt^awo%aAl0q7V{ozPhA^uj|!V`2WS#npE2hHAt{r7DV16=|k>Xij$SD|=w<16yB zkZ}JU{|U7}hQeIuse;Rb;}Es!1XQ~lGqvTz!y_d6rTn)TB0cF=Fuu+$eIU%fHGH3iC--Jl`1_MEyWJgM_-G-&P<5MQpi9c( zU&T({_hMQ{F+FQ{WZ7x6uwC}2_;9TbJy!P-qAhyB_{ND}?jfL1)8P6OQMvEJ{kC~4Aayk)+M*P9n}^sQ)!TcL#;%k*$qN-!1m z*h{{3KZFB@FU23)ZPJ&?DZ(htX_(<~off1Gf?0cMnUUFQuRY)?_ z0{g$77&@_qqny*lx~6_Ylur+Q>d+`oIaSS9XYR+6T{%2q?*OPyZ{gjR+c3fM7|lNJ zgwG$FNu>_Ig+Vg~9CPdo%^7$S-hMnK$myiPeM42uxV4GiY9nRDvtT<|&ZeYQDwk9#H*48G4%4u^!$hqj{GwraTi zPL+lx?GjIPy9PVVtZBXb36Yb|K;h+wASpRR6NZg|E=i&oIp38ObQR%iz+akc)PP$y zorhZc=R(dlM-GwkAf2?`V)vNE1hu)+-FMEzB_BCK=2dxZzX_9I(dV&HUHP-2HpYaG zd7JRFVbRd5U@ys@iHD8BCE&9@5j)1VL*S0DI4@LO!VD75Uv)6osT*nTYGrcE{j0(Yfa!IiCZmRUx zGYkHn-bGh#pXV)kr(k&c94!C&6h_ylz}1yAX}a$Qlygs`Nz!hO17j{zqw5<8eee;Q z^bN6h&nps5Jc6U|k<{$7g4^q3iz(^UJXTi-VY|Mw!Dw_CwpJNKa?n z)-y*aIQoF@WN7inL+Ri%?Hb&xJxUitiIft@z{cwn@yDZy*!Eu%KinNiF+KHJIer;h zzLaINbD8wtr~^>vGzu+(PD0#_N3?6lW8zg>;-`jA=(e3HwCBIG=zbGl`q?qf?Z#PO zE|JM3)jOeDx52CvFYC4w4$+hpqO?oF z;?V<_DL>B{n`TP+!ntx`-~n%;<(C{PzW1dp8D}10+DTF4vc{B#T0z9v5OVR`4l7^2 z0hK|;xcXT&=Z0N?6ktx2|zg-+(>&J6X*kXqLW3HZL1>xqC z_;iO6I+Z(<%yY4C;<8)!w*GaUIX!w};-e`f-xf2lEwUXiU{-`jnj|W*5vv zm04NHwdHWUx`}>VoyY0D;)MB4DFnanikBA1u-%M%U{|n|Bd?~h5D^bI^3TKB`}+Sf zufTiL+ToG9F53GZ$4%xE>PmIMCKGL5bzB=?R_KzhXPN z8PzN2H<+%A1J%MgLQ{Je&3V3EoMJzb$0l`mJDsM8W+(F4S?)AftiDK6+aTbrj^y`p z4Tw5e3-o488{XtC_C_JFO zb&b&9=nggY+)Cc7cha(1a-z1fI*!@@kdpNGLUP?XK}{|hWQP^t2(_Q0YPvfw-{;0n zb3_RC`T~<@I`QnOOUP#1HJGHTk9%xP>DVN9!CSS2_7^%yZ{Aj5(=Q+C)zzW+?dfB2 zSZpl63DjhxUR9zIIO6?Z{^TBiP%P^ERtO%r3=gWTg3^15cr{bX!=txT&xrm!F*gh= z`bYo|zoKiqcfrVvhw!Uai`MQxhttD9Q>^1(;rH1f;mMC0F(*ArjBHHe*^*?~VIGCE zKkUQv)w*o-sZtCx@1)#mLBh5@eR$bZ4K`0`Bk7@osB!w_zjK|22e)6)TrYLja4{CI zjvUR38GW$lA2SNr>&T-X`S6NkbH!J~B(Suf0vcM+6=RmX1Mjjy&@DNay^jxLkIr=b z`nCc>Up^MSMvvr`j^60~XFBc}-A)GjWBLB4?J!_N6s;F>Ky#25FSU$?pZ1nm^)>?> z_pq=B_6vQ2vU%i51^zI28OXm{jbTmIl7j(jC|x-V60&+@RX-0nbFB;u^UTFJ;g2D3 z>vy_XH&!S!_(~BgM{|b@Qc8FwRL!~|%#KLJ;A(;Y^f83z+VWiXQWcM`>_woRMkP;c z1aYH^+r|80G+b^IJh-u+4NrcfJ2_D_`q6rRw?PgIlX7vxgGu6m+uoe=*PrBX4dtI# z`rz#7`LBp3EL_RiiF6OI3|I1}kJhyJ*ju6U*L)oFVI7@S zEd$$g&*1ux_mXax+HwB09rSf)C+$AAlVASY4!8arh6}W9ndq+&?fZcLd|N_3EApim zC%uQtrBULp@@^QhWe2KXa1i1q$&>zNeSA3f18r#6;B6)beD8cwgOR2K#Jr3p&wPfC zai!3#bA-&TYk1ssbL<%NK-fPa5G&TJa_g#Ah)L^%ipO<@o4vhY$dT{-=(Z&lBzVxd zt~9J%l?qkX*QMDz)bQ);L)13JmFq%d`0UpmLdE)7@b{nl^_sLEhGxs-kC@#sYe@!m zbNIq%{CnYm9+o7Ydk1Bnj=<>(+-rLT*4fH)k14Xa`;jdF&bbabKQCaLLvI|qsEUZx z_-d#*jPiLaoNb)Q&a<7#Co3C=PphV@jng1#j=H$rNgE5y{HWc_lV`7#6W=TPqIT~X zUNPh|W&AxRo-6gl&Wlx0(=C)w&Flv6-h3B2zUE?OtuFP6c}lzYg!B2)+E93_T#S=G zq}=#Z;&+`JkZiFSjml+&1<$Wheq|G7SFVMw-7%2aI)hg$n$izrEwNknWELZB*+D@L z2Sw=O#6UxwUrVByS#}Ct8JPt)^Cn0FCLE^B-0fU%{+14YOvW;c|D^J%y(#jE4M&Ac!ILLGfo#!4 z?s3bXT|R~2Mms&eAH5IsRg1-IdvAiW;SC`9nQV2rKbU?r`-fkVC)Z+$YE^~qCooOld^YqFpyd1DU0&=zOLZ&A%j%iu*bs^P4iR z_0|=w2dt$rR>Va)KcyGtYM`b}8|{}K0>xT6ZaL$QgR&#hv|s=hc5_099{L>P(4C8p z4HfqcR_A_yr%+=0Tk^Q*#;QAikjdNbjSrS7^1&%Sg1Fusw;RsEm0H)~#e+6Z7?k?#J9R=#Dvq&dIpPc=PCeJdW-w!0xh=lWOQvQW@PSZfyO=D2}c#*<~ zUZy=W$D+=lerRX#l8?r^vC%pOUUy*n-cy^jBxhk3}lnQZKw-?I7&WTFNsm z%E%`Fvvl37D!6xD1==#AM2i|V+>zQ2Gg?Mq?l6VM_8-lBFWR2ICBKp!d+UihquWUJ zY8q;ce*k%(FOs+`8jXJM0r!RX1UX?muRC&uj4wCB;OG(>(zywARF|UZ*n?vA$aW#) zNiNU_b#qTUJT&3I6O*q=}I($UbL}lR|Gf zKDPcTUzxF-7cO=|Yc*{gvMmF&wXHy>G6J_ZS>bM#r`W%2FI{=q0)R&`I{v~f`SM1v91^#}AX~>V>FuHRuSuBXc z6I(A~%!a{e{=$X3|G7vb3Y59t^{sGux;2Nd9)xO{lQG_LJZC7p7Avlf=LH>}u*%Gk zJ!e=_*-JKGLnyv!zc+!&AHdHYx}QNz}kJ~Vqzg5+6f7wmEg;Ri3O zP{Hv8Y5eHNi#unrjPBj~P~Y`pz~ZfRch*ICta%Z(KOTgATLa-*PhV^yJ^p1|LmT@) zpvgwtL`TIba607;-P`ht9_w79tb`G~B=RT7?THnPS8T<{#T7Nz(hJ%gedRp6|46xBm zl$Cu=SNm#W^^sznyjlm{$I8&x)(oCKxrAnZyDjXVS|M(D`Gzh}kpL?jZciO&EsOeSu-We3`r%SnbMPD;3}RNU zAjmA|hGDa4w0&<5$vJ_si94wDkU5UO-}% z<9hsBHWshPUm%~HToSe{mo|M$gE+$=_H1uM$B>O&wCg5zJDvhwa^`qpvnkt1_wZV8 z?}jHHpQy=kCpJtS4P|MIdH$PToG?O%pYt_HyqHePSDwJtm=<_qQwZID+>EIVF%-wTsG6g~2ROfz3>`gx^2y=-bj8lyH6=#XTS@lC0t zWis3uMOfH)UveXSlh_%Q!Yl8t1-$`=-0XK={IoF=mph1f;HEORPE!Mi5*dzA?!hmW zf;oPI2bbV0QZM#&GJde)*QKI6CNHj7E4y}3Oy2B#+Pf|93}!m?4jV59XkGA@eZ z#BMK1VY3d)inrmtu^RUEQ-tqLBe2oro)}bk5<&(cD_3b_#5!YCsLB^B2R4f_fBLcS z1RY$wBa$kQ-V`0)9OidvcmE;fMHo161ty*Cgj06iDd*mE=q4n@+`+Kmi-ze$UE6=6MnkVU3hbuSF*2ksC-FV6qky;XO zv%A-S@L^RI-2E^TA9w2`ly8=y(A4o5aV8gk$Jk=fk;{1hz6Q^%z6eG=hVrpqWB5mu zz}r^Za?juW$m8u^3_m}Ry4OF3A64G`x)%$@b&XW`yFt9+U;|d_i%=o;9J-Vz;_6E~ zDeH3ttAEktk8cub_SJMD>}nN(X}!2=T5rr7yAs_WC)0Z!XWA%Ur`Nkjq0*vN;;$wn z_MWw!7q4H63*r{xh=HS^pkpFWJ#EE*cEn*(c6U;le@U!(vjvl^uHt|ScRbo_3ddYB z=WG*w&K(yF4~nO7O2K)_O}QHWoZ!kHH{JP{+G@OiaSnO+%Y!wmozVD(3!XN)4tK2$ zDehr39@JB%`m9zm(bngJr^f|9(7`#HuW4o4A4&hKhf%BI6~s*~7Ud$+i5A=y>o_ac`0~$vBj{`RcvNY-4d(mIxUlvMEMIj3GHy;H{}=6K zkW#|u3ntP`=`o>oXd-SKTn1|K#V~q+3N9a4iG{nf`1tJvNYf&^tv3^+OFN+l&f(92 z2%q+-qHv#L4z9DS zqhT|R*j@G%6=~IhM(Yu&#s0PIuddH~hV14n!$Q$iO9G>8Oz?#27<~Uqk*4bh;YgWl zbmUPiRa$nSi&VDpzLzr=S(vhhDnmw@9qqWkiX)el;Aht+ywRkJKicJSVQ?Ccn16ya zKV?9BU@sm&`m(V4?l*ds{vOJll(;G&3f10!A*(5B_(xZs%bym3O6f$Q0aUrnxq&p_ z7joR5<&0-{!WhK`Xny866ihe)JAM~IUc*eBz3G8O#a&UH7`uxVzKf#g6IIl#T92mP zU0iRry&*^6$MD4_7aIM8ahcr-nDa-8t&6-Vuf2}YKpS@5a^sca<4~1vfmBhZIBVl61Rl0mPOmMo(Sgp_iU8(It^3qcz zpSFxmY^-Te`%W%ib4@&;abB26XP{X=3uHql@|flJTsZw7*UWwouhq^{Zb<}P_-YCx z)_;RpQGIw_A3L&~XF&JQ_J$dg?!m3JLW&>cj|;C=(e2mwAb8(oI=`R~e&5}P1C@2@ z?3$OSyv!z zbSb!haK)I+u^jeaHkr9;HExL2$DyxNVR=j{_SLZAwjXOieS9!ZJCO%xH^|a~n*r$3 ztkU@6c?ivoPUWOhWz_S$0Hpz$!XG?~V(&OH=CCHtD=Wkaf5zaUXCqm1?ub}F`UwRk zJ5v9yY5Z%^b_`xRO3-UH>iQ8zbc)dQOTievq>A? zOMJDb;hfjY>GlI6)u$(So4g3qo3`=A*PlQwtc;9)>q4LH1K{PG5&Xsm zG5NfLv{k(??g@SCX>G_!EkQzAlJ`3)Sil8-i5orC+ z$LOFCs-F;s^?uOs;Zz?q>5${z8Q%Zy;FoB1{)m-?FjCU=KcO zxr4ZED!U6w5HUpx(_Sm_=|1P-{>mJbPuYuS$Aw5gYwutWi)U21J)0(Lo068Y6W?r< z!59x;kWM{7%NIJZL4IGjkhGO-s)pgceup9Nq&8+s3Shy?4Xod9FK-+H9IrOUwZdHi zJ?>^f_#%C*Ji8vfgGXbKWI$s`=ss?lv=~hu-+<{a_hF`bAw1`UcxcQPDOPB+#pOVJ z7h;R^mJE^Tx_XhkXvWi&cGLMqvh3{_E|`403Ij}gVDuGJ4%6Ntotj!gy^U&sEJMh4 z@;ISd(D$@XET#v&k4;x&xMh7S7N8*mPOdnTDc%X;Xji$Iyt(2@yHu30)9NxVy8H}s7@YX3^4E}y!GDkfH+}w2VMBp*%6eHQz zC4lRDc)+J4??naQwcwnX2)}}i@m%dbxD>h>&ezoP8ZRyM^t7V$H^Q*k_^;64{XSJl ze+yaH2k?=Ca(3?V7?!(bvese(w>O93;l|}ycybDgyMc9Z3S#Qi!KJ5|Sb%oKj8abNV z=Px;CA-dJ{LWOpQoQqJX)jOQ-#!iQ$6Ywe()J2i0O7ZYAr9E&RJr-@eTzF0Xg zkVDRS(dAwv#8SDXd_3QP;{vup?{zrm! z4<%l7Af5Q06?(;3@&r32wzZGK)HU6B`2b^VR*j}su{(ac-9QPS#`2kxLg~0&s`xQ% z6MtE!Oh1x!*j?EY$8Vbn_vcNcQEk~^anPNzzFtA^kNtVqG;Pc?8_gCwkI@s12VJDT8|b=`UIgBUEXJ}*>wPUD1_D3UkMg&CUjuwvRs4y(8< zf^iL%x1~W*pp~E$kVy&~Z^B`G3paaj<#TD8u<*rTUX_~*t!}+(bIJ|DA;u3+9l0i) zirkBrHYj0z*inqp@#Jp}1L@_jnVj@)8K~DCqTI+{+-v%6apL8ZbZCJodql*;^BLx( z8l{P!(vs-p7#o~_u2iU>+6$jqjfU8xvgq9!z;))=r3vfhc&f=sn)LoZT0C?**Z%B@ zUTY`wWY;NF+`p1i9DYJ>QH=2A!w$-?90GD1r@*qucEWM*c%DA81@^dYliKfW7Czpb z#DNCdLhF!K*!bcaWj9x1+r)8vw%lX}zWn!pD^;$Et~UMoiq>Slr8Gi}5APzG3jwZ&^D}AJ=RG_|EuZF-8U~JSg*7Dy z;N0q&q~x!O#o80F!?{!RDc{Tv3rBN+K*`1d;hV*_iDIrJ_irB z?4`K*+SvcwPL}mL$}_*Vic@@T;k;xIUP#L!!;GES_+%ygm9~QX*1fngHjjNaoAYgB zA2NHs7Ii{@!n<`7*}3#Qs2h!;`n`2=-@0b-m+aC7xs_iI}Wa_ zSm?|RHVd$DeiAf~oGE-6vkp$zoQG3A`mm1LHjL1JPc!G(VN|*!M|=vV^SulxHa~~5 zR&4{tNdljJREr<}bzH+vWAt4;o3}0B08#b_A?K+wE8C=@r{y)y-+EnitTtqs{9{n6 z*eqRLl1UBf(U=}<0_xp|-E$=Q!MFWyUF%hWz+xw)Dutt2CulmK>8pSS|e;CIt4weYN_WeDgC|?b$;oQ%2)E zvv3|VNlHeMr>Vc&c%JmaP3%4WFl+WKfX1bXpcC2zev9H@$nsE$;Nfy?_f(_Js|W$--jqap-nW9?Rm9&pLI{rGQ=Hqn%cexT%r! zmEO>klS44zzBR-ZC)f`*6*wH8^;%I*<0Z=K7pKE{He7?Pnz+x4c=jM`Krn*(<~#YTh6-Jg+{6R+mN>EB5$aorJdDI9P<2!+;U$R2WJAGg}m(l0@#vD9xKD(LT6YNYa zF}e1EaASo&Y?^ID=Kom1NMRcHo~MC0Ae1})t&8j$!TTb|!v_RVfFU5AbLvW_17B*Q)abjp8zU*<5-ld(Ugkgo`{J5NE7%t@J zE4;buX(fEoQ)|pVW5?dFegYn{!1ZtLgOjTbn2s;N=&5>QuY(`SL+=*7`k2U9n?t}j zuMBj@Mc{<-IpXu7wsgGZ1B3^r(4dT-FzQMOpFcYjHUAVq{CgElQ|rwiu_t?6&xPX( zTD&3T1_hesv9_VWquaF6K2Q;_I6r|I22G;Nzdr20$_3sV?GZi%n_%$CDqO0kisL|* zZ$BN#&-T3`pKA{EU9jflpBsdJ2G4N;JRv)G8<^IA7mxPaBc=!bM+fwOkXG1GoYQH7 z_}l=mRj2YyonfqaX)Z;&WZ*@M1X}cWE*C8w2`hT9;1OE~v(R~+9OLG|naA5<^@YPw z9`AJyO113xiefk?MgAvRIQVJeg(2$+y=~ zb=yVUyFw1mC~qg(s~)_uhZ=qe8vrGea8`5NOO6}sxbDDaZu#dFS|y$^XLTE-q)Z}R zzbL%j(hQNf8|Rk{<;LfGaP7NwJpcL%LGi{64jl4Rcw(gt<2_fC&{<8+U*aj{)+tOL z`BfOS-4*vvpUaDy6!GsrZ}##1Mgzi%;BDqoP(GZ%K|dNnc(;obTK>)S9tLbINsxHU zw8F&MD*VRwG}byOa>{^HLSSDE#Zv1lv&8PV*YVInFCf7!RhZDdi?Y`EKjf@-&?a`NY zns0-_>L-vL-kUy4??`vPI)(<>1?aMP5)U1yP3sbF(Q}zkFu2T>--ZWq?PO!b#j80i z6$RG;{UOlf1NdDYD6W&yrr{sY!J+2mLPc1q^yNKOywuVk?*?rp?Y2^>`kWW^Zn{18 zak6HODp?*L0d(7R9^HT6L4E88;=E(VaN@ZJCMsViaepgB|I7f#x<)c=%){!4C7k+o z1*R7M9HlJB1c5C|z^`Bmd zH4BE5bL1F|FOU~6j3`6n)>OFvGf{|f599e&wEwS7E6T|(UuF>M2L^w=A%wSZ(ie42Px(ioaNmULQM==;eHD=Pq8GsGI>1LXD*ia zoi2Qy5d+^8GvR@A8LHn(5X~396P64b$t&y>4@>#t)_vPzYs2IdP3GUfhdsk<1z z;5@5tu;9@;>$tz#3{<#jjT3Xv!{A|mVB#30`+WxEk^Wqsu(V2s?^Ygbi~>a&w=xFnsMtaF036(ZAl(xtN=@eCBY-EVGAO zQ+=r;bT{&d6|mrS0iB%|ix2eE#I&XZLcqON@>f46ZHZkV-nJUR6U%?o-<~ya{K;{Q zI{tyb>q$6rfiDMI?T5G%+d!|YnFbW4q9kw(Ms+H%)1yWF(mIEhZB@ag(MrPEQd4f6 zlmel({;1wjf=&;n(~2`T+07vv?J&ej2tCdyneNYi%#l-3#ID()SWS|6T~^?~TD%S|M2d;edz(v&2-@YEU*D zLirh|*?XWP1`W}{zae$FiWc04Nwc*4BU6@oA{gFkKT%VCLY zSn<(KoSJo9(79g?Q%bD)u)P*;8ZL(&y<%B@Ua54!g?!IYTqeLn9c`-64D=LAjMdbx#8$bnqiPQ!!jZK5)2hYJHe?<<}+aeA>b`LyW8_=nanP|UbCGP3n z0n@ZwBtE3y^nzl_{(c2-9qGl@vAQ__d4H~(6Hj|$ z_1IuwIUNskVFLqMe!13+>sG5`OZaW-+O-k(JJ?{#o)@6~VJPaq`A_TeFUQLyyT0L*l` z1@9_X!Oepwg?)w!_&Qmn?mtcGT8kE*&{&Ee{f~fN-|f`fOPwFsFBNxo_T~v=bh+^B zI8^TOg8D4*VYyBAd|3P<{gyikZ`ehN#m;}ARmTX&7hAC#MB_|%e~wt44lOo@)V)9( z%|A}Sqa{<=uSf$QCSRn1hFv&*p)>e6_@N!W6LOAjxy_@2rV}n zKgNjrS7gEZwyBr!A?1kTY+u%>TGuRzY!1B-nR(M^DXA>PcZ{R-3lXR)z*&I)n zJ3_F(OcW1tK7z*;OStr+DJ5QuV4vbO6xkR;4kMn?qtYEHGe#cP{<;I%+kkTypA%^_$IbCy@5-&V};}9pXsilGWMuczk^6)17|9=54>p zUZ)-EUXP-&i*tn&r(#gfLV=U($FcjuLFm3X06e?<;jNQ4o3)E{_%8?tV#qw-!^$ z*%9Ipz5T-K_y8UjpAENJf;+l~K$wDV@Gwj7z32W7}h84P9P6F*<6DkU6N zQbzhSVsPqeJznCl1?mqE!Ce0Y=xEr_*9*t<+v|ha`D`haw`_rB1EL{4;1L|0dk6IH z&Zl2%6Zp)3ChQV7P;%;XljQWOUa0f3KN$6P#ZifO!Fk(oG>X4XldqrUpn?C<`*8t+ zwb}=v>&6M<>4#z8maRDTbT*zGK84rR_eEdYz(@7I!N;vDDDB>P(Q|fxbXb0ro@}-R zqo6I4fiI`Bjpzz*3+I699Tg0?^p+karHiwV_Q#|Fn*3w)aNhT$l{PhAfJfh)Q8M43X4n&TDUk zu&4SY3@lqFeD?p_P?W!&4`?}IUXm96P9(wOa5OH9FX7uwrLbv9E{)vM4-qcQctc5(5-Ft=(w4N4KJRm~ zA_=K%k|Lw*kR((T?NVu2MWvxAq~7ObL{>x;70Mo8Wb^a;5AMB>b6?Nb^KtKT3Coo( zfhXQ>D5;R+l9Ci|?A!~|a|YmwhOJO#ct}(U9mk2|H{s+Fx5Ndn*NWGCm3US0386jf zE9Vp|ij#L}<8-wsOwx2g-v$GA`!*b7_g@jhr7LT1`Sq;x(^?9u6Sb*lULImL*}*loMt)@hmO`psrvrtsi((9n$0ABl*NAAvc!R_)Wpkrjqsz&mRARLNvL{} zxUwbzRu5Gn?Jsc@6Hx{0Ypy}AMkCq$P{!ZM|M4Zo!$Q)9k$k_;BFqamg?US|U`m`F z4hhKMLo+3$ zDfDHh)E}f$;U-*9DwL$w+w&&5c8K0nMhwI$1&Bi_#RZxGbtwga;1SeI<@VT;H zAU8yod$)WQY=pJE;(RYIdOZlnZ#xDT`}KgehgMNSq7`NhnF|K4_l1pfw&ATr4O|>l z2hq=)#9-|%nwj>T=J`rU9?bT)k0q?|GKlY0P5^Uc+eFJUBk~6|JyUpX+@5vz2BHojYmnE>Oa|_j!_TrDxBk}AOeeB3tFI*bl4~My>!J7zOEI2a-yvJ&x zDV5{qvOhQPK3aq!S!8i(K~*vK|hi*_>dkc+@Ty&GyDFp9$P*9RbnrCR6FjLu3|GPkx#TJp57uW>?hGDi;G6 z=U#E_`mQ%#9zUB;?Y{+)?oPDUX&Y<0ea8nb(xTy!FmYO%HT!jhi67lZpqADuJ|^P< zt&L+i{mW83vta@4ao!32{r1p@m1?LtqX%DjSWIbM;V?$;G3*UJ#4_zMcsE)T-p-l; zs`@DuxFLqBhiyS$Q+<9k)(`5m<2V2hbHN9Do)SJx=y&WSEFAw62LCWc^#zs~+vH7yU`UMnaY$b=*CSeJvcY!cIX@A0_amsKwOp z&r`UBGCbz}723B>;8{`8+_b(F4rJV6wd-oQahW0O{p&zxstvV|P2R%vU}voJ53(*Blo6rREOySAKAxQr!T7Ods-vUci!dT4v>IIRBagct8# zgHvXkV9c2X+;75A7%(e=uLP;UDZL)--rF3}cRzj%K`0xe18whS(M|1tz1=36CIu?M zlH1#9-%fq_p07lfrc?NJav?0Ocm>^yW@G7q{%|JXm6$ntGYxy`1x2RcXveF;yr%4pT+0vi{Q6(DdjD6#J+WH@WV}yb*1L> z0wXm{nC-~BEC*u1^h{E-u@m(5d%zR9)fD+!f&-8K2Un&4P(PWqyv9L~Tm!Apa&b5e ztS+Ge&TmEKAZLttSdLSoHt^TagYf;4X&m;S2fSNt#xBlEZ17_qj@VW$HurMn*gF%j zcmESOVZv{)exU)}$CF)#4TQTDH_2mdCB<*Mjyt#(KK~5kh-Nv~4*4a#>k7w)U%Pqw ztTGDUZb`u(+68@24Uh}X#_~@}LeDP_Y|}l0xyX$w8ntl2F=@X0b|Mx1FvDYcI&88h zRGe>ghDzt|7Xn>1An4Z_x-D}X<_r!+xkaHUrTPbSlP9vn#x}Zez?e6N-J_=-fjnNJ zRurENC)JlaIAe#hOX|ib((-*rD!yqPJ**vkWVb^^x)$duUKW#f5zd!6K<^Bni{sN| zxow#X9=}}+Tg64(c)N;L_gV)JT;=fM;wx-CPMt+36|x(!5NBD`g42mdWap^@&iSrz zqmLK%`SF@`CU}yY$#}L{A1R7X@4;Dn4V}Z;Cx@lMkQ({E0w;L+g9NZsIJcz6a}eJMAo;y)1{>!wOC%Ky5CE4Uae&4tc=E|4g zrir<1Wi*7ls#N%Sy(emI{tB6|?ozgJ5i0M!hN1H2*dr)|AK6uj1G}Sy0e#ls&Hof= z)8FyDvY-YYpY0YO)OX<2#Id+Xwgn!3*hAXS25`h2d-4A8L+so(w|3jrjd)E;2dg#= z;qet8>77T6#O%*SczW>`&5ms%^@E0JajiG6ykf!=ZK_D&f-F|Aj)H@$e+j{Pfx@E) zzu?Gk4?(tgrx<;FFz$8T%8%#%6`I(Goa(jEKE;b3O84bwlPvIk`A>}0nUCJz`_QJ? z-CP@B$@c~vf~#7(?0D;&uziaK)qdW?MnOHeSA-EResK?md1r!YU>|;vHV}heB*W;1 z$?S9-U3Bu=bC2)DhRl!mbxoc7jtezLj)7R{&9d~9l zD{M@~`G3y>4b`Ik@&2s5ekkh|uE(&!0-aY{OdkF@qHM4aikIAY_RZbUUA>pC9$Sc4 zeTMJ?Q%CmgwuaB;5$qAKg+pl-D~?RU&g+GwpR*Buy?R)EI6Ir*qdPj~w}V^PKDy@@ z#RK;ANF}LkyunI-Lfagu?>6MDF1ypw+u4SfFPQ zVZVRTo_G7Xen&8l%E=(Dl$W&1av#}Va)U$Bd-(G=V|pZgS;*bh7lW&&f>B!pY5(iX zN@d~vt!y~vA5g_1B^P1C`VdJ>gTFZSsvh>ucuOyyU87?8RgiwG7$-J_pnQ25T^jnH z78Uq%UTc~tmha>u!xm9~_)byzydB$0VsYP_@R~tiweZdPKAel6g@Nym)E0_;_}J4~ zfvB(6&HyMNbyIaEX-RH=xdok7>YvltE4};T>eq!P;Jv5fPK+8i0 zv7=5Hu3HcwXlZHS;RRV3w?}4n@XA_KCTqE|L{EBpgTWD004Ug|Ri`I6Y zm9!sN$ssOBVErU#irzaHKMqn7I(KKnVtGgSzG5MMWm}{b)%1DQG|GGNuXFE6gQPL~ ztnXt3OA^lty60B@o5xPc-@&Unaak@TZ&m}1)BQ1IeTq0-zf^qKd;q>bI>Z&V>a4WN znDgCtz{mJLV7JK+gU$!y_>=eHs-#9Z_s2n48L^TV|5^v-AMXh3*4KbcQ#`QPDE#hW ziV?|*T;|*j2Gh^*<@nJ!AYYcppb4s8JV-MaH3&{C6``p7s#vV+%VuugI4tY|O6BR| zHgct;>vH^S^E<&v!-NyQOyND1llXDdY&70tfNq^D;dJX1-XUBT=8sgzRLKY!?bb%x zOCHhpz;3kt;)nTFQJ^$lXp3o4IG;+BpJ!kLd*;MTAJ+s>7c)q6SWUvM2H%2UB(QkN+IYdp`} za}FY@Q6j%?I-K5ENm>pA#m)(anARhXJ`5isTHlJ`Cr5_h;2k#n!QckeUmYoQR=Puy zX-}N`$e4e|c0iBTzT(-j{aNey9xlk0A8y4D`L+XEBSPeaS)n?j9pAgDI(fXa#oaQ&toc5hqAO&;6m*NtzabZS4;Jl#n< z>TZkHG3Mz1w-vq__T-1ZPx0JuL;2{&S8!ta1dJ`n6~qhvaN}+}=;8uiH-00|SM3Xz zw)^7ix4z^#I6&;IcqmM|AaKDoc?g(#lzjKihozf5_|0`g+^u#~+&c3X46A!7N~)Vh zpNhlK*0+UJ&KhFF3u)|%a|GS#(zMuiKZg0ay6OmdTgLn$M$9jD^`bLOluu^uBm3k0*uNXYnf zgrn^J`N^({f~wJTim0lfBWL1x)#Vd-;KxL9LVOGSO5ek)7U-be-eX|3crhI+vgcER z1Lmu3=UYh=FmB>iy4~vx{A{p=S2E=!Lda(w+^JyBUk9oSb4yHV z(!LBx2`mz|nhwFU^)fj8%|h_Ew1C90Pntg+z$sxJ5>} zBTp=l5pD@Qu7EL|*7K5h|6m(7I_86sf(dK5Y^6>= z9sX?o9&|tLXM;z(Bv;n_6ed*2^QA|L;`mM}$*N^OfFY;Fm=7Ja*LNV!k5UAkp{jhk z=MFS7SWb17A~bp4pz@7UxGv(cP^R6VYxM&}wb)8BaX8My_U{%us;@(qNgU*;SCajh zlQ8J@ZVbG#6pqy@VlUIh=w|A|UE}Q7^Wk6W`-wnn_89o@Z#5ZB$cED2#^|B-hLswc z;q!5A9{#Kx?l+Z)4`k-5Bk*c~VO*LFzUs$}l`5zR}j9 z*QyVw^yU^?w>$uE_$?4iiY~>D@SCX{HPv}ucKRi9Si(D?;qYn>DVB4o( zpdp=&vGoeV-L-PqQ1P0YFD-zMnz?W~RF_8`wW5qx2fp-s6z7HChx3is>E(cPAZtFn zHq~SxUOjvd;%e>K{lj@ldGb2S*4E4&XnhfZUtZFlS#U z*9h-w+uc8K%ITXz*(O=UrtfgjBLCqw!jcEwkn1y# zbMM`xJwKyQ1)h`;M(=MZ z^Oa$jsHrXy>bKjVOLQ<^u}BrY_qg)QSB12^&jRtY{S7hmz+|3t?*^@&o4^}Z*ka0% zb8ru9h3U&x*=6Nj;o8d0czlGbxcg`omdy%Ajbk;e(6NLymkwp$`u*sY7eNO#|B+Mb zqG)3?9z#}r6Yq^uM&q`}6!Y^PggH#Cc7g96w-L1C zC!zbye%SC?pPTCvNyy!b+_sO0?i`Mrvs)pkV=Y7!DzN;PQpvWB&Zs1NwD$1FT*{J( zVf`&nVMD*;?C*P4aE#XCV-Zh5O?Eb#etRzTzY4f>^9j6pDpCA+@slt)V+2p~jDc-Q z`zd^sDUD8X5EEhzV922+3YxW>M!P!TvI7dZLm^*`R%swVp)aI{--0=I)?8Yg%u4Wr zi~3Hb2ba^abhtkDmJP1GF{eUENsq>Re(CT*IvywM-lw4p^2x3LG`6z93ectKi=Et2ja00hUP=nGeO_7_WG` zzPJ|#9e+fsYZr>Kb%yZQ#GHG(?j$+)dh}cwO^W_I#IdxO|3tlpJAcX`{9`8Vcb-je z|6Ipxy$Fo3-vQ+sC+X75ab*75h?Tn{xYs8`jeCYNY>uKu zJs%1Q!*^iA&`1~~2)J3R6rwcd;QRyL6t%S6gyY!IlfS%4`iUYHKDnX>0JZP{+3u@4)2B z=zlYp1S|G?!>kh_yrnr?sF*aG`z;xay|*+&J^0q`HNui>BjH)vVX8I{A`Q9OxVGXV4=~ICZBs+c ziavz*w_hNWb1IbF^%Mp!za!Ld+D~iG_vGr+#k^5U6+_G(3saY*LuTqxQgEmNX}u#D zIZBTPRFp!$B?CF3^(gOkbB6TI&M@r87g2_XGa3QE*r}=4c)a52Ow{77zV*l zYp9WA@%YbP_)WhHK9+ZZ+;DBG3{}LY&e157B+HRKbQrDraf2S zRiELaf=gqc6`Ufcjfx*LSSq6tV%)#djh&f%M4}G%e(`u(C!Gg;KMB=il-N;MA9KIl zp!U2cHPa_VVQAQJF4HaL=vzVD(pn40efnYhq5kOhy$Q6UOTg!>DP7+cBb-xFa7kPL z2!!pA$z1U;$Bv93rxs_-i0H+?x^n39uvKX2D34coKUOF%W$oepVd#+m$nwJqO1y8y zI(@C!cVIJ~?!S$9*sQ{ASql!lJrO>orvv5(b6}AZF7;Z(W0xsl{)lhl!;71^#J@lM zmly~dIc3ntY5*&7q8O|>7Dp5xLrs5qR-MB_)u;q{VezF=!re7-Lc>gNc6#T|cm5R6)TS43-%K7|Z|tDh2QR?5Z~|OydJN{;qo{c8 zS!}$P0_}a$gn6@ib4O<$jbD$#{we-EBe{>Lt#i8OM9(-LF@HHp9qFVq0m)GD{Jda3 zKnIeht73~mE*O?oaq@qQsm?E%E=gIS*$;P$xnoC13{|mbzXOt~4gT;lI}*$1NwIu* zBA;(w%gZVv;OmL(Cjuu-j__X3d zXm7T|l8W7wd*L81yc&U`V*-3lSkB!Ft9WKl5-%3KCF98{shuF2X>4+p8> zs$~ff@Q-JKJ3GX(EkSrFAza)SX3Zau_2$NN_rYa)U!3c=2ke%9q~qm^@Z~@|lwX`m z^7CqVo%dyaxosQGerf?NGCE)&Z;nYPhoV`B8_HQK(y{z;xbWE>vgvn({-pk(P}3|p z;5djZ-ruB?r{95K^KTztJYbUc06eSFic?Ldf%>W2l>K%suPz(LJqHgZ`zA-8yuqo~ zrRpKfo3)X5$c0erk9wMPSq?XThy;xrGigLa0Q$A3i)vP7aP^NrUmBf3sadh&$r??x z3fc~Ri==39pIuP(^NUciRf{e+5>LJ=!zZUEk^PM|sFJk?dY(1M`e)~0+=NugFcTRU zn?uX#&UiaqKTP1Ai{`@Gq$(=@Zw)6sTrY9&4xp_uk7!NwC|s(OFHEUE29@zUNlUF; z@KKNhed#W`bn}!Xf0-Q1H79e_$;YsJv@JMoAAqyIyOPhm9%vq5j0d80$^Y;m3^Q+| z$i;)od0Y5GU8y>SaoZu$#3Z>ICOvf|p* zFQ01{W{LFS38M3`TjUF)5ri zBMmct&gb*fKf;NRCiGtrpza?n9KO(D-rV|c}&m*kURDpbgw zgMn@{$i?I<<(n3>^9CnyIlB*Hx9z}!rFSGc>B-<0wFAC-MbosjSuD5B1{EVCC~2G} z=v(yUh4!}aQZEWe4wvEX{Exzs1S?AqbK0|`L29W zO`4yd8jj!Wiba`cPQLmw=M396|>aORVdY@(OTa}Q*r&ntC4pIIc%>+8m+KNzBUVInLa zkwJ2&>TBiREvHNVIh1sA72nX?3aQVE!FZTG7G7QjAw#2TC0BdkIz27g`uU|~)~I}n znpejoJk?pOTL&(Q@;LSTYsk9yqPDFXalyayaE`kSk2F&FervfHmXqVOu(P$i)Qp}TD9l5|I5Z?aWg3ILwqIpd+q?~odsHI8bC*cF-yi~{KRVf^{$e1%b zTEr_Of@;mr&P5CJ=j5vpjkjiws9AGR5#pxlW7)h!+`r+VFuu4&Vtd7jlZ7zqTRf2C zb?kYJ_ey>^V;Z%8)ZmR^Ye#34HsU1}T21 zq<}%0pcwHMrtTlii3LhHQl=Lw53B?GPbc_w(@a4+z?s#GEYU34oYT}_2z~C1!-T!c zXtC)8mhIh#CvC^k0Tn|oKfayq&$N;2&n&X_&w$zCm9S_>5$5%{MpBPXh|R)CcK`hd zuB>@L3fDaOPT4y8>k}`A^m|JKeW#-k-v+x3>c#hMuc$-u27PkZLxtxXD8|(n)5seZ zrX2$VQ?-BIF_3~e2+^= z)bQnJEd!OLlTK{YUeeV(QAXQv{36}}(tl=sE0YYf>DMq|q5T*!W= zLN|7-;dNW(>2&So+VZw02n<~*ENjdod$(^8FSSFcbyJ7dSz7pF(ovyhm=)S2rBHY8 zcyXxrLYnbs29;d+Q|oSAO>drN;XVr#|5x1sl;+?hecy-lpAmJpAwi!f;Z;R+q@LTfzJC^G!PgABz0EgUO$BXSs zv3pZBzG{=B$2Uu8BG zh-c;dvbmKEtKQS0J5sm#*v~M^@BatHzYB46Ul;Hie1WF@oPzSk>e&BkCQJ5}aA?;o zYWlkxOV-?gJogV&HQ5d9uJ1+b+{rKD_eJQAq!?6119Z#AllK!26${Pq)bf(+MGzxcnDAtXN9V8$9WwS{YgHnTW@G zmeBX`2H>lv{Bux)aAds=Rg9M7v5o0eRd$KgbA2G;awlx>RH?hLs}zim#fz5u<(QZ= zi`~vvQk}Ludf^7lbY*^DJsSS4A41yKVwBf&$=4IRcV!uI3*peX`9`X z?-ifnMDty!<0M0+_u?TGJg(S zo~qA|Z+r9Kt#gEJ$Cp!n+cbWiRD>5puJXD2=GaS0o?o`Qlh3%N9qffB!>;b`GbuMgu-$aW0mH703tFh>VA!I7u0qG$VQMP*; zwRx8aJ-sIIYAb7D8T=#z%kz};ZK0r5e-?U*N}TQ6MKiT3#mO8A8`dp{MT<0OrSdfN zF;F6-^jE^8O|voBBZ7S{Kch8qQha>=1Qfj9NZ!UCr)Y=eU?bHRCr&Uzf0;;jTItQs zlY8@P+1)r~T?|>SJOtB!%b;-91t$)X0pqR|SmTh3wJY=>!PA^0cBu0?{Q*2P{S16F z*JhnCXJ|h41q<@LQ9t_)Z4O*PD~+ZR?4AqHUZrtp-eWpGC7AI7!Scrz@>#Mlq)@BU!RpWq~-FV-0H~G}R234gF*k!wvQ}Uu|%)?~9 z+OL4c;CJF0bv3kj;EWTMYvAhKC$RZ#J+udm=2XSU|JL$~X4+Sv-mPWq^s_hI{+DmQ z*1BBX?IbF;Ke(dOj4BN%dCq+wX$J-$&Fhw7iU zaQT~y5S~4d)7MFZQo1L;X!}I>ce>)BXJP1Z@jq&|52K3w2wJG2i*L}Dhjf^-L}La# zj?2N~1uv=jk`lTVbVw90Na2?LM@VK#B!8O_BS?m6izhbC=9anhxwUs4n|AKN+)>%$ z#|%f*T&_-QORX_$o(WFL160V*6`Ye)(AVq=Ro?t9tS+BNQ-`XPe0(P<_qAomxwhPG z5DRv)v#HO#&GFu5HCC%hfcF@ z(fw=Q|NOJBpziSjq)w%P@rXSfSmY1kx+8Iayd3Wt=E|2Qr--@_c7ut6su=gR2Uow( z5)MVU<1}Z0AEkq#Tz)<)|GS@&bNy(wr3p?wmquelRK=x(^l*JZ6$V$gc=ak2lqGjt$n5dX;a!rAvL$*JHz zHo=s(~8V7VMO#zRY8oXJUOe;VIi!F=jbkD{7>!<89LjRQWFU2HW?3oO0F)n!cZ7<%r?h^TK zJ13N^mgZ4YM!@MsugUvuI)1p5fwfvTILD`pveyOE%T5=%5GmnN`EFda(}p!>o5M_F zZw?r9TX=LOjg(*ChlAI(up~u>nsib?{g?;IzaNO-RnDX0yJq2eW)*v10O97?cw}szlGr8npG@i z>}<9fx-8P!!7`IB7e!G8oP)`!xgh27Y213VSnR2PkY;Bbg}YA;L5y!@kHEY1tAE_M z{xj>q`OFwGaQqBm?5dc5E}eyWfjUBL^*~zO`zs|FeFynn`<>;r)OhD^OHQ6P35uj5 zNF!)AhD|L11({aR@m67r0VVWf&v|jQycQ4Em56yG4q+s;3OgEd;Nvn+u3Xm};urgh z#Y$;(wCap_;9&&4xMC~nebRvEk3%_o>SVYc-1{GkAHWoUPcg)7Cdm(ASnIo=Ep_hE zVSj6!xS|32jq-$bv+siK^CCF7R1u7ANAldL^;lHDfrd1>gZi62qQ|IJlKjxBS_?}T zo-c$6`LGfG79MA{$trkrpab6A+85v4dL-zq_({f!nwYb59RGQ7p3;&V&`2i)emqR2 z{ue?yCA^cIum((5_T=W23*rf@G*NExA$pmSkEdE=(ek+>W^QR9jazP1_&AV){X%%Z z+7LdX7{XqzL-_r_9Q;qN8y>Idi}T;Dp~!R%-1I(2cyl6KH0!kq-&7m{DYL`X!xs!= zOjM%kkW*xvXFwjiCXl_uEm%Ec9rk|X2>XI{@brv#RPs|9+=nL%d|HV=FFHs0-KAs} zFpv#i?1o3DhC^G+LYT9)k~|6{XoE`oVC3CI&V4)|R~ovDzmM2pkNjcWR&+%CT&s(>-Yyq+neT(Y zE0^N#KS#uoW#*vqt(r^}%D}DlHeIcIK$nLcCB>m4zCP{D6`t*+qUgYl#bp%L-2@5# zyBLSsVn)pvnCDYLy9}T3i{4&1(Q`0e`H_Pk=68t7KjYw)qZt;=3gS@TTAZz&B7Qk? zm<;ah;%#RQ#hJg9;L6FHG*$bo#8*RvK2hlya?KLX&C$0X07;b zfF{jo-pSSu`h5FSCRl_R@uf9-c+&b3nNQe+x#^OB4p$E57ACCRA`R=@M+<9L%Tb+j z0sPtQAxIfiLYG_`EV>p3Q|*=cqhu>R`J5``KKNDhI4GFcxHHCNPQnTea@?uxSwbDeT(VZ#0=;7adXkW$`PuxibdI~voJSl z3>IBbsJnCg9rV=r*U@k7#aAn;==l&+etvHdZu)C095*VVQ(o?D_v9MH#aKi2h89RI z-%FE9e8B4QEf{>EpZIL?7^*Pph72bkeDQJ#D0Ds*``aF)&M5-9SuLk~&l731T_z+c z>+atWg%0)p0^eRsVcFyhqWM-5qBiT}teh;|T+}X#Bl_Z}Wq$0s`QLmdcF_IX z8|d<-Z}9D5IE^by29rCwSRA~CCp)c&oC&6!ZKHPC`Ya`su!O(^yEpqcG9}lYE<^qj=j8B zq0g3SFy_)eXleNiKec+{w+)fP*86Ef!WDHc`Z<#-|C3@(n=bKh(_As@S{z=C---_| z=YyqO6sNC};^d+|wDjRA@qw8&&l|UlF!Kn%ZY^TVKJKJeIRcyu^&x3zBJ2$F!j73k zP+{34kTV^GLF|BYqe^McHa(IFDxm81J0$9icRUl_w)8(YTi0wWm*c4 zC_66Lj=2moKAs|lzAIRww*=$gBtk&{^<2K}Ae~(vPNjMOJZ|fAx^8t`c&r_Un+=vS zcrYzGb(h-Pr($!Pf-q2h27cbAjA`}#F|ay}J}=I}HKP=1xWQVK*51K4TGHUW)gN(~ zWh3=|kl-waEZ}vA^7ygkW^`+D=V^`_s5@hi*!z%|I5MIguJ0Jk1|v1m`u1{cij1Rp z{nwJ{|Gp3>p9SUCOVE}SNpfKZke2<0ww)JA{ogNG#w7|_tcnvT<1(foyIZZ!fE&))_OV@n!yeLU)o2*L6Q>AG9zUINM_ zI|q(ki~Y5BgV}Wlw%V~9FV>%?DbqDMC@Gd#**p+N8Mi_FQcXB%*a)rj9O1}kXPo6U zgmqOjILo4etRD5inYYYwcX_8Upxcb4Vr_8ofyYod*$_6L9)h`f#Z)X-)0u*ubXFJx z1CoZ}>HZ$v_H#G9lvzfvG)~jm-?^wV?-*~Lrj5_amhiEt>F^{YnhXnD=^}>Wws%o5 z>wX(a>@(oJi46BkwSfTHTXYL6Bv+rez?Z@!1b+{~UcX{oY;J_(r)Xf>&s|)NN6B~7 z0pYxV4ZRQD&kO$~QBq4Rz3-~!P_n7L;d}xLRwu&69uJ{ZO%$^lyim_#80vYIV#n-2 zTC?1M{rVbm<9S1Tm_8Mh9-Hv6tSs7<(?DhB-W)zx3Oub{u=g@m92M6nEKZaoN4MW# z+1MboW|rdiThsVZY#VJlG?J~&+M%gp3aY6sBSzx~TK@6`!ET$4L-v zvL9V+zKMq?Mq>SGb1oX4C&nG!$haB#!_Nbfc&YmWG+#s&D=%31w}^~Kd2(oBEamik zB3WN`hX!RD!^(F?*zbKDFFM}?O=r|l*ER&RSux_ubJnIqCQ$D#d{}8VA@z??z{Fog^xc@UOpS>?DjTvzE>|CE*^yD?9Jszi^y@^ z30k^oF8?zA0abc4`P0FXXl&J+HC^;EI67Jw9;5=BI}^kXb6eOj^*6+)YxDL957 z4yVlRi7j2mEb}Br6nbtILLB8t@zhlIv-RVhY6Wo8r439w?eNr$zQW?6H|Y7GA}H>= zj4tW#gw^H8M48ae2oV81aKMd`|Gk$9G$(C|>`uB`*bCxpKsB?bU~}5p+RsX%IP0Dt7cNnt`8%GHQ+=}-o^p#8 zrcU5?We+sb>&36~W3jrYGxzkJ3F-0*?6P()O%J*Sy|fR}u^JmJ+oS1HnVAg!!Sd{| zr<9wr#!*sHD(E&w@Y5xJ@M?e!`spg;fib4M`QSnd*Ye}))NCkhmFHsHLg8S@aIBtw z3x8V;K-sM+Ps+J^q7wkZFhMchV8>>T{6 zRyi-J_FTqIihu9V3guxu@ccBqG(ib>J+Z=?4r_5sn+$RO2>h09!fEafJbzv$9W>Ek zwc~Tp!fu=R*Un0^@4FTEDe;Bt=G~C}piA(YeH)EZrCs*eL||aPA_&^P{43;{828SD zKW8uC32(dU^@k1Ucgm7)-q+!K$9I9xpxzjMQ45Eyi(uso^^g~*M-#`~5R_WGxpd4R zBpwJ(*T&(kih4-zSV0{cBkmq-k4EcH37>Q7+3#vB#jH^RzZcsuX>l^`)7e4i zwH^sCU5jatjts{QO~V)?*IL(vKG^4qE>Ew!3>gT9Vr3U#>X9m2{bv^88ZxD@tIPj?< zGw_#`H(q{B;IRNPK+eDXiP*Vf9T$JvE0&M!CZ7?eJSS#1_SUiB(u;v~GFO9Rn)eC2 zT;7TX+ZK|`U1Q80QV&%J!?&BdiB7vjTVh@nw7Y@M6LQ|GNF8`a;UP4Z&wn$?5tdq-l+DP!<+UBpMeX7J{` zdxAyhXi2S1Z#*@nm9CeVpns-0I#+bnOkUptyR9Z-g4S1YP-u!csbmgcon;0ia(|Kg zcr6-yF-r2N@CV%Ut>J9dgOdLuG-=K}KWv8z@QVtk71Ot&T3{ZXSd@(?#|B|at_fe7 zv67|wCrT#04Ex-m`SEWa)Ue7;_Q=x2W^dM+3Ra(iKz7 zHo(plRYH{#uGz4Q-i?+MzG$nV^TkNwlp(Z5XCJ2fdSTMUZ&+JmhnM!fCfOHRd}_5b zrPwZod-JL(SY3xRHX8^z2U7UZdUgJ)Vubs12cUCDFr=m4qh0e&(DLq3-1)YWieHb! zv_1~}<8c&@qouqm-m!N7LMv9a9zr!+R^TxGy_6G|#_#j1N!QgUi9)Wb@iahl=zXIQHR^;3% zrWoNhg5_8JC*<^rpsfypw8+W;b!?7NqSjF?tkdGJ=he{EXBS$j34)Szt3po#&P&gR|;dshQXA!XmLsZSnTtyhAZ!HWRHp~!WYG3 za8R!WUKmAEd(cL-_wI*Hwd#UFgTMzO4r7MbGjXW3GDh3UbKC|wtO{%w^aEUY$ta{# znalZ0NHZMLwxTs^^Wd{jJw4gcB6xaFN5^&<3JJ@TM6x@d(4N4qPWtHVcol9=ajPBe zvw-{G)x!hH0oYk`gzUHFL4v{__Sf^Jw-N*1B4q`pb5d&)yi;ngE?J0;4i}+7w}6&- z#B;!%!CYH+2j;Gn#SeWNVVrdiy>RG>jqfIdbi#4?z3UoLfd_p5c9^OzsN;g-_rjoh zV|w1T4hq_Q$;sm#@2$JeIZ68|@nE+wuqg}vTsu$mZ|CDs(GYLkJp!E@gW;=D4jK%f z3NC(Su<5ELKP&K{J9BEtPeG20{r#z{T?wylzkx3gY!_!+1bXStY{V_#%Kc-$+cHX|X9hX-z4o_8Q z@jvU@t=FZQvx;EM=b1cbhBarXJmxg7Sn#Rw6T42mfgjd-?0WwvP5kc=b_GO2wO=a5 z^?L#XiVx#{TuVLMwW#2-Gs_!hQq}cNk}g!{d*V%K3W-6brnf@OffDk&NMcU=3rhK( z4c!VZJmJk$7&N&GW~(Kjtkx0ajZz?^`GSmc3u(xPC3N789b0%T;3+PVqN+jxcT9dw zCNrG){3u(Lxpx6{@P$z5I|C|j%oe0yPQYh()Nxc@GXBae6_rZ7&moZ{DoL7DzG-TgY*`JXh!9d#LW?Lq z?{lcMm(tW!(ozzYe*OM?{&=qI8Rt3o{kpFwe101(nRyaybML{E<1b)VBqKGrFGX8=%K+Qrt<8O*dkGw#8Ne0fWvqEEa zOGqyJO;S$|(1N5m>bz{kH%m&$DJh$`MeY&i39{__Pz5i<_Jhb_E*SKC7y5tNFU~XU zMY^Vnd_}g7n^a`Uf19pvWle2RM|qg55B&!3_Qxh0CSF! zw^}3F_mcvfZYhe}8z&ljuV8w8oTTT@=G;rFP<&z<*e;lbe)8k7>*G5}J2wa9J9Sw# z!i?+QM8aN~(ID%tim#H+(a%$FA#>F}A^mwDn7L#f6~P*I*_g&AVNanlsuw0lti+0H z8CoKd!NqHS!KvAy7`$!@AIBQ#SiYEltyMU#|P==HjI^3Z+oUJC5kW{22 z&y`k0qnz&oXIi0E^mUkeb_5O!k-~kwOIX&i0&*z`-FC^tq2;gXOrRWLuPta}vs~2u zuZjG>*y70iWl*nIgBWMcf39qTmkohz^jjOQudbqxYmU&4$v_8wnQ>e|Jjb<_kgrsK zv|5fhQR@xdwY?{X7;J{eqlRPQu3~JN@lWfg=m@PL135&aQCxhcfo@&%;JxNjSgu+H zgH6A4!Z6^cJBna>LJT@<{T5@A_4&Y#!MG%OA-=kjz?*!P>Ew0Pp)z~K7 zm(Pd!qf284ZP~qx)UKFtTrVvwcG>}x9R7_ns~p1bjiyyov-m^3DZiUK2(5jZ;XrLR zoCtYK>xu&Kj7ci&_&kxS{Jd$kX%!2Zb`H&95!aiK%&Y@WQo~Y;WIyV;5^sy*r%G>1ETIN=u#?ei>A2 zmrGtfbmw`qm*S$$5h#V>+`DBo-t}9}#@<%&U|(Ol;aOi@m^%SoMp^OdWJjvfwH2$V ziObeHU`m%nEa|rjwNJFru`~XV`OpvdLmwVsJDI0#^F{9yUxd7RE4=r_OHBXAH>QJv z!1}l)yG=G^(fSyF$qxtnVHaT5m~1?)blsst{TEE50Yd(-q2zop7wRjf2UXjR*Ap1AE^!N$uoD3;(+B@Y!T^?&N(ls{bU#1+&-K; zGp-5A{o#THEwsZnVLx z!JS}{>&qMLjQPjadcn9|U5wFxF6@&!M$4n8VY2%goKkz5biffEpL+4wlmz%*_lbP` z^u>$Iv_QVXij~6S=wq$|%RIfrZXWU&l;=r9uEpZJ$)icV?KjM6y9;h(I?0-!gG@#2+7^W*2>=8*Ueho5w{Snw#f)`pC*Cp^e5DivrVu}=*d(q$4>DY z;2-qg4iqUoJia>EQ*` zV6ho)Px7LB<`ekW{7d5J^kulcC6qhs?!d&2&2+?A6arP9h2g;iI8$>H+72GiUz_RV+5-QuPS-zotRS=5lDSd=uUW zYvS7IaT3jxk!Uq(1O2)d#f~cvND`YDqIGEk)Q=KiZPi=Si&=!yj!%W(t9IgNy)wG6 z_81KMbdHpUzJc@)kI3kd8=t&49LoF55xf3&3p>`{WxGL2;(l9MI@V(d8e5IWu`524 zu0{}gE`3ANVk-BLjo_ z*ERXktQlyLJ(}#g2f~NZYiPrp#q53DlOy7KQ@D~d-gGH}pna~SdGRY<*#Y=z!h0xh z^`i|hmh$BXg>cSh0%srjmvgMvNz8+L!jigB;fZ4z%~h4hZIAmohNhi_K`ZZpS+g-; z*3c6}zRqP0-#wf^T8r$irV3>{o4E4r8ru3y3$4tf&@<>U4@P-4hBAG-zBBp>YhW{Q`+ zQ)%WucvAXkK&u8_BOCh)IHkIo?-sof+Lqgi5u+Ak{ULuCZfZ#10uRE7qYdz6VFmYC z=+3u$91${A-SGCcSeTzTiw``WfZ;Lf81g-fhQ{4Kz`hPPmC;!0eM?h&R0K*w=Q>!C!0o5QX39lY)>7wgZo(GeL1v~mmMgHf_DDYuyx>n38)=f8yo7X!OBM;#chA9B(rbHaB_461x&dJ zjqRr?!A}NVCW)f6^iIj@tdlq|SOv649fn>NzWl81h>#cEkH1_W&F$N?DMjjokbg25 zTb}esOVcBu@n;gbnZ6}|V<|o?C&d>6_lbMgI-~K2eEc5MhcgH56&v%naqF^|V#cyT z{J>}htvTKUxA$p;X}XoTquB=|w#5p8=d$>6SWmii@-F?DpDIZfc5;4&4p#kA;rEl5 zaC?I>+4b&?{oAZ?X0Z;xv3vz{a!a6Ec{vA9_UGBh1l*Hog9_n8;QjgMs;3$0dnT7qhlI@Md3CEDqAe=wY&~ozmN(pOFDR*#8Y)D>gvT zgvm7c)j;}Q{7$?V5<%rh|zoQCISwZmwDkZE-Uw!z2w7UE3k}%P67D zLS%=ob-egvDtep5VUMZD0 zL_ZV#vMrFjR&dhI*R*v9(8mT1(#nnC+n+S^~xO2iuQEP zdjczU+0bLj2m3x=-E_P5kGNjx3dB3#fYldbMTeFQe1GmWHJ^}B){|EhVSmY?@|O~B zA8Nu8gHqTy^Mly^^Cy@m_QiqSu?{C^&V?w2W;l2Avd|Hszz_D%LB}zwSn;BiWkySp z_1+g$J9`bTf8xT)1ld! zLfK%P`Fk8o=@vuuSVfdn6>$7lCzeDG6RQ8QR)ow)$jY_m_U%KlZH_)R*Pa2#vdyT! ztc^~_$#ciI(_*X5P|UM1#B+&9Y}|(%S_6K1E`o-6ObSGMCH5 zZ$iJ@3-HdhYg{7^M`~p9$NJTezdyst)ePu*=~msQpa(o&=&{4?xOz5x}4!; z$4`H%(Wwc8NY|(w;>IozW*bIe_Xh#fme)%BHNVoy+kI$iNP-YD?=6k~@s1ATDRD>G zHOd|x!Nqpcyrwl9JZ8Ru#E@i=w|OU+uLhjlktAeZS7vF!BksyZy`e!HNP09RRIODUcK2D3qzBh=I$cuq3fR=w8|;#10*df84`x;?CVX z3T?Co17j_I^V+q_OVragomW$p1qW1Eul6vQsqia!)+ic#=bO1L>YR6ISa zT!M2Ncz^XLxIR4*wmPgqpYcqt;ySE4H9X}46N?U6la|VCA(=9&lI~5L{ zR>c1Q8H(Sct0?(TG-@~=P|zGvm0ruQhufiU%>eNc7Jy zrp{62lHRw6VXNOL;qR6c5Mb-aFHEn|-|>%ycaQ-u$EJat)dRX-@D83mU4r^KhuA-s zs7~b+{W!W6^!Lc(&S&McsZPND@1Hx!PoBuRQe$w}yGg>z;f>&Zrw0XizL2cHpn%_^ zf0K=2q7a~8LqU1t+00Cz*SML$mP3!hRCBbbefp~)zu^M>8sUpa_VuaN&>4nWslCL6 z6Imz;)MkAHPm-JBhjTuC7jJJc#L1p2yg*|lZqrx=AL1OKbhR-x6$H?|@$|E({}XhiW14{yE_k^?V$ErE^R*M<8h9zc#N;z&OybeB1ZrGMi1 zqP8pjN}WjFb$+%pqOEbvXF78{FF_~-E1e;joQ{``~^7VjO+q18v=!`c(1 zAMVCIUMTYxrzv9Xf({sY_b)AbB~K0eqX=_MV8qD1%qBr@*GO^rh!Whf@?TEz$;3+Nq}FBHJkb3U-4LsVx||~M^+h*+9F_~) zVH0ZK+U)Q)*q?vB@!?Ge?!ft$L1>*Yk-tW!legR`T-zqXMBO9k-JS%kXLUKx*o}QJ z)KH9hFqCdNMnOisplepE5bi&ir}g~IKklbOq5W;xQalS4q71npG9DsxN?}6S7vV^H zDSPXMLTP{o&#{+BkF`bAHTo-rey~8F*TurhAc0!ftD{*<9%xH<{q6Kvs9M`j;f=?aqCb!7RRla1$V!0Ky|atv^;hcF42_bUzzi%-C_z~y>kPa?bi$2QeKOewl=72 zv6Mb+iQ<8E>p1-7d|_S7EKL6YOFSUV3bf1d#9 zAA?yU%%Eq+|MEhI9ooHlBQ7b|7fVA_aJ91^nw2jG*O7gBmE%^tZXHVsJ~t)XwSeos zKN4TMn_`^#EvmD!!=*73xawqhO`vm|*n8n#*!aPS_CzA9nLLF#E*el10@cCyrg4k; zE}`(ctFXfN4rp)g&*xvN(yhJP=)CqU+-oyN<5gAkcEklYlvwiLj7fqQHX>M7cTd$YMY*G%GTKHSbbL^~_+-I$gj{sjXz; z`x6R!eS(`2&uCG=0hm$n9|mOU;Bl8!dS_S0L0Vp{rX&X!<^ICj$+?m^t4$911%R{n z2pE>~4&MA4Lus8eIXAf{%N$oC9NHxGS@TFR&SBwD(ifQWd>H&5au#hP!$Bxg5+`hQ z<$~oyKw7elHchxf*%BqzOE|?PUA275(Vy*ixzNX*ZBW#w69O8x;A{m?G!2(PgyvoR zIoXgj{1lcf`dZ|{l9<;NmDWhTy^_Ick37e8 zn)B|U3Ap^8JkGtY&!w-PfL*4@{x?H$#P?v-&FPF)UTkCW@**?+s?#fc6o_%;_W&_Qk^glE3((8u=%C>(5&96h-V zcW*Ug&A>e3#qHvNdsT3BLO;~FJA`K(919EN-0kOepXFl(A<)-wrSM|h1&BZQ1`d82 zN!OKUW6CFGp5AYg*saqKD|$#o%^yX4L;Z-bugi#z-wHvUyXM@yqZ&4vEr+Z?Y1Zu* z;BakhHJ1Ank>#A3P@!$fXFG@C+{d$M{je^ou(HIn8H`m2PdTi4{)S9HB5&R+foDga zQbgT$Ua`2F#+n{u<-}CqmRN^H4*LYJ!>0tFtx6nfVTI>T-KBu4l^pl#HOPcJWBiAysCjo3 zd+YqmoLeVS@?Iq|H1ij=P8`IBGd4n8*L0SB)eCpM&=xyx1LoyS6C-LS3;T`wL3ddx z`OG~=s8z@opZ7vqnlt3iB{)7!23NHA7H-WD@L{nAS8rH_QxZkgjM`21JywXbOas`x zJd7Mp4QAWw;e2AfD!zC4!L~y+xhS~;$Ym{N%AOLx=%fo$E6i|OrUdLiJ)pRu`LJW- zS#W+;!sT!5g^0i-5b)$bR98AcLn``n{?%M~<(0>Y9tK>$Y^qS}YKn<+?zp@7hp=Vu zczn}sNKbqEQo>734i88o`L$8_>{SG;>?_9`KaXVLh&%K@FW{KIQKU6)1&8lG$5-?| z!}xeF{5jMM@A>#q$ERh&m?M30nN|VZczqZ*YD-g1;CNx3(m(G0^B#8n+U*b;Cd-Fx z*U`e$uf*)uhl0{MJFM`Ui(9I`IoLgx<+{*Il$-roawp~lSr=OKo%agDZ;r!Ai>Wl- z*Tw$WSyw6^tAiRZeMFCPM=t0)l{(y_P^aQJkC!tQF0~C6HyT_7^K}Qr&yn+a!w(Bo z$-OId?-U&zubcCt69ugM>55o1cPI`YdKE58?h55bgT*ny8&G~)Jp|Vcf#H|;uz{E% zJ}fyXe*Zodi;hH*!<&)R)*KHfzfQ(o*J5$`xaVMeCYS6>jCpgw5T5e)DXrPkLDM6p zar4DpT>eA@%|>6~bzL6N9U3U?J?V=NT)H67dm!H#QUG`BHn5NR89wJ<09*c^h3KuT zz$e^^=bosB3bjB?`s0eZ`GM?N_J$gtMB|utb$s}{KbjfI3xlk>pl-A@h^ij^>*P*a zcet8X%D$olbw<$tMh(b(Jp~gMq&e&;+YCm7Owif4MU+%JqlbS4<~(hK{3ZXG#j1!h ziW;f;rWXHLHJ%rboyXY)5!jsbA3s|@2DR$isnDaI8jbo24~lB2vuQOpayiC1nX>Ea ze!OSpX5MT+o$5MSm@)fb-IQnIYrG9yZ;ll$Q{aKsY5Y4`kN3{Wra66_VlE_ zmx8dkj~_pLTMTdf)H!ll6}--wPA9pQ;x&}<+`^N>*qxbJ6nsSRhlgTeaXLT!{7mw* zS&`k%|I*r*gXqZLGO?upCiH3S341D6(NE)RH2mluQhZYfMe~~|cJKGA} z@_sFiiMIof8CTeZq-faZjd<;$E+r^MV(E%bK6Pd|+m136Rd*F*^2LTy`wredatZ59IY-tfqlIbbyvbx~07s{) zilN%4xqWdS7=6kVevM5;{g=ae{L4f*a5oSBoR@&9$ppzZD>uq@yN>P${OJ3qCy@8| z6lGQg3n!YoMDsa&`Q*(QZaAMRmL&fm!?Y0?^+}Z!f|W3T%mbKw$Qh#M%Yy%tc@*2Y z3W7Fm;vf4`!1Q;xWI)+9Ft9bFiO-LaZjB8N+J7BJH|k-TNfZuCKPuXG{h*It9$b@r zjc%YLU9K#k9%n9zT_fJH`}ht>{_m~5s{I|1ELhGzyRQn{3-)2)vt2Mf{SJj)oCH~2 zsc4zl108mzk@S@tG-BOA`kH!2*uHrp$MvegEUP)tJWXqTFxK72GllG4Xy{>q!TVfz=f00W6?VOI8%j@B*^ANE4 z-WN}Oj~2T(OvCiH^LWO!lE7^UDLP*#$HsdQ{CpDY+HYd1{7QUbrwCcYL-Drj2`*_W zrNvh|so(2(LFrGbea(YLI@)IuURXE*>vERj?ZQPo{9_S)>sI0n-8fk4m`yL|$?}?$ zRq$b4hu_j{*eJZ>_!;2$O{>}o%`f`p6cr0o(go=+w55!9f zeQ08S08X82h-XW7!8YMFT2)VG3)v=#&4DSrHRm<#9;JjG+Z$+Ao&wmPapBVTK(^Pl zq31`{*}`2NZ}4%@Rf`pUr#=;Wm*q@Kay7;vwVfoSPeiGq$#8Q1Wy#zSDSmY*!C{57 zA|6;^!P|Omr5COX&|_N+Ech6J+jg(z6<^+yqIR=zBsg7AO%WW5zd3STVIBTFD}~2= zhlq#U$Fj!52lhj&eT7Q{d|3WqPo6R7o49joA@3E3(j2c*xV>EpsofS6n)O)j$1sfh z;K^%C)VX2sOw3E|<+$9!8NY1OLXrhU31Zz9_#wnx{P0`FAcS4rp$Jx%w4iS;lCI=iHlsx(gwHFDT69`xW}wtKWB6nZ6P+t~ct9v%_IlJA@hC z)hN9^0W}up;h9rAXwEo+PtOV@Gz;c0lT_LAtpcBN*-67PWBF8l7SBj>6;fv0giD7A zLY~LjkL_~8^EYI0wFsPIa$A(%C5^drM3C9_L9~Nx`no9$gtJ-Vlrt|JMn`7B&U$%l z(2wQF8f7rDe_QQ&N(s{sd(*}$4IbQi67DR@p|L|kaq*of9D=c6YEeL)NsC$PmI8@Y zz4_{k1S*OyhMik8@qJSzT>EsGKBYY+{|H^)e4-HEb=&gCwfSP_=1ZuidPImiP)pN3 zZs(Vo`H~jP-!QeQipqBMVeN9Jf_W0WXSECRdg*~;#yc_P#3&x9HdZKF@6G$R{)GI@ z3h~Rkd@*NBC73CA^UT7R!sOrSBowBDw)ob;epeuMU9AGeZI!~6;eYYm_zYA&p^OK9 z_^^KT2wtbSgspO?@K4i7F{!$azN!Q=`<+DTpRzPL_6vOT7|Kr_mf-r59iXmeOrO8{ z(twqwc=x<44^2M}@we~O1#E!nA#1DE3MW#ovXn5+z>p=Q6Ywm}!;zyU@L+@o+xb~? zL6IHhD@V|{acik!cMO}3&}ZN2$Aq+1L7?bh1vxQN=<-4p6ZX6Ug>pSMb*kY9?)%VW z`zlCv(ZYda=YgTgM9I*>&Y14En|p7cPdlBSqp0)*_I%Nq;XLhjf+ssJ%`PN4NKqBqmpa&!u^|2Y`-6mXXFY~DB_kY8rE39@(R^X20zkazJd;qf|{ucRjESj=H5SG5|? zt6OM$Pd7NXaWL5y2q5#h?>~*dM9bc~qWQeNV&_&%m>v~HQty(5u8KE8Qc4${y3?EF zUZuio~*~jx!ws7}9`K`axA7>bcLsE?a{wY&M?Z2Uz5@sx3uTP^=({@tYZY{<& z?11T;%(#APyP)K$AkLnZ#vf_|vDs7>mF;_C%;OBwsC@=clg!be@iu*Ow__98DBRoU z7p%yr5QS$6yuRYOP_=0eDPJGM9lHwXg9^b)e{0sRlyWrw`kr;~{(@zfW4X899JJgp zkQQY6i9d#(hffdf*+1kUpLzeUmmfWVt+(F7o#7A3YiSl-%{E1qT7QnsiowSbmh9Bq zlSnp3W4K`V<2L#KOu$zo4Pd+a2Usw&A4+_zIJ&DZ+g4)ZH8t7y93r-b zvRkMescpZ`SH6#erHS&KqAZ2Kt%Af`&DWvwNieRkljRvJ?$VOLAQs++qjhFD_yY%GH=+=6!(Ww~NF8uXn;e^GbMBRsgbkJ3(vn8+@Go6pSxd`%RSFpTcJyxxWr)O=3bm8m}nk03hLA>=D@b@i+fp484^}7UyCc5Gbw>VmO*%>`w)Z^mjL!9sZ zjZP>%B?FT+ICHo(#ivK};q?W=SdA>9tG5N`ep$#m&lAC>A3>*%I`zM1N#gl$!U?5y zxazqf94U>$^Hztr&-Sy>yyZUqSmc6xDw?QylnPHbyavbHoN40#KTvD5#ve{M=ymgF z2e}QI^xJ9xwx(A*cnx?&s$NB$=Nbyd6|$%}W-caQ@5N8nBi~jo|xv!&oA}Cscxmb zJ|&FX+~v5KOJL9}8!__25qNZIEXpey;a#sCJ0uJeH_D-gw>4T$9e_bw zYX!}yFj{=NKUw=*@snFl!sTagC@=pLebADrJqwx+hu!jFd5H!}71qJb9q)z5Ba?BA z;kJJ{Z5V!E7m2wl{V=U(h4?nqfM>QTarszPK0M<(?KQTeGLYL_dlWYbUKJFBgv@K3}vK?__LWMPSg+NjnPlQY@9b&mHmY-_t99c7z&3~l+f+J zWKL8!!QV3VRC{p}POu-u3*4k}QQq-?o|_~&d^cZE`PfZUCdI<*qepS&cMbR!C!tjn z+&4u{U zznBk>$q+5OWcbgzC@|SzCThQ)z+Ym6u(zaNjn|KC+`8{Md_HQ(Tdnr9Qob$y_pDm@ zy{=L;Q20n*Ngg=DZ3JkZyNKS$Ceh}06IwK^4;vko#Q{?yMVm}TwoU6nt%W0mjNjo{ zw(j2^-WO45M=GT&>(k$a4A8v#hX#+@4YuAp`F{5inhJ{KS6l^0BL{%;tT@4MrU~Bb znJwzRkRzuRm$`7xU(i}PgjdhH1vb+T(TC0L5a&A@SN`oo3*JkUet{`3j8R30aXI)s zH4;h(B+$~KQ+YuBdZF^lUWy#~AB|GA<64(eRGt+^W0!t|orlNs>K6&1IG|dR+|Z8= zBxA__$5f8ZuoG8%?1xAHsp7zz;X+egl(_#>Ib7>EK!^_u6`d<*am&6{99w^wOE24D zMdEn;?y?=F9(2IqQEt%l`54KyRkLWuxx=jXy_B-MA4#-Z_ra3ylc@T75v-p&4#%D> zgdx>Mcq1$Wmi)YkcNb3K+w=cYq3$G(eWTzIq5K|P>ufmU#}2UCaf08463kDJhvZ3? z`1_h=&9tIy@~N1GvQ{$O-D@Yd&#YuAozZCa){_^FcE^V2$7uJ8xx$Q<9{-qrD1S~k zhI4k>p@CT-zfHYLH{NKm80&*Bhy3{a*;hiuRA;~o;XG@EAzFGr6j?Y~8XV@Hc6 zMTfX>&q4r&B2rU30+osq;nAf+kPaD%Jv8UzZR0BbaCj3M48K8njWckc`EjxFbOe1F z)f<=gn94`Bnjmfcd=9%5%{s+b$-HACJh;CEb1r8%48a+w*}nmv)}-;KOFFftJs)r% zqj=b$EyAmk2`DTbgyuI2aHZ2`oM3$&^zMgZ&(#^MxPBOHXiz2cM2x<9h7{!f`5L|k zvsXt^ZcsQZ9(f98&RM}~7c+!Z_s2s0H+_cR$~^l_G`;D&gSjdm-`y|d@nar=*570F zQa2uFOdgDt2?qQna;mspZ2)fS^#rp1E5?GumZY(|P*m?>$*Ql_dCU6ywQg?|)IlMMWH_I1Or#y`gR0D&nk5M%ZsHpv8#U^!R!=ZHulYx~@d` zn^utW%3^xEzYo?PD@I6sj+@d&f{!~{V)pGW!=Fir!JFHkS|L{4d#z?Tj-hNN-)t3 zp#`2}u;bA=@tWfU-0o0LrURFP;iCwa8YOEVcQ%tIohc>jKek|S$xh6wnukUHqxqee z33;6Jr^LXG*b!lh)!p%=6J7>CZFjTVo!%&!)dlzGjljW!d`M%|An@HHhZwqscI~=P zqgMYU%L_W#nKJ-u4mH7G6KnpgR|zG%OJPV%54d&Clcis6hAv58y1Ju=uU3bWU5+}; zGhU6y|Jx(U-q=8<`+tB?J5qQ#bq6=xi^i^^265=izwlKjo+{t$6=r$q;H2%yBYTJ7 zh=p!7W{qc|B3P3@z7j}i_9h?Mo75q*1mr(wQD>|ZtvowfkcnT!tLIG@1J>lz@-$gg znUXFvJhuY-ZzsU{W&&v~i=lOAmST`*PjakU2q!Z(@Z86q=%V#exN5PO4m^#5136vr zuBQdM$L^uR5rtG5o^wV<@uaRE`+MUYyWZh42_Kb(b2s3snh=iQ$cS*7J zExmb>C`_4|$vdj0@q(cu%i=WbUf7#z9O^*sT{C=ERbszIk(f2!pUz(1im$s9#fjbq zG-TX(KL36gm&Arc{q@E4)F7RW9_EQP7e7;ufg)CC9fkdgH$;QJgD`EoBG1(Q37$$5 zDgNqOxN)nLTcoOKTf|KJ5pP(ZI{J z025kLFvILH&7Ja-a`Xmr@Z9f^_051Yp0`qR%?&DVs}N;`Y|Q!LOw#e|z$thTUzqY0 zsw@mhNqRWP4cN>#$A$32q%+|7Ee!VC4aBgEIS{$l6(hxYAZan+`y0CGZK*qdoqUtG z4Cs&LQs?N7lM*(MJ|sFF4M*eqHn^-Hh&^@~GmIF=&5IpSkXQ=dUKZ%`>^sr;C@7nGj5ZsK@t|e zzgN@zeF@OXqxeN*iRkSq3xm==QAD!~yjt**JQ99E@BN3_{&zH%XABk1cUWLeV<;Ou z)aHSix4^MPqKnwcrF$FqC(B-J^aPacEWV ziiY+XkaTJmuRoMTcdXuvJM)!zb&V0*Iy{A!r5pJ0gM9WHQReXGqyo;-aEFHlEi@@G z8_pctjMH{*$M3t&u;2MZsF5GVJM(nV+-DT0y>%7#;{>dJnnmB|`qLz%VC*AFf_;NF z;gtz0{GX??7~NN&x28Jr&j?NK?v%pzf81v~^%11CT&#I%HA$5 zO>Rbrm1|dErClaD4;_pHqtvOmcn^dxs|T+$r=Z8zR8Y^6qc3|`2qVk_Yxe5=q1?&d za7pGBZ8bFkdE){qACU*YH%N&m)v=}i0?OP z(r5E^(Engxwmtt8WcNDpZ8r-(xpfZR@A(x*EByeuhAwa`&_k2-42XTHO2?%G`RtlJ zB)eEz9z2CQER=cpO&>vsSch)q+N>VrB?QbL$@`3$6$U;fiwBx`+G9Ni_zp*>%JHz% zYBIh|i=)@af6)`3fHJD3_|6P4K^z63t*;9KQDK1TPKa17&8PPg;{83)sL)FHPn;p?z8$pO zzy&XKZ(!%(^Mz(1vxIh?G>Bi<3wyO_bBp(?8mSq5xzCEglj-#%YHwjv}pb?4~!zUD;%O2IlT)5Dyq<^O9ln z*;wZ>xU^5lcfTi5@8CaF^2rHbPnd^MJuAo~Dv++#NT^Ss362=4CAe#JkW`XawSDJK z`0!{CKklK!b;qJ`r1>@s9(v!tbwdx13+;56+SUOB2Dej^_e?(fWeWFwrU*T@Jq5Qv z`iN4yiFck5&Pcw2<&yohN%t`=s*L0Mn*zHQRe|w_aQq(73v8x81h1xE;+)%&aB5Hk z=`83aw9z5aMIjYrPW==&&eMWlFRI{7fi+yOZ4%-R+=E?uq4;!a8m?BGMZcqs_|wv2 z%3ItfL?oRjE%ntbrx8t)dkjIj5BV(7`9V@z-IV!qB<|a2fa}LEp_rU#%c>ZdY<6Cf)oKPm=NX9GBNJif4MhxWox=~6l4_pX?!t-+72&L29b8K_;ssGA z_{;qg4O^znqw-_1F!T;yG1){~vE#VnN*K#Nn=Y9C8AgsG~L7cYNqiY==m zXv?$}3p!J(=^P<_V$R>a3P62e~hN;gzzj zkox&MSornF(KANkX7wuC+bu_NXRBysqZVw;&ZQ8VL|1;Df+hKL@l{|vt;`-#dvoA; zzVXyT7!g;5(Q6d3B>f~DsT_s;c0G-o`AE=PnTNXHqUiVShxB#fAfB6(2`$Z`Q1>{U z>KBPLs^3C3-7?qV$_97P-K&ZH|Gb5HlB>d1MGHI@aEpfQ-6OO;li@dJ_5AqJWvD*E za8Jn$)iOWRu$x7~`V1e8to9f4g;=hcc?iA^7zp38?Z8~CjRJJn(RuGNxbXLVq1Gyd zn*Ebl>iBX>^FWE?{eSyts3iIp2-e!F3**d}QG_=w1{?x)WxD z#c^qveoTQUx|?IelXTvyc9!(yZaUoDCx;#qCvvv!5Z_h0BHWik`NnoZKNz`k)GMrA z?IEg%4vEqRD_>IFd5R-su{I+_zz`&ZRVI*EZHY9K{-u%2@SV z1#h1=$01uU6P3#0qi1$det!|&{FhtYZYq)6J1?H(EDL=%DLMSgn1+F4`}3OV0T9tP zTksERqlRk)IDG)V95Wkc&I_XnuiuH@nptA*QCVvKdYh>80)L#}8v|PUVq)aVMdhr5`k`w6f@_FDGvIwUn{)A51CxYu%cZ%p$OjTtWlrck_?+2SxgG>)- z6Zi7cF(*N#SqI$41ff;SHLAFGhQ@CliPt`dkn;;A8limwy?!1C@%C(o^~QZTakd_B z&5si|NoTQBhM9wTM-|O5JOEv7(b!t=1hqy2nPz9w;`WWuV~;)=#Wm6GFCDn7zq6Q7 z^cajDOyy%^KT+|i4b*bt1V4I{2gxKy{Z}RNx!6dkS|y8imdgOYaCto55xgO!DriJ9v9!!05d?$zhA0Z;>217&bs^<-B)U`^VzAO{UO_7_Jqrlu)OD~5+%f%Dzwe0sAnU*6aZA%8vbMCnbQqq&^qHA7jq z-59G(mC02l8SV`8z(q+Ccr!^3e~;31xV0(;M|O2m&_@MG2@<&cxD*V#7e>aZ*`#mS zE~+H3P*VJkpR^AXM?{wkTUrLfE#EP4!!wOOUXR2#2B!E{C6X^YwNk;~QT#uO&NHsZ z_lx5VluD(fK~ou}$SM?l?{i8?nq-ubQOL?DJ2aF+looB31|s}aRQEZ^R-r_xWG7_r zzyGuA*>zp#yw2zId0!9i`~2n#=zD3J@D+N}hPp9W?x6?qVVUHhaD%SiyMF@R0%>|78Onjn}|`#9PQ*sKK75=irjB zIjx?RjfIv5&^yk8gbPOe*(?$AHpfBRWp5t(`Ub7?-c3p;-a^%*?L5Nb66`RO_Cav1XeyS~$q4R@htaQcCb=tT}t}n7hm*iGtp#XFMKf0QUkptba zOCbk?qT9txD^Ko<9l(a6MR4inl}Rzr@`Df+_9-02vL}AQ%U8R_ z5r0zo%k#ZLT5Fg%&2K%1P(L=S@u2P<|Cp|4yI5G^3ZbWMD;NA4hU@Akqo#Tg6#4eU z_)+DwXSXtR7CxkL3rwNdWrz4*XJ3AxJcC=>^Mp|6UocP09M$%flisYGv|-CF$ewWk z9FpIQW)^cW-L0JZ`8eUoxZ!-^vH~`zd==Azbir=(eA@QFgd@}wIJK)3omB5Y@0*=4 z&N!AI9SehVd&Xd$<3kD?rpr3}rP$5Gmd+IH=KbTY!%f9r_;u10+^b^^-(~sEt0b-L;4uJ&KbtO!e5yD z^(&pczK>Lsc2-3|12yd|i24&{WXQLxZw53CF?f_ozu;ML`WaGSa=2lx&l`}_*}G-+p* z-&x?21ghnxd?R)=uBW2T~Jx#PHwH9e9jE zUlp|<58-gNLb0$R0^WZzhRE~lar#{y6c;%2E7eRMJ$nMZ3{%4+Sr;HVES;u3Z-9K) zT^M=vJkH%19fdu58MK7F{&#}B(nkHy4JA<{jU z1BX1M#80_caz_!@&=kABn|JWcRC$cw6%B`NVrl({O14xw!mw>IsFsIe+_JTpy?BrC zyI~XzA2|_+N>3JUL@uP)g)8`}iV~OIsGu2bt<}|w4DmqE{UEpGH3Z333$fDEVP%g4 zxVqys27io)&uX$PZ@8Y#zr3Jffl3@S>;~CH+yeUvSvXY5f~Tn|R_Tr@rBe}>xGBnt zGMj*}JWs8y`;YA!9*{$x8s2=a4u#{F!7mqk3g3DdN0(0#ta2@BXOukt=wr!V_b))xRu*dm z^>OvCy>xM3e;&Bux-fiM2I=fCAouTC+&^|9ezsZzGh7Cvf4jPP{!>3_`yh)yOqXzx z)jal}8Hv-Ugut9iIh?+21&{oiC!C(02~rwgX{V^lmtxzi-(6qA=If6`R(mD%pRI;b zFWl%zWGppY>VZAP!?f&R7(doIK<}1!QS#_alpb0E)_FSrSlgc-jOZuy++>4p#z}ne z+86q%zK17C-G?{cx)`RQhNq9a;GO~Ng)R+8^wra&ye&^@d{Y`vYOID01$V(+O&{xa zc~EY`G6^l0Livu5ki2(2&X|1_X3h2|qXJ7x`qW6zP8U+s<$j#Lu{W4+9*NQS-_RDt zRyc8SDjohIjoB)%NaKbqt2a#rAJ-zneKXj9$#`hI@Sj93xEl&uUJ9=a!>RG&3pnv6 zm$n}17V`B^K&tB;jEIWC<*yHu`JKM(8(_>9-sXbw{^jJ|&`3GD`F!iZbg;c?PHHA5 zc);Nat%Occ_^pa%*;Vi-ESuWR)!8X$C*P}+<)xrkwcv>Y#_7#~8Rk~#8m5a6<@*AR zZUG!U4=lH{(ya2r5K9QugU%;x) z@oX*n@EqjP0@gL8_KvzaW3SE2cgYPA6FiThR2%>X<4=hYWgPd%-8W^ z>-<-u#WGnO@MIl@mF|P+n=06pdJrsYPf_%(3|==k2^$>b(9vHV^;Hb`TXqEXGQj|Ge_DTD6Jm_Zr5(|H#|4PC(u9sb>e$!F1(y!rM_a27@wv9)EcI!f z?agQ}iT%0?apK5)c(!y6ntwN=R<~)OakLLRZAuhE%k0Vg?gcpLd<5Ja%&NAB?1WQm z$yj^3eQ368p`9`$v}G%_m2}<-&Zfah1Zb5*M6q9gTAyL}BZJ92#YLQM4cF z&rh}~vuW{suJ|;Ce#GZ+8P;9{=;e!3|*Ev6|})_F%=U+pxSmN(k^dBe||} zh*M7|h+z?Opy@A-v#iF@9~qtM`brC|^)G?l6H|F;N)z08;LnjY0gxm+hF6wlLFYLi zG+O*#P_KIpUTeeXn%M?k@WGtV^!NqGW?z8cCja=Vy+O2EGXTGPT&r$7G=dG(*K&yV z8QL&Lgxb4R&_1#U=I}~zF3`vFq5pp@tl}M6I^0Lxi8tkaur*r_S0=l_3WYrj?t$OPVo8!myMzeAJFV`pIK%oZ}7SR#y$ zIf=F-QbehJ|LQ(>7atbq38jZ$OP)S@N59HOP*}+xbom^_DNxGuU(BJQ#WU#hoUPbd z{2T@yTa3E$Utz+FO3F#y!)kZiAZO}CUbOKu_$ahdlx`%vZu$c%4-W~6tKSF;zES+b za3{AH*TNRZE@(}SK~JkNP&A(leLM3&$Jm+qVFV6*rOVcv=aQepQHpEp5Z)GN3WKG( zXwIY`uwE|Mu4BkxmWr}xuSG$)qhbsyoYRMt$qi&s^G^-pKr6cqNozw^L?l|(1cg_9DpSQ3gC3yGJG~LT=3bKBIfLx$devL($OqcZm(*j zWux6;@YRdhY9h^QX)gHCF`VtA+#$0~-B0Ge&cD{1!vp z?K+27eg5b5&%Z-Nu!~?Uv~ zm)E>k!~A2xsJtfyH#QWBJ50lPWL_GzpS)jXSmRCk-3R#m#`6$)EeAuh`&FJ8ctn`f z*_%VMy2L3{rD0y98@JExEfHJhkn)5x@aBgD_I{SZ{>fUf#59An8%AK$`5|m#9ZJ&D zJuo#RjvoYv^82VG>^=GgWxBRNOq~NtU0jGhw!6XoS`oZF{jXOa51~zCfmjnpv{q#T z`+t5f_<2jg*~VM+_Rub2w*3=I{GrQ7s=_fpC{Wb(-VGg-j7Z5e32fJ|g2JnRNOt=~ z{Or4i#%YMP^q>1dg=`;M*n2x8)_n_X}fBma%0ipW_W!h-)=5#HN zGgD;OGcGh)eKi=X$|I!?#~vRakiN%Xx}dd6Y(G3h{A(Nw7uw!Y$gLr`J-h(V4R549 zXP*mQ@3i>smjvqk0Tk)*luQ+6@qGHWe`g+p)}JGAK*TZX`F;R$BIuI-e*=)luP!iODD%F`WCj zRYBI0sXWxK8m8?FgiofINOp%V_6uG}_dl-0g$MP;E>BnC@}NQ7klaqurAE}cYdlYV z97Y$tN8=uOH_WOzBP>&x%KdtrCbLf`q5t}y;+nOZ{HkvPtodC-AN}3%WBXiM-ctq_ z8PB4bHwwk7DP5BHf6mbU9shXpc_)o)+QGUz4uNs%TvUx+3c6vIXn!GJ+*B#SqepxqcJ$>gpsLubT-PZc}mZ-H#yqY?>{;UGWk69vgrbv2L(BE1UEVs-umoJFo8;%lF=0 zMAtG8JlXO^xW4cJ9X!9AjZM}_PH*{_(|RZio}@=#di@n%f;#&Z@8I7(yTERoJdQQ$ z7AB==@S7R`{C>V7)_ggOv!XmjqsXMHv>D2*u;8ZnVMi@A8w_LB-Ma8;#|tvZ2*eNb zkJF>BD_GK|#g4^Nz&$qdtd|}z>4pNm4VL4BbK2;(=~rRKl_u1Yogh4}l;P!$p=>&( z4RX(E;4LE)R!=l!i|x|5qRAbhwiU+R9YNjI2I9Qw$uREn5xTZVk6WX^^0V|I+*`Mc zKD|!Bn1!RMT-9Fe|49m$3|Gd%Exo`izX4t*??&(Rb~tVIKq4>e#0EF}3KsIaIKfPb zbPZ#{9TQky?*{3%-yy%fJu$iDI{A3ThG3e_QmdNTNwE_p^V*ZZ_?>1!2NyoT+>PM%LTXOVcWd7&!@l zdxc@xn!b2`dT(^7=*j89Nuu1O$7Jaz$4^^(v;6N+(*7ik!S+-6{<9Qrv04NzNBX1w z@m%Ovt|Dr5kH?BNE;#G`0gAKTiAn>^a7^Jp%|1Vu&y4&m3{cn%<6X|v{sp?G9M&Jpu`|yLH+3ci0khkXR2u@2P*g|TZ;56w1IE*v~ zr!^h?ee+S#ZK1jt01I%(Xl;CWN0&z2c0su@s=Q09L6|*cH@lBI3~u=gA^yvAkeh#l z4EuJ8$x)u@`)~<(wO$6#jNPd8Rui0mG}G(i%kJ-<%S0uE3ADI#FGA~2>h2N7y72>eX5b&VneB}C9oi{e zQ=3Y*e}uYVNBVkpAV#h)VnxXVD0hw)zASUZ{*8h3XUKFezZe43q)gCbP8l~}iW0mJ z0k?gb2jkbK(WvNoV0Sndb>{C9*3J0>-Sc(%Mh{oUm-of=Z=uzyPi(N^@knZau8&R4 zokE+^RIEGlLcBe%2>yz5xijyWxW;;)aJ|bY7*sm4N-eIj%=Y2)S#Q?b{!>q7Y7Ulcm>l0cQu>24^IhYPSj4cRx|4sWsZ2yDGk1*e$%7 zy_fbKPlxW=yr(rGbfL1Ox$VFA{!p_XC>bGcc%}B z;@H~Qm=Ac$(k91xx-xah<<3ZVaE@3GORi?%DTiT#;}|{Mq16}n)lB7IC5Ko+^$NaG ztq~_SYa*|YWa*{aSo}s7C(UlASlM=TJT@AiehY>D@>4iyNG&NG>A{nqy7T=jNwiAn z3(abPEiP81f3FU&#oZ*2t8FmYCYno@jOMDoRg^kfjbG22$Gtp7IMRDBX(uQ&GWnLlf!d@X;s?0obs=_vPU_cIfEe4_mAb;2_T$>Wa4DN5>|h@9S#HjtQcS z&Kw@0JOE$2s$syDS5V$yM*8CmDY;}U`g(_&zyX8P z1PCR;Ev1~kB*w$=!UNd5_yRjSKA@IyPiXm$rFhigD*VXr!GkXz1G5jou(;@kXnnj0 zJ;QHPKW%Azb6=IMPlbyIhi#*+UsO2!(JG$Nb0;N_jKs&~1rRb$oj#q)uzR9)63i@) zf`w?u^13#taomXuqq}JF@;Hi^v{%sYZv;+p^J(6vQP}B`4yC?ZV9I|sbW!0SYg9W@ z>40MB*b_@3M}9+Fzvsff8QT2lM<=w~$Iz`GxqL6PH#H4b#Uaak;mGOIReSdbk=H>F zOnI8mD~0_yzx-cn(Q1%rS%3} zu~EYTr4xB%kTf1&QA<77$#cnNf!{c+WbOT``0Yx6tg7^YjEz-QE86$MC4*0}<763l zRqsK0+>Sewc9N0J9kTM@#%gWjBqkTfa3`J?UHWc;>M=+7ltv`>+}4-BXm!JzY*~J( z907M0uRyu^ihRYqi@ur#!0(_rxMblFY@9gWPV0#bb>wJZ&6+dRmNbMH?exaLp~b|} zp4`>X=3lNFj^TAqLi=??Ry&tmJ^9f_+}P!d|6Pmb?Y#+#=FegeDF@gS@Q$ue|1H_7 z9DvR1rU;}j=F2swm8yZk1as~Sp+MxWU zNqqgf3>;gtgTIGPQCRM;%CN?{$$R(U`uL4M^b1^hp_fejTn@;nrGE0Z`@s@fXDfEhUW{r0{O|ebMUs2lCE#L=Wp>{NhU$=Iw5x zJ+&hRI~f%&hG0ml9g1T$Jh{)$T@ZLZnf1#~L*e5Q{PCN2_0Ym!WFA}q!&V)@ZF^4A zG{arO)U;iAE_^)1op!07v^AOnvs%SpsRzaK;$9qGb4{YS>Mm#nzZ6%t)nn!cCA<{y zLD({HCs#i(;4$MfXwrganl;E2I&uR*e@rW@H5}%(@z3dU%LVWoABs)+pTtjtcj40J z0-&E+TtCh1@~gEeJXv!9ey=`>Qw<(~pGhdLG2&|Y0#m^Wa9N$ zaC{pm={0L7;TA*qls<)Kt43B|(Tt}+gTsuMAHed1mnBh#^h7mzpEE9vUtv{#L}=9mAN8T4BY{yFzpI8b}Mtsb2B$ z2(&i$!B-EavF$JgYK$?%yFq=idGsn=b9EGZ_3X=8BL?ut*eJoOSClAKG><&acarL- zwOp6j0F&P6;9s?JNO*UXHeP=y+?2iu{!^4+#h3y zrh?4`}a1`I;x4TJ>2N)wsQE>rwSfC8Hu6g&mi6;2>cbT zc=nQKB)|Lzjk+`*yq)igEfep<)@ya(>!^vX?+_2Wv5N6E}@4`$yiKl@Ks>E& zb%D(nJ>iP_3JTD+g~R7ltM{g_Lj(W6u-a6Q`o9XNk3W?8ta=d5o#Mwc=Ln+P1W~*- zw;v1qPV&gEH~VA>!mkn2g``dm>>)mesQ1gDMf$K{wji5s*tp@ZyC)>+ZXboJuw4}T zBSrAfXc1y}o}m{r3&g=s9dK}|9dB7Umyi6}#=Bp3Lc;k*;d1+Y_!e^sdOaSAd-{r8 z@WGQ3=Fa1k;zQ6alOp5>1CAe_j73`{@MnLe-JOd;+_F2IyI-0KCuC(YX?7qQPAP>+ zp`|cP$q6>A$nc*>J~V$p1ux3W;$au(qu=5@L1tk;%gfMxqRg5RQk@ofbpjLH(0l{!P> zq(k^3q?RlU<#FULz+1j!xu&Hjzb*eoV^2t9RZx~-w)I)Hj_)tfx^R?BlRZV-LQDKQ zIv+xu(QK`= zft8$P*{1Ij_KVvBCtaTkI%}5#{5Kd2<4$vroh-4-cc+Gl0r=2j4p|%N)BcU~!0c-# zgirj(ivKc?y%$kNpEMG>-a$pJMODC%Wfb0j6qcLz!ltS^zB*wAJDMJ%vH?di^I0y` z<;aMA#w>yLjh$dU(UO;Rei!48Gt2Z|fMa5l;K7;&xJ)vfJ{^5UX@><&vbBQt+>>DZ zx(w%fYr*64h4gNQDqGr}pv0?X!iLMW>wbdZjRCUMM zZS6vFuYT+ppoA;m#p5!K5_a35%$~D-`L%ntSnx@WI}& z7`?0A1H9k>8?8RXGYvE(+P^2Jza&J3ra>R*N5HIXf$Fj)2zXH`dQFf@t+`-sEqB80euU+LGy+h7r4sv z?UD!L);Dv+k;k6W!k(8P*=h^=zKG-0%jrZDT{(5ZU=(}ok&IQJBJ3C^gBh_SC*Klw z!yNkommeg#;PKxh;i!W(ZaU(|yAw;r=eK6#kAwgGD@~7-r%l5fGlRgYXeDiXbWQZU zSpwq=UJFCzRXB6VZlN&Yie%#EBj|rFfXhoGAa%oV{=TgkCU{2DySSa4EQIsjiP;=f zn@Z9Pb@17tdT{Z)M;`kw3dd~6V3?sDe$y=gt$%)&yE>4U$~H=*uXVxUOWJ5!^@!{W zt%V^Lfe`by5MCRvLJu2P)I72sWF&HIFaP`jVoKqpgSt;?eed;8L!$;W8KkxlHhs1N)s$QNRq_hI9sbTVw4!gddQI5oOhY?{;$ zd<~9K(dN4_?n8ex-ClyR6F-nw?tRF66VAP+nTR74zgPF%oJyY4q_O(V9dbDQSn_&9 zAP$$Dqpy`YFldt_*M25g@M5Q^;;2hmiit3Ny}-veUgr7EQW)}UDn7q(TiAbXf_PU! z3R)bKQC(#fx%Uo0>B#N;@~S@ebqeJPW$)n2zxXik*-ZFWWQ@N;Qz&QbRgC=apRlJX zf$OSWeA2>(o+hrRMZ^91^@QEx-j2_L#|90F{q$6Jt~gHc4Vai8rco6(=*2ja@=%r+s{hs=seh7t%t7($T0ytlugNKLDMd4!_nR%^Y zsjz!+X}JQ)oSjDNn>MhQeI^|k^b+f(zLDO&97vl#mUl>RlteXb64MHnvYkl^_!^F* zn=-N(d)Go(c`yZLCR)(u#q&t>S!nf4r)mm2xkcD9w~Qh-ouqy4(%d!sHDsKM2InWQ z!NS+d?%cwG5GUM#ji-*n#~aKwZCCi%qCYfj#8wQQppHvN+=qaJry#>X4`;1V!}j~d z=(T?=sp#Ds$U_Q;*}|$t_y^5O8V$}H-oAi&r9x3i=o{`6Ddad zh}gcagVci_K|*sND^%7?)(<{KOVl*+3zd#(OS zmwpf7Kb7k!=wAzWJev&d@&5dD-YQ-gpU-BA|FqFb3qLGY#2NqQ_-x=aVbSO(FwJ@d z&b_ONE)C|KF+2?ldJN^?+xnvXsF@O_u~Bs9K%=DJsxMR?KOLP(As-59xYPi*vWF(bx)J?T&BU@wnowU zt$|o{+8K)+GRWrOHXdXg!rxu@gWR_a(4G7q#?@Kz*6-~g?I(w3&egEuTTfQ;s+Zi+ zUBokVR)e`o2zdQ)s@8r~0gn{~`faTx?BG4kuFDC|@-2m9@XS z<~&49_(*r^)ZpIX7NKpFJ_Sf}*kbx2T2Qdl&R~ZjK3#DJeq350xFl$C^7(A>*4t1D z_rF7biz2WnY7IW=`-In>Dx@4+efmAk1NDasH1>B0mldevMaNMbX0wyiCm(>VPxiq_ zll4&M?g|UUP)Hp%20xhIq6b-1IM(tu=qpRp{h$IUx|b-qxbv`3Vjzo8&rarhG9M*N zKWlSehf8?*nk@cF9uKQ>l6mZ5X;KZJ3w0yqNGDE)H`(T}Va^(yNb#6(%M7(_9jbfx z%BF8s9@x{fC+j@-=f#>cs%#z!C#Sy%Otl4A@WQ zGELISrKL?{`EGt=b@G`&*84LT_Zkg`AfMuNHYOLVENM}SSgqA3~5-`mr8-kv`fvGjiNOkUgdS>yN z?u-fNZ%1EAo@EwGRw{1b>bc&uMb{N4I7`qrLmC_|%@m(SLZ_oZxSA9B$2v$JT7LEA&)$8Vz4Dea3B6#8BJPQDYQ-{9P;}p@Sn64xOZg& zj6Gn6`uPc>|5G0xc)I+ktbOIdZ) zSa}Ql{sfA0)2#U14()%eoyzGAm3TpO7mh5KQ1h&C&M$dL7aNw~@54Ft=TsY2SH$DV zJ;m7G@l*_W`hfZvFXfodS`fj3tv`8D*mD~`(Ds^sJ{m$DYC3!{{i_f)uvF}Bb;0Ro zG0)#f~2VIX(ZZ{gmNwQTfU0iVz}s4qIjNQ^VKYRmNW_+Rpw)lzl?enIn;7T zhwb|97cFHb3c53A(V{#qU8LtwYSB~P6<7T++;Q#;Q z6id5GW@4!KE~qTjL&u-SJnv&qyw&qF#g4ip47z@Vz9l%I{|w+tA7!ju@PVME9h45p z($lL0Y4!K-Fh_YgoQ-#cyKl0vwQ!y|zMl$q^qa$FXTMPR+P*wCv5O3r7SXIuDT0V} zcDi3r!=?_Sl&Suh@1~1Z8pmK^ygs&E&A<(QGw5#bK{)u=cQPz6!j@K3+Fvk~$33}C z?{hlo_|^fiux2`Lt#{<{rsj12h?e+1C=!ZS2w-<<3Wv$-;V|Xiyi`*S%;Lsic-l4C zdUqfxxA)?x!EtbAvkZxK88pe`AA4FA2;ZvrQ@+102fG|2&ACzFHq@Ea-p&N`Y$d1} zq=+5MMuF+<{Wwc~9Iepo&)2-B(!L9q#T^53;MrL()=n^D{qd%#wo!&#zAY7!u4R(i z-*&JW*B7-C66yN^SGwe`1+wQd;L6fap0+-fLIc99Gt?>|I_N0udMZx_pNuhm&`ZvF zG!NY$I8(pXi!gVW998+v!6VTQIK#)B6P^uY**!h# z0KM(AFt~aQe%WzdTvQ(cy_^+MYv&?JcRNXzKMGMiISUO(6+pMK2lx76M4m0L#Vsy1 z)sZDLIHa4* zVn5Tk*b~r{t4uxaG)qRkFNS&7&ys^wJo--_!%=m|Kx^drp`&2LYM18SG>3Y$Bk z`ne(eyea^r3z;HD+oH2Ytr$^X3o8ACA$#K?c1xI5eQp(U_=p)eEyRl7EH=iUmpjO} z)|o=~r3qz5Pv}XO25vvL8{b$B6$UC3gtUy|VaY3K{hUsT)bL~)KVv6M+xVJ{N(10m zA1`W}*2x3MOb7MydKxbO3&QvIrawPauvG3J+ou|FK%pWI>hm6tCN+a~YBxodrE~Ah z3NZVy9JJPbr;I@hc+Gf6R2iNJIzMEw!}K-L(d}fQTQ4}N)snluF-@3jD}+Wz!0*)# z{2qcP)hr!D(1f^V5?fuq`!ZPju zDCznxKKpzWJJ-m7g=QS@^fX3rD93x7d~jEW1+Pw5;tPug@WX%>an=w&mhan}PP7lD zexHV7=4wZb`C%ta8dxHEs!>568?|9Ui8+tyI!NUo!(mKD45mys<<&K+c+#$%wtv*X z%9cgEBGZ^>z8C`bYqw$FhrPJSX1(w^@hY{(KNGrU+0y4;efY%lJlLgr2)gGrv*oob zRQE0brw6RVi`NoFyY18X)b&YtV!{yILD^!@%orT*U&Vt|>nVDmEN3h@j7K{jh&$|T zc+=`c$(NFukhs7ZCykTkl+V>LAa**BOwfaQk!`T%xHNyV^MRGA$a0<|xF$E3aX}_k zOxuE&&weI6OKmR^m+^Db%<>o6oF{K&Or6{Oi?D>{#80WpBNQEnXS4f8{qa z{1t{#I!7hxL1mn({u1tIpB0><7U4dx7j`G)il{!K1*%uwquv!-obvM?cP{LNXCCVK zboEadF}sTtcJ3u##S!Ro_bgoZ-wxL^mF#n`-J(w-|Uthl)?@3Ne)+a5)v2n}kc!IiUV7x?hlXv5lGt6;hsWDat=Av`JB~nhlN_Eqs z>CwtQYzf3s#o*XQ2m*bD46?nlXE7S~CfImNzq5l+9PWzey6M|0Ao#DQ8 zXGSO)jLoBx5(z(1G{=CG8Z>P1bh_oegfH||BgYGq@TgEvk!OAicb}xgwX@6EWY;6O zq`I6+-z1^Ygs~@2lB)E1dKR;Y`hK?*wvsLzu8gL`l}XUhkp>5E^`TSoE|eB{fr{D< zv2#ff^>{f(C~>zS)u=r{vSQ^$5L>)eE(q6(IDTLDKJwpvtmL zxL23X&TWc#@R%)zX?M~fb&=N2(Bhhw{X*|qvV>4e!`GYQtPd+ulGFtb`!n$$R8WPk zBMkj(&W4_G6d&NlrZ)Fz)n+$7{vn*tIH^#!+5lXetBQXP&4y2-d%)+@z3}E;YnXaA z4xBUPapQmTwB=vDZ!eD^<)Uj~7#Kx;BF(tW=b7-KtBbw%#PPhdi*WJ-TfA2hf|hP( zTqPHd_Kp!GFL%YRW3xYJRBUCt{o_!aF%JFS9ujYVnaqOvc;Q3aDy-EDC$CN&?x!#l zex0f1am5><#-^FNh9zN@%?YU4(i4aO?2VH=LV1AQLmF_clcj#klku0gw73R;z zx30I~yq*lctINVhm4oQ?V=l`p&*7mmPHaD9GM@2lqnQpQ?y(q1(+mfo^y$5{dCh#x zmCWF)1qRTu`UUl`7%Vt?e-|b#P-BDTzE!5_%kbh%CHr?~D5>gZ|>=BTK7ev`lGAk0hvxpUukMj&M9K0VDJlQ;1Z%IA%o{ z%^UXy)P}_fS7es(WpkvcA6`5$Jpv0RAHvqbCUAT1NIq)RMNtbaQGL;EalS(iRUN!e zd8!#4y=yyrC$>R9>&>|1>?gS0oFgU{Ul1n!8izX~qB(Y!F@9U=jcuo&2=~rPc=D2q zbV}m@N*%duYwJmraQYKz<6CmSyo2=?PD8h~29h7k3SqBKlsMSx1IR7gkD-bmz-!$@ zp1n>MC;J)WRnr~l@uU}Dyko@g?R%o?V=XakttQpBKH?d&F+BIZ2{|uu#{-}XzpQ`2 z=YzkYt(PhKY!6_gA&an)6?s(H9+>SM%(-(H!M#b-(B5w`>7GjiSuu{zzIaVT&sLzb zT^Qh~7`jmC&&Q_bfOKLH6dt@MUHLUUc!CF-|9M6O^e@9~rx?La_71c+7sI+}R}Mb3 zLiD!N!V&lExS#GBzUL>!I|jzX_5^Lr7A^}vtR~}vx?Xr;OBO4y3C3^pZ%LN6#iHr- zr*zm~i)^oj37cZC(Y}naIB*1Txz=>PH0L|Nc-H{Eo?e6Mic#ngH4fZ5Evf9U4-Srv zg4aD|#F@`F!HWq`#bn4K{odx>&`S+flGar#e(t8}C&CbJ_r#iWd+6;RH$EUypbm}8 z@V8r$)z&r8QoBfsEgXxfy>@W7{z)*ZF%niU)x^z`FTy5aBk%IGM$I3^l-CX<^WiWm zkO1e$x{^;2?m@Ut7=lvc!=<8B9MdApJ9GI~QcpJh`${ZQ)JE51uBh!EE#{7U0cRdA6n2>j z;5I3bYp$)RzG<2(&Y0|i^G=N>Yl{wgYdZ_yz3qun%Eje0}8D#u)gYsXtd?I@<`CThw+goSpwE7C3r>2OZJ;JGGwkn3mtwqbHO|VqOtVzk#xrpb>vnu0}*#uNycwFC!`NRT8vRYA*Udu)jRAhhk8#7f6c0=?~o zKNH^G7cnAcA($-vO|=iQIdX(5h$U8ht4@Qm;w`wrESfuo7FeUdU%>QG z5S68QYG5(cEwn`sA8QDD_=c|?`ohbW@5iI*LosFjeJHY9%E=~c(d$JBj!G;QQa(6C zli^<)c0P@FC8?5O#YzZK4#Tc5=b$3@Da`W?gie|MsZR0J8c0?rmdb_*+;eU$>aVmXrBZEF%PF9rr=;;_{XV#wKAhW%HsD$F0v^Kg z{6C7#`>*G>i{q6fq>?m9iL{ZnM19`plvF}gR`!TWW=3eLC?cYyXlfWCBcuAf&&dcS zghH|sLK4CkxBEZ1uE%v==k*Zsk?{Ddi z(+gpS(hUBz+6HE5MpLNqB=Tu}2gXSZfmcj1w>*PP&|b_iNEgRMY=aG(m0-y0b~4G z<%#*`^zqIH*l{ur9Uk?@9ot2ivfqTaY~DjrA@gCT@QY3<%HZ+W+N?KpHm+-Iq0FIj z|9076nmgtMb-63h%6Ki79J|Y>=H;Qmr1!LRV+79d|42(Qfz;={0Nc^M*#FTGoW5WW zx>zjXT%Vg_dYUh{U)GYerHzm%*c-66Of(j0HVDJ*Z84y^l=GcsAW7>#`twW+<55cU zjz?3%WqrJHb~@}hUB%1X^!VAaTd+NP8R*oUgL%4UY`u9MF2AM>7Ah;?s_ZhJK*M?M z)I*RRWrH$`+Xb04+scArf-vSyC|-V>OaHw$teP?+7I)^(g}9={D0I28^$}3tU99?JP+>Ap2b7aA!aa!Hg3Yr?b9hq!-nkZu9I=*6-j4cITZ?) z9NwCQIVw(k+NPFg-&NqM^KMx6I0kNx{zCmPn83HwY3NcIg)^%LNM3A@V|mwD>b>eX z>0gt>qP{vj`;r+{TDYOO(gTlGeqbz88zJqf=&9D>#cL-F1=OYyeqP%OStiZ8-rvGI^4!;lDGwpWJ_y*n!| zG7~6DZa4=SSYqc>5Ag85%PR|dS2mr};Tf^RkQX~q?vqYPv(m+ugacr({5mF0$>NCI zC;xi;F!zzuz>>;LVe<9^(4H5Jh7EEcBi9L6r}yX7*9UQ??|Lx2rwSdrjrsghGj7_w z39?rya%I$OQ0#e)RnuZ61xxmeqwLgiaQ|vrl6a10>dr=0e-B7aNMoMJ z8P(4I%a|mcoQ;A|X3AKumR$u~d%NSMguPR+C_%HJyKLLGZLhs-+qP}n+RL_W+qP}n zv*(=u+?lv9QxP4R)!mhu75$c-m7h%a{Id{s_1}hQA{a^YYXepoX(|G}?b3gciiZK* zM<->22lSpDo&JkWI7KsiKwg_o;8w4%fQiBYmO*b2zP~mQ$dbPgNm610KG7-a&n%d` z*<2v6PMJj=(~;)S->kGd-}qCwNI}3~BZb3nSmnEU=5$v zH)}LI?D7F)RvTn&acqGi z-7WcUnaCg6T!OXKQ*WCS>jQNB&@jyOfX{~tEPH9R_~~`fFM9KUv7D5qqu-AUkYe** zrBMh9ez^_bK5g%!HE*vUq!d_Hec14~MevD2Z+O?z_XcM6e|P`nG@EmuA49O%tjU&j zKLAEI6TfYy08?-$p(v0LK}|!5x&uNQ#f#+iagA*1!`7N8|JpL$WpTzs^EPQpTKgyADhv_q79pq($B))qzH*O>q}JKRrr+uC1yAnj26&bs!hGI<*Fw7zJ9C0VALMYxSPwgP z{^q>BmzjTF!oSc#6!(*HY1`CSt7%QCRHRBdw(XCq{{-dFVs?fq3Zp4KK7}vHbml8F z9y%Cjb-A1K=6J@F;Sha+z%(x_!aKiY)LLaqWec-O;ebi%7(Ay(B{Y>r%q(O#Il?qY-b#>RONsh-oh7n6PNv52z{WpsO#OpD5zStA#8IJ<3?tq&Xem?VC5Uh+4nt6il)U~)?e5oEhZ3fO3eDr1W!S+*2EX;?qiGV`>Y33uEn(N zw?il>JM?RGwAD$7YbCQnhIxS85sHqnW*9`DoA1jl2}u?q1LATiY4u_w?n)cg#Fg60 z;!E}(C9gc5mlyniajwOXta-_Tstfy^+_FeDlgKV?(|T`tjQ<;*~KoI5rdMg5CEjYsm>4 zHK3+DBFxu2{C$tFO0GMj@}?L3cc(kWVstc6Ts%R_y1M9wGM~UXYOG znrs*pNZ~GTtD6=ni6qP5L3nPjwU6pIH^COFuK-J#${||qk0dz zZ|`$)&{+gRlV9wuu-Ki~Pxl5h6?*Akw#Mgq5`lfm2TT4E^O(5gk7XJe4BPQ% z?JYuv$({;V#G%q*QA=I=5njg4kI=TDRW%mECvU9GA*8_&7PQ4|x$rII_X$$)<P2orZngy>5-3v5-Z53|l(veUrTWtr#xs zrV@ck+n)%#V>BM(H`KzZpm*FU2P`==gZ=WsD;$XN5wIUU_efuJn_-0XThI(3Tm6 z;~~dzApMHd!W6S#twt|2-|THa`w(z_*+AH53Ws%b7BnvUS#M;9PnBs9wBl(*mC`xw ze-KO3@ii0$JImdF$h__Td9NP5!Gt5LySNu|?eOFpi|&rYPw1`@X9E1of#t0M>|&R; zSL|^*GyTZeIRkHv0+`T$g-knyvPd_!|L z=y=^Tt4tkqbR+bzbACbvjX7m*=ZdwH#A_bwTi8BrG;etnm*ZoNK$bTzc(f_-O;}CO zbwwwLANhH{QCx5ia$(QI>~#=(oNGyKN5;T+Mc;*6^G%TbUSHPFJ4siN7BUfVc-?8i+XIfTMqM!0ONZlDg@acj@_3`H$K1U^ z#=2>7s8FjK^!XiZt>u7U9fA33S1TuA6gieDb_c%L?E~`0(`x>3!b3a`f1F_#@yO+H zZ)#j1!)+mT&`%eodvJH4t1$9yk|dO=mX0XOlCy~kcU){`ScS?b`rywku(OR2SMxAT z7y>`HwvR=wed7SYv>f%G!L&GpUuU9EObn-=b@r0ShuWE05jk9EPuh>H!ccJHHcz8g z07Kpx;9Q2RxkC>1OxHIST&B$^<1?r8ei_4h-@7(qWUst?2%RHE8&NjI-gY%f}Umkh@xXWNSCQ(E={@ z7Z2TE@GVeZg9K@QKkO*ks7?p#5%IAK3*zmZ?FwVwwEmFU8v-=ZgRyNpbDzIVY^&Ht zLs39&on{cXx!d4+#mD+BgYsEOcv3zaOYfUTMoiDrMb}u^?vK-WS%eypvEZ|NQ#&6E zYDxHu_2SsJRxkdGxV!lbV+mIHU=r-;;P)dJuYWmNLhwxdfRg;(YZ$Eq8!0jKmOipZ zej^5NCx0Vxe^Cu@gB7{BOt_=JJF`S`m#rTpacjNh3Kw%)vN|lWbJOclh;G*!O11Ht(6;xa zcn>8OKB=wQEJHI{4-GyB0b&eeb@YbRH#Y~MSM~YK+2ps%KR`ZVyJ1u;8wpr+_cS73gC~F$P;yKLg@ZjQyp{Ty zpby#zY>}HjXh%cwR`(^-fTbiwh0pM?=eRl0iM@SDGHc*QD$kdnl(hSDJJ7)%_JmKp4<^^2Wyp>*S|j1#QE#P8@yyjMj(8AFIWOsL#&Lhk{~$T z*P&6ZrswWFh-67!@Hp)7UK4+cf2`cXYxbcK8rQRgd0+2`#*-xKONnM#=K7Qr=n#Ca zfLS27>l{v;B5Jp^`;9jRx_rKIa#J`44z={oMhC(F)lZ|x;y@K1$-*Z?!H=~a;jlTV;2y#l=i-WR?bj{5-})vg8C3oG7TwH6xY|9HTu-pu-uL>U~VgYbMc z*Ov8CrdjgweY%x+L9|Yu4H99h|4k8Hm|rBMaUp`&!XH&~WESvMgV>Ux5Pnz}I>pHp zq9qowRmxlwb)sb_Q(JsB($&vc4yVs$ovX(-GdTGO_^lxsYBvP@IXB^LlvxE-)`2$!sQ9{cdE^wIIg<@)NaAqPg75%>RZhaYdKm2xgbHCvW-c4?MjLSxEz)xwu`{F(=PV5vKy;YMk z7JnDu;B7DQA|Eb}jyY83?g-=zaPGh$z1W^*PWMu$H5;F`n$fUtL?WY9^?XAZfF~>M zn!6jBm<+#I-0F7`qZxjH*061SbM9a>)u(&Uk45xu z!HE#HuNF7DTJ7>sFViCBuNqy^a}1SF|(m zGk&?Ul4A}OpBGezR!#iHPGMr|C-nTf5!Z|D_&_!w{5Xp-7tb6l;_QyE$PKcXjXR9TtR5|rL&6jeiBnR)E+nf_IXhm0))gL09F_#WX+M|=^C>QHkmTHEQAaL^ zI{Oy7B&aZ4l;R-6zV*6T*K(2YxEL>~s!zFov2W-5@?n;nE{8-S&5iT2cM55qJYkvh z*(~lLY|XSpdcktfn6QPx1V^vTJ`Tn#|C>DrtMld=joV#$z@Po zXIk*1-YTI%u@m)zo`BGtl+znK6pxQU7K6eCVk&GinIAx(Jo66j5uWZ~ayX8N-2kV*H!{z>frRc`gcCP4eH&K) z(${7aIQo@=PH=k1zO*tJC%I$5vem=e9|~WS-*s(I(KH8F`V~Pb9A_3ZvKtsd4ZKbv zYP&%gI&d*msUzv% z1hLH#h2+Ju?v(<_VLi9PpR(d_!4Cw^HCoX6OtEAPZN?EK;JQlA0=&rh4ge1i*bK$?b3#DfSbZSY%vE8NzWKMv78(f0x zoL=Epl;~ShCy?Z+x&xr2)AHr2xU$YPr+EfO?n4=-n#?^(e7Ja&85q{54`!)rs;V-A zWZe2QMb-wJW!7uH1Bj)l*mut_Wc_pW*#$|q{pO=KUy{1A?pW3R5lSmjfYmW|5A8AP z)^$i;V6?-qn@j4~DTumw?7_mwszUzH%C4%Fgp0H7dB#a(&puq>TWUX>g5$eorUo=5 zHD&&@(wqXC5V(5R0;mUY3hH_aDvZ=QB&Y3*433{VgSd~3~=Rw?G%FxL-Z~S|W z2JV%r$$!`_!Am0G&#h5~C;a!li3D?q%~^BHDhvObS$ULiNsKMpfoyXg3b6b3nt%Tk zsXtbc``)#SRmx??7i!TwX&%e$+n8K2D+KVsq89B`f>cSX7MAD6`a5h6d+dMchjGrHpbH8ne55;!>v5Cf*t0MJ3BdF`A3mq<(%1b@r6F$oWoRoCfA7s(a z6_N#BMY7yyw=$i7|D6q$_1fF2=ILB;qH@IsEBqW33d&ToXB0+P}A z*@Ag(IhS-*#bPBSxMZ>QKgO%dwDQ10QJhZ4e_XAC^ zOXHCSCb#|fgSBSDYRp(gG!^)th;=1|TbQSlS`{saq7(a2)N=O~V?x+TNw6e?goA!| zw65>vKb!L&I@kbcc-B$2d+n2L+0ngWF$s$cT!UUN!Mj7N zJ8RVjgb(ZFxvV!~=^iHFu=SL1v1g?7<8LQpmq#LLPZVhCP>Q;RaQPqH_Qcm7jZuQF zz%gU^u3iabUU+OHBX@{#-VDI=`N)In?$!O3`t7bF8K6lVrLoR&5Z&oC$=|nVR59G0 zaIfAYL;CF?8XC#aYCF{Tx%=BZMp3j#oF>kvZYW*8&rIi3i#o?yB^Xh;eEn`lo5y$H zv|jilhIg;L4Iao_ylEuS?QfA!*pI@?4E1Q}*bvoSbIneMz*$}nkciG>b(josO5dEW zok;*v=8O6BDJm{4qY10XEDcUKDpj$w{@IiEtHj%gLf&roVH4g07KO{=lA(|?+dTh{u+5_j$*^^s>ue!F1scYx0IVOvp|1vh;F8^BZu$yFG2Y2J@EF73pyS@8d0~wQ@?Q0NbN-* z6$;8(SfBPIqUfa(VlZp%ahc6gzH;c|UFlH!6mrZI&o$xrS@?6L$%CY3y)npaqSv>e zD_ZayDBh)nA;Xl9)%EZuH+K1pgme`*STRFpKA|qi9;K!jk(I3cTQ4xGYX^mpIQ$&d z;Be`bH|xlVu-bU7M?O_3cX>fESBo81D?d=qbU#2jEyY4(%*ng81jCK)8^Tza6U9*6 zTUV@xgp!>mysoJ8TDYY44axM_o5OL&sZ4~in}5A?#Ve&WR#!v`^Yi!>Lm2~Y-L|z2kWzWLYJD0 zNieO;kv(XQ>+U(bIp^Sr*lXoHtT8PYB9UoD$Z^Hz^IkL7h@>l|v&w3T)q)l9c;mf2K9dwH?_dg0WsVz7HxWlcbPlhrMbK}8 z40bqzThWy_jD0xzyf?|*IVANK`J)X57*u`^5IK&*Xo6U!LWw^5FTd0piLk|JLfqVA zS)#OGxJF??LF2=aP+KWivTqf-knlyKnxzgrOnp6U!8c;gI+QGpe-lEHJXjreK{@M< z@6#LCcC!R_|8+w=H4R>NGDK_N>4KWLy*pp9GMKz&g%nx3HE(|?eE!X9#xQRXL6NK$ ze*(tqo5+~adfp^t5=r!H?+`i+vhggtnj@ap_4K_AE#l(1ut<#7=&zl|CDS?!j$`J{*9zLGgg{%*ge z&;0w?I{tWyOEcS9DEA&k0~=v1+tvkAzd6%XME#!zY}D-;M`1n znuGP!^vcoWDgd6F#Y=SddmV&4Fq`zd0%xGB%AUV}Afkw;44ac4CGcSjM!Jew21M=HN|+E#)fW@TO5YwSfySPUj6W%teGnpFiVt`?N@HlD~5i* zX#!m1R~*c%I=k;uNER{qky(Gjh?!$=$oA3efc&AmypPy3o)vx}N!4nY6K0O#1iZ(AZ ztKLA3=PnQjGk<9W$YUR0TBC8gf7npTaxhAsI8z_+y((j$lR|u6!jE#z>gg0zj?|LO zm2k9;RPm8CIr^#+FT9}{tI7_LNfOwV`OVPb#{|}+L0E#9I*`&$Rdt3vBEi%c!mldH z(KiFL+A-?S(XQ_4>3}WWT`RH;i}!$DXpptho;k^mGbBGac~=*hZ)pqPZxT!78H02; z*MP_H`K<5WD-h{wXSx5gBX$rpfB1G7W!~|dFaJ?*j;BV09eE8kkK?xqd6?+@zBBt- z_nEGFeC$iT*Qv>xbzal&rx*{X`$ zFIHPpaC2&=eA65PRvlUNK@H3(W5R`B%`Y+FiXFMgCuRUi)I07HoGuHy$Fhp$XI>hw zXNczV%sf)W&AoR@M*U;VntLm|a1zk1bC=%(y79&zxK^BzQUMOtH%5)O^4W{9nDSg- z;E~GF9+#$M^GzSQ+DmL3lR;E5!b=L@tASz94|9tZ+kYhvs%$?~O0S_(_pszfxHg>l ztF1k5@{3zMD#lkBBt+JYaWnSm8go<;%O3w=LFRdB;v{S3*N}xq#1hVZcQZni1@zJ8 z(t)IwM#l8-6t~6U5ob?6yT=AwR4dUd6P?sB#W2o|kGh)q>t$Y-S+~RK_i)>J504p5 zZb16P#n9*Wef>8XjF%t&mx^V+tVTL}Zk7-;-{<{z6u(62Ar-81?i5xK7L}LCZpbES z1xLw3Odm~rPS$xGENdi>r65Yn?0x@Lq`Niz>Pg<~x5qb4z%&fXc~U99hb}wmX~ZuV zF>9=r*Do5r-UPypS399gb}1phR^Hiy*4cy=k}d4^M8%+z!g0Tm^erAxt6A$DT@nc2 z;w$V`y7d&IMZZw89J&SzxTDCjhvMe1&YB?8n^hopf(&1o22VilZATyRP5aq)6L{h* z$lcp_z02F!(G#)f2@kdTbc*hC1G#>fe@u`Si}6RYp=+fV&t{j zQ(l8!S)k%)_M--F%`ecAhJy#-y8}nC;n#YB*T$YZ`$v5F_j`Hm`(^yj_uKr5eYYVA z+(Gx>^31@Xb<{JZ3L!u)&iKm$$QJl$^J6{gs<*XnOV?xZd+|b8cn9s6;#tpuNs(^? zMFYZ@+>CKJ;xs^Tj)L=*-97J~)KIwaz$!zpXf;(tJ+ME&k79^YE!)S9)e;=;a#eM- zK7>76_JOkB83R;MQ4V!+;!f6DL$7Wxke__q`ST+o123K?8w$HZJD=IZpVeafW8F-K z?Hm(pH6dcz38!0bZ)qZGISnL{$#j`fxU=X{zQ|&GVO(;$1-4O8fUS8ZfrJpGo>{rg zA#}A(Lq>v5XR~3iMDR+-DLP5+(oxG+#*t@omp zaAr{i@I5@PkZ5$blLv?W1TlAkdU`wkDNbqz)m_rds?^}ByEMS(nNAFL=EZx+Im9Vo zF@ouk!17L&e0G}Eu`9#SXD^qEOYEp3pLP=@zU#x2-BW8WTSW7o8cgrv*Yg&F@OZ}A zq#4`LB}srVjjrJF-@1E2yF3Ezs|IHbm7u4KGG5sQR{JBR?6Pk|D&L}1h zSi?{*Mz9Lnzcd6-WD6*^IdF5hZBFC+a+2GJ{?fy;6wa-8?*ExL%StaD3Hy!SPw?@Z zON3t~9VM?CL>#WS_92873bQWsyj8&PBFRQ?)kRH%^QQ8?DT$gn#~+d{T=wSTga>-n z2~6qzSWGbDmyqy7_9{K`7pcPf0b|ACv96Klb4xepB8T=}Mj3GM^Wk};i*gCo%YR8^ zskfN(FyCGvjKq*qImTvCRvu3CGI>8b2x_xA5rJZmA+^(z${~CWv{a1~X?=0{I_^Nm zC>~e)#-xB&<;_v-=)l6;{f@+OeF^mJMQ%Hf#4+yL9dtDWdNnZJa7$Vbf zH_H#f#mpUosT9)8Iu6`K^9?RBI#KrHkBAnQp`76V2VCrrw{m(}?2lnuLNgxXRVqS2 z)dIK#Ztd&X5<$6b65(RLVOGEBNZbf(WwExx<3oNd(~qqw8rg`G5+;|>d*&A=9&Jnb zrKhgKE`T0E7JG#MO|pMBgFVA*0*=#_DyruHebzD{M`8UUNgKe^zPpE1$W1ZVT9f#y z0_H2qDwZpeNX(iVH|E_;)2b~I+8Kssm~iDOrGQ8Ao{cM&A7!ZPXb;MAq&+*@U})OZ zqvA!sp0Qo!d6!=2__{ryR9|`|GWX#n6s_)na|3G<+@g``$tKZ; zC|>jS<3{7xnZk`o9T+ok>wA7f>PcAx&n&SG`mltyR!XOSujcX3Wmy;6I5v#zpcJTC zil#rG4jW`M(5|)iXWXw1acSP3_caQctHm{+h;S{FLQp6)3F5Hd!;^*fri%T*8!+1% zHM&@u^p>NP|J&|}E?y19sr`fW&BKQ=*q9@fX>F%j*OY)$u{{41gqVuQf8%|!qucS> z9ImC9k&+jCNsFOypN;g{ocBw7#Biz|;hpI$!o))Jz$s^n^3Qw<{BZ0c zdcR%pW%j22*Fl6bf+k2*4ECPkKbnaJ4|qh_Xv9k8b=?AQlq<%|XcwYm+rbG2!{%}j z^eb+l13TIt5GiX;w*qERN_Lys?C{=g$;|gD`g~1;xVrNLa+R#)sr4|x49>0`RjnmR zJJSkBZ7$|#r%0Z!I5Wvuy5U9PFbc0Z9$cd*`PC(dEI%o$GM`q&s_rLjK4NH>?=A}6 zD#E<)CWmWok-t?Sv4&p@wdG5Akc1Jq<8OP^S%NFg`VBrcN?h$Ra#YN)%mV$Lx_YEn zM>Z0crS+TbI)*l3dJxwH<6HTxxa6*Te9cy;ID934pT{fX71LJu@Z@?C+HrJ?rB|89 z8rg)hZGL6G-BA1JN`kEnye{hrL~=U~U~a1xV!?;v=rB8rTyG4}DoBv;?jJ$+ZP*5gaX=0#cZN7J#K(e)v^2TJO^bgZ#9k&F-Tbak-Df# zK5tswQ8VB5{Qxnlt|v=c&~85pb?JYsP`B8}AAiifW}~K~?@#$JE>BFA;?MoJ1B>`x zwg^>Bo)hGcs4>q66Z5XJ2%jG(!RZ0EH!}R7lF`WVyWWVUk5Z{D`x|zZo!Y)?+nzlm zPBav>k%f#$baO)yz9mZ=V=X&soO7+oMQ1apVO!)jNMeQ0Ck=BRB#N0J*|M$gSdx1S zb4Fi=+8JLNdYfyF*D&y*1il@qoWX|Ej>5ImD)(O_5X_qO0Orq%j)Pq zg}Gk)lVJR@iN0vEun{Lq?c5FzbSg`+A3&_wAU~d`VAVX1=smOW`TfkW5_+CcyVuSK z0i`%~+YQ{k7_XX+tHyE0u6-^hQ; zE2a(Y+v*fL?7jWVYMemKM-UuZ+=wV>#le>eIG29xP~+%%Bpwq_>Smody^FKtkm=DO zq+T?Qgd9-0tLBYAkMSrfDm9+m*9(?xkRjqt6gVF+KCkuL-vF@r5Rxt%B9yNUxlSu-rO%j)Ad=?{1rP zx1Jr?WhdKV63WFzA?ZoY^gK5yZvG z{RAH~{+PFJp=5S?<+al6t)=?#sOqIVU0ZwTT+lJl;=^R0PM>)lu~m7|4(dFL8AP4p z&MD$Xo84+QdLA$tWQ;J)B~O;nEoVLnRRV+_!ydK3Q>|6425H-79BkabTBOF{XI~_S zgmG<;dsgCh(q@fZ?ttbUmJ+t*3qVVGXXiEkDxB5d6K&npCpAa=+{ev|+j?+i*5I+6 z`p>;1*sa7cw`eBrpoq|@T*c~vSM8fT3)c^*0=6EJ1>R4pSX*gI!N*PiiBk9!FuIlG z@?(%0>upcsS2H^ZpVNIicS7otRWqq32R2wAOs8073ZDgyKB-lU%JW&a*2U9>G@Bv& zcU&6Xo#B9wN5MV>t(gPE3=Np7MXFxxON8QMO*98Qcdp^7(Ag%E7pDyA-|1afu!vrHK$WvLZ>ZAwP^vV{49yFXf?vdfl#x}9bdwmJRIqQ&vUVmS z$)-g~5f!ruHmS{Z%?pU9<0O*~9&Uj}_cVkB2;A6kX5P!YwA}nD@+yx}bA0Z+z>j zWPi<{4i2X`V8;Ii=$9+a*mZ|mR@OuEJi`?+ZNmu@zETYKLj%Xv^p|+V$87Og&-`9S zql?Q8s|n;;wD@OJ|9y%0tnEHA4=+C&oYuA8C89&QZI>*V{5RMGmVbCDnY?J-2tl-% zm}DpAV5SXc!=mPjiF!8Frd4BaS_Eur+lA5~m5!euVS-^bOiQmf^m7?oLCP1QgI0^0 zH^Cvw5j&bt%Y)b?{mHlx((kQ5~en@HIjH^6R&+hK-ODQWAcrr}wlUo88dwCL6er*LELr5eT1g6t#-Gd&bMp4;Gi ztrQG6$?~SJ@-yr~f{_%(H8fVfZEuLHR#AhiSOL6pPMFM!?6*JtXoTa>oZqOg^F@gW z-qLYrbI|yzH}5$o&)Xxju4xgCs!!l)kP7C?*MX2P{07CpV)KP3M3nIAvQ|X=4lb`q ze;3R8DSHkPTJ-O^(P4 zzsC-^ta%HBR$ju&pZ2ydNFDy+dXb3ue6k|4s^;xuEu^Tb0!ckXj@C(w?A%CRa|{LI z<4T`e)FI9uWPYZ2bY_Bu_68Vd8dly|fwg+&32gf5z@R)?+}IyH6aO8HtXZVM;}c=o zQp_wwfjgXFr|EcVG=Y}#TJiircU&6Gdt8BGE3+ty%-vYCT43XOx+X|&c@9_{cl&+6 z#xyXu1dB;VQL6aD%P@}`AnJxh3|#JXe>{zK1gGowvD z>H+Kqkush0Wbp@o|En{`{xG{>k}b{^%TYNMzrBmJR2}~f#RqE%P4t0&5`)4zE@Ym* zkf8L}wTG>jo`sZcKKIg9z2-OdCe0#zW+SEUh+oIqPY*08Yf6De1|d@{ECRmaLBe$f zKO^Dr&tVGMoU4(@%yRR=dfJiw2q?9;yao-8ho`vW`@4Y2P72_gMGz^rTkCN6t`w)^ zx`Qv{CS(m>dK`JJR^H~vdX~pY9gF2Di}f{k4qmWHzDY73JA4MPNpbDjDgkd->4xlM zBRdzNb|k0rM(yC9$F8TXnh#yQY?0ciJmTNNa#hxCk~+t@bxanp z>M2jvk(}0n&DEY~`c@%+a^uh*v!{D(w;(jybJcm{qrTkGoU81s5}5EA=pNn0T8MwH%;=5E@W4)70$LH5ZZV4C0QvIDM|90#hx zh5s7HYN0D}eu%(V;gZXbKx%xk`qcd)7gqRKE92HQg|Z(kPFzW;JUnmoU}^I-G}#JZ zVmjvrA~U-VQ)9F_C{!8I-rj^tG%l?(m0>gAq6>;8u)}EmgfZ6PllI!ZH1bvexvhFI zOqbx^+iEAEQNe`y^!tEnGMB1L?u4fNbTJ6P`WbT+=`3 zgI1hUxSp4}Q_dX2%qgvxc}Db+b|;i{wr+2*=GSq-2ywX({G#5LgD~%%X`GPRzn+!x zRwqWM!}uu}SP`T+#10=dMeXZs9lo;}RMmaDVVKdjqVsTZ?R?|&0#Kt}JRr~@&&s;( z3!$bWFfq1kIinbiawD6M?qRmSE+)EodM70@K2aLabm3{Q5a;1$!b%JyRyzL=Mv`oQj!Q)3nPoGmXrw3|G0Y+~A##vLKlq{5kdgqe1! zDuvIlc$=h<#Ncf~biToW&TU8%I36M6@H}M`q5VsI0=E<>+k33fxCgV{tb8(k0m|TQ zD|d5jk80~%?tdZ;n!(${&adGiQve8>c%qh&XGB<>LCqFM+sKqoGT zO+>@A8D#gB!l}it$762+@M`Hn*+K{Yv1iw3CEGlZc>x^wsz(jeYF+p=g?ff|CEls} zj2h)T_LJG0V_m-rM!mWuf6=49!p9ip%Ri^WCDD=u zzn}ALGdJqMbA44&n$=$7ZF0@^cZDIy#EMU{s&Xb$)spyqxH740=##Qd4jvhmZB}5n z4tTFwKJY>+SNO9QpT+ES!tb*bHaqBAzhlA_Mzbjacxgm(bg6CO6`swTyX!CCB9pFp z?f?^@n8Rb$ZJqI+XTGCt^_#sXSQg$@U`G&om%qig~K~AtM0Qq*()tP>ciH`ynUSP%)e7>^h&%#x!ghZo_&sAyq2ud z9oAt%s28%Mm!^KT5*-NqrxR(oV>i%!-v0A0S0x{;O4DL>8~hR2}v}#@6PaM zwe@Jzjeo}7ZE%xQuqSzW(EB2HclGrP@N;ds0RkKz=X89acDUx?WlzcHD?_UV@X{zr ze<9yvFK7PRK|rtI2Xazs-bs9endn&|+&*8&U27dv8TooBh8rc`y~>fST6FFGP5b$> zjz>zR;K+*+BM+wTMZ5GgF^W^Nv+y{F!zp-@g>l`W^(}8bHat$7J52$)DPKO__d}OV z!enQ}L7$i(vZ7wC0Q+u0sF zz^#W`KOqo)JQ!{6XVUS?wks$tcs4&rZQ)$P8V)~Nb83=VH}881lH+indjBvSmY;kpsb%{esE5%@{``=AE7LQ`@X6Gn-+>g*&KcGi3rYX%GR9ih5kQpXwd_In z6&(itB@iB}{O$B#vjxo6sKMX&*XiAgtoQEh0&K-$rwZ009WT@^E}PO-5x_lJMPsbg!gPoD7zN=vKRqnM_#E{KL)uJL@hUTbfP!A9ut6 z6U~3kP+ow*T*)FL#|Isj?Vac{oBWfD3)>p%A}d_d9LKwX48B8vv)pyGxSYJ8N?-Nj zsJkqO<};feMxuN%EaE}SH$Nevr)C_#YdPS2lL)wMcVl+NO#SzR&BcE;fqFYQ4UaNS zJ?j>sx}kRG=}P6QT3-miOK&1p^1c;zqL;aXEi5Bl(tb{foS zq4VDjKXMfYMsznR58L1}dD|y+$$%z0vO+AK$d_uj2P`^Q<*Oo~MlewPFJjN1xR*mZ z#YpT0TQ#wGJrUS4d;XP^`Xu^>bnXYux^J0rh`!lbG{>`5VedC`YNzRoxNItpw-Dk7 zZ&eCaZF=0%(tzwXaHz9rCh*JhM5?Y|$g@8{cR^Z{bUJA|E0<~*vf2>FF*+F+ckg=> z(g2to>CAm)6QA)&lS;f$?_aT-HL2f@gsq4e{ZSZfYgL*Qc)q81sN0r*o6C}5ofQ3c z+IJk!hTROtdzY&>Ul&w=IgQotFyrM8E!_J&LiyXZaw>Wp_H=V>Jkni5b8Z))wIy`F zk0{2Ya6z{0TQTI(;c{>`yK`mq`q#H-uCSgo)LrTqq~>ES^SEciA+G=Rd@!@|PMs~G zM!BeNeuXh>!szX8s*`7U8DDZ|?4aEOKNz0UuJ7RwAr1Xzkkp`y{oZ3l)k2+C1?vHu z2L(s|Ym8How^+<=Sqk)KN~&Nj_F?_&b5E9CMHJVBu*QgX6xC1L-KWvIqUsi~STDhr zYCACau5aGl0Qwt`8$OBikkaC1z?O?4yTyrLNXxZs7pHZ&KCTmrRBcUY2!7oB0i>_@ zAFWXMvMG>f3f5RC4cPwU`nfr*2+Gyg#^o=xj+^|6U#m7-Z^PI@0Dp2yT5Y71v?5f= z@y;rbOOy{@x#R_la)qQ67cGzM zVr^mXpD1`PV^;ii2p_o|DK;GpvM}jCt7XD}L$U4aMa6C-X;2KZ`?DiyDtHkF??t(f zuOdx4jqqLBn&&@7{7;qi@p+OMbVcPBRB$*u5& zOZ9pc#BI-Lh@~=+V0u7&ZN1x+8fNMY0BpsFjO(_JvYx33fP@j&s$I1FI15vG?q*m!91x7mk~PX4D@r2VjrLtb2U z5c0gtgOr>M-2O_?tgLmy{H-a*ccLPn$eYO%&pMzO7}WS(8+=vPlHkjpg|;$N^^jj< z#vnzCkfB?+Yl0&1fMG`?t601o~unnoS4d<|0Q<_|%htr9n^IfjZdF6voCw1mM4i{C_0Se+#V8NvLQ{QZ9nU=GRS zS>8onRMpd*THpg7uK(EK{g3=7{>$KPTwb4i0b*;1oy{PShpD@eoH~J$xS+hq{}%}m zARy#_76JdC#s9QB{{IQm_&@jEv%C%$uloE!cJ%jw0qh4rA2|N=g#G`l{NHX7P}ecP z1DvZ;Q5@zkfFVdzZKv zQMBX*kZc;ekGCh~Gh63P;Cvj3MuV8H)z^grM0zf1_k3H<+e`QN4i03fmdTT_-5 zlmFlP{|*@Re;)ovvPTI1m&W?v0lEL1B>%f&2?+@ijB#(mmm*8cu8dWXlADXLAu)Kx z9EwVAB!E82qn@LO((1rcIGLt~ocr~4~ zkgB}^%c1i(U#-Uh*!G`fp+lgu4J{Zg<8y!jEj)4N$rMrf=|q=w_|!upiREzK%FT+6 zgTXX{>(DSwLbBWX#32v-O~$~II6_5fOa1epsaH5oHk3%~^dh1i43?eJkKm{VvVgR$ z5&%S?AEYbX?_-jdWpaHKG=`kFrseU!p-3s?wQv&#LCKaQG7BS-C?xRAYs$j*viym6t;=J!v6g3P-M5LRAWoanqX1 z$+R8aFEmsm>*}#vbRMElmH_ZwBL%D6!Hb;-r|LYD z`vCuhB$*Zv2J15rgx15vtD7w`q6gVf_G`E)Bm8NLv|iXCxP+l98}@}p!di+1(V$AM zn;+ylU8yb$InIJw9AX)PSF>qW4dN&R$ajK9!7l{K@G#}p#dVt{xYg7m+P7HOe})=1 zmTDNEEAD5dQkSwI52u=~BtzY@x0F>*rZN4l0eZSoX2KG>mw%^Jk;aHkVJQffHR(@^ zEU&K`x4Mqe;wx`VFf;nIh$>DLfA@^s0Wmt}6 z?;V|jN~JSGaT$dxvC~EsY7ma-wX+-VAShQQ;63NSkE-3=vWId40$Xo)rvr-OKiIxH zSY>^%e@w8XmWcV)!vu?NCd>RBGjV`WneWT_#>fCcn7FI4zrZ9roW-Y^8W863OVNm% zGL1&Pd;rlT>NVc)tQPwm0X5#g>l}|a7LyDx0of%BCl8D%;O#;3%FVeoh|nOCrU69O z&%t#9QhTTsVHqKBdAQRJ8f9Cu5Xd%!)mUF*Ti{J3SMZmTmG-b~+71f8V4Yz;VUSMj zK$+##a02%ow+nz%Yg9cs8HnYZ^?9v<3V#yoQmMAxHN~r^L_|tqj>OdzZ^Crgd=R7! z!O;-pxy+fxFgETk*7ciMuY_ltt0-~2FXvi%IXisB*azZH5WkYb8HUKVK)bkDH#1=v z=xU+vu7m~a9{V<;KcOfWx8kn)s31sYksam1G_c4y53ske)8X~DBqM8sqRE&fps}lz z`8OzoypI-=P&)IPYJeT>)d(Sx;7=!`0d3^sD06jp$zs;Nq)%O%jJ0+T+&45{6DijHe!uZ18 z^XC#6R~RfmOo_!o0t#eYL4FNhzeXuijzS%BUMNt+ecB!G$yF{teTw4)_zg`OY9)W`V1~*b2 zsZkppOj6t0A*G`DSLY%eNtDQI3_MR$v=2=DhIdtZZbH^IQLDMa@i1J3TuGcPU_tHy z2kUgWqCvfU!4dQZVHaK(8c0dj4##q2Z2Kx(R6eAN$rD{21DNM~>oK@-Eo^IU&~^n< zspYWErqGkOU!R;&!mBdAKPv&9f2G2Dm8dXcO}JK*$%|qlI&89==TFAeL%L zd$8DKeRVrX=#xE8Y#Z>@qQ!V4bd9rrL5U-`&yy}U#&&9kD91AFW{GTDV`K85&9SM< zG+X5NE1ChWH99BNlE=I==((a7!x~>qv_1}sc9NrAXLp=B2F$5q~m1}oYJ@Ok(F%T<- zE*?*%Q7w@y0u*iV&=;$<+yJMHPdVvl*dUQ20S<8AJA)A>#v+K_p#BKdE!vrj}Z8^~qbJ;owirHECfAA#zTbQ)60Q8zyo zfnz;jZ76GXX}I?hSVf?QNOsh!i9$lq95z2RIK^DsBu5hxR53d1As9)^U6QELqYW$! z{IqVTNme(2mTf8zxBl$xl*gzF+ z7_q|d$-xB6ph!#w(WJC93$wr#wV{pPP*1X0XE)yutH0&nW=e2cn&N-K+ z9aq^P6Ifh#P_=e4iIIwJD|M=Xd@OkHl>n26B=|zm3J_8}Fw=u3ILOx~9_a>kFw_B% z5mbzu+l(<&Ao8V%lx$t2#(!}04}-#VPQRLS(}xA#AqKup(z>e0Fjoa5PQ+c~ccPgw zq~m*W{M`4$mRKoZ_gJHWG6#gNrux)Ubq6PCufF6AO}t`h?1Zko;hhE zsZSE-m4VD~LB9fANjst@#<^jxHcC>XPLS$ZIRkg_^tCI1y$g9I0AbXahzK??<j#Y;!{qWg|?YH_GIbFaw8Z)-Zt9wWJ}%K$@)7 z_iqeTu!A<)c2aLis>h)s@*M~UI2Jac))iC4PSpi0vW}JUSI{9d5`*GWCmZzaI?qor z0yEm>#F`l!eH2_dO{v>r-3(%Njr5?mr@#7_s)AY)-x^DSn!BXOjC;HDg{hOr_ zN^Fyqnmu>TRI7*VDie|%IffyPzfCD7(oQaE22is=rYsYSi6OnCB>SjJ==E$)zq!`K zSVbn}SGw1VgsYR?AGd?i#LQNuB(U!dD9W?>y=~W7`yCCr@oX@q)r~<^t`xwH+Zms= z0vB5&WCsgEKf?kf5-X2zE{}#(mxE>qNr1|Q#N5Yy{uNAv!}5?;{n?jd-~pQ|RGz>$ zzuz#qSW$>N9labFg(3swh7myQjAKf;i_B6r3JF$Snb`r)kvcBcl2PJum`)LhQdl*E z{`NgND3G=)EupXGWs8wD#H&x!1U4r2&^XYMI0`S387N?>I_kty#)%)JG&#QAL5eZqj5PI6=ewc0f2atADXf=rpT>0@&BTI*OuS z8IP6>V8T=}(gx0^t#B`s33h1ccAM=^i*CWo;n!SBvZTg(0X^;gX2*LkzDQhzLx~4_8*I zruPuO81&*hC3d_n;Ylm>3rJMoG^s37!Al36A6sm9S?FqKH0L(Np)0a9Rm8DF`bhPx zIcbBW;3YU}vdnbLuKFUWn^rqRFLM&EoL&clUhF?R1sMabmLUil)FZ54reE|3Hb_fs z5`IiBFq67BJYWu&)3Kr7hOQfFTF3|7uhJVh`#nSS$T#ENEj>y!3dTVg5y_)Vj7h?U zomHtxD)gk_p6wRZR2Kpiwc{zhLfkQwPMv6tam>|WEW(_GWXXZd6|1`6WLuJy#Jg`s<1;YQ)bN-1y;k?OhXy-5YpS3#1UR zTZmy*%+!DmREFfj3msId+YBfBQHB$2+@B+aI8{7f>;Sym(HT>O{a$`MmUYYG>c`bH zc1_g`WC(yF2wqn*aqml5dY(MNTUXS02W!0mB}rQb4=oA#2MQIq!oWGn{RW(rpj=fP zE@X+EkwYpy0yl^^kkZ(bBMDVeo&Xd2tO|sMAVF z!8W6Zeg}{oG6XV6t;Ix2LbP}J&;r8AIFtkzk??>!WOLlukb+&scWuof zLbdOO$1XOeR?TP_Dj+kI~8LRthJec{@Qh`MJTAXcIpii!#;-172l9W ztKmD#BIu4QJn`1M$cjzj8PTQ5uWRy{#BhaD7eT2%;ukM!t5=lI47*W5;C|tLxSB0;Gc`+Yb~TU0nUAz_j*VEG>X#xI|_!GX)w3 z5ipde-dJR2F>r*)mtT#g&=i1U5M9c9#OAHRzkASZ< z0L_%cJQ`zc1>Kqzvd^9IIJz#`L?q`hklD98aZnY=LOYuTBP1!&6R6@Q2$PkD6}H63 z>adL7WrqBB@`-X~coBE1W&@Xk#IqgCFs1)j3BkHT+TzO*MyGSXgqAtg?G<9vN2v&G zI=DMl913TRx^c`@B3%V;jgXg@IW3Y*vJ}@JC04AmnRRBM$61lfe~hAU>uBB6)l+rg zkd*3AUPp>vQVR}cg!tO$ z9jp;qSbhLKeVoD2Ns|i}G{YbS4}aPxlR#j5ZKK1B$Ww`tpAZrv$`4N%K6muMaotar zS;3pLhX(SjHDpx!lCEgx4fG&JtQgeFe-%(>YJ^Ea4JM7f5h9-e-k*$^ht9$v4)0=+ z8j9#rs^Gl|p2d8{#~P#_*!HC?ss5Up&+exE701PPX|=W?L+1zrsGDHl4zI*_$J z)PP%_Figa&VJ7eSsn3PK;$9N~ItO!of}L8XFgGZGJ^o%Iwst9Wk;%(Uc!q&IPA(zv znC-BS8yb>b#IHBh8GgdwkZr!)p2*m>{mhJkv6&C2VkbM#Z{y&r>3^?C}u z0j7y+y!(WdK$5oX5QWNx+`VxVb^QktN{3>RK}RLPRDZF3zOGME4SxXc=Qh${EU8*V z%`+?QOKsDJ=;|rQzDkm(Dhy|n_e0W@#J)Z_ExHOwcUIER?d~c*uWg6A7$!SWWD4zZ zix)Z9Ad%ctd?7lq<+va^$sFN9sHN>`u4RBN_(M^K*ySEry62Q10d>qbL%?^erKwH~ zTh<=XQ|^)cfx$~s>dzoXl+J4C(X3k=ODZ3xBA^3SmeUY`M!412h#8&pj_Lrulx8ZF zhSv5m?Bb}>#lA$&C~s#%@9NgmQmAB31#0n-Sd>i!T^!50Xy23yg@zs0Wse}ug+F-g z%|n2;#><=Ja*b)4Ylsa6Yl;8ze=Lq6*Dwn$;lJM%!IsPSkz|b!j<5{mLgV|W4(+5e z76p@<#?ngmL?IOb@M6X&`;X*twK(*r++q7`hdyJEIONMCU@@MVU=TgAgS+PE$E@6| zDZee+#~xRBC)$S=2vb>)nK7I~AlT)RBowD=+;Y2PVB$XOka>5LuQ4MJ6eMrkK1$}T z3lIr$6EBQR$RtXK6*cg>%n z*{%xDgwrQWN}9xf8PUY&)f_RaR_69EZ^0K z!q zEQ3s4l5V^bSE#WJfwjD?#QZA2J)Z5&mT~Lp!Op79ht!#+enSKO^{>MF3*_JOUypl_ zk97YrKy3f`S76KZoeUY}?xjjWC$k4BF^d3Pk%%}$xqqN!?x z`)v@_{yC&3B1j*V%omfJj13s}0TRybLWRL09IT=5$KdGPk-hF0jlp_6W{#ss{I(r? zWuC6+xq2yfp&8$kdI_3ov{f2HcEtEBQ|8o~#4~bc4B0j~UEfEmMgYcn12+ofMG=X-T((JW%VAsa83r zG{9xstl7xoUoL-PuU?NZOmqZEn_NpJr2b3@5)Dj%le#>{aDT&LZL85Gi^a6#qSDQV z`-yZJnWE)oJ3W_h7Ch{6 z+2-mJ%`b7(MhS7%32jcKp#uVP6e!~#`QiqS8oMMXr__CTG(qxWId1@T#x;_RotT7P zl02Td{sVzL5-#ak=hl0=N#d=HWs|}40e_yhxR7ok-XZ>DzRjI3l+M9-RS!CehNfy% zuj-(k%9};_7Rt)}b~vhQmp~)%+N~igzi5G_iU@_@RRGl1opiLl&N%o650#h7$obQc zlMxIrY)JPp8^MW_m>J;*=#BduxW{}dv0a%V0sR^v;kmj-hO>|IP0fcQxq47sUy|FK zjbqTJETYc!_gV{{dj&00I(=#L`pzAOO4RVvzTQq3)OgZqqFG5FObD6qRqs~gx&$5i z=TAH&gy0-!^Kpt4Za*@LQO&UGxH~0^aFydegGNf>0-&BKKpySQ2zXOnDo@BdKTyN@ zlL9H_pwi&n3ygMO{P@e@y z&+Zml6*;*OvhqI_s$723B9Tu%-y9h;pyy8(d*PcES-IUa=Jp?mG3&u@PiDQlqJ@{K zh`LD5gJ87UEZCA=5-rgUyECQ82juB6TiV2a0czbOAg=yqXKm9)vZOC z0(p5BLT50$$qY}W$Q5`*q&dn=_Sx7I0W_DIPNLcIlt1IXm{Cb1o2-}pU=Daf|Aoz3 zMkT}`ltP>QmWZ5ZE9J##1YV^Sj4HUft?zcDA&Hj7rmAxwQ&omb^sjC@hb_@?Mvx4X zpU=4Grty5By-T|1SRAS+B_=qzi?nZ0N2SuUOR$6QD}GBn-O5L4(&PVZ5qlg!`3je4 zN@jrGS;|rQ-t~8;UCha5JQ<`k{yO~@2E@WaI09iL@rr?8PH~In3yR4P$mYO-y*e-s z=$ReLyFiq}TO1_a3=gg{*ZJxUM68IxTCx>1CW#KKyx3~db@FkSD#aUv$R3ZhCv54L zK0OtH>wLFn8aY|@SsC6=~S z50Q(1YN`nw3+^M08;oUebriIkgGvbc`>4Ts=6$5$;fVFki;FCHHL7H^CI)e-98vJ;7>J%BW#r5Sop`F>D4C*6v(wwWQpnlxbQI^eW16ef6EJb+W5TQ2_u? zj^LBoP761qaa@n?lH`PMq`QZA(95ZYy-PBmAbG{zsMdS`V#J6$TeZsHg1Q}rz6O0GbG?u{gO+IGY{plLXS22WZ_Pf~fQ!*L=}_y%AZ53R zy;t*L2`S^ApRpLAOr>deEzTKMYVZ7wXzhp5|n&>t=J+L23SVw=2?=9BJug0KAg zNzVGMC#0)^$Ofou#$=>rO50q#?I>Z=;-Zemx+Cnate7y?DX+tXgc!W^K3~Cggh=%t zs9W?*TzyIa;Zn)y>&O@Y_x_hNn89%`4e@!g_pb6kgqqFjy7lZ}3es_WE^ z%@>rT-c~51N=eyRM4X2JFT0fUiDk<^l7$Lz$nI2$>n)*jrF*Z08_HqzA89CwO`MqZ zV2D-(kirRQE0|WAW9#xeNKv6fd211{>;N~gFGb5A`aRr10@37vSLN&#Lid#ea$F^c zOm$DpS*YcU{)#*Wl3Xf|3yzo<)j=E)S(6H--SNX&GEwUQ`w>@P!z#hr#LFFp?N^lR z)Q<(zNayJ9Ji;&dnzU{e3n8-NR`0`@qpand)L+32OfkIv%)!&7%!dt2pk1KdSsyu- zxwc3!mwq;WRD;CI;T*TO40rI1+U;CiUmc5|!g4%|nwulyN@uh`*&k)34j7csA> z9Y_PR_Vn%I+Z=U57|SDJ!RA*jq|@R>1a#hd#(2tV=GaM9hs2Bvp|W@=D=3CTvlO-* zF1Kd8b@mVOtt#SNg3T5#3m8c+zYQ?O?8*57br6&NJ&nUBoLxfK2XR@8vZd<@F2aqHpfirtEJWK*Mf{Cl%muusCJN9eW= z*ofdMz*~xRj`O*chz|8Czbsr`VaR_WA0#BIl_2jg%`3||JJ8~{=Or(xlAgG)V%^-J zjkhl_=QmzLXD1~I3~(es&6R*nt8CFYkQU|e-n9YK3?pE!+No!*3`tep+BA~|B4-a| zagN3m4AuShq2E`CuPQEAOGJDDzM&Y~#;K7zHioggcG0IzKN&4s@}HjW|9p~(=F=~S zlvl}Gm#zN+^pSEDP2^R7VD16*lf?$$`BQE3t!_5a(p(^q*;X~C zq|}&;R3BXi@H7%!!~7T6m>Y>K#kOio+O)$O-+GMe4uybF1@j*(7^q%y>N?1ndH8Xl zNqb+|`znp%+(Hj2C5@(2%o~U0L)^YxAK2je((540fG)Hkn!_HIkFAk zQQFxHg+dL4R&G>kL!QGBu><6MfTd%4$785wuh0V|9_HFyJgj=)o$9h^%Gf?_H z9a}X_Vu!&~pr)pWGIeaa^z}AlhwPt(U(Oo!>YLc z9AG|AI@8>E%aYp5L@DQ+xOTk*@3u%FVX9ndz!&xcISy#S%2hfu8bG* zn3f~9`!4Q=nX*wN@NGAXleo2r5~2xU-BnwLuN}KMW)?yIV2W5|Iv(jBet3DQ#HdYK z9SZLL$CDmAcL3Y5I>U>|)r-d>(C3P0OeyEzFQ4gWJcjxQff0+02{*Q(8=a1`(VqZ8 z{(Wr;-k&K-kABPexM*ffGPf8#wd&jhs*jH!MDWh|;YU>Rwhe!l4w$Dc<8f`RlZ7gqsKR9{Dy z$R7Gar2%j)9oX@qOd~N`?V5r*P^aCM2!iH?9^Go@oc z%BQh)yh&V!(t{V-LV^qc=6|bO$B(Y)p}HLa*PLfW$XQkoi-)KT4#vKnse@>lJUR)W z-D@L{wk^Ni`-Szdv)e7nI~9V<5|apTptv{A`PdAfEkw8&IyL7O8t72x zgNU%f94?u+XI8v&y)gh+iPJtb9x8jBLD?R&$+Mr9LwU}^A-y<&rru|i@53+E=D2@?0P?&YlXMU|2yvhOrAn;(x8$T4lp z(DkKm_Neh&pz8poXAnEqa?Psw8Y$qY-loB^Y>1Ood$f<6A;YCh!Fh-%35(4=9VjTA zNv+8Q9c9qgtt^NbL@aOr!XlO?c~s#x1bv73N@)I3hJNAXu(Kl0Ooho4>lXhR(6~ir zQ|9d-rm_YBg*f}t9V)9D-||g4($?~~UX(OL(*ib>x&ptm+EgfUQ~C zmmj}(dosSH^d8iqU=RbXNraGzg`qcb_Xrwq|2faZGqmuIS!nvE;uU+hV0b& zS~+cSB5C)Y_DtPrJm?0JJYCLSyZjHi^@o<6O2vR5>SpXfXg)IK_zsRcn@>&{#cW|@ zs*tN_xnWJk-8Uv(sutm@le*g&KaPrYf6m)!;iIN)!jSG@!t|(2_aUXY&OXSqhOC5y zJ6C0OcVj91sr*a$7($_lnz&asFH3pEE$qHbd(b zq?Sz8WvWO0m^(=z#FZPfh(_`c@`arsYT<0}ej8Fdc96F~+;T9G*vZ4kZg&yCEyf#? z>jmUmsjJM~JA&=ya!&RNFfO5$799rdv)%I1Yt8y@_+1{jAQcOfJ=2SzXa@ znap}bacWQeGou%tn_RtD);B(n;=O))Jj1eCR$dn*)#+sqgPsmF(_NhCn5vXj#xG%j zgW$}FRt%M{CW}qEnb)k8xwIX30EiFKaPmh>5^)dln;o|St$Z!_oa6Cn>5iK>QG$($ zh0u9_*7|`x!}u=sV40DCgw^tYpJPOuta3b3v*jFx z%>p}&*b3tmNcKe?_uN@gl@U;*dk>MAuJW2@0hO@DV3=v}EnyKR)_ikq7|L!4Og=HI zXW6mJ;`6l81NY?3AfMPaoK-s4!d%lpy3q3^qe(NNJFZf=X}Za*U)M*);VcLKv^~~b z;yaht`>Q3ys00YesuEiH*6iE+t}S*qk4tEObjIQQH{;g+5UgGAJ9uA^C$J^{5|lmJf=_@X%qe z!NexHW$(pD23Wi^I}<76WgGr_oR9e6@i2{bua50UUn-HRITZ^1KU-Rnr``g2M1|A( z4b*iAio^o_5$d12X--kZ5~6b=tF@?na?=ZSAx$dHXYMAX5aH6dcKApPQHc~cJAPFA z0=GUWDOn_HTedNYIYv?Z8bh-oCo1#s&x%zs*~HHW#$1r}8ZXLI8~H{Wh75I1Yl?XH z{n4g8$BCDCE?o1qBmm<||Nrt@k8c1%CeFxUhpJif6o@OVuxo;3E?Vo)iNM=%PJu#x zXfRdLR>*YPTZA7jDeZ>~9_w z29(cr08&u0(O6h10-iTf!dj-}?y_#N=Yny#B5g1GHs=%&*?)`54oY_3P2L2OJLScP zhvV_uoHX+gZzD!h;Q9?B%%S&b_71NWf1Viia3==Uw{x`1#K5KK4s)L|&!l8wOtm4e z9Ih!NTM!jYrp4-u^?0`fF((qaL+Of3!`_P?&|C$ZlHo^IJTyI+?~-)pEb8v3g1cY> zT<$aII)2MOPOmw1#%wEY{C(AF2`XBi_+Fy2L48u z6fYC6BeUO#4x8*np+42vrB;DilV>5W7vB=9Xe$ktc<48o%>@lzlF?WC8pieM*^1{F zU(lr~)|z{Av*lwPGWVSXR?%7c@=?~vqOxF$$9f{0XDj9_G$f#WWuc4b$*}OHNYxrc z{nzC>{kU#wdo!kQJVfEoGX!z`NXwua`?DF{q#8L!zR(OL@qTxTS}xlV8-7iReWW0_ zK8U?zHbC*Rl(>yhTHVHdQ126mlV@=XA!w##xmK%X@#q5DfK03dP}TCiB#$@L92nxI zRT2?;!(5Dwyvi}BVz;PpI`97($O}aV;3QM+lomw|c%t=JrWs>X@!s0@!3F z4kUC)WTqCk3$KqyU+lnoW&9ob2RBw5CyTFai{!He%XuS+;-c3r5f4E*v+;1ZGZ~h) z3onu7YSRjcjS7CNd!6P%s*}7hL1*(ibj+?OG>PPDF=_408?*QJ;6VozGL-+)Ur~hU zZ0UAdj^-o!mFOWX^fOf-G``;6?lEaicx0IoA zW({Ob(kxm{JcW|}knkgZLOla)C87#SDLfX#6T)t)k)Do&fGK%8W!=p6*#gm2-Xfls zC`eWRFH^C%*fCi)+XepUF=tr4#eh?Ege>-XeU{$$1cMx^&HU0I5Id3qTA-_}yRlSY zNWgIh%={$Rsbs{xOn>W_ ztcuIc_5?Z->o!H{4Yp!jjmHeo_NQ)7+{+cp`D~`MAsbvrWYvGImnVtiu zrB1|M#qfcP*lj2aF2sQ~&v}h{)%J(5VkCSjfQ^0!k~F!z(f|*$I{Ox&62N?grO8_B zac#GNcC$LzCw)KsYGlL0R~e5z&IkdwZWUBo+new=_MlYApq!5$58DEhx#n6I-c|_K z;85DdcNGL^H&cd?%eA2)2ew62;5gR*Ea{Rp8)9iXcx=Q8AvN0pSJnA&R{(eE1`CM) z!rEnmPbj33_XqcN%vGsrRNdSa zxuL_`#fY!Ts75eOn;{?Qjdeavc(&ttuRFQ>(m~WjW`#43yxxjn@3ks8KkhV1pnkBA z&O1WZ*c=sW(O&~0tAPctq%R!4$tPcj{0JRm)X7d2^fN&zcoz*1CJJ3|fxq94jJp`o zvt#lX%fy8K>{2RTdx98W=xjOcl`bk_B$)MJtFC2}?vlbQux7l&Hfh0nXh`k>a;WdCb#4K1 zLVAC9T>P_uJhgnY-Aw=9dX@3REo0L#7Z3BWksPs0ION7M3)t<=f+TbvAUnuP!JZ0?0?76=5Q5|q zd2!xQwc~eC&~xjp>KaRns@bG;a`y3lms4SQogB4J!`u>WW0}}px?!6qAeTkC>-uU1 zh{eC!K;ypR?vn%ekGbS&^#eJ^11FK!#uUa>Y>ID+6dP0tIOmlt%Y#FSf$>3;z#;v= zJ9b&HAo3uqn54dI3X<)+l*aeg{^-5ff6ert*zye`@V*(R%GfV(fZ?sO;S0)=19Dct2lf~*s4C!3_ zgVKFfS}0u~;9sLi5!O_xxj!#B#i0rh8`jwzV#Nz9e_22O3L=&Fn8>zh6wIuB2I*@&ky@+Tl1z zL6dpEpkIA$18q2$px*>|6uPP_f7sJFFH>kf>Q^9M+dx4R!pNF3qzGT_>ob>0mP!56U{r)TGyho_d9~F;q+5%FHTFqS9j*eP1+oCb& zTy6vF<1Gy`$gY^pulNLk=zF1FW7ROk(F5MDo1L^TZ1@gpTc~=a! zO^NFBQjs0*Fg9z~-kQ%0PXJNAipvC}P*)H7&E=&ikLtBA9UjOXn^Ox!?}aV}@j(V* zDa*Db8sbnT^|=K1WU83w9Yp z_(XL#zfiF8kN<$vtIt?YvkSAdTU`OI=%$1?0=SST2on7Jtk`KjQJ=|zw_t|dk+o|{ z&9V~0MS8s>0_0rPuJU*Cpz|5y&V0c)wMo(bfhB&fD9w?A=`*`^L93Szfmi zI`>54ii8>svNWSw?T&umrs+0(z4N+>{n{A3whRa3QL?i5{q)Oaoe&B)(tO!#w9ef& zuFZ;1+gkWM-2!SU5U%>cEcF-TB$}?(M%3$?uE?Bi+L1n9L&ULi20Gn5VVapk2uYI6EN;S@T{nemr zlj^aWOs!@V#9@p*eBlBRcRiH!HNDQaacjvDqCr=SL%>yJ=bv|N9A;F>DLw7JL%n)Gon zlnot(Dn-#+2uFQF`u->h*hOJV*|2sRb9D;|4E$tva8k#iLw z{w71%uoMdsE*!m+2?1DdhKjz_l+Rf4G6#vK0V`s3PLq4t>h5x<7=@HyDH_t&P5|co zaTucP10Xgn3*ZhH%;7W}DU8`A0x$*?v96(4KF+|6f5JD=o_CqyJQtx9LOyP2h!iGQ zT*84bE!w!x9cnH?iK)XzFW)|j3=Vy{V$8uHU!1KFTug%ZGiSO6QmhX>?AJBVgwSB6 zHx>2rWD=I|e*Z(={}>SMS3H zI+Y++mtzXzT4Erm_vkdt5`CCAg!8Df7@uLh;$oqdBzho)GDjDwasOWEo2CU-8y)rx z95*RA;Z~9Gvauq+(DP8Kk+K-LAz!r>1)*Vy={p}mV-swFBv6){2*Ome%ElaYhhI|) zw1!a;v_fsvg^u{}v0@9#f`yZZVR9=v6ecff&ptEoA%5RXj&m&ZHl9futk+-xc)?D{ zNG&1!Yyj7^MMqV%B_BSvn&iy>lj{d-c0NZ-tC>b(($og@*T zR&-`+=Pahi4^w{cU84;^SN^)zBGgD&vTFgoRHa$T9Ni)zk%n6Dm>Nu&=50mxcI?x4 zORWGZFkv+LAX?B=(Dd@=A9;Tmsmp~W z5Pi7F^fS{zI?eZ?5yA90wWlqSCZ0U^+w0R=zGl~p^#ori6Ua0O zjq&esmWLSG^tC{xl_SMH^Ofm$*hh}Y67PRfAV4IOIW~bO)FX-df@U8{#t>>t*ko1O z6P0&BvFYV2e!6GC2>C;08yaY^0|s4ezFD<4x9*iL7FZJ0dZuUAgYlj=ZKvU&?JxY6?qxZlESMp#WjY5hwI9wt#dre zy`wXz(k!DF{pVcJp%j9>sKw|y_h3#-1a1$UA5~9<<4aTeH7+5tEMCgQY33=sG|Rtt z_a7_0aMd6)_4r4)Q?dp3IH#BZ?_WWsbG*b zsxi-7Rf&>*t<_N_{xnLpb7d@d!{$PFlX6 z%&|dT`QS}2V_bFTXi9}n`5@pRR4qB>MouB66cU+3COgpo!U}V9x1~(8Bt6c0!ri`;o zcuvf&)8@<}BV-TDLhm-c_XJ2&7RB@4EfGwLm!{ZLfSkqwO!N;WeC`tKc3`l&m1z;8 zA5}|Bg9I<#e6}n@={BfeqCgZastwSfuWFkd-VxPK2c<3YXFM_U`TAgSEaG(Z^fIIX z-v>jnZ~~)pp)W z=L1+0>V5!eLo5pX0zBOEG|C|SE8AnEM`Bbzf<)U6%ja^?QIko);mAN;O1_gSNI z;%Sn)F$0!vO|4AJ{K9cdKf7ITat|WxoBC2UQ*gu!EdArpX z&~YiCVid=$0DvW#gn`|EC1OI57VytCqJr~I&gyZl#IqGtE7x(BT|08yxR&;g8pMwO z_Q9N(r`0<>7#{G%BI)mvlN%`-n|AQyo`ZokqhmMw2!Uib-Y~vM8C~lq#VIXy?R!SD zNd`1FoO@ZrX+M4SDUf6}Z{lb^E{X}8>mDF$d)VL^aco)*7uC@s6FH95SH1)wyZS+< z#}XknmOPyS^vppzhczNOCx8dC;EjwQz?r@2GPSXh#>y?w`S5{jHIpV*FSKwJ40Ga< z_9R2a8}O*oGoczu2UCX5f{)j}Jgn)|gld04LE~>q+>G|rij2-iEVh_E#(tn%t_SLB zb$s&kmZ_1!&Y(Q~t}%rR3eg$H8`9fSEfKY5ydv)E4{Dk^+rv9$v4G(xpKqm{$E7z@K;IbiD_?f4R0@EU8F;nsdc25}Y2M?XNC!yrpcYc#;^`L|wC81W>viw60~?syT>^s?JV{tB+Q}A= zl;fM+`*MZ71PY#hzELJ2M}vboUui z&T|mi!XBWcL&0O#zwlpPqWx{oT2ERr2nHb3#ueesCtwgw#;q=|#KzzoJPd@LeJay| zHK?Xiq9mlA=3dPoLk+sv+&FfT3`&x0^=qw&NvmynIm_h&E%i>KIiTREZD%b=&ksGN zg|L2Wu39#x)0#mQVLBYMji@44MA1ki2}Bt-kmYC8-bnLLq>85&rdom{h z*o_~g?PI~#&`~bRg&meIr!br2R z!*44e52|Hmoc^*Vi-yK5^Q>wNRZe<(dct$Y8V zo474h$oye)B!RE)<|z0Q`<>kgl6wQk!ZxsK@%K#6;rNfLdsL9SAzI|BAk%gD=m*71 z#?a=1;_fF7HV-*|_#=lb<@dP9s~Uo1TTkC&#xjg;Kh5~@spL?3B z;erGcsmZ3{_eH6&5G;e4YP~Fc{cKxnI!r<5Sy=a@H7Z_lIY(kF3eierwb?n+ZKuez zw<0QWc25^6jS_-zktOg0nQ+52-*53cD2P1+RA44FoRC!(hv+T4!(-~_CySKK3LaI> zMor3Hz@6%+A94@VluwQzp+horENeA?vPjiV`hAE{5FE>1^e%=0Uz4wJJrq7Ft8(7j zk_rnF#c|WNB&IeBb+++&Cf=tEex3CLrmGOn2Eth25{p)V^jwKJ1$3)%MXga7;sx&Addd(Et)jR<0*8@@f0S`)u)ih8G~mE-WjWdRx&vT z*TmWtg6Igh=7Zs7f}?Uypa^aFR-XbaSBpX*3YLpKyj3AbE2Mi=Jy}cBq4}YLMzT5- z?WG-*c?{AKXKn)d>ccsVKoGINC2Qy!6X|~5gzIZL#U0U5K2`KZ?|VF-rl_08TGCti&(Bu1qqz@^= z&F-Y&ExM!wAx*d?U~`x?aMb?{*5FQC=P=s3-uHUrQxmb&(DgBq&=&r!symkt+@s@i zWT9;kv0O-A#cb*|(UDIH+rq`VbM$*SkrYp+cWtjv&s}9lhjW=a$-Uu)o9S-H)qpTs zUs7tvVS{nM6Fga}GPVs7nPLJQzSBvErcLXM=$5d%_#W`7Rw$tYvS3gArp?qn>@ACNGTZT2HWYH zf&qVDuhXM}aYW-u@8v{^QwKVqSA=@!o7|LfwH3_?LQj3ZP%4x&n#df@C<@q<6`Rg4 zKb9|wXn+x+d6cDpy6tDd$&*g-{;-47xTQC7lXKiZ^@H%I#3^*K1ACHNmY+6Gj|073 z($#tP6|r#*dDg4o@KW>JoE>U0!SaX2dh*>=r&{^B0zsx-Mth1K*=pvDwevvt2|!rx z9{)nxS+UJ@`mgx8!#m~F^?%k007vY~()K2w=DGW(o(z@$N@}hyCrbFE{iAeaHgxqe zGZ-bvG{H|s40I{VIH3|c7y5iVZf{1N{wFt>aTIfm{I1OAXvC|uX?G_G+@5vEMmZR3 zu~6*m9>bzSKbTcNRrGn z_l^=tadRhkbOJ^H7(@~{X}3Ln)HjhyN-ziHRJpx)K8#s*-l>u)YAEtYMqM=XI2A)i zCAlFkgzINueXM8Ww_5~1^Z$NRGZc*fty6wrx9&Z6}QytFeF&4j5BAZ_oXyEx*UUT5d*8A!mkw7{y0R*1 zGmG)yy2YVY_PHo1esT~wwHBcB+zgE#by;>y%EMpNNAqz%MBgroej^aXWJuUftnwuB z>ow1k4xr{3ZWTVUb3zwx4lO!8OG2+7V9Oz9FfQLjZ#Hnu=;VX9&J+SJc?J7AvQ@#I zLZ>9GZl$$3OSWM|q6W*jYr_u}ec9|J~jevdLc}S*rVtwc@4Y-MXmX|5$$xXcDAoL>GL^ zpSNd!;CS6(LjuobA;(8CYxzm*US&kN(-+H<;p*LvuS@LO~}RK?zx;EXsC5sk>o3D^35l zVqJ*uU0AE4+%$86oF?s`Emf#vdv~X;1j^G!vYMym2Qz@&;At`&F{LsOe)fd=)$KMU z!m@AOJtkGGPpGcBZu^MXN&8vbr6Oc> zJI$TlnP$NYoO2_-W5EM4w`a7Njzx&sRhRwtqdMm=G=QdhVl9Kb?OKfsKbq<${2hMP zX%sQxV$Xr(Yj~1~zV%hJH^)Mz-TKz zk8#vN1=~yuQGs7)v3iVKUgKZ~Y$Fn~G*|XlkFuo_sA*)l^DM2%d<9CR)frPHsZU4-E7Icisl2KG<@dl`L;y$r0$Uf?5RilXltR#q5nC z-5WTgiWqe-WQN9|D}6>R^jl4Ic=$`7B%*wnLF`0m@~ayuRZ=@&v#tJ(OKo(8gATQ@ zCTF+TsYA&)^kDpy0|CLSrlwvZfjzm2^<~ey%ZxhEuhj%GBtg<_;Y)7nhyFz}32~1< z*bnD4qLLIf{BXD&oY^5-&W}gGj~U7S>ZC^(j!2Akr8Szv)9Vuge^x*_4I$f(tA2Xm zuCf^HMYW+Q1gN*-+E4i1JJUkRs!5QbJ%Vu|yq{UkL(s^<3XJV4s%i)sB%G9$hm`r6 z)K&K~hNFmuzeneife=u5zBWR;&hB+?t$PtQyAynfc+V@YdcKW{RyYaEMt&9^f)9`5 zTFZM+!N@o9bNQCw!^Y}2Ve7T8qUrc=O-O^JFFir+f>oM^!I#APbv97ZTz@O`xBFFf zdlHWKm*(Z8VpdpDor~@lOEV1T_W}nu*YC&@sjXOMe*D3QQ~}nMdA(=85l{}Mw^r+b zk)j#7p0j^WO2b~R-Cy;8#*p{=1vTBS^hGNqEMIb8V$Bqtta-gg%GL1`3D$g z?c&osdLFdSVN*JjX-!`qM5y4b}N4 zXO)FhM`OA}kskG^IEQ!Pj&2Fm?m5Wvk_VX_^n!g+tlQ672`oswuAZ ze`k!K5!UE&iUQ$fPEjl11T=A(nfn9FS9NYcM>2W6=BH#2oWD!{Kdb4V^dEc>SpIrk ziw8|iJsum;tQG1$1d;t{e{cAUeJjETwQ4$B9i*&o!15en{9h9-A&h=QI5J-ZDeW5j zwpJ^W0ss7~;6A`|eurOV_ad>!?d8`BeQGo=`Zfj8s(7`9D0ut_QHt3vnWU|$ea15^ z_*Q_ahcS&GEK=Qf;xFqx{`%oE5;z?iM(0;Zds%wCXSp@TO9z?h>4B?5F^~-3E*zV$ zqrny(*#Xq_gImL7bLE192-K^faS1oJm)C05I|t`p;tgFk8j> zjHLu@E3JScn^&0Pc?3E1V90Hq?bKVl}Z2RVPtOOM3jDAn1ozaVtIG1$bVF31F2WW zbxAihHv~a`<+qvcPFti=m!??%{WRY1zSNB@g9Hs-&M^8Yj<_%#T@Mn?lA~6uUetWK z{6x#zz`@`)Vnzo_h7zoX;rJ4amGw{FZdPki1UNEVdYkB4s|RByJXt_-7lYbUSe;U_ zf;TkXs`G=lB==THz?##-aR01n09Ep^D!K66cGPXb0D07LWDO*f`X4d~JuN}SadU{w zFWRMi%Q!o@M&)<|;`QBjI#=|azGNNZ9#E_|B$Ox=()>2au@Zx7S{0o8~B zLAQ5EU|nMvYHz=uV4Juc_aX1y1Wyw?>eZMG#!C>KHRWD9E>6~p=x?0Wh+Y37-pmq5 zt*Xy=_8Dma(gBRT`2@Oe5As}~(+8P<(u*1zQ%$diyWnptsvk`9&f3&n;P_|7woLVu z)XP=A4^!n3qn*MMVsE3S`AUu4beQoflEgao)3v~KB^0T}6|o01_mifhIAxIH;Zc@{ zX8FLdN;%2kN?MH=^_46#w26pU;1j#6m)$7PY~6%hA&DL(BTK0W|Tt6zaMx)*5`NSFyKeU0)9m3gLFwqkg?woc-!y zh6a`feUR<)~TWoXeTjaC5>crSj$Q6#>`(s>w z^u7b#QVcXN9S?#-nl@p!>Tlp5pl+s;n&`htF~NDPQLwA&KHnKAq4i0>PfbyZnz+vq zyra^XQ5HcvH(`vHGPzPENesvDoX+XeUahEeWyOH2>|fx%#XO2JPho8J2ncFbxKR;J z%(1WGzpVXMlFE2j!YREdb`Of9z8t53R^f?~K<^Aa)qI=8?u~r2@FRf^D0b0QW8%k$ z`^Z-&Z+815ZJ2pS;Q%ScqZM8Rvx1@d=&=S_iLd#YrCk*4d&R^E_Ulh}am(|!a>AK3 z;@<+*$a?UylXdp#-WYIG!s5vinV^_9aW|TbjBXn4N})?bnkXTI?#_N6@K-hITR}v6l7Z ze2=A^kG_7yYPD}-kdA=e3QvNpLos-CU^Q!#kO$bNz}E2}_GSMZRjW9|0*&Sa<{b$8 z@gy$Ng^%#PzhgTldHM2xiq5{DfAf^uvbU1XR#7!*ZmTfaVfZ3V%&xU)VAqTSAwMNV z44HABnkLWNwo!-8zl$s1P60`9@Hwx%t)B;N`~wY;l1D8v8hd4>q_Is56 zK*8AhavBSKi7K{vlBY2R$gFybt{*Se+%|sY+QN1@r%!ZKQPoVE>@9;&J{*dlV!e;E z39!2gJ+GO6uy-slGnsqs%{FSmkoW^UmZ2r<)9+ApCfF*QhOmZCDj3z7AfNJ9`K|;x zw7GDCo5Xyh2uvcj;ou)>R02L*4JVZ2yp4E!YnJY z3)gJQIIPXwflQA%oo!Pti3XfZV9A8`nfDRM2h)3`Z-x6QCqCekjK?aV-M-SQ`dC&* z1I(&OFp1wHX~;2wy?WX!%^RpwTuJ+wUHd=wZ|>#aUnL}WgM&Xl8m zzL)MGuOs2ba}+ajeS_3okb_dkEmRC;+_v;5u0hQ_V}quKGZKmDu{gX1)>J~LM2T!1ZrHIWOlOt&^+6w$P3ev&8$DVd1QY&+qu zTF=&&cTdpv4}&bqHgRJIt?do&!$aKL;pz5$R(TTp<81S(bid<5g2~h8R0AFau?7Xt zhMV!1Nd=m!3N3FlxYEFtB~--qErE;;YG7CTprI{^A|GDj2_b_NTDJN6>~a7y zpk}w(xodB8_TUpEKC|-TUf{MQhghEu>ifGgs<&1uA!}dMLk?G?E=jF7{(-3flgs^5 zAfBm$HZrT5_ei8rsEFm^sjyl=SV%1D-q1WHOJEOK-G14Z>R*b~XcWr|k<~MdH^xW) z1r7T+pNs0X3Sxz1C;)lDsmg^@A5j`5TkYLmN_rtQ(ci&CtcyOhvvRpDQ2rrVMdhy@ z4Wj^4Jn1?4IAKh~-C!K~GRykYQXg-SV{rNH;q;?no4(LZE06D)+^G(k z9wMv_XNB86n1)sTc!{k(8S~mbYW%zceIp2Mpt;#|&y{u^(93t*$q;a%$N8M%15Wiq zDPAwuF!G%z_iV;7@P3h0g9`HD9cMGkVMjEW8Bc=w;7k%kr6>S5Og`fVp}TF(S7@)6 z{wRPzeBOQ%izCZQDbsI_Marwk4$CPcRmpB=A9@hYIS&5mkApb#Ru`n@=kUTa0c@fz z2T+|1+Jz--7!7Je{+V$UK+=o{`ytL27qq<*Zx`d!3t8!Rn|0Kz95AFE%z%hF6x|v5(I6r89)=a8ya-2f4X%WCv~7y6W(Rk1YL+bo8^aIsu?rtU6+7fIZ0w!N7n$f zWMy8IhGnO(p{>aXq3?Wc03w^n6@E9ZcP^$%iTGTLm~wA+EddTX{jA~YP0 zf+_tf@E~-Ih$x2;QS5zX7rpXK&__;RKoi+P&UXYqZP(qynrsUKR`j1o>aukk7aPnu zWwow%iS&Ck-B3?iLI3(I@G)M&GEzEz<3$nOL?2V6DX)A;kpN4v;UGM%h9$(VBAr!b zNnC!rdT!ZrQ3N7WdF!5{Etk_2!74j9x+A>$&zX`yVQpn_@-ASDd8zmx)$*_1Rf@}u zR{*JWmwP>-w9cQHa30+|x{Mb=K*d}}RxASeW54aM4`)`-FMrGi&Bp?$q6F;vQ&TOg zM{fdhd)BhiE`*JYviV|0CGkw&oR>;i+{d>Qy0sv!QKb)07or&WQXK}YlBZXGdGLX5 zu=sCk*G5QTbf`P1BySo_c%DPTVbfw%9m5Wq;Mdv@mWtB@l%OLhZv1Ert-<{gLhY4bVN2uC6iJSKZb3IJ5>*JsK5BTD&X@ZJGQ!TH(Tfc>D%YRgVyrqqF*|Laj+d zz{tiE7WX+vdk++kSIpXIV=T{IYx~#~cd3+~K3jO&9{c~KBYwYw^2$wvya)~Y`5G?D zs}g;y8dG6$51PRCYOA*=hHWNFgOGxS7ym7B*5AU-@HK>WU^pO;^Vism6x0 z_>1U!^K2B+TOhs*w8W{&)*!46 zu)b}tMoDdn?xmyJsMgHe+g7l>J>FmWDonptCc49F5X8p#TE$&=?#C7~1$l>$44Z4h z%CVmN{0u=;5=qSD(bcDIt zOP5ECp^SFP+G8M#ukPto?PX?q@yc6S?_<)<;;4jQG6 zDEKaPuXWMBw7-fFRp-7)GRf&{ZSi}qe=AbHA{|p0Xsk|$ep|8=asc=Oqr8hs%C+^; zU?y^`ryf(a?xFfCL4rjfhWLFTadQ8JoS;Tebf~O49V%*q1l#%4=lJv!SwfTCdLH3C zQ&hr+Ihs45x_Et%)oXT;y{rZ;zhbJS%9Tu0A_pRW%_Ncb5o;WWSQNQsuxl$Q;13=W znrTUtsfx*1!XrDIX3`|R8=vC$W69Nls@&WA4<&I5WJKJaRt?Hd;IJkn_7d5b z)ZsWLu8~13x^ihi){|2AdA+;JtLu`O&INVt*lPC;bRzv{9d=5C2pB1ygV>UcNI-wJ z<)Bzat|f)VjWVaBTlymv+eqECIpUFeDPK~i6@u{>2op9BoVsM6n-xv!#}Xvz_++&%PHk@S_n2hj4=&-hC~bh^ak% zvMk%q$V4!nuWgIAf#QSS(9Y#BTH7YC&1|%K~lC828$-Nl_o-Vzk-ulh{U$*TZmciAS z`zQSKgAvGr0~Yp1JW@3wT~^%S#Vh1@(eT%_j?_&iBAnb}C`Qf_s+dSY<1nF)V@zAZ zn9}aUpHw`DEQYTQ66P-JTK(tSi>&wud;$dBbzwoTlQxwcE-V}`;UDOGrY_G!L=k-@8OcJNb9>9f{XKV$_^ zh|AQBWEM`lxXwNR!`oB$I;PT-@~AnF4qzb@xPk?4_8p8=esyteN5>QjlZ*;KD$L}J zvB~*?CtRsyCBuA`Hz~m}d0c_lFV`6!hRF7iPe21O3+SY!*5Y?uJMN?*MBDu? zEm$%v{Yqo)9spLP0o`f=-B|f&EWQa*IOM$j=NA-OQzjEuF>xoP?Ipnr6~&`n899;~ z<`HaeHJIyf69X9{(!H&>HpD8ELHQ@B&MlrLnQ!E|R&z0gRA~kkeXJ8UvGPw!m}0sq z70Au`gub{igGA`nIcerH%C1@0>gbxRijq;VR~YH;SXGkGxE}vNj*)^jXtTg^#5BB3 z2nsw3(ozf}(I7}w@4*orvUe73w2DC8CcxkNzd>cw<(De1F=?yAxNRd2yDX}^@ zPYA)94L?2f8^F#qL^`NXgNbIsA10b6zN1mFpAQ4(H4Bv!RT3g+*CyD zrb#q-{l~yURTCu5(KcV}sJS*U>^=Ut>Etv)?|=ya;!UkDeOmKZ@a{7lbB)A;Fy+{E zIjK!?YN3#5;lgUSJu((G=-pZc9e<)tQ<}W^aotJ{Z!xQKdn-8fGM$3}98$pCc<$l5 zuF(_GmU-}g1e@V{Up@=o4kVDaQ4{qqeGuHfs%|%r7wNFBd!(D5Jo416nU~3J-2y)n zd!BT;Ct98q+NK5H+~SqdFPp-PPKKol3FV*#U*R{tH%?C(03~k7LrvyXO~^lWH(Qxv z+GbU8xi~8kScT{w#GS8obJh{s4mil)7smQcewC_9s;t-Zv9MbU%4x-peNiv>HYy_Ty_58{diuofyQ89ReH_kpg8&3>7S z(y4Cz$N{Dp&#-JBfsWWsMEHBprYdj6j9_9(wvP(KCKEOp$CNfIK%{onM~cDmCGt(n z@HU67ZUUxwIa;@Iq#HH=Bh)S;4LaOK{vRE0)lzs((WEyrJ)sadh@6No)^K!4QKA{^ ztM3HVH;rFDL&edGpOFG7<>1(5I5hBxiB8kl5HJvwbhGB!EGSmxh=j^ufa07|-*>T7 zYapsO65nvx>{snOb*wq9DTz>QHg*n$^f#c3vC*%(cS9SFrG`}Hc`chdX^5$_>>~OQ z&WG~{|Ds%c>8*+}8O8Uu>^J$0Vtio3yS`60$Pt&%Yvgl^}9b{M+ zDV(+3@x@B1$LZc6m}_N6vNo)ZpHuYGmCb41kO|Fnr7>a;UJq|?A#ff+mU7G3xy$Cc zePtJ#U|ei`JVMO*PMZKB18V}##GqD{IpR{pUkdp&5F^X>?6)mfrUY!5Lwcp>nTMVojUE)WvWJ5%*=TP1iotOfZ>ufQSTBPzh zXzaVWQW8tHv!WU4C4QmxKv6bq2}kx(I)f85c}8hvD0TXFuYC5ZGx2-VR@x^P!LQZ~^lI!r%IsuCKAWd4W%VQ< zViAk@@=0<~mjDuTdhk+8pUJfixQjnpD0_GRgK0E3^x2dZNhm8tzBMSXW(O@m(=Kij` z+OXxFJoAa3=c}|8RZww7WT6$rw*6Ww1_C_N-6aZHV~dJVj`^qR2dVUVqK^b+s-TU@ z+tIGk5n(Vn;2Vo{^oPa-i}R#Sk8Qj2+x!$GcyP1isSjI-L4y)CMu-2gi0SRumd-m|elB`G3U8V=g8Y4y(MF&m8 z?rWtBbc?;H5$Td!;VC;%owTxwreQ{)u~7b38w*)}Rer6ch~`WmD{_)obqaYfC^;>- z6`^{3u|d(~Fn{&JSVk~77e2gfA7Bi@6z_j*c4xZ6#}I*+&;^y^ zQs;=4)-NL%MJ#M#OWyHTKZO^zi8Sco)oAdXan{A=*ODfk%vG1$Sq3X*X(VZ(YCBo% zbO==-YY_r9>WSzxB_a$~Ch{TtvTz?$?$qG5GxwvN(VWhoYLfme4pT$st#_iIpiqa& z2s|VISptV;p6DZk-w^Sdcg|6z@~>^AN~Ws+*ukvsAXC>LjESb&HRwlQitZ^vx3wW* z+@K7dpe`_g?hhn$bMESuZ>?UcG>^$R`dC+wQ9goT-8vK&04*u9P8Ro29}fpEx`K^A zO{2$iKX#*flB74hxEc$OtM8AP=5$S?N6$?%3(x^u94F3?!y#+w706xuxkW2-EELjc zDV1k!)(ViQkUJqsNAtFyd84^m(P+<C7=V z0D)|u!C!7h1%@dk4UdU>;|{MN|6gk+G8O}laR24>}&_!DC5759E9HWy*Q?o zMM-T+#KXHv>MCdfS&O%bnmFn~sAHK%3s8|&j{-!uG0Ztgm--xRxT+<~34%8jcHlYN z*KcROS*fDTi@;5?0I_qrr~X4tz9CKBJ(V9hqgH%Ruy1ngs1vu_S zS-@@;4Fczkui7~?Pa~+3z%a($9#yB<02e|~K5>}I;L--d=t&7F90t;o_yb?y?b*E@ z|E`VSy0#I)bYz5oWlq{AM#i3%#@kls|NJJ2SW6Zu@V;aznW39?odXWRATYvfrg=fJ zh-7%Yb0w_366$xnB|+lI~7n_R}Sx1EfBCF+vCqV zwmeq1L?kg3)`3A!W8P`|a>CZ4KU4VStI1Rjmx8(1BscU`m(fc5g`neL zCp5+;C2KdN#Kd@~Ok6l#R~0B`1g!8!RL6UUHYazKpn$_ueQc#4J(j)=3O8{$C6zL_y%c zMS*m>|85qB-GnAm8r*ld4bjgR#x*@mUTmxYO#-zW7q@hAnrlq5tjdcUQk(>g+?fIr z3h^8se2vVE+VZ%8LX+&hqli$UX%epYW=gB`dr+hsH#qyNv(y#H3kffUIHpUm#`r$+ zPR?A#jC1q)P&m#z9J$Bamd1shZziRs|H+ye0u(WgwRv_*5h(ke94u0-fI@Fc1;vV{h_+@%qB?x!hu}cCS`U|rR7vcFUblo8fyJN$3t|dA=A!6x zf&M-j{@hxegI$d|`tjAgPcd}wNkDr0XI?F1EF`)SjzD2s{U{;W2-&RX3fw0wIFe1? z;Jt~ZRwAhKh86b2^vH-=ZlG0z**u%QAC?AH90l$z!%x&)pS8kB_1%791#reZmK_G? z5HtwEOH!qphigP*o_B(mx~$u2^aUS_$dE_Kdrc6U(S^t(%KD8ZHY==M)t<$b<6c!s|K z3P>ZT(nNtE4eO-Qrr=#E-W}och;I=yacGZM>bfMXqX?8Cv9HJK)2PTp*56l@;2<67 zUh9iv2DHdBoJ_%ewDFB&LL|Yl5R*VjY+NySjv2U+EHT)kI1+yEm@k@uuL{-iAcg3~ zO{htMV*ZCz79o~29q3R#HdLp#V<_rt_$vZJ90^h+k`+$v3#|E6z9CqR6|$6Z4)C_%Rx?8 z+P3=pc;428S(lXTcwBSrAR6c6gyS|4QUu zq$D%JeLzPSLfLf*Ro&G|5Ou-XD)y0B)#YLeGeZnQ7fc2sgD5s8BshMsB40$3fQotB zK*<_lu%Q~Uk=G7O#+>zr(0FUTAV_Ke;AX%ly%d^1=9*|=)eb2f$f1{fdJ>)t4PXm= z2LGK(DW+q}KDb=#huUGBx{wDusAI-*Z_gxNfuW! zj-~;AiySfdhl*CEPZpj(<48_|F&~v`JnW46ATW(gG&(25*?R1KCUa&e$R|-ll(qSa zN$i73(kL$RsT-ZPeI3%=f_Hm70G%aFg$gFRYyTn40<)GacWI-lI8Q2EJ$Og)SRjed zcIY>L6BLUV;NLfQWxRVIhmgk{_u|mL zb?XSQ)pkA|O-q=v?>+UQ+6OPeXw&Q%D)qE`F^gLP7Y zj6V@^C0&a=*qXn5&79KnBYXOzp}%9Z>PM*gZ!>m7h)tsNQ^?N2xLcv_ZHF#k?}(Jn zN=qoiZfc2R>Sj_m8H#olBhRTuY=E{+gqSPevjqhGo6;nUG0BN%H28!QlXPwwmck)3 z3G)207+nSW_8@9J$i%Q$1SfnMzg_9FDa2sH4mW>b8+dR|m~uG@bR#PZU?lymd|=EU z5auU^^pu*^x=nPTzWGbG3vqf`QNGP$%lHhoiiM3-mLkNKHTX)bwlO~o(~!xj^t&E) zZSOusR9R{MxyV1rBAl1V!`ruYL_Ou)*S3tod{dDlLRm^`52<9e(&V zC#s;aQ?tEDK&3QRCulH-96`c~NK-Yg>9xdwMvD~QWFJ)>{|OhakaPq)-ob8yV~MO> zI8)5mBg)c*VA_-v+C1HArC!3#kQ15!v-AFD4~Ys$MjlPM#*J-~P2GtG6@)I$?c%X& zEaR85 z$~?TvJuO+ca014|kCZd&NO8o%ZfJi@b`J($eJUp}_N%g$e&s_WxMS(|u#Pm-!cVgk zig&uP&Zuib#_Oa)jXxTbj9m`~HCgc&t_4IEH!4AVP*`B^qdTQUDFRw#5Q1SL7C3hz z_2_aBy&^!kUtIUhMGK8_g$k_sp$%6KY=$*+GrSo5apUX9wr?5qB>3(av@P)z#gN5l zAx?+tjM48#gvWc1DL5S;yV#KS#LZQNAqrqFf^%#%R*KHMU1gs9O zsb)xD6{My7!(!qZ4B-WVL*}NC%ak9?4>IAo&t7Qs5!m=gH&_>qqWNF!+zBD26uxRZ z;_e&CNhBWNOaHP_Q!jDU8?|ao@a)QREaajJ2h}~|`Abd}p>sFfm@vcuAVhp&n{-MH zx$X&eS5GUGUh-^+Ith@Hdy4ixDG;F0`4hkSL<(H8&C51i6jwHzo1Gz}OS&$67{z^* z?J6DM;+Khp0vhBh*@Ton2-I>b1H=5jp)i>^|Bh9d-SX4`7F4W|uL@dyUUdiX>GIw?~GYNHQFmc#8d$oc!w36*5M>HKI zMWG&^2rIuWsLGZX_ZJ$E65=QCVTZUzTy9{hU!fPVoaihqojQwn4GfDWVO)hP(@2dA z-A?Z1AiW*|M5_#m3G|;kq-b#Pld9JujVx=0^#l3D&RB=d^nOBC1AeD1As+OMK(K6x z_G@RW+dK@?DTxHtvUXO*%Q!k<5U8B12VdG-g;cfzJu>S``*3>)gEIRxQaocro8hUq z2?sZ4 z3oZHjQ#_{d4rHcA4-U6o#6_2tPGuw8NTpVE2`qZHVIc~|{iC6aBB?W0v9w`_`8BFh z%15A4OG`Agz-7#O4bk`|%(o98stP=N3xdH4qto=CF_LW?8|PTA44LlZZjeX(;H?!{m+<93)k zUcyBzzZX`9Aq`$!`8Z&sP>4f5*jH1c#Sy%bmnJ9)g9VS4audGU&K3A8on{&Zb5_?0 ztOp4uowiFj_Y9K+iG9CDmd87y<`^0k4y8}EbDR`SfgB0qHXTq8nUajqgsZZ%mZRy% zrHT*h_t>NB>(9l*FyH0aPW?VSKWY~mclW8`3V?5FlS8_HQwe@xP(mj9h7S9eR9zz6 zJ5|i(E2OB8NTZH$oqb`jsZdXm6i_4yM44`dS6FdzlqJSuF(;>ap}_A;y$PAze_i)d z{g}f5g(VR28SRfzvQCA3N8=x>7;l0<3=vB}DSA-V9oZ-`8->Qr8V&FkEH0Khj1K|^ z&)_M+0poPh#QnSKI25->e-mcPtVQap1SD*IZWc z0bxZ9m>cjHYsexAq|r_ix{fYIx-b(zVKn3{EV)zbM0j*xtCKJBcO`4(#n62(L#9mI zC~P)F-$4V*i;Q%Y{I!s1@9HxC-;eXparU@)nFkb z!g|XeO8Tuhr=uqj6OvXhI*m3X+0(7oXW{zVp+Zyq$S^(Ww0Z(-h2T-b&t)rpZp37nuLsi8ZU;1tAihAf-XM;YQ^WmGmP8$K;ErNX$JZ*Th z6sP#kVq^x2l>4gV#vH;IgDhc`b$uTPXYBkA(x=Fg>JGWX+$`P{?OzY+JgreupG{J^ zL!d!>arBBMK_{y%y9p z``^-quQ7H(@+{u5TB{7LGHS9-F^gCm(}^5R?cqJ9mXfqySy}kWcZb9daRvPS1Fo$Z zBsg=jfdWGnT+ls(8R>if1^v-Jcyu>PhA1|BQ6Vb-x6?~u%oMm^D?YGk?nz~j;HEzO?}B!U)Z2d==#kHf*VX*;A(I`ya;AqQ%JcUP}W`pYH$vU;(l z_jw{AWH*B3MyOzw>`J4vRQZJ%zc7x}5RFJwtw!Oh+09xh+_7naY&_ROv31(`G{Wo# z*ou^$bv}@SrhND#w$(6?1e9ZD#mNzgIfG}{f7O*rR2QtTgsFU9A$xZ%eu?qnq4 zv-_QO=^}bls3Dt`oFqt&eQw-9_N4FuHIX|-bNyYC35)E6)Ze__W2?m|5X`7}DFcn# z?BKm+u9Bg3N|E{#ijzsDK9X-sPFH()M6{%^5j@xs+Vfe>ZdWIHZgnlBG>(8c;g*o` z+ph4kpRlOVvv3RsXGIP~u?}-d7K*66EutJyyG(zDoAVdp7zNLSfU!JDEZIplWF<>q}Jq)9!MdcFej6w$fjzK9=+s@7$i2m(!Pgv87mSi0pwv~UvK@d5d zo+?#{Sh5l}5MxAG)OoxSIG_Qm*b{MS4iY|Bn^E}zpNJv7`T1k{E$KdDaMoC=5Y0oB zj5eawkkts=s9^$5F1YPyXl`)FPoqjPmY?im{2U3c`p|9%_4qiirto58HOZR3snlVi zbWoiLt@@0N_=C$tlv@VLvZ!)t;VQvDg1X^vyEME49?@y5I@1?an6_M!WVLHBd$P%a zqVFBTt!FY-EtbOQM&WvDw*7<&@y|uv01<||Ci;7)XAK0GCSq1JizGcMn0IWWG1$si z!AUFJJZy4A5G}dy4=0YL>J>x(iQ>-);bO^q(!f)w(6k>5m7G6$T-0K97|~&0V8RoQWvby^%K? zeL-4(<8Yaz@{}~?&$Pc8tT9cdLRfpCVG-KVUIEX4lpYMi*V-BkrECN(Ru3|}#UT!? zZOR5|-`FC;e>Vy~Ev@cq+k(7l?y`rKUbyHi(ebCXcS%1yozM*lmn5ncV2q6u+#VNb z*8PAQQ8}0KSsv>PDaekIO$}|VZjen|<5Y;XS_#pTn6+7C%$4z8;V%J~k>g7s;(~7xoU1CI7A4~er1_#WwRE4E2 zjQmz3FNeVy;+JOpMR#l)$9;_z^KIN^+nf!xUz+74U@_D}GmwaI12%17Faa9$!xEKCJ*{{r-o@<41yDpu>G5gtd@#Lv7l{1FjF6qJtI zg4u$EAftLeM!pg^5$l-fZO<;u0cIiPBKgp{wtt9`8|RFG!5JMWA}mwh1ow?RQ4Y}n zZy;IfbW{hIAL!hhRB?<8&jv0e={oi;1#{R3xLtWN4SOi?CI8(Fcu^~J=B2V<8t#!H z7MC)@41TC;mY6HBdL9of^On*0%vgP>BK%TfwrPL$_tlwIJ#!9Ci8$xhLZXJQ7i|Fq z#)ZZ%+iegR&IS2#gz{Vf0kJZLqxAC8`5Ec^LczE39E9yUs^8$e{tHJyxW8WAI^wuL zy%jxZIyBVfZr~!Fg(Dek7=oI*(V8!tz9kp6EPJ4j5HX6RzS}nLHA)3 z=gZ+zUy<~SrX0(PmN3S)$1pl-YlxQ&E*K-6KVA4TW0eYls4?qW4ih=Hgo|e)x^bxf z>k+@K$B7k|b-pWVREKusoue{M5(GO){#~ZaRrM_bDS#qQ_P)xHz?Jeci;!p?4#-~?ff&W((cQ4|p}jnBW@G*enY%RiwDpzg38 z1{z8jlAW5l7v%PwDDuXrWjhAQkFqvEseu}VPMr?6*)+J2Vt$cBoT8RHL)E9{ZtGDL zB(Yg6BtoqEAC~>lh}v1mt^g=s2=*)ha1C-}@~}3yQS#)cGks$PDlJw(XB|plS$aQ2 zOlnQnB4@=S9c6*z2i6&E$fJuBJ!*9O@H%J)^}m|wu{!wU{|OdI4hjdCR)^pzb6kox zxCo@~lgGQG4*gWarnkUJ|CB8lMKU|=Jxw>A)bJ(%wOmHX79rLC2DR2*TrO`_(2EE? zKT;HhNQIV$mk)j9w34kHs_}_1I`D+)7fw3y35q2(F4ktUu+y44w2M)aJT4gMtg+f^ zdmu9cQVm58+9BYul`j0=&VQKfTl1Wlka{^%(pFlw5wbZU(Y1>*y3xX*LR32)Nwk;s zPDK_tF$f%_ClKLQ9ul^Jff&Bo|K^R=7ZkNE3Jg7foZ@OM6Xcm`sVTo)jx>))b)5;|1+>kRH!jqcSRmEHVD~sMmRUxe1*G z-4?v;RIn6~79&kWgaL$0V+`T|`xBH0FLk)Ul5dV4N+i%CZ6{8X^ON?gHw}W(+f=GNLIdsNpNrA!a3O4aFKl zyW{4U5NK!>*kwRSvLsA?f7q$@V#Z z@$s2YFc^-S0?lY%74i9W4~td&^*ZXvy+wEBtG zRUELsg86LbB4DZ1)Tiotq9qitq!H*T0*FvH72tm?tt`JVR_U1S8Ra{|-YT zCj4mgI(whh^rTr~WDBkb>N9|&t0UzM z!zE3g1*hOr7#T^ynj_5XnM(1mfJ^kR1av%mLs*GyC}$y*@%vdQM5M|Hy6EYzaMAz~ zM^tj?C<-{l7sm}nf(iir3SP7TiB#LD<{47Pn3Wm8phk_r6@D}}!mI@4USeYFJP!-; zsQk?bU;-52N~W_Q6_8zuh(Zii znO81Jg*pIMxQ2L6faI$-=ns0RV(VCCpyv}!h7@#aY^H|QHSw9snLRN0^0te(DM6s2 z%u?K`ndkjpDwiw_h#&#jhMV4RbFvF<<+U)Zln>cuW$cPE>cjLz0P#yLbT5en=(M2?&lC1j`_(CdTNjyo%Nhs@uTrlGt07st znvxDQ1HAtnM#uKyFM?h$qVdzg96FayL@cm@VhJ!+oiJhl0QysCK?lTGt2#}%RmtK^Yz!Sn z5$nj?E#+4HhN6#|PjyH`LXwl1K47MO!Bwjyw$Nd%_A8UvjS`uBU?W~PnpMz8^yn4@E`kCBw2WEdG_u1REW?*ekgd*$A5DZmQgWU4;_;_a{azL3E{ zMXI30STbH-0pu9;XQHoD1jCKY#zZ=kLozJf6wN0Z=B%kAXR?tZzb0Xsgozud+3ea{ z#El_xzC3K~GF_|~rq~M_X#up6!G$K8;Ii8k@kE*q{RV*|1um`o-k^L1L4&%$s_5lq zv(MkCojd}O)SLBwU0UK^m#PsOk&zQ4S^x%H*)|2mp)RS@yt~QCt=PGMrnehlxrES* zEH4bwG->Z`$+T&Bk{o9SC=Xi&pP9F@L^RBbj0oIZc25AY#HY3YG@+@^V2&)pKk1gD z2q*=z;j=Qdp?w{Nph@HWJcuP^VC4>{CmGDdT;C}p0wjLLH1aG!S#!rD4))^M5u+8c zL`UI7iE14r$Rcuk`l{hq<=`XPP{{CMA;ve9AHrL6R_lsXJ&!Rm!mEK zPC*??sY`6Bk_M#!DJt=W5lSc(varQm#KC$#o9s&orbw0n!u+40y_Df?O`i4?(5KQq z)q?0yBt-&PaMYExgQJ3yU>4y;_@UyO;I8Zl>rhf^aoW)~2lW*@M2d(PDRk)rDgqw| ztx_-=$vp?eaBop#310@$0fGsd66}Uhmg&&5uk1nxAtQZJc_ufEnJytgA#TkRoj>99 z`9ZSGoKu7|(p+T*3`#U9gdR(@^4g3jpEut|sZa6GZ6d=#8A)|$Ahh2!plQ%{cW;;p zkoAMAL@7x)GM6`Q+7y>6h(}X{zSE_q1)!*j7L^N)@TCkg|GDhYpD;nzBqiAw#LztC` z4~yu$DjWu27Q5XaqUEZsNe8P+3eB^MJMWM@w&3|dw9}p}pB$on%O-(@n;s;r!oU_D z$D@8B(Z$0q-RQbs3q_irsLD;y;lPf%Hqbx*IDWM^_>b|tM8xP{!zYi>`9b}NyA3-E zv$Q`~hKFB(btscz7&NtnJUBzAM0OcaenP_s-ff#j29-~Pef68@oudviS<8h6!P7z( z1x?QzlLv1ud(el5Evut?`0|0Iz$|?1{{0!af2a(7H7;mgQ5KEcB1eT7g0aYQ#S+>RY_kN>EU<}q!eW_rRes`Gg|$o zh#=q!Z43YrL>9a%2MGigTEY(-MIZp4HVa4UO2shxi=8K+h_r1!B47|h zTP_y^*&qV%4lvqFWQYu^Txfi8n`|F}Yk+}8jBhGDNd!9>=W!&G_wewNM@w4hNI#5H zlQX^I;^?2#}rg~ zzZzdEl;`Ufjy$@7EJ``r%39btuf7`)mkj!Sb-ARSSmdd4iCzOzW35}$&JU#Wxj@6> zELZyB2ArV=8*)y|5nxccD|?d2CC2_xMLFJK8pL8xVC~DCBm+u~FOW#bskx#GbtSz) zZ8KhNBT(1EBAuA+JZ*{qa#2&wkVc(?I=iVuiFh6u9RbtdGQ)$eVUW0~i83{wPQe}0 zug~F^7!nPRK;hEx^+PYc7E@!BnQjme(t7zLR)cuPkDsHLkk&vV57Py~XqcUzt}dhL zn8K{RAt2u62g2HoDDnCB6-h9jAPcSpUX}UVsmgFY;Jte}nnLe0XN==OJ7(CP_9~|Jw$1m_)>cI}qEF1EGLa02?rq0e#gv==phqOFL zPs#(hjJSuzRgp|%VfD{Lr=3@+T>;`G!+MfEo!?t%$Qww-&E>{XI{GmaNA%xq;Rx^#ZMMokV zjjak|0IVzM1r^hng~dxjw8L-*?G()*&!m{;p^dDsWF191ku#>;JVD8fYW6WwSolW{ zH}xEpbYFmRPGX$p6VQc9xPO>#h_v!7k!xj|v#B%qE+~r7SVXNMh$E z%qW~SQa)~&s{zE(8k(&kCh?BuB^mHaGA_FhH`w^BcG^?>^_^M~A6>1V-gPX-gfwoB z79c2s52HjZxX{(lt((yV`W`rI2n1jOPJ%GJqTH1$V#!l<24D+FV%A;wqL)+FsPZTw z+O>YEOtoB~IcIS)RF!lj5D0!Ebfxyxk*;4qS$MWCC_OMJ1gEr*q^OC{(4a${Ow5{i zf@Bg+8$sYo^AD=22*d0htq}Y|0S{F?ComB2!#Zh{wM|-Mk%@1g7@wgImj+5G4OFG1 zguoGl$OpyY>Xt(eN8*;wH8jzfTUE1)KW!ImlbP<+)DF>tRb}6(tz@8*gFG2Gpnff zN4dpkO=;w1O4#w-qNI)v&5oR3;HLsVl^NO%L+482J{pbOEb`&eS+|9+T3{p-C6c96 zYgq7M#KBipohDBKjQp5SLr~aQpd4`#c%;ZK`?QOQi~|!%_!ogf1?=WGE^GaRzh^FI z$4#CX(9zYT*h|_}n*tsrAuv#1WV2$_*d(ypJVS)Q{IE6^I0a*8=MfkjP%zvNj}*HPDMya1rlHU~jssG{5o8y1{+YNu zsYyg48pwJNk{yOb+(O%~8lJ}eHTi3jbKHzTBfp{)EI#KIL(P$nS+!sfB_A3L z7}-LHgyaTDd||1I(!t{ihc+QX!n_vt8#paeR&jML2==Xz*(#=Gu#QxP@k*yzJ`PA( z3L#;W05YY5F{;6l%m+qD+e}|1r_rcOLJGO^D$6>}$u$|o+ByGRy$$6t**s2V$7;nc zZ`B$+#akCC6`q+?pchA!!f=5$41itFGhh$R7)uvDfPqJmlLVHcD{MN2zPp!e3rED7 z5EBa=Nrd#l#|;?j{vx*#LG2F*dF}rL6mkPa5lrkY?NIH>?mza`f=@CgnIe@DwLXFF z3+B5g1Zd$vh*G#N@(TGfQiG~TC51B-eAFIjC#bP@vjmaXopLnY`Ym;NL?HB`JR~Le zql~OIDzTBjBHly`KpCnmUrm*~Rsi|Z_8y_&j-x%KR3bAH(t@HbI@jzcBni!n*{C9^ zKrpaff&CBBc|Y+g|Kh1V*cb2or_QT+&%@E6r(FoU&gfLBr}Ezsv4C8{y$C8PKj%!8MtmQ4v_ zp9x#Q%Sco{lI4Wgt-a~`6K}Zx6;VfyAHZ6 zlCrdVOK_<2tBeezscqqg9MU4*896vWMjWKLYgDo9>`C)@V)AD>elbMBVr4{pGE&r6 z+FONYuP#M|uyd!Oqypm#1&NfpcFaF&E7&?ql5`}CAJcP9R{t&<{ePvq&DdXg9bM{%qAUeFI1zX^9K?7^p^xkmA}G@t}M49Ots zh|t0&7MV?LE6}ObNntJrJB>XEp?eqEdeUr&c%QRY^X<+BIwFuLsyUd#jz3lq^vyw`}J09O8g>N?|~u#CF~7lPaEy2q-*V2=RRVw1YFpm3qM z-(gkM`L$P*d~;PzwLN4qUF|=p&_o6lDmo_oT&1{=O?MK^GNeTvv-oz9+aZU$IA7@< zO4mn!EWBnZ&Vy$cKw3lsyaE*G1I$!BojB~2yqLlo1Jd&RSlXSc!28neM2yr=Q7{`A zkIrts^xa3chKyiyjmkr%Rs;z>`un00p8S(eN@}vzEA-!JVnrv5)m!*FgBrQO4IK zOAL(Z9hMFbY)1l%TnvF?>arctd#^?YoiqS5NAnI^-tdi@G~V#_LQYeJIA!CkA+>Ld z`zi>oJ);dxqh`Ai#Fft$q)s3|jm2@C%*n@~FX4GYGJkWcbz7|H_0P;*58(;q13v9i z7Bo7RoKY~rQwtD@$eQ=?pQeUFif}am_PI~%*kr2)7bF%jhvCIcrsV?^o~W@0ffI=A zLRM=$puN!R_KU+cLv2jZzq_M!R_9%eO$cagEFR!0m>6{iG64bIDU1$rn93YYj|l?s z)vrl`q;Qia9+zNMBg+N+&@v^}dUtA0`+j3p4kY&bmDDhl1Or8Fm9RjbLu`0hQNGqy zu!BpIkZeTf9GJ#6sUa)1G}dQ7F|H*~Xb;_iF^&+wKsXxgc7}pLZT8*=lJ%yc z@cmoP$S-m=w1>V=5>;{C_Xe&mLi-B^9G==HRrfOsnCbEe`3dL&I%v>51{cHAzZ1n3 zJ^aFnz+72xwQkcD!Rfzf7XtCWg+FASFk&l?<4}BzeqJnpN0%U=0Of!0*Qsgg?4+avFs@ zES^i|UV+e&#wf~00gwf7OL5dCBnJ4p($mh&sQ7xR|0znFuN%--l?o9AeLx-@eX}`h z@J7NKWr!$R1))w!p}&`Q50Ayz&*2z_*T970 zMp&tUs;E&50Cs#PmO-?&stT@L5TG#wpd>51d}e1S^?Cure>+hine5ZV9mkSdb_y5l z87;^f(pwwII4k8cf|Qjt%DgqDrCITfY{(%i4wajFVTr;s>G1=Q88vmi`_z{jR6Y0_ zB?X5_xMqN*-GwZ}Nhz;}pz@88S8*WFR>4+d6TD?UoZq5i67bL2#!4KHaz>_Z=c!gT z2_Q+it`hO_Z+KTxO0#%~;zbQXL*7rYNk*#)@YX~UKn_PEOPUCC0rz|&Q4qLB8$bW= zx5x~#xp?)bAd;p+0Z1D@i?K7z3+&jTsDOae#t&!pNC@L1{{ZWFXAdiOB^OVZNasbL$@mQ zf&TkRguryH_1Bm<96CvHRFZtaCOl)@bbj1JqG;-%FEq5&MqN28_I}EHT~PLvT@Gbu z2tt?&uc-#Wq))za3~nmgu>zjzv_Uw)e~E9a<9#swWCZ642q=ucFya^>$(SGn!{}u$ zW;e4bg3yL#2)HX+6kH!;>;07^jO4oBF$J; zPzkpl%rBOMAtG47MgEdvEJA4FH=@NfBH54~%Z&>qA;gJjN#;2ZMO2(pT3JK`_)W2Ano@N*lvj+&ma*M4P0&c#y87`n3dx!^M+qD0%9E zHaL({;Qu6U3St3;RTfm-H3z)3+r*oCYd;&w$zmarqL zUS(p6I0Y8!>I};*gu*!pJqtjQgy%R)!0Sg}23FikCSm|&tj&CjoiDmrb&V1>i`IKd z64{sXB&t%#Ux`Cmwd>iGOAeA(DE|N^4RMRyV^6mUM2PeuS~v);gEoMNXsA!7LvvjH8hxHz#Y|i zYj5P@6uh~8;~JwEjm(eOJ3?*)u*~f~A?RQA1`sDGn$`17mwL=ej8Ei+O1UBQ(F6$% z4@JCbaH)z2!A&Nrda7`vbt!B78Sm%IBP}KnI#-*}Rq*!AAWjoXsUkYiRW5V5#MTs6 zYQ=)%jG2dh#+*Ex3|in^tx=q)(k+&taL^)|5C|=n83L; zBHv9mw&tSCbJdJxSVk^8Fd%D{8I8a#GKTD{Z;G`ZuxrLrv;a!>%Ve^LaLmLoMxPVF zWAv^T(@cX++AJpq=Pp$M!yGO*o&!l%d8dWOK`Ojz(39yyT!V_}IZm3brZMV{Vem0Z4og(eMw< zdO=FIbt9vcLdEDi8@ zACWQ>EVEg5tE`kxqL6&cc2fR5kh6q|p7h;qqw+Y`+#H=<;4uR3Myk*)diE_b$ z*0TXR25MFeek(pDQDZ_ahuUAXr5Ei)7;F??#iYaAbs!?X_w(t=coqF2D|e zkS~MsyvVprIB8V)KYfrI(TyL2EF1d8iLdBXFs^b!;-}Qg1XdwZ9gK|?lNeS0Fe{QTEJe1z!##%)mJe z*klvu`^a$$7RNSEZjWesn+dOoU3#YleJP`J#AKKB;by%8T%n<{UxZT1~d?pI7$RUAY_Y3 z?7B=qA(G6q5M6ZEEvPDbmF6eC1p4F~#w8WOOs2uTm7W7Tro{|xj7;Jydlz;A<2kB; z@Fn1BydmXFfsOFSQNmS@A(SehDp<)2k|<6&d{A&0Efqd5(PMFFm^(Fd;`OT!0?g;F~%*sE$51mlG88|o;4o)7F1FpgAH=)ETj zKbcWRsx?S~t48@vAVQ;bC@_j^N6M-3tTj8wFpPjYrt>Jt0s?oUCE24jVc0hlcq~PK zp_G)o0>7UC%R~hX1JD?m3Mg2jQ~<5TDHr@x7&AH7Y574Abd3y_b6}qLl1QY)_wN)) zlBxiCFQ>+^YZZOC?{(^*DG{IxS3@nNcGgKf9P1aN?-Qt>6;*v9pfRbdZft}Ike7=X z7Tb$pZAuE*tjTT_HcUPEA!u8Ljb4@*8UQX6ZUR27Rb5Z!z|HHx9?LKTE&0QEW54Bu z{(69WdC_ijXd=^;^2}(SCRZ3W#X_@KQh}l~LO?edhv|pW7$=-W z(%Sc1vW5kedBbCp957`=phOL}DD@I&g`7l_WB_#&C*rj3C23a-89vr?(WsyoU5sne z0Td_T@DRUbCU$&VqGtbQ6whjS>?3YHZj&G*d5LzZNr2F2oskp~LsQ!DKgJS=5f)f} zg&l>|EUB9ez3$(p-EjVy3P zV@`dRw~av@x$yj^Dy9bZhD%m5pS%(P$I$B+b8m}|O#0|^Nx+BYA*iT4FgV=N6$C~ zPCR*bDnwRZXo7_<8c$efK&fg$`&a1^1yntwl_QH04{<3h(XdBlk)C3fJ`rHkNgRp* zH=Ap=1r)BdML1-)ZGw@8K6AU6TO5}JV!&-b@)YlKB_TACfYV?kA97$9Sny~zy-n@? zg%e&pbhfGFMN`g?IKWdNZSF$%L}>fa(J7mktezuym2ud!_yhIkieV#~rw#hG}4eZ-`JlQUG{uYyOjd0$q;( zEiNva?%DZR39y-pOsd}x59wt7bnxj!3S7%GRr)uL}x>DoRk4r6U30cx# zj|Od3_bCPys+T30x$xeoJl%$P!}*VxMf$jSUKrjnCn>)v&lb;oTNY**lNmsa?1voV zWs$D|l31sl3ja)TP%W9<1m5sTj0#tExW@(K?M+ zQGBT@~-iu$%*9AI!!W)T0e5<`Z}G<~Z%lMzWOT-Y01mSn(O zm3bzn6{E_<*ke61*+Bh6vrq^)LGpn@l}g0==|3La>PUGJ57lFJDqPi?m2#x$vX6ky zZ`t`cCqe`yJRWOKguC_+@ zaybtKhdv^h(GPcJlxC9jlZu~ZL zM|-MxKRsE`Zj(-DO`<|PG$kRbY4dP+@-G7f`eqy#(C9csZt!+6Vho~cV^ASBL-1b_`*>qBMzT;0#v3~pfz9gz zF70#SQ=SvY8(t7CK4hY}&_h+sqKLv~q#i=R;L0MhhPDJ6WsDe7>~y1e8UoUzUx{Ro zfKj4kGP|V){5O2M7Kcu@64jlTV

kP0UoLC^0M!$$fN7j z`H=xF)6j_KJN$F|+F`O_Pq5e}_I;`KNo8mYLsnEeNP)n~eB5z(acRe@uVhUOzuJ1C zRk;F5u;rA>>NKB2@Vkc1Q!TDcV2w>=m|N*)3;RKQ5CIu!@MBggD1_@lM6O@EHV*Z( z1wt55V8m^XzfB~{M1UAkNQ8lPi#nL_Ic+U8u!d>+W;-UG&%iS7V*qeg^t|f*ZwIb4 z#({8&Qsp@9h_hk*>?4&jS=Ne%x^%f-OLWjX2v)|tArxeXQ27jje!GYYlZCIUZ6+zp zV6ZoEe^$e6N*t!mB`|x-Z9ruXC-+g&;3Lsd0Sqp}Be@3jr~You#JnK+REB=Ja= zmwRHd7V*p2qS!gxj+W@b^ZqZXlEGrZ%nBN-K^DCAWeVOPR9&0q;S?4$+{KGUFzm#z zU>I;50Wng;8o4o4smlSgX|#ZtnFnnhCRSxA^i$R<>UQwIFbI+VDD?x@qIzX)1*DCf zxPwhg1BV6{Y*a(MwwN-iDP>pHV@ahL0mx{05r{7W04mixhK)SvyVZMn@Wm^jU=8fO z8B87W(yW^%y5zpRJy*?*K&tKiLco&uh^~n;{#?Csf!@fi1~G<{hLTEr&ULALl5xUh zl)yjp40@{zFqMe_*!3~|Sa?Ml?h1&JurYaptM|Db`J#Qr2Cznb6ijWrriO!G)K;P} zPHk*1DHk&2hg6-!A&(1aNP5CJo2CkETgV6%SC24y_xLpxf)kMzJOKCn$~_BjNPM^? zqk=a~StgXwrGf>1F6R=&R+k>K%`QNz-t4o5FJ6fi!s{+ccnv2SNVtwfkm3|7o?7~O z<4>f)nQRc6Phf!S&ybBmFEXjh?3A4Kd23^#}lDDxD<`rp6%Ro(-_0jVBm>L&MZ1p7FERi&dx2s#cP) zbaUBQ=L9TsMN)VG1saFvO5)rt26A05*joKaEv3pUNdzD;3+^k2WplwnBc!YN3{$_42j(f%qG6&xYX|K z;7M~FXuntO=*w%GD+SF8t8yiXYJYMF_|MyS#QUisIJH2-YJ zMv7ZTH&XF57&^woF=U) zsV$?nM6c`jQW8Fp1gt5r?blc8YG~<9Zz_rN-wZOu8Nal38S>TSeJ@ZF7g>#15XHjC z&~^t1%|1H*}G*ngoe zCLBYTxU`H&4)!q(1Q19aaoV&C$eGHcS-?CWXzQXM0pPhef`Xu94jx``e^`W2@rdY;_g^sKj96r|5VGWC~0*Q!=P@#`diFwEfZnj3!hIlYdn!7Rvi_s zLL2EuY0;3EhTIJM{rYyO5rN3m;CVu4oRS-4%y=mQFGYGtY5yW9vt0YRt^n3s4YMJv zxAeZ2o;UYgl&|BE{)2xOUJ=viQs7!yt3b1_^?dk=yD3beTAF;N z3r~+RE4&g&%+NCI)FOA$xu9#-5nSI!Y~g@KTu)R)v}=q;d^=z&acw_4MIqnusnL-N zU;`lzhEsUvec)w4Am%t$VNrpqG!lj?8iJ&&P0$DagG{23}iwiV#*^Y417cg8t|()H-e!Qa5%{+=+PuWYgu2GEe9ti zFW?Nz+k$qImLe`uxJ^PE0FU&-rMWT})=6T(sS$@%yHXV)!CH-7-Owa)O%^+dFRZ9E z=o*c<_W(&w1#60vT2LZzrMcP^>L**9$Wj&>=QwQa#E9}0QD`&iA;hjEvYgVUhe*FR zBvhc-=`n(yL>0_oCi-M!!!R-@q=YS@GM6;=@|D5!fld_*C;1JbD91rq+2MSFGi)mP3$gF^a+PIOjzGJCv)}9NcI`4~ZN(|Bf|m z>N4OG?SDB{+o;j^!pzp{ zi>2CtqO%8_x>iPwJLZfLj}fne5+30!SwGb@fQS(UalwOcKgT@>v(unP)voRqdOdyW^!DCz=~q%900olPi^ z(|tXFcrXh{6~)`!M|$N4iOtf16V_YYW-l@s0(qAdGqPwR6Ew$SDztV3T(Tu@05F}N zgy&Fn!!2UTwquI5{!w#95_0|UZhG@EZtDn6wbD#6AT9xtZR025oG{1^X+^T%tk*W6 z2aw~O?B|3TYG@knn#{SZ(Kz*j99hLBrEeo{fZ;8oA2TF`82WX}QVU4O7MU1g0Pk#{ z(8d*jnD6^wKEpNHNeO)dryG7SqafkrZkke*-pxxkx!#1=0Nb)sS$Y0YI!t1Gt2DC< z=sc07@6as`keu>vv!m^5&{)y?)khEwMI@EC8I^z@s))t7QK4%fIE?Bx!C2}5PdjD5 zibXPe8T{3WFNixjQNP&6nd~tbTz1;N^fsF*CCikIc0ZVmzAGgF3EVI%B@7hx4jyvG zK!|IE^BS$Fd!WT#n%Wo5h)TMUx|%ekb|e$&GV(&#&5H~sORlT9p&okvV zKr6lt)+Nh8RTG>8IBd`sNdLerT!nK#= zhK3If{-^fJfkk(AjJX0Mr(kK)C!CfWN4jmZ1(NCHNQsOJ&qg#ZATu!L&8Sz*De^LY zRQj23Esz3hlA97~V6SYBdn#~p%j9gd5IceB#P7})aP(6i7WhHK(-vIZG+M0-aI_C4 z2)wvD&6-Nc>5BSK)FX;Q@k}fjn^+;NxnIbXt=Nx~8+^ufLnHo8m{$hQ)V8S3Y|x2S zInob?Vn1%c?D@9WsKgIBVFzl>H~1Ez44_@05*S$`q;k5fNdI{knFO`o@p4l0Cyq;trI;E=ED9bZ}AVJyTOlos2Lr&$mE3jI-%8NY24T+SUs;@1p4$cQh zlMyPTG*yU@DTp)^LjBLA(xmWjkYGs~gQQyL11J;FhhdXV90TReAT}&IM?vkkO>)SX z!c{2(PxvsB$#OjWu-gI}2?uiD)nV!-V@RT6@%4Lf&4R>qJN$1as1u2U4<~=KAjSfP z?K^$`i^2Fg;Xa|tW0626#bUE3T>q+kv$7wsTd!FwUoy4i-*kX`ZiYxZU=-Cehsk(H zq*=usUTMp}DMJI?i{@uHw+?{RgPYivUWQVsiKj!Uc?8f8Ze(8}nVTLm550W>Ln!qo z1RN`}grX!zkUY`fRrqZN@e`1?#Z$_1XZn+%WCZXGl(MMJ;6$mkO+lCyC;|f!at{ml z6^Sp*Y7qnDKpS#Hg}{AkC|#8B@sheiWl(#@M&Zqm77{#kA`K9U35@v|=*ywr>k@$P zL~Svubz;Kk7o0TE=4V=H4xn*x`cg|Ol}(Tt9nHu?lA&p+DdcKPauyJ>b7B)}(sdFW zW7%gkt5VIPDQWXN9i}Py4j`<8tpR4NR3(kjRuU>m9tWOgnGRJ`K#vLy3{a7WMiJKI z0Fap*e`Kdpd{c}Y2NT8(1XT_MXXwx^M6ajp2yBuks|;MaH@&4omNgJ@6O&T1|pW4R8yM1-uIzOZr-^b4jyaE@G}^uA)cmToi)!$6Cg z=(R|s^CRioON3R!k3u|yn593xx!6nYNA?w*?Ddg+*yl?R>NMB$kbG!HWs zHV_kN80s+~xS9d_d~4gfk)0l$^BKI$;B9|#XZ`?PKL%V1F9&0+ydG;&36`|IH~ zDmVlfc<=Tj>FR&7DoNX3fyjs=8iwYbIRvBUp-N_|*7rv!E1BdrJYFR!e4^+oyYJsB zjD&;^MQ~V9OSP^LePO8}-s%;o|46QdV?bwT4~?S+5R(X@Of2=>hch#ajueeUu*Sk; z?Rm3@9-6U*C<#~fDHAdzl`H@@O8|hF<>m3`Lw%H-HS#@Wijk1ASh|d`0R*xuCW`^c z?1Ux%K;>jJw-2K_J12{z&q?x;Kd(FDX&$!fzef-;G=PTCB3Mus=2qybXq#OSLikA% z5n}q~jO;JGKGJzQs*rA>Px_t;tx_fEUaieTnTDA}GA-Lm3`pGo7Y*|Eqx#?yseZuo zfEayQ1?*6Sb?Vs7fDI)`viNi|pmvx_X^}*tD0qHG;W>17m%@PfP&9!YtoCEsr9e}Z zS#{yBEunrTdYV>R%ld{XWF^KNts`XAPzz(8__1n`;djO!e_~_HOC&^ny4`#umDNdY z__b6@utKZ~+k0PQex^C%S@Qb-GgrutKa%#`R<%h(o{#Dxcw4tyXSQ4(jKrp*Nf zI$9zCiJ^-OMxs(}pD%}JN>np|RAd*L6-Fy`$8DobgFu?-c0ZqRL_aOFN_6;53!%A4 zxKOmXh4~q&JAuzdfVXc;4^FVIAOaT;48DS@q{BoxshGbR@qFSi~q!5EgvzxC14uy;W z3Zd7o1;w}SPQ`O8$?V!WDk4BA4uM9l0iIV$MHl4(0GQy5V6(6-D8ygf1~MX!%!uiQZfg_w{i$3CB@4aIiU zyDG0rD`im?T%kJf=yH|`|1J3fVtg=W0i;LlMw3GNG386r%2u9&(%s5miKX_($^8~< zjlB(^9Wg{9he{jBu>snZnMm2e7O(+!V5&o|U)V5K!SUY6#hGheK=hb^7;y(}9e22y z?n#lObUlRVTU0b(unV=3h7Buy80;FvYXy_=1>E&nJ9MlOLB>WRS`OV>80E&@2TzR3 zrqFWkAju?1*{&o;ZsQXrS|D$1MzSd9U-dV*6PgbgkD(5oKXv>dU>c7s<9MNzVdBKjzBaYo18LYSqhJ&m*XQpylw zqiwh^?V$9bAb|{5jaAVg4^It*Bt3GifXQ=YnD%JbhkZ4T6=?cDW$87cUkaW^|K+VC zAY$r_uC7sPIu}U}urJP!Z zN)TO(oO&90j|L(NmqAGvMcbDBBSyrPn1>QKp!XKR zidPK|@1w9OhIqq4TfrYPtT;HfCP{=5$)fOy+weG);i#y zDTXmJ53H>Pf}~6cgKbjwGZgdGw>}oQG}4l2dx$!u>m}1yt2!IRB$}0MeX;RPUwZ{A zTW=Rx4(v#)r_iXSSq9;VY*jCiP^z5ijnLj`!FF4ENfBv$SC%ADTMCO@9?)3k7*{An zsMOUHmd_rdsz@6h?(J4%FsFy&J=q+!gb&+us+$ECy38Emyf1_xK++*GgTP27b#Jow z8x`d*3R{G%HVOVlDj)ArJt z_ogA8$l&C|nkNx+9 zuYWX}@F_pZzz{5;j=;x5{YXjCM&FavwMQN5GCKSz9MFU_B3tD6)Av^F9OXx>I?xya zXflaFvo5aeh%fg-!n&RUaOGdqb%yjYJe3`u^(yef^>~O4u{z?w#OP8mxXQWKAcd}Y zU||DoNs4cb^)L&@0V|1>gRVCi4k{*U*}sff7BNMGOk$d+`P3wDr4U{dYKxOVK5Bn3 z3y@S;9Ac8oDUHTT1(4+-l35tIOM+OG0bKYhh)5ICwf6rZ>^I&QMTLYEpjf;NIp#m> zYWOTKktz_dW|-Dga)YEymr~dkWbalE~5d+}@Q=pbIA}`8f z8dI)kb4R*K#vut@#<%tgUJ*Fy)t9xnqphzC*h9LQU+wOD@&6(9uTcZ zMEw^E3YYpM1SX4?p^3Vb<;JC5Z^kkcl_EePCG2J@*$p1DgBc8qkU)JfF$Q2j38ei9 zn+NOgy~hX`wZBYByp*bW=P|)z{Jx+%XD06_`nSwHK9I=G>Hdcj>Vis!m~N6SGY6y` zED~#zLNnMwvYauuBTB=E?yF^C3JG-(nC@U4vip>IF6Aww8!Dv`wqa}2WAeykdg+=g zjN@3jjd^eLq7u8HOvdNC&Gyv935_4d=4ldJh;*1xq`1F@8?w~E7j%H}bcI|<;;{Jv z0RirXdc6&?*wKU7uqy<}b*T=EvmK7GNQh23wW}{r^Tv$|VZ$pz2nNGGhUw3kWQ1th z#Z%rQ(gEzHA=HP;6`rcM%M)Sgv2J^b)MNmo%-g-jQ3@-8)laS|B`@A*4rOIhhc$|V ztITv&>^z9>S{O~G zY}dw`vrepE*lE9-qf`C2TZNnrsIq zRnC9|Q40SiFT+V#p#laGoG7!eH4*5l474z{o$TV2gtXQ5`3#9^4}&aU{b!9QS4x6orGv5 z+41j1(K2KjI)RZx2xYP%q+(O+UAso1(;Mz)C@ehB+zI%C#X70Gzc{c)UPAC zBP;mii(d1#dlBcN1&|#g+*pzt?1Vy+!$~0IKfwYpE*q;DlXqQRk#GLU*9<{0=oE}1 z)8EM8<)(HQd4=Z(rJ&$Tw0Rh4>9G^ z98Kt!FJC||8>nxEGRMEcV?g2HYcrZG+z}1O~zRq7oltlpk^w` z%i~myDwd63C^&}mN2S|M#5F?NUsH$+Ga(w0lO0Xh8 zMJeoKWh{r9YhNHj3)hMHF&Gx0HRj0=Y$bw;$nFQ6HjwgSO?*6J(tRgVbX;MA7xCW zOa8tz;%%yEE7>e2G0v|qM!RMNrDN`dw0_vJFN+X0IXd+sh^Ak=v8Cy&%WreVS zDcCS;y0ZdVjN5~D$pc&H3SD~bKhn;dswKtxC$bj%3aTjYlZ}WFwbJO3F8QK!z&GWD{8aZ-Wn* z&rFknU`+oi(6WG9K3b_n^-;vJN)D|Y%R~q+`Uxcf!)A5*KS--b?0Yp)QMO!bipovw zcXm%?n?QX6hIb2#i*Ot~U~ju>3=MMi=%Hb)%NCEQkk!N0&*a<2?ic9sQBRal5P?$g zni&d{*^2hYVylJ|Av9TKIRFELpJ=P1gtS*3S=U7-r*H<>=HwZK^9w`LB>{kQwb4vV zp~eCX4XFU?Z@Vd-K#QiwyeT|$LWmC<$vS!Loh@;7XkM`hN5v|+bs#Y3(5L1GkTFd^ zL0Wk?gG9dD5$VwQ29|#V`{R+-CaOA1@Zw) znJH~U$6!IN+aY<x1u#Xw?0QTe-`!W)5y6Uz{+t#~(3H1GNV z*99zdBPyED^C4>RQxn8>R7Y7E^i)XWR;+Bu;LI44WkV;b`pXc_HjVXRAixP>@5erf zS(v68U|!cH&cVf;k=8+)^hb95yXrNWLg`G7k~-tvwFOed_uJ@!8M;F>7#@`>(K5Iy ziW6b>i!Wu6`$3`d8W)`?4I-wp!VS*I6+?n!ZO2eeOFZy1-!#ewEvXsUQ8n$xu>cfQ z^^(r&OkxX>PX5{N+ak!I3TAl9^igwP;ZSimw$DaHgc6Bx;eB}z&OX>#H2=(_L(CE@xA7zJ_; zzS&RF7^Rz7Fq6X+YdyHOg;+6tMO_9HvB&MXv$Su-5^yAMnL$t8R7$gVS~s_}%bK?~ z3xNu604@q?6Bks{^n4X}6bme+TZ!R9XwQO3$&D!7YShCkrK#Dk%FJOqha03_JH*&g zQk@dN`%F{;S-OFp>*86%o}_Ry5J?8_5*i^-Xz(rE}LnURS4i{8Kki!7W(QL(#orZx| z^IW>JWB$<@UI-CrW=_{kugnim8hg7q3~6^WHfyf~XtDoI1dCK302yZzDJ4-Mu@5N5 zVqM=^EZLxlDC#=EFgTh17ZWX`fG$ttqB2QyWP-iwn3N{ZdJ;#t1-D9O>F6B-n5 zE;3}SY|3XCBoxI`_{YZ=Nz!)TWS)eJk+)#Ej!?h}9zzQY7(2wU#z?fB?$#IsTCKMs z#oc^G;QfSwWW89fE5HyoXmBcEWSX@?MI~jUf-tPQW@RSHXC63XO-K#C&53fbI&VE$ zY$FopH5SM@icm6^+PxHz1MzrI7n=BfizPfB%rUjbwq=+?|I>}Er>Z>)ruZBc%Y9X4G;UnJ{a0a^WI+>}EYQhB&OpMa(&AZ0zcM1;qH*#cdM z^X9YdK)4iHBJj_X_$Yz_K^QfIDZ+HFhr1&q@U~lW!6M*_AzXhHKNI}} z0->snrcZ}!WH($72I$iw+6mWUvz)19dVg|KnWWh-wW*B{Jd;2|778rBLg{Xw_!VGb z!`LewI2BW1avdH#XTny|L##A_98~Zi704r^n=r*=FU#5oQL+(-HjQYLKk2PNJ8h73Bz!J{}Ed^1r+Ab%;ALCP+?b%hZ^1wG|L zW7x@IAMSR7tHh@ri6e!8{(5?PbeBz=1V-o8P=6LH5K0|ijCUQ4fyUDUZw?^v9_eV z25ra*tzxmr3PN)MS$$(mk0PpT5W--E3J?gThWY?QC&tNm2r6HPD0Ix4Y#^32x?n2d z9)%OoM*}D?aiVi@!&Vzs4%ZMe2i!)5MD{4t5)hkkrr=#a>NG|+8>5JmD>J7xY{?3M zhNY@a8z1LS{6_(QWgXYX^~*|6jF$Rul^&NL5GZXToLIh^e=;6w8v8D6vX)QiJm2gj zsvn^LA(g|;padv2hSa1iGYIq)eYH7m1!4KA8O1Iy+PPWR=3fTL<7S|iS7Oj~=3iIb#Vvo@fVgC$nGT@ZnpqamB}>O3Kk zz-bs$9Ihj$-^^Cnu>nK-)4i9FUg&TnyMqgQ6pfMkH+!RQ`M)#6H*fx<^Nn zcQ^wLmGGM*egbZ;5Hw)BG?E6`#RP6NT-UY#fHIo;l)Hrl4C~`Oa!1GQm02;uK1&fh zZcr4RR~4v(TjYRbXfmRvy0vJE4P04^Mf%Z7>_eYc4I7)g+Dh#>3kws3^#C8Tmy66o zNq-IEO#q(QgK-POU_rt|1qVi~TmT%S<@kbBh<%DIYua=eP$UO0h0=vg2;2-y8~3AG zz_+NfcmW#l*g$ldyHzbHahoQx)W_-QQ=!8t?b`N1D)>MMq|Y`Zt0@2kb*FZLGGz%= zFgwp_a{V!bN!XDV1X5rh7J6g@Bg9yHUB5f)nT`(YKJis@)BE3!`8*lKpW(o{R;YjXf;{*t)73JYs@RkA_@8@Ak39w3nhj z&YROHiU$Wrf8aIjHk>OpNT7s7Ni7Kru^lvA{y7ELc210#W^`BG^bQjt1~yT|ttMBN zy|4Htheq|wfF@~iPT9D+7gv*$Zvl|_1Pc-a4hplaUo{wsL^>b&Z=MLL@(D^r4pVaQ zsIiV7kPxqN2o-wM^t*20itPtRwJg*WJQCL<6esS`QVb_eMPgvO79IOVZgwwS1?)&5 z3vA+g=GclBy<)_4p#NkcYWPR*ywF{Db03AX?BqrmXhrC$z|u;P1#JT5FZxZQMaJu) zBViq-@$Nsm_YeY?=7$ryqQb-L0xo1M;*mS(L`~z7_+L`QS1lb2HNOu@=wUq+CZ6q8 zHFc=n01hMcd*ml^ajy+epTjH&sD$nPu+B4P#NOCn3A_?`@@v~pV236U(I%mimosh}3?j(`UX!!0>g{$T0@X$uO1 z3St%TXjFTKUx$pW>|ml0Tq6X4qOcq&0bUMspcPs~nIt+fSt?EDjziOuYrRI1ERdxf z8k$6wH%tjv08~70TsgojjVP><3L$&Lixv~n>$!;e@?i9-Z%qmp^l@&ffCDNgzfve# z!>I59i+;rbXOB90BDd1iWprL-qan8t1cV$ZYW>mCAXWhOujyO>UKm&>_$5T(05~O$ z!Yv+r-?(IhT4; z3V53gxpmB(72ABq80BQu!V;Lt!hf*~%tWJ_;8XNr9+Crdca7^JlQhUO@wSvOQmd#& z1*BytU6Ca1g>>P-7Q>XX6H&21`J@Q zWs58*h z0YTCpQu-dG2y9NhayM#|3e=#ZZ+OlqrIpGkOWd0|@*-GeyP*7G>f(XmsxY|hD+3px z2K*Bs2KYF74$BCw$GY6+kIg#=$ZFT5Z_BB;oShhhkXoZrL)CUMMN)zRvGc-MQDK%_ zl*9XqdoDDy{OAL_+A6cyfh^suPi@svFRHpU6~U8)kP%O?k=kwgMkHV_MVmFiN+V#u znlohQxt4=%Vwt*#&H}_S-W2w!O-PrFoGH=?p>V+|Z@Q`74Gf9_C~Y6S=$nZG-5Dj} z2`>qHH`2Z~Pc1?wL~$j_)X#cCxChRegQR=1o`pkKaY|f8MGtT64&ES+J0tAI)!bl` zDp$*_d=Cs0JhktI5gw}aYGiymhL3=ZA40}Kr;@>rQr=$T&PZFtBm_`l76Lht`oh(Fl!zygO?zp$AYyq9(PWp^BbV6G>hCVj1Ds6RG-Nft}6*}Uq^RE-;A+0C~p0F04!RaNnWw`2B z3|)<5Rd{b>vz>T1do{|sPFy{yDt&3XH2K2tF-9K9szhLi>ki*;*4|s0lxA?AW7)Jl zitXSDvha#W{@_n3d!|70+U*j8W#|R@&i5~U&6hGPlj%|PH3}Ra9aH+^n#-)U#RdH< z)*9s-1-B4UkGnS&$Jx7wK0Wqk?%aAn!E5h?T7}PmlKa6M&}df~B&Nkt^@kms;*&P~ z4q_ErSdxmo97pC@KgW3cvC-hIzrmGn!w5shPx&uJuI+&N66NI=7n0meUzGM?$ieVa z`F@xpVAuFIVv_5URjy8$B`zww+F|kTI45DTQ7r6TZ4?6i79UvUipkHHHD2F$1(}`N z6p|}mTj{@Pd+YOn&`zs!6vK_Re)-QrZLb&1IbKg7c-;Nq_yi#?GA%(c2cO>Nxkyjd zy)fPsfF>i8;JKR>LU-QHxsUx8vi9RuLdl0c&ud1TKn*+>g^d1AUOC3D_=^boRSyyR z$<4peS(=FOeOs6dwK*%gTXgZk1saNG10>Y3o1oUA*yFN@DdtTf>?=>0(A(fYxiKxL zN7oHK?)GxJ5sK8o7iFbGqjhycw>8Pt*-wBaW*x_uEPu}@HEx_cFKYGeH|n(e?(t@W z9MqyR!cY^6MMH5;gUnY#MLuOPG!fim?Vyt2i4uw~EKKni{**yx74T(iy^wDx*+bbQ zdQ=|KIP{zkVpndL+?N*|!X91T2zn2(#fq-~XW~6Z*7$A+Q#a<&QZh10Ea4T%IJR!d(czd=JU5Y80jbUq2F5HoGUwP=rt$gdxb=$*XIWC`?wcor`I!3 zsv=VjCrbjoFBdKAmQw)LtSZB^7MKlQ2UHqt?+kms_`%X`Xv&W#|1!2{LRdGl?;ct> zE9hL#krLrHmv_)@D20R&ndpGvmrbLm7%%Qi^XbQqz2lTPwoCPUNWJ*{hfi5q7fM+gzYA`w%*`d_*#}AG9ph;|*CKtUW8N(PrX0BcHa?orfJz zTX$54lit6<1)t4BLCL`m8|M68=E+2Ty=qdErULLwya&zo?EaD6K~Et!Lo;s1n_cfc z1?Ko9RkR}8My+9M7G%bwJ)|thBbbbJZ6XeRi}A>LQiY2Xxu+TF4XR%tSVGz#iQ`xW zB9s`lx3kA~aZP&7gAOZRpKbL**Ooo-FhA@u%w4`RMvD33`chGbE31v?HUEP3q_g%n zN97t~=gKHyodtxi5OFLt1jWef7mCI-s+2EDZ>kZc_-@igs9jn4Uep6wr)>$I4snyN z@4_1Y-HmA3lU}~EhvBWL93Tjr=JnY@xTV-0HlTM6RV4n$t$6cd@>uivmXh{#R3smA-SODy#ZnbUUiZaQUd(Nbx1DnG^YiDN$5zZ=<UG8_3E2C!>R%^kRjf z{?7TlA@xias`=ff2k&jebnY$2_5HkHcwG@W<^fk~E;s#p@Oqt)iJ_q&Q=KocWRJ|{ zRc+*I?Dp_}AAm#GmO{dRtm!v_uR+PZ(8185lZ;4^l=F6^9rCAEA`mmKc#OXMg1I;?&0%Tv-0i^OLm2AZuNjJj1wY0|2G zaa*cksUK(W_a(T|nbcyHKsk5!i+iKOEWtw-?b`Qi=&<1@1sheAY?RUG1Y+pAAAf-R zftQAE0y)kPW~?5KL{alY=99;%>aJ^D4An*RREQ1TZO|9qKMiM%XqvnnTR5CWH4kRl%hrR!QEKi}FMp zq6_w*XJ0X;pr=@PA)zi@7+QBii#S1h+W$KYZFRLRjx9^=sxSAULq6n$@8 z(A31!o_!I4h%N^yWJ)>Kkep?3p2fm?U z3*Vk97sz@MaFkm(#k3XlcaI;2*$C`tVch2RiorzrJmuph^vhyCoRmj*XO{9_1;?LW z*%a(er~w)l{q~nLmYR=BP&npQ$LmwidhsnWq_ z+12u$VZgoMCRHaR-ujpy6_@HyQqEToP+t%8aQ{Pnh&^x4q&C)!eKOyqORHJeuXX7S(dKbPYh2+LOAJeFHI_jhC8B$a58$IUFLH-9;! zPHW?byYXs++9YZCxa|b1S=zAGU{8lDZzNZDmE#v^9?B~GUX$s zioG~3r^RTLbWeVhU~$uLEnBV&p7il2TJMr%JPm^fdev8E)*=Q_PNsjploc%SDC)A9 zP?hawQQSB`j(%?>hO_I&7Kj-nVHGdsJ6}8+FEoNBzlaB)CxG7*45@5*4gr4Sv+p;o zs3E@YqP}V41>V*vp#&?@I?G zd}&_nqBEaBX@(Qu$&|QgQd=J4nf|Uk15fN(TyYU~=E~bhMjRvUIyuJbt$heW&>^KLv zTyS~ucW7_`{f5;W&Q|(!SPOE$8~TQ!&SsI zS2w2}F6G3QmY+-I$m0@iz9<-SX^Ux2$KI$=&*ut&a&FTn2}qi&(QaqG`P72W@=PCo zT$1=^X2dFRWA6zd9Pb5LNM|4WliLE0+xzkNB(;&Z^zfw2(fW%^geT9M;-SRmyd`{& zn;JgjSZ=z_BAN0)te|5Hldpz4`>Vh|Uo$4DuWu!fe(1bxyRbXI$cA3^CnZEH zgCCD_ELyh|?Kx}*?4$4!O0N(yJWTs9G|W{G&?ArW;f59QXnoQ85!qC3hs3FP9b!+Y zv-iBBU9h_(tlyIDX|^WUZ}7zkalp3YiDOq_YI@JPX?5};1!XYkY&PM3UskfcH=Y&5GT?4{QRsolM| z%{>uN<;5P-UoU*>o-!=B3IMxw8GtTC>2Lerz)9ZR2E4*Cw)Is*!G!0M>`#Ew+zGwd z8?|6oJBjnKkw$lP77Zs?1WS1KBFtbWpu2lsIKT6bSuT6z6R$aeacGy)}1@z~cj}A8F zPk6civ1lNGA(~z_e$D0&x)>2G5nxsMyU4%$@ccKh)^D-wh{=}SiU&^rd^nis-O(>g zL^+yubiy~7U{*P`!h9QSCJ%XV0%7HmXcKK8mrfkru9Gu_vdRm4Yc^JNq?ecnIpmuvc7<`2k`Vuuw zss}7Jc&m=5gJ~F?2dRnBB7pw3&W~(kOa1^@?=W~e3rOf*kK-qIIsNqrO=vvm!I9#j zV6*H?y`syVdIw%pK4F7d)#nY2|5`Z~7I#|ea_hI2}h>+sFppov4M8~a4>o)o_z z#pzshuuuZ|{h~_xo% z-*Z=V@TQKldgK~WbkFpixBwjd53;n`s=tEPfi#RZD}Y;QSMtvaP5OdgnXY>sz4(j9 zbR*L^bk|+!{3qGJ6QfDWg5{kwM~b2tFDvcYAsuke3r#$G`^oSkLhpJ>eW0v_!6Jq| z?83BPWGBB$Wh;}UCW226>qv#fT0bwiqQiQfwms0My(Pj>KKNsbf|hHmI4)%x+{w(1 z)aIQhKKX~YgHIaQe|4MTd#;fjIt zc7S|Yg93Er$Z27GP3cq1m3}u<2W0XVSa9!^LDQpTVQ6ga`Rj({^+BC<9)x=V_X}qg z_hwqq{8~Y-G2u8ZA2>hw>0_dPyk+?la9g)oQ0J2|kI2<8Xv>8B`ca9fQY83Py*uf4 z1+T+=m!Qwme6~+tM{aknD|-M(L{sRW%6R~Q;t=q-L&QcKU)@3xx7HAEn@;1 za-1!$@W0&?;y#ZZ0Viu^$Y^Ab;alsLIX4U*hm<4TJUx%4zZHIC*!p%E3 z@?_2U3$t`OYdvove^a<9CV2IKAG_N3x@ExIPL!i7-QO42t*8vE;?XZ?mG`B=_!2+c z61$q*`RJx}2Qe_hzYF77#!yNJJ$d2pfhhW7v&Dd_WgZe-uSdXylcqr$q{5HMW1^3{8EBi4*#9vVvIxcrn* zMfPlixdf2ic$s81n<~nb)m&)7a`{EK_RAmBfTDt~t_T`)M*ENwyPWtVnu6+ofc|rN@UcH$M_Y-=7Ye_`4O(YXrl?am z-pYt`W#dIrb;$JDuVGOHp{0jX} z^gQS7!RUC5C$iklq1!3i3H6G?pH^!f!Z~7SWMm$MWLRr5_eHeG?h4MWNMj#f55~z` zCYr99^zO1kFCz$5?fro9;g|xJA#76|b|c5v92Wy$$q)72)N(yv!WcMPLa=I^*FFa= z`}@fv^Jt!`v{aKLyuM|{qk+BezSW4h2*c4S?h&m=UCldK%-4!E!kf@~g9~Hi z3vBa3+r9SS`Z3Cgu+7o$Ie11>XqtV-htaO1zX@)GNW-GUIJ&_#zNRog=I?RdunRzh zbD*_s_<;#w_4mcMd^-&eqE7<&dFPyXU)|#nfNxp*meU@uuNlCDPr(CaYsQm(C#@(A z-_$iPSTJUoY!v1v=PeXPDNrw|0&i1T!*a*FG|yL@LH_n#Q zpQ?`-C(c)Rn9)sk^c8oPwy9+JiQpsVECxiLE zoILbHP&fYA!@F5$4}?ae4>rNKt-q?9X?!i7|!C{1pECT3R6lj*hAto)xSAu#u08*g!71Tk6NAvmCXAy20 z$?x`8Ou6fG=)If&K>m=x4vz$IzS?j71zW>>gAPvRKcBRhv_k8fw`AjxZc`H{y$;Ls zSgC%pZp3o=yw+)>%>q{Fi%3Tnoh z@N(Ui%Yg+R8rp?Ju{IWAPT5#z5IiYLEo zU{)fu!FxSh7WWnaJ=M%WJsIb^A48H}r1$6;pR$M58N)%!JU_WRuSgQT`oVq!_w&1N zYr{kne4URc65M`$)|X`M{41>2&>e{F3j_hul65%w2CnXqon5?Ve$S%Z+K_J4{hvE=pX@X58r7 zqh-u3nucR#VjP7z6lfn;j{aNZ=Z_yL%#`c!RhBv9a}FB0eRTp$ug>5@-Ns>a;jjk( z3$3cHKU}D<6Q!ji+HL1^e#?d;;;pR9!CH88#b2&aMxSQlihoWZCVta~cQdJ8Wf$pW z9y5&lxW%KgYEYH_(V(F*&5It67`qmHG51)2QY@9+{ffy?{pC8VC+lSG!%-k;uSfMI zD3|*O6%MvN92F9i_q4Y zR>r{=`jb$2(QTPO4rZA!gM3NE#cs>~m?c!o-eJnZF6CIg*LbxL66vhgkL3sswhr$F zNe*8Wy|Vd2LL%l!e}eI2r+oh6YC54mu0%!y|}JQsG0ck%}n{3@?4yy=H0&zpU4 z0=FYb9eyWvFnIaUTgwrN96zZIHOoHs()^OU9nn$#)x%S&8b@mxdRhK!Njg?n4T`ry zgzdfQR`Y05IK5nhXCY9TzCC#JrlSUDK81l?MuW?rmPWC&TF(*1K{_e7W62O)l5aBP zQ99*=WHSiHj}hJXZ}kM8`;NtCq|(#@M+!GnhzpU{x!FGTCcc+KPiZ<>>em#d?=TU@ zo)cD_|Lhoh`<>!W385F!Ott8&E__p zUB>ay9CDcR^5rmxvtx1z+Z8%R8}~zu_i4pxKB&1>ox+Qs!HVXTkJA^U+V`2y;L=h7 ziyhKjiu+*5c-(z)4{A{MO#?>{Ubu#7tl=lE{%xLqCrWu1&zeW`A4RR}2ja_l%Z*}Uc4jAnkUq&c3-%5aQ9Pl4Q|N4-t|(Z6zS_}f{kyS-Ij!b^8BcrR%Ogx8QNm< z9a@cc;<*2GQGczMczn3Evy6Dv50NtTGB2NCTg@pNWu^pP`$}D1y;?oE3c&fW>;*c@ z%vE~pl5~Rcmg_CV43CktDiS8|JNm{FzD>}%Fm($F{j3fzBWO*jtsxTA@`oY1yF4C| zfHPdLA~6_ms6ycKLZg7xmUUKuvznX&HJi=2b*1mhYW=#rEb5nyi6 zAFh%ddg}Ot-P@sE9`d`d!m0xFw?H8L-;#f4G{XJr-ynXj;FQldQd1m!+3_&mA=@fg z7URThcdZa)IzMyowG5f`cM9iG&uTnk<|#4A$iqQ@+ydBDmi|q0lZ?;B3`$-ACS7Rm zoy*zrN$p0vIHzM_c=wSWX^5AnX*&xLdqK?e5W)BR^C7Lxd5Ap{lNBg!vvy_J603A; z+{4&2&p5aT_G{r=3`Rikm>Lczvtc`&S#w8StP-5g(}D%p4f^OPgYtja2OjV7wf)-H);E*HQ)`p0u^0xz-WhuTI7Z!+HQ*kB^XE7?A-aK=K~*5o68q}Ll< z#0q0B6T`8nimE==6M8WR)xoTh_V+m^aVKXN5M#enDP95F+m{@;vz9#K7lcX^gFh_~ zH?}yw04?NF$G?XjCSVr^Sf5)md1{SJ$?ijc8X{)6n2y1eTR3CMSza;N5wxlYe|U;# z+)3vG6aph>=9r6|6D?on0Xh&JEPi0Tqc&*chX>M)Kk!%98nYzFI6ylr3f1Ibu#zrP zJ!f|Uds=SLXjJDgp@Dyw{w5gBor!|BmcC2!Q~L0UUHM`TZ^zFRHP_z>d5J6^l-6j} zxBjtXmnptV&mx?v6fi%(UL0c9&v(HrSQL}`!uzo7AveWk_N&Nz53A-jx zlQl6Ex#4o%!(9%a8>0WRcpvpBX7T%~wC;EhK3dZYS07jPFs-Dlw#^a2PNg5(blrYD z?mbAnE#;zI;1~sNC#cc~jVt9ie)0wOuvLe$ylzNStF;Wn`JudivTMzO<{v}TzVR5y z%eCKGiWO9Md=%+!_APQfd}MTdF6B0>!){`E z4CsOCtlaY0Trfp{G;lTvX|d;mRUDo&%rq;k(KQs_in7ZY8ZlMV*2LcWj`?^M$xd;q z&VUsw>axD3`>aQQpEN`R)zDDrpzJ-RdOo@*>n{;D9zXt3%w2i)&Y4A4KNh#O7HRK_ zWgyZ-)gLblbn-%o^0t!B@|JJd-#K`Wh9WBLBX$(?OSf%1ugj5XA03S%W0AJ^pH#Iw z=BwsQ%x!o_kfJ)EdoORG;PVZ|mK}sXM4E8zpcVm>2V51l-7#5>?0Dj?)S;QwqPr|5 zj}~+E={7#lO&gfamKsHif9=dO2RA><66~ zx5<-I@q*#{^DUiKX1Me}uKa}Al2{v09pJEi)zSbP=;M^vxj@?bUEcsd*$xWd zW5j7Tn-S~Ou?LO~K8~AQK0YiS81r4+$VwrG&emK+Sa7;A_GW*Bjp1aT;mMS$+fk-n zNpwAT>mmwO-Ms5wyt4_7!#nS$Io{g(a1I>Ct9Xoz(&!s3yPg(nBDPX;$j?b|$)jrKxQ?>PtD9K|16=~aOAMFmPGmjV zRnvSO-h|wPG390Hjf;Cf8cclwLf@f(B`%=$7LGG}UKliU8R+=sLL-=k==Yb)O4^#9ISS?T5vhVKR$tgoc(HhZ#SaBmh$xZvx;a?tb5)*WZ;jcxF(z{hd%r1SLE z2HM0=d?*VM@P05R#^P`ZsvQu-^zi7}-e3nV9pxzn*zgziYK~7Z}(u|Eq4L$4JVy8Ei`78zs46f=r=oF)v-8u&V~8%b|g7yBNr`F$x6GGzwu^@Z-5w?6>D+E?!Jkb7N7K9|4Qsmw?nR%NlRBVdNb zUjlgZ(4bcNF8}ANXHlKLDT6q>`5rK&7v`s||JV=Qg`OL3tx&<~VC$s1d}Pt_yC8Vq z-5LY5M=v@#2f#_-$n3cedqi47*v)$n8am@roZS#X0)rC(#(+g#M8PU@h-JT<3<7jU zx!-_6ososN+cVQrku`LW3!9({r~JtmP(yCSJcABg5dMLv$V^8!AZ0IxnR$^c*E|+V#Q) zDo5}6XQntD)K(`96}LyRF%h9v1u>Dnn&&+ zu;BBb=^)+kt4anVA^e_bN9Jkgeli)SiOTE=KRJt$Rr!l25o zDZCOZ-EWXh+Vqaqq`hzphq2St|GgIB|YLLt6F(m2htd5%=Os-$%CD6B~{pC~y z0?uJJuyZG!g0KVBr~$blJ;h+5jgjJSDkHqRV8BA?+n>CQnw!k z&u(xah?p`29b%7tT4eE*nAiIO^96sUw7qvS6flLc+vbN&t6c`yKLm(vQe5I4&z`J3 z#^-=ps?5t%&#sE?79kmrbiY`q!KGPCdi&^00kX|B+BP6$)&B%w@4^p^*_}MWEIV|$ z`URPPTNbsqo8$VLETU*nAzpk$uX^-)4bi9tj)v(Xv%j+-k*+UavJI)h&5xxAcK^1W?Bm8LdrM=Rq7nZ_5 ze~dBLs$}bY(3QJ&Bu+~CHN!d4xePyi44qoxcO2b=>$+$Ep)cG6qv;cO9^27NdB@X>T( z@f@rTjFqH&de-sk7}CKMuKTM9`{ruy`N=!lI#+QFG@ToSt1zA<{2$Bkf3iXgMwM`0 z`M9B_gLKL@Q|@UkpHdrbUdIhP&Jpm&mcH(`1*anZU3c}dQ~kQ3XeeVhYQ_;#-=>Yv z9dre)YEj+zLq%TV(6sog`NB<00$3kO^j(}I=;))5ohJ&%jnuph7iPq@y>3V~<5NSy zU);ijK5F?~gdu-eeP=SaffF8InO^;XHN49L{c*bU+Ae6m9*`Q`g812;BhUIPj8j}+ zL6-A?%xtiz$1Sh>aU<&OPI6rDb@GM!wM>M>_GtC*BbOZIGJ`&Ulu4T%ng_`F@}E`3 z9IICu8s-Z?CoV&d3!@f>8DdecCvT!>bqz|p%%|+d$LM?Y5jVYiN^IhE@rR$8&iy4W zS(!CvG#;gHgQX>nxxIpUwYbTQjxXHOkhS3j>O0B$Ez!!S!90O#aYu0r*ym*IIp9^c z!1>ccn;mvwxp)uJmDXT~w~FB45Vp&o+jQ7Vfw;*&yD2K4CRSlwT*S)1cB5 z7t;Yg$J`f772OkH^q^IzUfKP%2@EP=||y{U3WPn>Y&98hQ*h0jO=vdqI;>pu|EWl4>F+9_-g(S;Ki zNMqPso|9ijdHIX!#cwNm9UFlU*Smmt)dnixzks_~O}(-yN$FRTfoaw{maj zHCTxScIQ%=1u&J2@W2&c?!CJo|0oT{VzXo1E^ABk+#KPmO$5@Z;W%sW5dJ#f5mT1+ zqZ7|;Vam6jysr3#a9-Z3>iRPsG}4X|Q*uYpjJB`R-m;7sWZZuLNG zlFl;v!)ftJdG>O>1Fy!aL5*Hdd}T2Ndu+>s-^u4O*hkJezGNoEw+h_%AAi;^KS^^U zcfzbImK+!O0sC*g#AR`YJoNZ-vbe2`mX0}aHz|gVvc_U`+#%SzTpc^IFTnxZp?E@d z9t~a_Dh_UO7JffbV5P8+v}m&}Kfb5TnnMdPsQ*>r^uQmm)cY>=J6$OFrM;83otwsi zzEMi>D3|*!N#b+(~)q_#6!^ji|l`f>Ff(ei< zQ%^1#ZZKYTD%r2zN(IqoLVNmf9Qm?0E;8uLR>y3adc34{hmVRG3&Wfi6`iJr$%@#2 zoh+Ujy$%chTg=|CWoUzP09Pq1OE>@gLhoM}i+A>o!?pMJ@#2vm{@t}T|Mn_^3U5VB zOc^SAS(45Mr&{epIEqyl>Yl8dcMsh#m;zo@N5^J z617nO>k^^;vl2JAo)9C}?uOGha>zD1m6o-YiC&AN*&;%hoeuQpC+j2eQ{08BD>}xQ zEmsY%*ZSj*hvj1VpDk!xahtbSX^^(lU_P_{1WamEho`PuwEogs+|ap%4C1uVrc~fV zzvTJv-Egt{XD0xaavF?gvX%@=4nhO%N#qjdU=y%HRP)&Hol|m=vVMZ zJraA&FBRU|R#Ru@PSjp(M++3rpt;Q<{&Q!Hs2=ObMh`^sr~e#yb<~*Sq|s=tSj?I| zClPKB6Rum8K=S+R!hiFwgF>knF7p{k2A3dvpR|*gZ&Bd6VPmS?^Y!p)?|g9T9EvTX1uCm+2z~qd@*ra) zPRd&c&)sCP=0c*hqUS!+&VCG;cH_}bB^9Fk8{?M3Y{5wXy_h!l7pXiDC~pu+B=cX> ze}a#1tGSdXl@A z8m`IuMw7KZ!OVMVETcIMx}Mz<98R4l@6bFrIZU04vK;XD+Gvz@`9{mu>T-vfC+EL4 zrKsi6;<}S+JU<+9(yTZ*?%k()=89U_OJ@8fAOXF7iYTc114R4J!Y6jAVufBdIpszR zXZqaYV{1yO<4g!xEi*>{0~Ij)MmQy=ti;)wH4xJ8DySFV#kbRXVCdDy^lm{QpSV7f zZ9ZNT&RVVIIp-``Q8@&TJ}na4KD~gW@6JhXUNI2;`aghqT8}Abr8ex=3*sgRQ(nJj z1V{UQfS8wW;LHhS96Elv@WwD0Ebcggg>`Q}{#j(teTT53*CsNux5cUFG+5$23k$v! zN!FMDYwo8X#S*=0j%%KZPdJAhRRHIy{qxrUWHF=S5Hu_t4Hpt3Xr^5n`!&zSGuxE$ zs=EqS=%x#LyQ9Tj-;8i%gg>iheHP+A^AZcV9#^UM|2Nln8?PYf_9iWCi1^qL1EJ!TLlhD8;!#O6V`>xPK8E zJza!=rb4kR#*#vEPw)!qb&{0^!0M~tM9Y7CQFf>BbWSXk z^qhrbHEN-6kt6lEQz_P8=mKr+FuJN)hLJ(z*k=jBJ&*0QUwaj3FCR}bH4*HQb_!SS zJ_5PN_u&e&2zoX&i;gNEV|T+4E_m}@481A^mzG~*RBH)kt(9YmiwMg^|W4d+WL2JByRng=@fcD^~~ z8y&~hsJBOjlJ@z-^oLGR)bBV)rf3RjUytIaLa8`ky$N!ro~P9tS3N-htMJHw!i~DU#QY5MNY1}V_($Qayf#xQQE92~s51nw5Q<18gho)9|^M(y^e zVaME1rfVQo_gu|h^2%^*;BoGIyA20A=%S~eF*a`hkDn~71+#5yV2|B*${at9zg}Ml zMbD4n_Q*}*qFDy~JMRg-tjU3OrYE6d%NA~bt^=vVXJA)#k+kJ=HGfVX#NmIH{xyO& zIw`EB;qZ$x17~ASZZ{nE;v}jrlEsvFZv3{tDerz>O+J16VM4)T)<1uX)D)e_{7x_I zY@5!%+J*?aV_WYzJPB@Z~CDz7~5Vs!>l45pskH!V6Q2-jmL>gx-BNB(skr_X${#LM1#vq zb@p>>CL;xZjMFpaSGRiO-nVw7p(T%#)91tO&^he-E?K&LsT`hp7gp8xcmfxE45LH! ztrT#p1C(Z0QpepPcyy^DmT#K|;|~Pjy8ah=cpTH&a9=u(mM7@?Cl}PNWVZ6@<)(YBAac*Yt!goBau$SdN1~zP()d2ycH-L6Y z2x$4llU?E)(0z6jw7k~hr~xIU+rXsxqeHZgJ`Ky73d91RiEOZ~MQRjv0^-B|(4juL z9J104_Da2k+kgJCH7izBlJiD8s)M#GC4#DTAdj>j!%Z0jDDcgBA^d1IbSTb%zwO$1 zKQjv6R8N(BP}F3HwXs4(`V@}rQvqS`LqPi56#qEs;Cx?IdOLXxxZcl@TtDE=!Q%rU zy?zjN*zSdssXE}-_)f^9LojasE_(Mi0k#^w#xs8%IQ+sXde&7dr1_7=!&_s7xpx!U zF;x)nOP|8=oJ3yR{(=e~o+gvB@%TvNDG8zF^hdQCQd@L!^7s}$=_Z43#BfO;XFoLQ zT|{}C24d~A8R+n$m9!>n^MCDScqIHc{hYs^Z~8h@+K*6>TNDPz&Bt+F^AK2BF#=DY z*#?8UM)UlCGp&8_I4!%`3aCDbGJG0f=uIuOKdw&u_Wf(lK2zCxr6$VxJ%^3vdGJv| zLF{uufR!Vk!>h_uv`6ZPv1x{IjAS|d@da^`>{|-meHVK464>e2;mR?Af?)Y*3@n>H zkC&Jqzwu|z!(bSashp*fRv+3kY&p3;=!;H&WKd<> z0KOm64q>+ins=a4JeZP!KAmG|$IlKSEHHt!?DR3|;xm%A{-Q@Po0R_bVUPUFyl$mA zSYoGSPuyCh`~h^nIF}}A>!8~bBXNuMK1}gC!D_az#Y)vp{3muO26rg(u8dCc^%PTF zP}B)yo+YtzUNtpQAVZmnUj`iKr^Pb4I#$*awU#|JSDRNn&`A0soq_nBN~-B$Q81=koI9 zqH$WGSbHiP?j!}Gmenm#)*M9_Ogkwn;3-}A+aXRcP-V~I$57bl#*GEN_=m0|%a-N~ zvkrd-+mHp^kcXIIJp!868RFlk3f%qR1{U|HQgO)$ao<5*;q&58w4fmduDo!MU@fTaGH65n!5oTiylB7q zc&?Re0+-0`JV|yfkL`O*2=a)A3%#E}Yk(~k`B~z@>=Kwe=ZCO=*KW?bW{wkoe1~ac zOmOn(Rniyc>bzpWBn&?LkiHpdLQl0M?0VbDsk(V^VG3>lc1q?kE(+Tpe=tOH#-KiC`jOnjX&C6i|6<)7lm1* z$SHq%qNC0b{%-W1-oEJs-A4%=ed#G3aBE=o+dJ^yisLZgKqz#jH^3Q1?=<{-DXD%PfT`lD2e&aC@WEsC?gWlbDvYFlr7mLdxWo$@p}J;>zwO+KEIqDIB(ik>iP03 z%0xF{;xL9v_Ej;L<}E@h~{~|AK;~Q4{qL)Ll5Ww>&9J6St64RzUSJ7 zsK8mwiv}9!Zfj@a~6D${0@c(OweqiEjPE=q3sM;mY4O!RiFEbcODsGx!Zx7fDlzy z`5}T?b|{XonZzfbYhtgK7%nj!3Huuk3mc9<7cZSrzz>g9STwi@N1D&z5$kf)X;$Lq zg=Re1Ya$;wumO}Ty}7iz63x|;=UzF9u*)Tgx1ZNXnf!eM)=WlQuV}ci?>NnO`Yqh? z+CYPjU*jULD$+jJm(Hqs;{KnOR5Psy>IACd7f%r$H%22~kl?UYi4dFa&Bw33A}^!e zR4u0@${*N6qkeeMWLaAro*GN&~~mi8>A?plRh6CQW5RNI48Z`%yX&b)mriAaZlcNE|VXebE3fgw%Fopg`s!ufYH>|Fs$Jt zBt4!^>B@U}S=9$jtg1q^-iDv<>9e3WLey5+DeUZ6#=7>C*-dtiFreTn`i!{(%GR^s z%;K$__pjqJex0FwM|HNnFpJL?!@shIfG*%{nuDj^qawQF%mOGoT=)}Y4Me%gm zIZGNRGaMJU-epOwEKbcbfo*kfLAKFZ-15?iQ)j2(>R^Rh<$XI?Va{QU(~ZM7R&qG9 zE{P}pXN!IhVqn2Zb@ZF?mQM7@6X|&op7d%3^;?55{Xc8owIp6h32mg17n*!{L4#mv zyNXBr=fZvL1I4;mTA0Q7sQWAMBgpQ;lHM`SMoTLf9^s}t~Vijqy?{vtDrFz=@>J0 zIDRXC0iV|G7tftA;;gk>gdkxH>(8?j6Uz?qliw%kJgj10=Sc8W9!S1pXJfXPE{>D! zful|QM7#MCIF)Zjdwyr(#71}6x^NT7j_k&-Vy}_M2R+I8v-3Dp#*Sli5{31z`(f(0 znV56$gH-Q8GNrXl60cr)4pC#5@Xyj*R&!3^39}Dl(u5og>ox<=4>0D|Thp`49@@l(S zT3&e@%FONx(f1tq#0f)Qpmz%&{cND8DTDaglTaQloS~s{kDy!hJF1io#oi{C5UQ$! z-=F!Td}R__Oddqd@?&{lR2m7HOe=Ih1_SQZL8ILtdC&n6+VxG~gNq@y} z=Z0fohzUeJs}{`v26J1GspQ?o2C#{!g=Q0VP{cvl^?eCmw)ZFA`I6pe4}kf@2a(;G z_t%oG*#7@fbG8F+%LizhPZ4e19?^c)W?85qpnNO>%D-L z_Z6Wv8DBHcdd{>27kx0Z{i5*~~9qLz!t z|Mm0bcz+xaTF8oeUH|f~rFW5iapjXI;Hgwk8?6VTwA_iSLsEF_znu?Sk}lQ!YKq;` zFA3?955*|o42byBm#e$=ran&|(5895ba>!+uAUPM%~_|#(BuK=W-<`ox9NlZB`bJ0 zekgC3SqY6_^jR}<3YIi@3JM_)V5RbQF-=*Yj5XxZLejy9HmE@SrtK8u;e!DUx5(!0 zWN7!^f)Asj!0+`Dap>&|@^&xAzXc_%^P(MmuIX}3kqL|Hxa2Y}*ds4|RY`Oq3A)XFbK98qJqev}nWQWn{a|S8!fiE9^XPEZ7a)?V94R z#CoHS(M`t*R2~}x4pZI;uez*-VU-iHe?qxrkFnrcJ#93;S_~Ps#Shr&ZUOb!&fBbffOYLXFhk!fqrb3SUXdht5KVI-WZWL&D z_QZm)X_BMQ{s{3$<6-m7Ig~k2iz6>u@#52K@#VA2wAXqHo-owqvjfe=`G@1+tG5Ky^hzpGjX;f?~U9x?NX~nVJdAJDIRUD&W zjfp57;={8%LfD^bg<&g>if`p+bKLgXJhAo>&Pepb42yWz0Y+;%>hoP8rPUoz^zi0Z z#SHOQQ8AR6--V*&%hI{ex01tIW73?OS(93PL^|0!f#xjQg4-@_M2{Em@QV1BPR+0p zsyDA@Ke$6a){1p~KYqL*)~2v`N5^KR09h zdk0+a{~v@t`$L+iuTW<2Nz(YC&ZlRVP~)c<2)mLk{a74F57r0M>G&7{KN;h>$%|q7 z-5tXGJCkYCt{f=KxQkz$-Kc8KT8?a(#QsN2NVa#A5N71UyQj$F_f3P)**S|V&nBRc z;wn%&wozEJWIOq7UMT$M8G)|{=aQj4Q+vZ)_&sVKJ}f*<<=c%p&!dTazL-gz&!&(} zVRug9x%e$KS173820OI|an6fc`f~B3sFRcoPnO?z#p z_5Jy3*Bh2f9z5eF-9V#k9uQ3>$(PlXYQ4fMS!EvkT-u{c8YE4GCx*C`EOr=k8#x*B8 zF5$FSQDC)kK1_dP%t1ekz(8RP_5KjT4xet*&!wYltew6JTirdl^w459j>v@i)Zy4v z-vfnG1CT8%gvf~|IC8Qno}Z)!VrVdZ>>o`Fujh)kYIcIRVPB5Zod%9+YeB~PqYz-N z&cRigIJPws8XVq;QuFEDJoE%T?QDYwk$-5_xocu_&(pm0>UB}Ua+EZ2qXa|x^=B2Y z0-@H;3mfNmK!Nr@t_;=TpA)z8(0=`3^I#@IZ`(((rKZ*}H~@s7%E<&$T&Z;b^{CF&wK`-VovgKS`|f6gk%H1w85) zg;SQ!q;}5(bnnnyobWgS6NT%-m#;s_v}pnxOz{G>4XUIxX(&A`KY;N`OR++BE4(f4 z3At-O(-yNpGFX|#sWb19Y%e3SQD~>a_RFw#Ndf9DRL01fE@55G1!9{;aH7nD7mC3cGK|nUwKqZeMiklB1I>aDE@Hp9%Q|mOQl{-kiW1)XpH$RygBy}!i`nO zer*eeg-cvurI8{}yp{r=+hR%YbR0+2yr%g>4hY+i+-1$dA4R|3TgAVxMx&)`E37Qm z<80Xl_{lVvW@Q}&`e4Uj#d;q7X%<}`h4^iPF|J#iN8QYC0lO{0(teZSd`ALG>rV2} zGpp%mu{xVQUxmHa=8Crl|D-eCQt+JI4IlrhmOL!;;f&4&n7wci4UDUXEd|@iXq*o$ zXvl)G4VHZ5W&#;cd_X7MqOf+=PjQgRHkd6UcRQkvo>LS+PU#jkTe-u})^u9VDHvyz zM70}|VA8%iDqbf`kG?Ob;;nYP&Uzn?*lLI+^NV2PeSIDv1k#WJXB&;`t?BobIJd^~M*)7K16g zOj(bn{bR7VPc$&Z)(KR;jiThxtI)%)P3(Jk7?wIeev4?V8H z+GW3>Al4KcLf(P=vi<1eeHa$}5;7Q;P7IuX2lS9g^krRPKzxRR@3zcA3++TR)Yl2q8 ztkCaUEPYcyjZYJrsqyg$GOoNt-2*zPeE2kw8>Gry8jO!dtj5WY+8{gksW1&kad_z? zaxUq{5A~TEclH$rdRzqMucw4UefhDs<1}%LYZ+Kp$MM%~b)wtXFsd*gzzX@9!tb%K zsQX_xam$@2_|ktdbr{`%4SV|Y?t7IWIl7kal?JljQ+Fun_$hf;xeKQiqzNbQe4?Ep zLpdh1jE>4xL+}uJ-oNQ3xJ8}kpPj3b_B@AB-C$hiz?3#Nm`(3y!n-ngzExTWPIs(1 zc-0nu|0IHzgy^8mq2ah{`4GYV@*B9Hx(|-LtwVd+cT_N3g55fTSwEp#czQ{P8iaJQ zOuNAK?xa6d_Pqx>tP8-@Cj}&&RN-ey7wFfL5w3p@eHKscI7*uiX`+GN6xQCaLDRCn zQ~!(2aK>r}{7$n(s#QlLZD+wSR!h3U!x8mdtWc?+9$u?=rYDQ1P>Sjts?F`mo{ffV z(>p_)RWyf_qlV+|<2s81~;R0&y77f;x%Di~_H7N116e~Ah!2$BO|#FjPSmJ?dNF>Eg@qL2?p8#x12^#Rcq>|4yi{pH4msny3)oNRI<$oX_~CvqJHLg#zgFZtg=!e~yO8eAKMn!PJ^23I-@=WB`nWeeA6lz^lU4R7 z^3HfCyz#yTXXaVb`oFs|+`p4-KNrHI)Go>oTQA*x>JX*ISg?c2OE~rVk=W<*N-B1< z#!UO;!ktAY$Umlorf7A7$&DSL_o0JcAGu7{!GL|n+cD|qK@0q)$h=h+xH;K zaxj=LPr%*1*Wqgqc|3LHFgeM@&@2_?>tlPfpQ}i_y7j>1n>)CVjT<(;+ejn&^~Z7d zn?%!~1{x4`0hT*x@v^}Ku<6HD$2%m3l<69p)J*Fo1|D@R_qP2XFL zQ1c(Jh27HQ*R7*i44Z=8w-uquUkN&9{}R0NW%!bt41Yf+@aikmIOteBU4JnY8iH1m zTK{NV#s^8szaGMM^?8iJ3phN*nih^)O-Z{u*<)H9FTS`F9)*VD=?G^u(e;3o-x_#Q zeTT68x+S{}DdsQ6CE}9HWunsGFkI#sE&X#}1yVQG!6J>@FiWfx7c4Eo>0MiKZ9iQ) z{Gw3s=(k(6?RrluGZynMvsU^#v|RhsDj-n6rmTEq@Zb9_hcOGsRN7RIR5Rdj0p#{scgOhhD4XqvZ3RJ5Bt0^LO%*UXT|fpx*%50+)ktI z2jbk?ZdiP5BAdL9g;z_0Ytp0g#feqm z@6nW#S8#7aPt3p;;gQTpK9Xj~A@!MH5bncCsT*N~c?YVRy(Pcb%h(b?+wnz|Lv{Ai4#ux->b&|w0nS`$$2;a|qRs5p^ee@d z%6-=gwKsO~WCe5HU#P+>BRHpt>wrM{>o>f$_vhl5Ya$6aVt)Y5ov;HzP&r{DZ=DCpD|HEh zANBG6HXjUKTMu8a?4;bHLiC%ljTUS$_ryK0yEhO^9=o&apofyx zfm5K@@I%t27SU8Hdl8;H#*$OF-jKRzA?^1y0VH;gu{O_~&~wXfF2dGLVYS`$={7NvT2qPpq!9RlN2-0_x*J z@a4JvVD72FYd-m5TT>Q$Zi{B~=TG72mkIdkUa}9vYmuvXz#OTMl61t@=ctlFp%Yn7xOdOJHjz-9UgS1R!CA$gcY|$;rrow7+2emM-A#j zAG-3zr)OfIrE(RxMZXl!eNxBraT|DY<99H4l#7~XufelrI9I!OC-J}25NPW_31tFn z|ELmVzx?L0LHqFBKl7>U;RTBf^f+swo7jJ5GP>$srLmUvbgSoLEQ8r7{b43P?$w+9 zUm5e4VhLKd_vYeJpD6F(Ik4KD$LinpK~2?&kE`^>6nGAuy?aCH&pt?_Yp7k%6Q*WF z^Nz#2#T$k3)MLwa_^<3CY1plXsMT|D_=x?G^vM8=w;$w-+Gu2}&M#**(CBYPBs<@dFYhRU0H<-d+xh^!FO{WDr;Z6nXUXHpmcumPc>{+J zh{0aw-mqIU28Q=eo1esIMA*0+69JP*%ziXee`a%udb;J;kcN>74-=)D)mFa@$ zx*T^mjAqkEGkEFe7$}kLhULQo;7`L)N>Df{?04>t=}w{WHd=@OOezGof9^8(_d{;| z*R@CA&I4tmF_>^OA1)g=&==ozSgE&$3&JaL`S@L=`01LUu_}+`o^_C#L=KNf1aMxa z3?>!{G(a+ly+?=gfNV34i&+WFx{>f>*FMlHPypqK1e|^Dpde>c#EzQxX^+u<(3>&@ z>vna==GZS3Z*7F1&43==C?=<~J9v7=Xu5G+OS)Sp0S~EX3**nG!mHtz1gHK71UZXQ zWTw8A=iRtRHzuwY!UyZ%HRTVk_R=dt#>YZtDu781^<>e4W1mrLn82Zsa>~?z;-}_A$TeX3SqR zy|`Lg1$TdslD1^&(m2UteD!`j%I(>Mhw7z*L53zAXqE7+%0{7omH}J6?#Zqio|G^D zjI+K6V#cen=rqj$b)L`Rw}abhPY2wWe3KoBD?I0Lov<9=)^>7L`)g2{q79$6XQBJr6Oxy&6WMBH5^Tl89M^^X zv*9I-GWA5!<`HkaE@xh2e@z;E z`>C)pupdv~qXt%AyW_R3eBDY5c=_WT+&SaCSlj*w92RTB$$+z%@;(s{E~ubq;l?ZQm`7;4hD3 z_zn(%n5Jg@tN9<@Yj6jJhyA!}X^r$me4cQ{W-?zKZ-hHbw@896e1x&l$DmxY8CSGS za{U`yC*J6BmNK6mq1gPVl=b4@T=@(~(~ttlDf8uJLI_W=Hl=1aOL)@hN6)r9^Vws* z_;W)mx>Zb(KGy4l<`+EKA*6&-ANz8IboylfJ0bYIDGJN4m{mk~^w+l&9iOrQt8 zzWA_J4#y;p&bjN9s`0}5-J-#%DFK#pk%};CbYG)?+yuKtth5}#OD=YD-IVWll zR^i~OCSvoxrdNBS{^{xbY|m2c`SKh7QqLCC zmv&087e(=&aUK|+*M~p7c}PP->v2zY4!ww&C^}tG)R#s7iQ z-)wLgW65fi!jDhe!iYBpnE2~DTuL?I2?YOX?W>u2a0QwJ(Zdvtah= zk1+n)3(y#>#+NQvN#8oGM4{N3nw=0Adl~SYg?B|w)4?3Cc9XK+e-o}fY8K^pXHv$o zXJq$g9rZh(0|t(_VaNC}ke6I5E?leyvsJR-o7zBLE6BtB9lHFbWtU{ltRxut`aX0j zDd3E;S#YIYZ8ycs@+;9ks6W5k--9(~P2hTqNASd_Mark<(z}E} zs4mTf=}WpO|Kefnbe>B-8%M&;TLI$xx@VwuC=a&G$mGhgE5y{Y1pK=t@Sg#0(Crik#&6)^D*`C_`djgar{!CKK>5a~LMZEtwP^O+}T z-1_lsKPH|XV?V>{VgcUgrUuqxL_su3s?hddE0yjf8HO zigc#09VcGZ|mDwe}re=mM~Yck&KwN;#K8pAIfXHun85|I#0xB}E7Z}99t*C462j-QqLV1|w=Mau1k zI$In3klQ7O9p8deyFS3gVLG(hAPINu@5}3qTLqQ2Myh+*A?*D2Qb?bCnY5IPDPz~p=%zNiB@d6 z#h*@jZwAX6AHMuyC_jlbr`qw&aOmeuFg^ECaG0!%ZA$(awyjOFZ&)JQyi!E`&?TtI z_vKCQcf@|GabP;bh8%vLBn{^b{FB`v1f^Dkf6!V!Auk1^4f^cu;rh?*t@-EIk01>$ zA*D}8*l|ZHSKXb8zaOndx2LJla!Hpj{5M8aR*XfThKYPX_XJyA(-zmfvcn=%f5a)* zM04p!@!>Kl?0R-ns$U$4qLUGC^x8_T9t!MOTna(u-6+V^fNy=?1`4loVSB6vJ>RQF zC$#rr&$aVKS)Vp|a9{|VJUS>8MSP`*(cRc_TLhYon$Jni+T0{3$IB1+;>kjQn?<|n zPJBKxD$=^ErX`d0v3e?Qsq;Dr#aN7DY^O8CcQG~~K|hBa$b zF?)1(x?!?Q+A_Bf`(K#EPPu2G{#7Qd^qCI{cj6`c@16nW?f4y(F!hGJLcw z4ij^tC698>3*O5H@e?&8*SxOtpj*92G|oDPqeevIH?L+P$uy68toCN@z-zEEFN8pRxbnWKY6#9%a~z?=8a+r&pl41k3WQIo}S5SD|%z=_mhz8*9EGAHp_*@N;b+jLx}e&G44<*f65RA zi+gGGY|T+fycF#ke0~+EW$B`IObXRho6(}SaNgBfipMukL$y9r@O8Wmhosig$ozCM zxz(6MpRM4wSJfQX(a2UVG1wJ;3ifOB$S$|auv{x$AdMBJkCu8YH;+TH9hHe9P)Z?q3yk<;#E}{H1Bl@g6eg+qUaJY(eDn5 zv%7Jyq!WrN?$hfLIw<)ZjY**^>6CpG9XzdzCy#otNvRSqvGb;3x0YkgRD0>e=O!HS zr$qd!?*KBBvU$bqJ~Vg()92OwaevcaSYiJ_2ub}2^`Fnu=W*wS#qH@hf;zWS>lE(Nuc}wrSR&31-?r*1iL;iyy(|z-dNsAZKsCgX3N2tmv#m&Yc>kg z?o7wvzG~RgEuB;OBHPau*t;PRi>4>Sw*H#n-YWr~Dy_wWb(bV#?(5^I=jz;Ttvt%^ zai_;yX2Zk=MgF{~ni8Jxhq(`5^S85Kg`vg$@cimYxJ&&vT@)8dea*A+ctD?KBc%W%0JxWV~P70PQ}TQRV6yVXC7Zjs3Whm1eBw_wJWz$h|2zY=S55 z)|m~Cp&F9EYaWB`=fU)@bCI|YUW)x4`k_U%A=uwGhMH#=XxI>c2;X>Js(bl3%?!zd zy;B~GeM?h$*MrZXrW(J7>zePUf^xH09#w-O$Ew7biFT6sH9kk?heqc~M=pSsp)eE5&KO8vO!5Yy;EUjeGt!c_QN5~?&!1p0_)G~5=Zov@H}w9!9%aY z%JUtNH*zFK*#;GRD<~80kkh~sYjF5!t|FT{3Iv$2> z?+p{eDk-fboJYtRid%+9<07|SXc7NG)DIlZwp)I}#GG{kCwkDgab-9(&JKLEmheVt zCL8@8FS#0JWMO7#GgL@I@!aQJsO=t2zb>5x^EOp3&pg9t zGxczl;xH^&bR9B{!(l^en3!G~g-LjmrmmaKoyWDg)mR%mm3y*%izQ5K8X<^heZl3l z3TE_NOw}n(ux6$`_P+N3zMS5L?R7IH_gIeey)AjEc{)94*h+O48tm_f+?19op15Dn z{p+oSm4+ddsS|`@PkzCrJL-7$lL_M8G5mC#J!&r9$u3R(K}JT8cTb;>%dCHa_oZKw z2?O?l?(?1y{@9vN{r*LV>U+~YIW@GO`B=DnaG1F0?+fru*1{!&Jb74-FWh)#i`hY= zv72Ki^%$H%v3mu`3tk|)taw0kR2|s=g9p$xS03%sBn??$Bz#Ph!;>AB_~pem688*% z5jzv<$c{|BIYR~qzny}fNu|{GvV{VJdh(jy6S&D;g@2t$#!;PRLgeWNzGIO~mt_#}PrOgw|FPLN1(k(b=MG2)ZmE$nAyI^zRB*|=BElf4M zgA**4@bveKxUj;Bqt;Kx`G;Fz)_EUJc<@K8C|(EMjWpPST-aPI9i{)WP%NK}VSy>^ z^7|zORq8>^)B!{T_wZ-y4^X~VPz&O3P*Z#?NMUbNPNpIWtKbv2Ey$`0cDw>ID6Z?7OPthph%E zPwmb>DobeD{)5nHo4_R<6R5)~2K|RBV0g$T*X^-JG$N}%*0j|Mo^Gz(BK0JfTxQLU zeZkUeh`6rDApEm-H>JlX!_kM1SU)uxQZwD~v6&L5Bvf)_z&=_(Jr3Ty*oNy5T_OkN zN^sZ9gfB^NXz0N4Ji_-YX^is537i1-?drH)a*GZfoPb%MZ^E5>_IP;s8M?7lik88_ z!s(fcm}Pi^+HSm~jRi&Gpx+*R$fAn>49|q^^-km->Wv{EGli@VrQj9*8YcD{Om6f7Z8byp9Xu|6ik5l1tU9fXs$US;!V2-RdNG}(%WMBbgygmxIpE{sP zV7u6+sK}c3J+Z&Xcq%%Z1x7>MdB%sE@ORf{NbDE_r#==?&dpBh|H}}69aJD@9CzzR{j` zh%1JXsNyyf(_`{Tdhs%yS!)Xy#yzAh@`L$N>nXZxJRidvr^3%ESD>pxpDh;T!QqGU zR537(er!C0*%DXjji&eT_5ePZpF*~M5;3?$m-D6sK(8~Gg`Q>0 zIco8F-sB#SeVUy_XxGBx>vk}4<0d%gsEY5-2D9JyRTO@&nf5hbU;}S?%s)F2wV#LM z+6~L3LGP-mVfRHim88o^e=BTlJfgNr6E_>)5#_XLt_amJFT0h~8oK|DcE45h1ewCs?C04b6Se!IvgQ?tHogcE}8+j$dcE#`_)x zp9Nv1UnG7`uYpQMefrPl6(|Otq5ScVxcqb+?lIP+iZeUl{^or0Nv;L0&-%P*{{UWT z=7a;R8nDDOf+7rqr1d?FSv^OQw>u2wB{hbeKT-qxkJZ5}p%b_EwWI}pTKs8UUupNg zMUWbzAi72@U{~o5IJR^JJ#spTW}YsvW0Mzkt~BGa;1#sIMk+m9nw%*3CIR>H(pC9db9 zl`ysNFx5nvqV9nxz7yI4W$|Os+v_77mmSWFsGTaO{QqwyE*#@Cl%OsZtC{F@i$L0nV}%;d#wV+FWOgCpHw*=s7Jy zZlW{BKblX@^)DfE)n-nv97*?FHqxoRX6UXz04vU4B#Z4z=zDc9w=Ss?C3TVfpK%Ca zgC#UQw8T}-^{{YRwd6_dPPqK^E{7Ow#K+0E;nGqgjB~btNb?u8?e++)mGfi+t5f3h zo;8v`b{9DB_D(K!juMq)$DmhPG&blz5ihnF;BT1_sz2NhTRdWgQ&(EBMJC$SNnss1 z#;@VasUx|>%EvV`rJVxiE<=URD?CGX25Ib?%#K}$Akm{kGX9#5IB9z-T4-ho*`s1{ zipMT?4mt}PPTZinVR|??VGNf%xkxU%R^YKxdm&@HBX*2-L6yhnBuSfOxg;>1UJUb~ zC%a-O`bA&X4O0c}ecQmpI~fB8^uW`l@5i+0I2cLr;aj zCj`;N^D_Ly-W{SxkHw>B=5j#q+fdW(IW?IV(D_i-&n=5qjMiz}L z^+)?P3#3b8>cLh$1|$3E;pwbOz5)Gs@5~n3{qekDHuoRPyy~J=*YokfyJ}dZ;l!_B z+#>wkK}XA;!P&~A;ALY%g?|&lT4yFaohOS|hbQvzw1eW}m=u~i(-`}z?t@>O^&s7^ z35?C&)r_t3g0r?Q@NQTW5iD@5!xn5mag>!?a#17~&czymISJ3+*(a+H?%5 zR)+|ioRV2Pd#_-$;VKxZ55Ti#n&3T0p0CZ;#m-5ZeE9T8IwBJf{!gw!;j5l(Zrdg< zC?txFP=G(83>gUi%ATuq2Dn}ObxfMgXY~M9{ek>m7VWq@r**FZ;G{E`t7h%uk z$#~OR6V5J7z@r|rykTKHP3f?v1L^ySj}-x2_u$!~xA;+Dcg%2_$wBtvxT)qSMbu2f zeYNV?ICZb2yP+3d@i_yP$4Yq5xmpM*yht;(OwegY0zG&eE4*{)gB{BX=<1AW9=6V( zMjrfk$I2qnO5RKO`@U3YNm9b{IgY|}Z{(*+0xrHhjZ5{nV?^s+F}wXJT=$y669=pC zGrzAe)w_zml$;S}eJkX5C;hPZuQPD!fk=;@R!G&SD_gEMVURkcLiU81U+Ke@qm$|Fqjq?!-It%-*W#n= zYrH|w!fM^#JSV9DW>1*M)9<&z6vIuJFhLsvN_JxQ+ykQKd0Twcw3N3`)KxKzn(LY(tp6JxC8K6Rf&MD-Rr9`SK!{N^De5^Tm9(#3J(AcSV zaKv^lZ@j!+RQa-rAJ;smiz5!Po0L2|+!(^XIVSks^DKPN*+NpIhN0iu9b!xPF#MY^ zk7aTTSy5xJI8#u<i{ zdVjZzuJuW$b-M@9{a_LHI}PDA21nsZ?>JaEAsw^76w+$BR?5kbrNhMyutPTju3ufs zKV2t-Y5fKGIHeSaOzg)FUAeQ<~3q&ma4!Bm-M zfvI2fpnR$tA3M8_e3bRLcS9O1ZQVr;bB5ychreOBR1A3O9dj8FKLa?#hxHOqW4&zw z4cneCoYV>u^IKy|JKbIV6GZQbn zPQb_EL(rn(y>LH!94h3w@RMs7Va98Jx?q`!LvBByj$XxZe(+lUccERPll&h{HrA(g zy|wF7Ke}_RV==zkycHPx;FFQ^{OV01op`cS7;dytCEVN zuhgLYpCfof&xzdrc++94xh&L~^V^#NJkm~%U3;`s_M>9nt}u+=hN)rXzG+zUC{=K} zUqC_Iv~iI_p`iF&+I8&kcv{%p6Rnh`_-9NMwgrR<{#z1x+apWX@%>I$^Zo-xn-7>p z2CR2M9~ZpcP9f`k;MBhcx-&L||5;{&Q)x2G{L=;Nb=$Gw>`ho%`$R}Fh~dnt%~*S{ znI`8Zlh^feRDLlJ!*8nc%VRfTp+W%FUzmtJKj_h!1KI5H)RhK$=JF@yv%yG+@!MID}=>yp~V&4`Hef3tR)egL` zmXhl-(Ro~ivqQHNYHHl4+kRu=UBMW%+qQ}|rbY?%v6gVU;<~kIAPSY4dpX{JXSOV>g&gE&%yinyldYNVK|Rj&8z1 zvQEv!L%YNA-Owo*-=mglZ1h);K|aTcz<^@hr5y$?$%&I|xy&pMd-+=*D(v)){n%8893PCCV=;h2*9%x+1j(htFk3E*5M@}T<8mpjAuhn9~ zkoA};r^@9Yv-rdkfMzHor7y3cS=NIq>~+Dye-yT>E8sPUY~kS3p*(eSGoIeyjPvDH zXrPBP`xQ>$d238C5$xF3S)O*}stV86*TSUT_n;&x8{9(Q($Rc5Ht%mqFFFe)|IFOE zbBMm=`q@F?A^#gae#QxHk-Nn=wtINX>}6v1z>Mt1OFul5c>y-b2ZFOBYDG7!R;k9%T=V zV7qDeNPSWd*F(qs@piN5Y^QF+N-{4*BS?W!dy?4c`9^$Q7D#u)0{E2mXs%Vc0-@7l zgoBAM#c^%LLjI_E*m5d~uLQLVKbOwtrMpy7v(}JDOuq#2txqAqCmDVe#KZ5Qdm(;w zISz}J@RHC&-4k(Ox0`eE(?2`@od1AaR;l9t69+iXRSr-6w;yem?FBY?LdUK;bZ3DP z)(<~Sxy$qTZ@5~0+2IxF^X&@cj5&uMa%tjc+a03)R%0CZVLV^_`HezGXR!QCN8TX+ z4&-!h!Ss=;Xsrg+bFT&V&c6;x6-X_&mU48&COogX1ec%DL;uPJeDnD&AtSR10^Api znNpGL8s>%L^hU7P`pG!nRhMr?D8ZMWZ^?AxZc#hL6#qW&E1n-J&2DPP`N`?1x~_%3 z!qvM|aL(ev@cnQPxIeiQBol}6Ntr)l+4l+Z$K!Sw>k^Cg|8! z4R1>iOSU{1!5g@V_uLAnJ70dokJtsc?Z-2SZ!&^i7Naou_L8k9Imq?Nj{xX$RiV79 z7*2n>hrdhD6lNLD;ZaG?4s56f2N(6()K*lP!R51fPh(q7Qiq5r|tQ|H8nk~92j z@DoZnxs*(Aufn;~@xq9IO5is05R6fF0?pOsATx45sBAnc2K~Oz<`4@?o>36{aV|El zzDjB;*MyenrTAPY6^z$Jb08+;&(kVs-TV<2N^PU1VMe^L=pbBN{+n(kIg7=k=aEt3 zN;G)?+u0Gz!RNUd_j?-;){d)TTtP1m-51O4=OQ^hVIlv;DVVnMHLSbc0b3ILfxdVb z4n24RS9G?(4EF|?ozBN;?>{YexYZ`?RXPGUZw#lZ{(b31zv<%rjE#KCG8SKdP=*t# zmToSEu@ROZg^m) zKet;4WBM_Fn6NlS@tA2q#Ja79;>>-q&}n~IlJL?NmBXWO=FMi1r=_Hn^Va3# z{j0nnU9S z+En3S$)UQfenY8n@phb|UQHhAVN|}jl-|tSBij3j@YZ(|*S=|m=C_GL$&wD%cHN7i zcTUjp;xznG?!fD%pTewk;c!NUlx$sB4)&Bzh zo8*qcA6*)GX!nBK*~wcw||Fx)thZ-=G9 zL-P$RJF$TC)OHHbO?>fn_zYBfeuE}2)Prw6$6@-4AJAfOMl8#_&MzI@c;UVO#08a+ zcxhh)tTKHhRBZeNBZ`9Y#PMKOFt&%%uov{s-Ua*p9ZhOO4H<4d5j@rP#j@@1Xkwuh zHQw}+eC}L#1F+;BMNyxtP*|x3E@GAto!`7Pn;##GUhEY2oSKbYk0U z7!|dZub#Dn`roqLR$$4s`2x-{zXO#s`@qKS9U?yI-hpw(=+>al7iurl=8M~~BXTLf zk`2b?eQntAaVxkrItmvRuhX3?T?hQav*%3 zt<9GAc8Zs}ocUSvWQ+-r;iVyl5M9wlaLovRe3nPgH?}muNrslalXrEG+707cr3J0n za4uWegUfxS$)>+Pue#g-nzu_xt>Qem#|6OK3R51lyMpc>Z5OXE)yCdYag;RGm?W+u zOkCJgC>T5&1fN>GnsI>~g(#BBQs=`^1L`aPic?mN;RAz`anX(<>eqb6MH7n1N8VhV zWqSiw?*Bz7saQxW#6gH_C%&2Mh6>u_+4+?#zyHx24GbTVzG4FZ zTi;CheY+64>^rQ~`YIfo!r&{Xgtt>%F!NU_?fSlo9qiO-(DQR(tt`Te+lrv3n@2PC z=b+o+tMJonpO8N#25VNuu=>cou-s)RN6JmbH06OL_KTtb;UN69{XsX2?{L>z3^s-~lkt!mx;)nxm*ob-&M$3H(f%1!op$hdmBH9Yw^Qht@)-I)bKo;eZqWHF zL1-7F13pSR{A!{E(>8Q-=G`TPgO;+BS~FR%F~sE`2k;7AHTuxjmls|ALVlBa)o+RT z3!eAwz&mpfO17M$v@l&m4x|P>su{m%qwCC&Kos?_PRhW%g zk1R-Y(>?r^xPcE{Y!-Zlc`P&YJA6I*O@hNsxkb7+6dLY8qb7a!Rp`Tx*$XMuVJD2Y z{Q>2pNAQ!RU~zC>8ahwgMT^(j@XpQ&Y<}P;SeiW+7ndf|i;eSXXLt`R>$8VPc!bfc z({lKtDi<{K+Mx4zBW<+z#HVh0!u>cSao3AL_SiZW9ac`lpE3tPxwM#$Z#Cw#M;QXD zPl+X^y@ZqTiF|L_9U)+Srm$v>C6;|$15Wv);cGa-kl22FZN++eXfTLd4yT}V9~*RQ zzalCHOyr++N@C~2G3Y+v3`NFj@^ZPWxKe(R;C%Cv^Sz#5$xT6B>^FCrc zJHiFShCF~HPE+{LL34bfq|8&=^sv=em1{f~iQ>?`q;J#*OjP_`o~q2HbJ7ZUv>{7e z81swgj?N|j{g;JYaXLmEUM`WX@4m-t5%?v+T__T@dAOGiPWC7l=e>@EXKUs8;o$>> z)77CaCWpr7Re^Jh8msK}$F|59bZ*Q_Zk?&e(r$w>z$*Z{@rZu4n!>bK0caiYmF{F! z@tdQU;Zn3H#*Ws+yAQv>g3H%n!n*>zK6aU4UU&`%*`1{O36UHvo5uUw{*g~x3v>=? zr8YSyyx1Nke3~8&D|LR-<1O+0ZP6}D|KHiS9}wKt<7me0-D30hiD>vX1s|lx^Qkpk zS$5EEqIO3*VEG9qr%AEn=1FM&M-_+Pe~JGrP5|s0h*i}2 zw<73_dqs|8)u|-v120`6#kvUWwOs9=kmnSBI5QaOAHCQE$<^NBVjonipVkCGr+ z+)rlnJXz^lIuGjC3pCPa;-s~Kq?xQWbL@43Ntr9RlsKi@r>?MbW z9-@wAH^qfl)mU~d)%iNROMV%J<|+ttS(5U9xn~>sO}+}`*mqI(;Tnfl&{MM z+fMW9emQv4*8!!@55#;GC7#^XM=W}^9B*GRWsaJ7ulG;M2QzQ3o@|GehoV`b z-w!yF@RL?;>+KSu^Mu}f_&`tAJK?y7G#a;Whs5@qCuV35$C{tMg7(Qj;_DTg$jvO7 zKGlxm`a7Y-oFu%OYJ?gixAIy%4?P!HQOGY-Si2L+P%i2J_dS0113I4jiT%!GiF1`E zQ?2zPY@8MfZcaP!gMkX(xp2niT97)uUowxcRG#K(fhQq1{5gDiI}>dV$x+h^GsvB1 z3$SKC+doR>#9fPF5Bz{dS99OV;B+yE5V4!%Q*DD+S%&tmPrI9kFq#J5Rgl zg&FT|(3Az%{4AtUc%9Qls-OJmxzPdM@JE%O=3Ix9n^$0*Pd0p!HWTf?&xYC8(qYhu zRaAU^8!T&D&95q+LjM9USRl0@t|=LiL7g_6G`xYH*BbeoUnUlKUjseNt;@6w;p^M( z2w|#6vEXMAC6@G}MvH-5Z*vQNp4!5>%kRUwKN|eMZ$JN3+dyW`Y>@1+Mm6^bsfqYY2 zeAYOSPh45;eBqe~-)UaMk19VA2gKoeOBR2D^>m)$e^WM z1i?}LxXPhiSbk|4d+)d|yt3?&+>X>j)uY~^y=XA`n>+)j!$Guil`>ymwGRfu3#z}` z4zBNI;P3F$P_uB3uq0h1&jT@VILrmVh3!JOF=^DjA}{=@<*F2J3RkmD5>AHW8Efc z*6*)J<$7vt_G*|AKSCK@-DmJJ{lC=tN(FoUAc&1mkicbkzJvPsdg@zO0;8pXD|QDgRQS)n+&4 zPrF6q0=L0y=f%|aZ#t*kp24qryK%Y0Lm2Yj3;!GS5mF)s!r9N8#L)Sfz%Lqw&9!k% zUrPDTIU`OikF2X)H4Ep))CnCU*P{3KF1RuN7@yfV3?tw9p=FwuP$1PwW4=X+Cnm&T z@^u5+R%XTftLY91 zE#Cbo%U>6d#<~;FgqXPAxPGAvdnB!M`Qvm6mOB}emum|5P#=sfHv%N>Nm7uz@d#yU zJtoHkvZ$VsTzBv18JJ`wOD_}bIWl985P$WYOW!ODTy?Yr#+~p5g}KYX{C68&?RyaV zZuP*L69ce9Q;RRHzeE;`%{VJfMwk$4#+xhCsn4GS>@jPvaO-)cOU2NuP?;#uZk;G9 zjG2HZX04UT-pqi1NzxFp#(_&dMe@bWoh~B-`$AV;82b5HQhS39j#(OCXPh?%o!-<5 zbAD|AUF`*2;gRg(W_O=X`0XXD03%8ZPk@-ZOfXQq!1tVwfzTNs+#6tvYu(R5&=Dmn zygdWY>dW#C7eoH=t{)~$DJ9>WS%P_g8$P~94u!yC(3+JXn)gZ;hgj}*DO>j*{IB@% zLbv&#dRdhtEB=Fwr%vKg4O2KB@E9V0Ov1H`Cg8~a`{+^HH_`V*f6i%8rFTm1teCig z`mWZ%&b)qjMtdzAh8dxjx*oB|Fbqf;&$BH?@iOD9@HQw3q-#EavAZX-dnM;Rm?U-u z|0Ip7d%MkPDW$;&j=kLa^CBc<$0g ze-!mts@($jj5HA<5BKg--h+xOPt|bU8&*d&LFFm3jj@<^ilU zXqzyoW`Q`r{TSqYyDiE-?WBAD-yp2HT3lmkihU{v^IBeymiL-z@sTpn*(}FXU5<(c zEk&>^voBZVEXJlp9af8p!JhZ}vvBYu+`71*aX3*wTLw6c0Z^=I0JVgnwZaHH#T z3>jQU?q_Xj!T@8QJL*jpT{;CDl`_6bMGqS*9o%x`??g4eANn?HSgiK z)D4)lk=Sg`FbJ*i#03H{u{-AGVGyq?^J9m zFX4?oW}F&&0xDcA@SV3E9x6Ho?Tg*51A=-nAZ`XU{yRBm?U54##*!l)tmKJA?7n3Ik@El=@z91g?f_Rz&q9nhel!`5lj zm~Xpcuu=!;*b+-6FDL&Q^I5gI7uxPPPCws_h95UpqmtqxcxB>-W8kg0aOW1hTRw(& z?AamYE%E1=d#9ni+)Y@OZX<3^P{hKPdoB;vyg5{AUiU1lDd?^@j``3R!WvxYzNS3- z?>$5YhAo=eHZS?oPvjMzKLen z9t(MWYT(P)SmAWrb^76)j8)Sn(!QkQxc*la87wFe&fXir`hS{e{|!&bOi|`!9Ra_e z+k~Z?$Mg7W+Csng?W9l;1-%qC`FO`W@~fA}z^4MwsBuDzN+}%mQXj;@+sPs6Zr!r0 zO4#fD4vLy3&zin&++4i{9kvbP|MpbD*Rd;jyS6MWv@yh)gU8U5h9|JTNE)yC_hTLN zIo#V)k4L?%hEFbg!0=&!=)QMYUB7wXAgX(A^_0x>O((Ga^uD0EKMl*eyGc@81g3|O zj)X*`?(EA@6%z))~lOm7Vt!4IZ~XTP7mg|OU}QEB>Rw5TzOQXew|A_&lrKM{coqJ zIsFejT6&$vKiY<;v%@e+H5S7nBe&DRxmk<@le0+{}2suw4m#oYi@A%V7L$wvZ0pABWcy zWihYm4+S1MMAEKNU~ptOpRJ05?S*&5zAC=>J}8HVU%3bEzk7j;P6G|vZp?3s)VXc{ zc(PoZ0Ud$0F!04Eu_V9_ht-~fmS3MC?^P2l>rA9_WmgPPh$Y_v*C4a7g}RECi%WY| zi5;3{)UzT*$Wck6%DqeZS>iw8=|>q*v-Zd3sd}WE@y`2a3Oad^Jj3wM7TgnBOZ^uR@(?@hI4mq8QQY5ZV1);S3V zK9~jS`4WhNJ#{?TT9RT;I16cFqUaD~Gp1ne#^ZhxEG~PLxI%)&>i1aa9Q+!rvFv|zU*BWrw zLk7p$mc!N3D6$MbgR7gncj?4bR`X7vX~x4~ZLlJ4Srp8j7Y3s8d=CgbXvyC#ec8S~ zpHt4-VRofEqE8$AJr)Q*0`e%g#U3rjJ%>#_Q}J13JD9(?Ns9`5am6tc{xi^o?)

  • WG9J>kyFGBi2sj0p^l&4ukg-h!iLI$gTa3h6u_9pDUP?MjCBm?ZKK z>%n$Cwu_JcsIjr_6d_T^hUVOf#G#>n!jq8a_#`5n&t95I!Ocx{(oT__-1orME4e)V zy$w%Y+XDj&JaJQIkTC4{SK8NgQJkms9d31e5CiT_V5Q6oF{((l_(m;+ z-8hb~tJhP&(oQJz+zpq*wP{TCN(`xx$9>gtkW#&cB#D(S^3xo}2Qr$RFj~PPeA}9R3`I+ERcvI}VRS%zRiKKNOUP$^WjNtk&8%32tawHe@AKdBC zg0ro|VWRF_NQ>@6%d_+v(`LI?}gU}xt6JTjmfG{R~H-4_hY zCUnrfb=xUot|A!+J%ww!*66?V=$(ra_fw*hul-+z%AG;2`&{Il%XO z9wmdXLvh8Wp182do_wh@%Gj^yiFz)f4^4eGs?iPQ<_9ew^sV^MlCK2+9i%Nc??U} ztzlh@Hm8ghv~du%|X4M$*&`(%2yrU-No z?SN`c6ONf^f*#{`lIhb+pjxFuUPC6(&gh4N#T#w58XE!XdZpAjL%BZj^$mz3l9Oiq6Jkhf_qbq`YauO};7>h6meKKxOL*%n?U5cIarg&!J1?Nuu~ZuN(+LdiyPY#e;7ivI)2zepJh#{z zJ@mdvvb#OoZTIQ`%hI-nm!w8=ctw{D=Q2mrFzsX1v}F#3|I5Km0|)W-AxB}2 z{RDDJmcicxyrI~AJ@>u8UZ|Se-C6C?9I-!>62~cW>MsdsIh=!;a>k%mbQ(fVU6Ca3 zP{GvgBRH(5J;uKn!Bfv^V^ygFXx+5I9tDwrwmE3Cv>eX9RD~Danjmw+QOeq~ zfc0lJ(yu#K)VN$E>o<|G_5BRKZ!}u+(l`svCgei;cX>YJ>&&LJrSNBPA&hEzMN5QX z>{VIF{ucfiSn&;Zt3b-I}Dm{%Z~cTar(YwN|RkKtULzXpsYfpD_w9{f)=N}O2B)o-_nXF zb09eCD&2Gb4%^28FJ0uz&z18?<8U^F&C4SLIXj-8smLn+i>bdD3*&=pU_+G?R2M4X zM}2iT&}4zx)|c^?#$J5;w}i}Ft+=6Nr%QN{6D^q@#L{EDSmybAadMyW;JhP>-OijP z-+-G!NsqBu^hz7u7VQ?k>rPN)25u+@{ADroNFRbMog`%ccr!}v+RJCd5{HgcOe1wY9d(w4Qmp?zvE z9^1nlV56llDk+wpT!fw zgSb{cvP&J8Y}3cj@)7vw#VqdF^ANny3)h7y!^Po6IPI1(y2qvoJzA}4ef)CT-+jNe zFOoPUHl0#NEkTuz4%!kilosgEXPJBppiw7a*)~o76E>alk7x>~;|w2Yq@ zBxCNAY{4^cCSKlRi**xCpl-|qy7q7>T~_$Q{rj1-fdbQaufACG*$zEB`rwww0l91Ko zt59+!mA3EALoIWE7ZZ1Dn(ZFNzegF06?YU-Lv3?2jd+-EB>+brLcC58#feA6TU9* zgu&jvAb&;=k0pK)axZV^=wZ*qeru+|LA?h;^RvN_cIG=dnT*G)epATe?<2Ut*HEU< zQEcxODfa97M!l_kc&tqp-HP|+pmT8~`z=?9dOI8gj^xtGi;IPR5e7U?X|(XBhcU-K z87yXYnBoEXGuZL2hiLVE5O4ZDnhU!-ckiNMs4?A}D=Y`o;hb^&50$!%){GLb&&>-=JB81#1UDVJmGVtAiLj`9d=cTQw?1(FWr+{J_c~Pw=oW=?T-tK z@?pG{BAm`y3omD9!@6;O*=A%ZuBi`~{PT!Kzp$e;>BoJs%~O=vZFk|G7d{EL%X~Pr zat_?mYeMT2dqt^7-Z0DX6`4<5L^ivx(~QIwESr!od7(&Xh|NG0#uT^jC0a)reW!F1L=mqO`z`03MVuHCCnwoPepM$ZNNYxOz^r9x8-IX23DWwQ{i)ljTBLaV<}DObBE!;Y5iYlU2houpq4@lu3Ljmv zf_B#_@jsb8(912IB>jr0<4-f(xpo`A#4W}g{s*sutnpWZD%ZadT}EU?k>9rl3i+eX zhHXaNbuL7ldu1O^m&{^YofskX=pf3J3&PxpVi&m`5nR`Pq&Br>5siPT$9m7Q_-0Zf z7-lkjRrV%wBZPx1&asWu zHog~k0Y@%xfvf)0vCPJk6`#dot3?JC{#-?Fue*dzZvR~De*1CmwibH+$dXt|9~WHQ z3lApcivwP$`7)42x)4K#NUs?hA5?PYkwV$f{Cz6j>FPQjd zvv8&3C^UcVL)$h!hRJ1>;;rpNVN&raTwm_($=M;ys_c&v#gm}QLwRdhE1`3g_WI7+0xTkgV}byj@nOc4!! zwj53vdZJfqJam@XQMlJ>8a^SBG)`-g-0O=J`=?o4+j#^AXk5TM@3s^7lB3E?*_@`J zM}HrwP{{>b?yv8OLu_PuQ`b-E?>d>yj)g-@tQv3e{RcDqycXoLK1ou0Z-7y2;_&mO z-w+!-mNiW6IO^9KIgd)Id45t>Oq)}82oAw3!Px8>sgD{=!7B#B!|%l$DdgbBkp8^>)CA~heu=EqMq;e= zQgmo{G~d<${)$pON!^YZ9lzXbG-T5)BD4O$f(#>pnJ?5Tek zH~Ah0-#{}QxiXN=bmKX0K{9wZ?V*volOs>=??_fL zdT2cC6&M|w%SXOmg3*y*g^8&{aO1k)_#h%1m!IvV3eO&3vS|$0$`{bUr^i|AcMWB1 z9muomd&1gydpu|z21^%I(&_>$y2@UtVAIRR?dM+_e!iRAUjP^B9%7@D;~{^)G#-4H zfjRV?QgqjdZ-%!*llTJXq@U*vcg%6&981pn2cTLzo2v^avAS_AzP+bRHwGzVYF#Jw zS~MP4Z}~%)0xyd_PnFP-=MhvoPXS*(nZScC4B~Hl>Ldflw9=}F0U%%D166;Y2}cyC zz_@v-q`aaO93Ob0Z`?fY(Q1ibTXs=iX$vgd_>w~ZICHz*S>asq7s~DWjuj0`{CJWh zrj!+N(Rpbc@X3;%?Qj)kJgQ0i@j9Nm^%{N;QQ|w-L-_0O3?V648T&Y?VXx0?cui_A zTCrOlnv{*O#M>SxCSL#}=c6QUm?S!s+epm5JQsI9H{&^VU&Lp_=fm8{Y<`-d!f9K^ z!XeLd@N~Ki-j=&Zb*D$;@PBtGz3nb1-6QNLGT$0 zQg24%EA6F{$H%Xc=l#W`q@2JjV}U)6HoN$&`~==wyWpLRJ{%fmjF(rGL0(5H%T3=) zsq21|U(k2>o$^zR_g2Hb-CfMZTF&pm|CDZD|(S4vSR^IPPwmstLVMPv1w<`fh z$Ej@aC=HM9zm30n4GK$~*e7u(NBPaBnL!5P(E|y>OCv)b9sCLs14c-e7G!XTcBWWT zT;yUbwE$BrYN&7cLKw2K7jEJRE*~_C>EpUbuh#ROs@z;Eqp&@J?(v2iorBQGw6k zYxzJpz9)(rvVPJ?HAVcjzzb)bJwg5FCG+{c%~%>e0^L3wtDCvViycO_kjm4E7^8BN zre$m*53@q7ZJ)&<>#LwyA&(9@xWOFTMwn4x$hL`b&}{3-HWOcnaWj8$j@3_)ANhl# z^R7VR?{kuoaShP7Y$M+PB+sAA-_YFiub|Jucr04j3}b6|3u}hHp#PrikhC7RVyn&q zF)x}~!^D8szgdU))eED3ED&`S@+qjNJz9rN#}&?|thzFYE)gJOV zvC4?n$9xy{Lag!kW;wJER)8PoXVKM4jvwkJKv1L{OBE-Ghp(H_9vN?jCoAC1)Melq zd>l=sD{;x|Xn5k)K{qw}bNILxnmc_Gdu0Z2?%W6P?oAAiyp_RMOUtN0V;UQC7F;>i zlfErJDO|j%ik+da==9dhgeIKGKTlY+kxII$P~%x{Nv-xou(>Oq<~ z$b?Vs_7XolehIJlBYIu6qJ;~?z-jXm=yiLTFt|{M+a?Pfp&1}PjW$Eivn^n7?htey zmWJI$J+S|qjpX2G$f?phkx1FFxpO4|sj|asgii+HP@(uYu_y>#ShT^0#rtCM&kKTQf z5>mRNc+~niI4AJ0cxU!`As|j#;(ue)nomIU#Ip# z*{pq>KT?+$9_@B{cN-k0e_O&;-^stB5Bh{Y2m3?KqJr-fDs5`PpUschHCm4h4AXhj zY!l2#cb8qyMAmyyJTQ zzBt~JhDxPGlBR@0O9Or0=R}kuA!R39e#kBQ+Z|>iRN8FA_go zNIsit^o4X&d$POydH#8AG&`t-(rVAkkh)|5#>fxAGW~^kUeyDNiiY#;J&Q3^p*yGA zufY7(vD7a~ho*YyfKoqO?&++9)!QBmpY1wn{hWjBAO1?rH5e|GhEB(~_x6EQUl*Ua zo8kTDaO!n9fy$J<&^q4$RPH?#Q;vM1SNBde%#79quL;lT;%ZGyFH}Iw)?rxf*oW^r z=cmU)o#jaA}cm1Q_X<_!F{`Hz&h9DonozvKL#3Ovf}0r^KelB=Z( zm`$Dy`kHBM|11hJKbKPR?FZP;v5-3~w4k&#l~v+uAu+z1TAZxua=8&sx_Xc1MMYDu zq9QDnS4UCr8%Xu$viqG%ah%~&Y5P_+zQ3l8j(Bx&LyrO&uzI*)zbFIDm5)=b@_#Vf zBpWx4suu6uNus3}T=1|;0XbUT5XP^$Lu!{)&|6*(m!7Jj>Yq16-&eO#nl_v7+{u6o zUJ2a4T~;`k7E7zM^T|JO8M@@QNc=zM;ixoQ(A~L@rr~n_@l};nZ7RuVMg?td8X@c} z=z%j89bnG6rEAu^;@gGAP;)+9yqh^5w1jpzlY2qjSQw2zf>I?5?AxGl zOclxf$%Rn$TGC9_rWK#;o z97qt>*qEWtww-i$@O$`mI}-8|e?q=-G`=?I&c0sLC|o_4YJV0$hgol$_qQ+4e{V(w zGq(tr=YE3LFWXVU_PU^;lth`D!St-oQhX6?FWq`;CHHbv!XL5MIm%Z+@1-$hCrv@$ zsumj4CBum+J3#$mCCxcv$l6ZlMfEp_*x9p?uC6f`Oa4y5vVCi@YsNldh;MiNsN#m( zhkE0#dt=djUx{FA4;(gMk$i?*u+hLmp|9f?@pZW(tLf!)_4x|EEYlseANpZbSTxRn z8=}SqS!{F}C)AFXJC`YQk$cMb!cNCzv_>q^8FwmKY++2eG1CQbW z>J1@=*Qs`}CCfSV!s8jeX=6q)^=p1cNhkaBlK0#2)XIBeYG)IeuYV>gd&bhq=?`J% zTUSmtdk^nJlX1XRbFK=v|=&{;=pxda5Zr@dT%hWxB&a>}A{p(HWwoMHiw@3Wr zsYq`%9|@n_B%+tclAJ(mYoPRcBXoeA_(;%yZ@^p)#Bs zJBGHsjNpt@gCs5%-@$%{J=#}36(Vn_L7xpzU{>BavNuxUM^9gYb4w8~{Mto|;ca5T zN`Kt;Lk`cMI7*XS=fYLqC$*WkTl9LmS5(9VcFC=vbKYLGK4T%ucPxWvt+CMg<1gei zoF}VYirno^7(O1Vfh~UqLuIr(OKw`wi$|I`UOtjem1c8e;#vB%IE|NV48`9gj?jR2 zj(D`Q2lX8~9eelekBtKl;MAM**kXP+e&oHL2OPBklbKFCB75P=51qFiHvwRQB6E|NC5+T z_TuF65!B;;KRjBNB{YN|qfx(3u#9Xt$ZT3F93DFj$)-E++xZ4QNM%vCU;%7Ayi$z4 zy5=68wUYxRL=$J>ipziYtKZ5Hm%NF|@mcj#iD z$>^jUEj;|_g3^`<_D_t3j>N&Nvcwyp+LQ;+>k{u8_rYmi$E5Sdhx5UkSv>i{Yz? zVO{rO{H-7YUadNd@f~UKd65Y_)=F4;a2@DprwcoLj+63yb6CCCiOp73107T48P!tw zs?kBGM|#6GqfX%Pxv(@a0fQfA;kL8U_|tEnsN5ODH}<)(>%xuf*`q)_d~Kg#a4Hg6rO$D1$Z&^D``VxD!_+2uRJSaWX>n1xIM4~;q~@@p5mNn1$X zVhBDMvW}u&s7v(P^YNyAom8%`JfCjZ#KXFu7W#ksC3)F&lloWx6umF>!_xa-@way> z%X=2VwVg$5?cN7}DBYkfX-)KFP7OTxeG2X$O{VQ#4LttWIxyekUm1W8l_iBu6S2eJNfItDz`9;$a5rQVt)Ab9pA=jW-oLNH zU+I(K*|?YV&}s*V{pSrv;W8*&r^d?;9isDlKhTG_<#6|i(Z4%%hKCcS)V8q{4mG=D zi%P7ZYN)_lT(h{KRfZSY0v0!~g-)3gQIy^!H^oV4e9a9qIhIg&UOIo90be~tkkc%tWvg#?VF`X+6Nz`K@ z_#4cXT`yemvf<$3N0fbEAChr_`14nmIN4W$j$ZIZv+yCjNVfpi8(-w-!XmhIbQu58 znSrycVxjQn4VZA@Bs`PV;iaFF$e?!#{jEL-so9sso2^+O`{D@9&dh=29eSdNIF*xD z$YYDiRQ#%BfzfQtjU%F|Zl5#e#mbP+taK_{W{ewUP1#&Y52wtw7x$bWhyivUg1Z6G zVdICwiPTa2X+k;7+uQ;*Cw{@*`Yn(y#M7CvI{fjYw>a)d1Uar+ zK?xqC>49GbDs}u7w6AOxTkhpjA8!-7lm42nrlxa3g}Q5xO?$y;)O#LuYcXt9wWSLm z1Mruh9zQVKC{#^(4~K(9YUt8H^@5#jAe#ldCX9eRquXHk0}&Pk=#cbHD}3=B&as~@_Jzi8A!yk17des?RCOPqN68Hmlj30eBxl}Qqm6%R3g|~}IJeI4#l03vId+8~ z*KP0l8igMbL$TD!2EzRO>CjG3ykA@h zlg5=ogxX|26rar9I;$iD=6GVCR}Ud?OSSO$K#XLGVQ-waqKLXXWQrrtd!o|LF}&!} zA-Fcfk{?tx}5c-adHycFwGc!V-td1XbeNdQL1jGB9QAGG>$@?!s*q-@^j>cPIx6}S)nfe}2zfqz~>h?Hxv^#6r zZKII0l{9%w9G7Jx9`-wo;et9%dsjm0?^p4*|FqEcUSC#kRAHqy86IAJP>eYkNlE2C zxa@Vg_~Y3?u_Z)FDzSwv0K5 zd22<h)pEp%GBU^0g8U+P96G=ZUw^R1roW@GJvome?@z(33HH2u zOfYM$okd{_^QBYfj6!)IOWuE96K~wK5#_p>V)=9%Owp<3VOcrirGz6A)$jXpeDO~T zTr`}g=bFPni;-55*9XePuD6!gr8jg1Cib=z*(7Bdf2Tv3dj`j3O# zbTIbvE^e|}i5UY7P}a5^eyX#l&r2M6Nx}y>`V#rvMyU|)4X*N=)L)ej1S9Fi&vvbwn+vY8r84zVuenaTvo#A=(t# zd&C@GzWJcUaLEZF*VPuj{z!rki?wm)TmwX>JgT)KGFmf%4b|?l&WlotpOGtgtl5kS zDyFCx>VTjBdkI7S#bUQ|58jlxG$eOf313GI;RIz>_D#`}mJHKklL-cReNO?lS3DNP zPnY@p6F;Hyw>j*5?}qQztmQ>R<;4?T)_6TkjZ^JLaYl8%MD@HWUbrfU$M;wYdATFt zxnC+!?OHgv?G?T>Ov7~kLWg_CvGS&JNP@mN_xk`oF+H61%7)O{)B7lEbOVQ8-G9gHpe3ce~CQ4gj<>c}FV8|VD&*??~xHQ1E|CTvi zubeC6xl5ScR509Bq(hbya9f{dNUIKkg_eupipOMh2=v3P4g%j^Y{}uN zmVBYq9B*7pp%k?+>ao*=avF=!&|C)R)(yjwch{)u#TZ`RwpTnmbT0>Ou!iTp130v) znjJLvqt|E!*v*%rvuZ4VSX4x3ca6n|^CG44&2573tV)`zYLDH1$6#;eGoW+pmt@}; zQ$C{_M!_>3_)dI0nO_fOqaZmN;V>CGYF*){M-&bDSw@@oZ@`FG-x}Hu6jIocgQD!o zQRrDSikFOthI#3Byzj&UD9rdI-qxNf2Da`4MV|^^e`OxxhWKR!8N;(b@#^1FlB*^&+&(WF|O z2?_IaXvM1$+)raCzD?NLqROmhe~R zIDf5qj1|4)sIe>pcl?ZGyECm6-^&x4XJ~Uqv<9|~?-I6*ImcOd|H7#wMZ$^938)@y z!EyuRY4adMR8TGzN4u%=#uO$i?e2U$s~1MD_yyKMvGmMF6VImVa^gTWTp|6B=bmgG z<1f|Z7D*kfD!Kyxx*x>drR#BYR5qq*tCc5y(JI*)I?Bh(KXgKOR%qsUlG*cV}l zO?&5K)jyB8z2rTnrlMC$x!xioQA)Z|AN-0L0mUy7oEHj%4OXQ(CQy=Ja_nl z`{9dF4I|j#!Y`Os5X(pIFBJ#tq_Nk3UF54JLZo^P^!!{5Uhem(wnRV=B~zFYumIvJ zClh*4ru*@pD3#wvMwuOw1v+E+US$r9Ub08H7~hL6-dS_tfjeB>F;A>n)*`gY#A4X{ zOVqk+E4ub^!45RVgCqJtqtYq(^lcLssMgT5Wj6&A!$98r-+P!O69gIxLpdod99N&& zkA=tyk7x~A~!U^&4#J-$XDUD(%wq$3mm1uJIJS=bhEaXYQP?P>&vj5V9{;RcN z^~BYXHcW=jI}l%LI4>#~-60q2aoG3#6XE55*>LISFIaufo4jIkCOr3ru-FoX=fTF2l*PPxLr{C0T?!;?e1wsJi_==X?L_ z`CrJOs#g+v^sgpN)uC&)J#o3_6-uk!2RdV7$Z%{sZ`9f=gq07#pQEPXu?_EO$`2XQ z?1l&G?E5!=-cx=UxQ+gPFhpJBQF!5+7nX&Nr9~mDajx1h9yn+u&%Z3kSDSX?t_o8e z=%Od2tF@5s-U6ZX{vcH8t;f3??6`FHYJPh|j*{KZ3Sp+6cqk{DA~%gjAJ6$9=KGXm!a|QtbPfvSZS*VaaT9>67lb{KEu({I!sj-LKNp zeFM0%c^2$ZTZ$Tg&vR=2Hu1)?dNNx#SX{qU7RPt(phH`C<1fc2bZBoi&%XRpvUtu? zRP-N;JMSz2OQTt&c)YKQ2ZgNF*4&x%W^OwQk`#OGQaqoM@>72Z#Et0oe55ujEbNOOtG`za;i9+LFL3(~Bt@tK~fk)d!ufj?6dP9N` zaaEq>9c!UIQys3&%fo`UdTL%il!mX<6PGl*!P23Ypl`8}A1|=OfSPPLKK3H&+@Azn z8kT@|z9-KT=kTrdy{K}S6C2$(=huxjJTYK7U2k#32PrQgw5|+BwcaA^Al&Pw!|L+3l-S_Gfe|m^-1b-W=uU_5Lc%;JsIgugCYo9vS`dt(gr>eX2no;gi_$r43jKOiQ6mFmkP6Po-RJiH;TP z=OZFJ%;T0Ghooa`g`poiz64S zz}~d)9Q|{#n4hhUW;ydOVixTGY?Tca1aW|T-N{ldABb)l9NqDGzB%Dcn#2<>E2qmMI ziF-~AL5N27S1pDwtDN!kux4<1A4lE?C0r%v%?5Uw6gF%r?78NR!(J~Dz8hbJxIzi& z{K^(%cPxRjewT%j*RwFE=rzUZAE0f1ZM0pkF9^*yCB+UFY+PPP)xv0AJ|Ko?ZEc1z zstTCgHy+O4?@0muehGK>=%JQL9p2k?O1$s&lSbz(L?qptHzW|#{VtB6bi0*9a&F(wT39A*Kz#XS!LP;N6 zY#!KC+@{|L?PJS1@ydQGk8#2tQ?5bB(tFf)--TbMMd6>eKj3rSjLtSyg8BPl0XAP=oPCkz71)>nvDv4y!j_#sSaxg7Q(WiItUu#$u0vAifi{N;wrlWOdGU| zCYLF5yORnB>pzBzeJ4=6M25%hw54r7R>By16SmxQrPSj!Ff8voC>>H3 zI&~J~@9P8kgrnxaGb*gK*$dFDzYCiibM8xplX{3nMI*`1t2E z?y%fRPHXz{$KZo>*Vl}!1259E&2==lTO9YkVkk}uP!?b5guqqp7f`#r5cC84V4t8u zyqOxt>NhS@y{;#Zc%+E?Z&$+Xlq1yKwFe>w1c>+dmD9VU8l3kw0=F*kfzMs75>1zI zULAS`3O_!A371xrR$pT{@@Fp81>eJ0J3i8fTYG6ntttnqm%+-Xg_4A84!U;Eq?>JBlD&fG`dc$AjzOrwQ+UAXVFGU!-7h>jeJ zL!*x45f9Mttq=?F*`)&v)A_nJl4et2S;9p_$Ujy6{?26?R4<< zui-d%_s137WCVzE}f7Z0}G!_!#5WF@WxOnjOx(<-JeYqY+j5(4by*p z#)?Ss(ZOcAGH?MD8T2E|3T3WPJ43OaJNekXVW2xu9k*xhfKL&HFy1Ie=zQmk>FbwM zi>VW{HyJIE6-C% zl|6h&9Vov3uE>SP!>}tmpB4ukq}l7W@r9=*yx(nrH!O#e;<$5ga@tYXj$UKwNk{;f z%^1Qit193`xDlG~*Z?kjuhMSY@esMIKW0{+5OR!%oK;DvpbigvJ~pw1#z!25kv?s1^*qf(KRitXG!{B7sMzxDHNVjG(f8JY!q1$hOSbK#Y%za1AR-Hn8oE04pnao#q z4&aB+t3mn11^Re;4R?QY6uo!75wi8h<3z!lcPLxZwU1FW=&dhLSRBAZcbpT0r!2>0 zQ;UCoax)CMsmk5Y%HZ0^GiYeoX-Zh`hrg1Fq1)EeT%RAo((HoA<=|NNw? ziTU{RuZ&y1`g-oKH-Ua#d_r2`*J=9eo>YOOIPRbYDk&*}w!%92`6v@*c9hehz_0YC zM1ii9&4ekMKCJCxN z%tL>ah;1vY*g{(!N3{D>r|UR;E%OEn6!yTISCi22z)9%tT8tJQEY*yMN74y?cd~moJo6~zzpxbXD`PFSY7Vi(fIxPYo2I`+2N z&Q50~xa3z3wE9cof%$&W4K&4+Nds_AbcT?2Th}eF(1)!elVF6OHE+}ogQ(y)RAw}T z>phB~xgr{$C{B@BPCE%rm(nT!PZ0$<%JNO`34Hv>kp>g(J;J0RX6PLkN%KzS;Jh!! zkh8cq&VJaFEiCQ%M!G(Yjc6p59CIwI8O8c>7X?lIdlY262k%T@FOM;(^-o{osle6{CrQ@eK65>4H&y4* zXE{7>dk3^CH451$r~K2L-Q=ibh3CE`g6zsY(rO_CHm`H$$n@F#N+k+nR{VwidCOq$ zKmVAPB8Mv)&2eoX3wqml4K?C|SpDm2O6}f@SJX~NBj-k_uSntAcbQ5dsv(O_qGs#y#JI~(EEh>uvX%E+zz_yxkAvPj-=SBL#I^;z|s zfjH|xG)K(}r+&c}96axxu>HhT@rJw#?$Irv&QJ@qwKB(w-yvWWEfSplA-3cdV6~Sz zSl_q;4FQRKGp7i;Cz?}pgeu2>Eaw~RcfkEOdVH@c9WUPwk=&^;6}GK?Bji3);7j-P z(CA${C;M)aWUe?1t+_!sKd?@!c_W#;OlLr1-*;4?W&oN47IW{|i-JkIE?mE*h>J&? z&|AH8;?IGv;YX7K{L)v0r4?Uj-Md%tVg7c^Yo3fl0-8nHL~YvoU_V_=2&5t{AHFfs zMCga9XxS9cu@l*Oo$kQNjX$0{y;RZ z`c8}M%P@1vcKEq?AU%nkjnBW0=L4@FLE*l2G;Xsg{^*!NE64R@c6%exqgEQ6)d8xl z{#=)zCG0i4MV~*-fFa8R;Mu7+LQB0KHb0NyM`r)_%iVbX_+c0_b_5#Tvc#l1Svyw54OGr{coVsa!d(2j0Bh zNNO*mQ4-gK+?F7%f4CaXO4jpr$-hE)R10yXn}bK7oqR8BfM6(7sG#@r5glk+!`0C%0EWmYa)ohsbb#k#k>#K!pWt2;?Q_KRBY`Jx_8>C z&ighfn_k~~E+l8$=gZadAJ(ecU6~Ena7XsE6)9bPM zV&pnme5KkScT5Qv9Ud#8ZRrH*d9S{>@4F^H``kvuMpl!OG!GKLoB(B&N_zG1HE4WY zC@GH|${)j{Xqfp1{BorVPOjI*KiW^|Y={p;RR}aiXs2`T7rD>h7__&O=gvOK`1sie zaZ`6WoMY1hcb|E2f^7l3SXBC^IcYSlW6L z){gSx%5C;+)W??e=as|j^1is$;ewbuTo)CWo|dfaD}(c1k3)CKEl_!~oKCg>p-)vF ztbTDB$=K>2a*VT@HUGuzNri1)5K`X@ zwHz+N*SPIiu=xZpjEx1q!;5%*;TYUGLydA!)BurL*$|^_&W9HIz^;D%amw2w;krX5d8fPZ&!#r9rTali%ZrClH}e*S z_sJsDuvk2sWDRqy3c3mFM;vZ)ha4>S)4Zn6*$ z`#qCt98SPa%UEzZ)d(}XTA(Cyt?;4ZrLa*x5av9oMaTBRF!Ng%e5stk-E*glD{9SH z?Uf-j4a5$oG`ts6EaeYN$>)hFCp|2NBNw`H&Yx4%E1`-;lEiS}WA~dR$vgY8$)Q-TecnQC6V-%GhLy0!^azX7lzC-7m(Q{i)nGDnmgf@j)4!05#(ivLfO`l%1+rim*==MxXaA?ksocKAOSTwup? zQD%5K@*=)@`?#TdM-?T1kL4!=ose(IK+3^^e8op9=&u^Zzvso#@^`+ZxhMi8T{B_L zJtxS|QpSu67Gwjzi`+@poXH zevFEKeHI(N^YHc3-5~cR6RuVaW{oGEuJ!9Yq?B#R15;$#Pdq|%9fG(eI*@Dbl|l#n z7G%{6VM6p;F1oz}uiUGG`hP6-nOKB+8oOOzN&4_o9XCGc(~}-#^uxPdI$Ww7DRK37 zm+Tzb8*h%)=D!!Ou;q!dbnV7$A>>^$HuTS>W5aZ?c*SIxbV!T(Ju~GzuQZ(aC5|p6 z%!btMy4>@C4$g2Ih`p^6Y5BloLa*S7log0al3G#Rrhd?7DvQP5Uuj>o%K$g%%fa~a#c24S zNOx`#u9$NfRrb5VFzrxw3E#mVt9HSwo*SsLXb6k4^Z2n@0N>ne!9N-{;>f`RFh5~5 zhPe8PPb;gz=KxE?*T=Ktk=dMD+7}!hH0j)DZPYw57Sf@c79mGrH@Im(tS!XEd!#LG)33d7aI>4ZT!e0e;I>EIK(Ub2U84w_Bj z)~Tqe{zsTnahp^}zNBT-N1?QPCM3V?$;U?ZI+yVEo$z!5^3Pq0ILzq)eFSULirUl?a9(Np4jBg1q>S}0C<9`sC zn+$#nL&Ra)nz-L97;YLWN$ve_lh|nm?waqV)XSExy4|MbXSZ?xy)tgeMq!}UHVMY9 zImla^+eueHi(-sixOi3?{I|yrVqIo(-Rd})+@q6{j|D>KG9}jDd;-3$`VV|Zj{r5@ z4-mF|Ija5{0{i~U5giX(aH=TJThxkaTaRRFo>2_aj&1lwTLr(=2~cI$pZi?P1~1nr zP+p?XZwJKjf{l6Nq|xqT-=`9GTw98#ejFm{%o;kaw2A}XwL(C6uZOm@)ba4E>WPPM4Dc4^m^z)?$Nez(m@s79|CSjttXSu z9-`HZk5qJKENnX4gWvsmLBTefFkPsQyl_PfW+M9f#rLKo7BW zya`VWM%X12fM@Pm@`z*Zg2J{Y=$$V>dD&=g(U9klTdqrN7Jn6fz*XfE??G3QuSD=WCPtyIo2#S{J z!KYT}!jG@=yzf93CpvV)-s*S6lNJ-v{d^t`pL!Mcbp8ZZjuW@`$)THDZ}Fsi``ITV zjeX;iaKfA>h?u56I$62~^B}8#x%k1I{WKylQIr)AJ z7q8FI0!R7P?Cewx)^jSsa!X&FJ;n-#YNk@{tB;`FGK)fWuEBTp;kYJw*tsE@g~GLa zt>Wmy%eYn=1CDo)>xMN$)1k9yDQk=EtMzH&Tt9YbnMyBgW(zitELeM|DqCGC7B|$p z@&eyD#AV)b1;#st3D-;V_Uh z{I0w9(`8|8^H>)A^r2~CHGeL4g<^>S>M?^bcYGCHJKCLZ+MD3#Bg2KC2~jY3SQ8D2 z$b_K@JE(vCK-{=F3U;2pDmFgfBUIS6(Rr_UemM9gn9R+GLNhJMA6Y?@7tJOm^Z6Lu z6-2!ZtiZbU8qa%Rjrt`5rC8L!<|{oo@MSu!Srv`H?s`fOdWFCPuN~+gW6d^q#zUEz zqqw6-CzMVzCOM_0?B;z5W>@NnCastFEOto?a#L}8yczN!Gxj;OjSlQq#lY3d=$@*@ zpLPrte|JYTTw!@`uwyj^jQ=CPSvVft&-)99bCkH+q!{y54xs8aPqw8mFfhZD@3ytW zlSR9Py=PpxELREIR*dB~)gAmRd_QNoMq=Z?`AsjzphAD9&0k|-dg@(K&GR`exLQOH zkIX>7sTo)@x{)FebO>JBW*olM3|AggWZk*uEOAxtT~ zVZDO^YXq&v6!kE?ndk(j8~<^&L7!ZdCeYFeJ^6Es2S+{WDaJaMv%we>JY65bKdvvq z6Mh3JW4$G|g+7-~Ij!>Vj!Fd0EgI({=TG5$`4G&$D+Rx$=CprNs(4{UDf$*D;qvwm z^!~a#Z89H*qogV<>%0fnoxV-mN_$|`(H^iYP?4?rcnia%hNwQ^A=&pg7i%Z4;-?3G z3%>$QK)phrevGVxQw4D_{$-<(^{4>krk>@wOFv5&biEP|)Lwx3weobuRhjquhvHbT zp-A`c04_k$zeyD9^03j;oh!H966w1FXFM(d>*bBGUrvT+eCole+S_?pa3uDTyA7wE z&q4k2kvvxU2>kyw%ZsZr^z5H!cjrXj5 z{Bf?3&w5Mc*?+B(6cawV2F`u~<4(x(e{Xg1{k;|;#cDM^-rPxD>4A7)@gs6ucYw5o zlygjMyz;$9zJQ-T{n#>rH?K1%_A_UMgA73DZN zVg`BmKgDU+dJt;Wk>Qn>biTS3Hos_w`2(_eXv!V&VqPEa_AY_jjC$b%byZwFMG*&C z>QRsGw_%6YBGk0V!JhWj)YJVCJ>2ER0k;MTk#nPI+yOPd`Ee;!9#F*v{@wX$@Km-| ziACA<60nWG0WbYmlaufY?tIjTtHwPTpBwU;*D-WJwVuD6`zCfA351rNO1ODjKXgm@ zEEr}7U|Ql%UNStN+;0}*OaoV(l<7yehm2>md3h3$JC1ifpgf%k#dDQlU z(C6wH%ABf?n{4YSzf}XzCYj(VGC<4T#b{V9#}Rqw>B-^s-0y7(K6-@hhNmg`Gc ztks`j_$Rm(XoIyT2jN3fw6N^fTt4R&N;2;YX!pGz;{3r|_}RBOo;^(@^Yx>oHhpj02fT3wUj9Hl8=!Ef_C17YE#O<|QfV;(|%5QKwX!btY${ z&FXddz-%JBxXAL^doj{WYvP4rwF0MWEat#}y+~4RIPTt*KnFwT#O)^tuPT@(xTiS&5b36|p2)hX!;rfS=PV;Ht+0j#2c%UdDTA zNd1on1BbO7q^}EmAJ)KxoQqUj_W-s%N)}ViU-QTZ3(&YY3HPnc!xvxFc+K%X+{V&> zeoLMeccqA7_NsV$RXR@Y+6MC-?D%7jH)mX%E=uOKiqpJ$(q`i^Tz4ahCmg;+@0vsT z>If&?o=tQ|RtMUXA3=NFXw1lHfV&BUVa&Q@SSb66tTh{G-mc02^rILSE>hwPS_qHS6vBqjK<(i&A-xFnYJYFu&LhI8;gip~44=l2Wa z6%}dksg#7G5@|{A*Eu0VNFpmjGBYxxJ*Y@2m7*ddA(bMk*E#tlBa)Tul}#Zd`TG6| z_v3M{>v}$axFrK3$@{qpjGv~)x|x}7E(d$y`iv)(cYZE-Mc$%?N`o*y@GTSr8<;d-3%= z1*nXy0OxzA^o^He^6oY4^kp4t@?c&aHxPf+sS9C48=>c>9`M36nroLn6iT)ZrC#}(>hIBUjMGVghh`dxR$-ts45VW1b^{-gkLa-%svV>1@ZU!sa%TSfaA zf6i=QPtOhPP;qgB+mvv1RD8M!XN3=?McW7Sg$!AaSePz0HUK^f_2l4@dEl6)N7twQ z6c>;GhzF)E#@08^7}6k8SH|;N@9C*xV0t*m7rXIcr8K;AW07Q?`aefZ+dvx!1yXop zAJSXApU+8dh~KZqQ?K_iq<`g+aPrt;9H|jbTjGDwkGUgRseTt+{7?k06NmDrlBKLT zVJo~}IRq8wr-5U*6nM*yW=nN@v|X4_{q9FV#?5dX`^S!_^ps#&$|eYTcTqAvUIm&hr&+Y*u6S zdUKdru!BOr=|kqiOwsE^xp4O0Mp*Ret{~HA4u@GfkoT6Uoa!_b*RSvrhp1eEebVj1 z##~L5IxmC6@@I&(S*c{wCzFOZ7}JNVj%c|*QcRL z*FizQe${G(tibHoZIsy1Nv8e+?D-l)Axd#Lwud3?HL=EbfBW#8dxhY9=PUglAjN(~ z8eBYZ9$5SKqfs;SIq*a#t=$|?#w+x2_p4umVOTrVO|rrT4oTdY{uz@zck_?4ET}r< zbJHee9FiM_!9Q-3bK@!SxM@L)wv~u?GA8nNon^4d;vl3-PeA+ZUfd@_mP`xfaMUez zmOHJ@{vGMO<+T(kIk-UB{ZveP?T)h7Uc*hj!%#A3HSXzK4>Pv5!8F}N6!;-Ue4e7s zz7|USr7DZ2-OwWI^0#Q%o{j0}H&L)l4!IePoh_U%+*=p08ZxYLvUp7y5s@A}}L*uJDZNn6aDQATC5j+kqD z0d{@dL5DZU@R$BAWH2%e=P9MY9?a1O88_2l9yJ$PB7A&*n(jhR{sC_N~U zn>Xi4ZqC`oxw?ZfN_VOl@j47AWh!#7c!Ec3eW5w@Aat0h;lxi3xIRV~&;G2btvE+? z`S1j8-+!3Iv_!7#YYxIG6?~K%O+GHR{5tO)nYJ7eb?uLVZq6z<#~m}l{lhu1|GJ8c zk2gWa`%KX=p$cX^wV}K2%J}DgAa*pjP~pY=T6ne+*Ln3rE!ZH>Q)8%u%Q2X`Sn}w)IM!$8(Ip^9K zD~9vAb;)$4<}ez1M8e%YBkAV2V{paS4ApjCp!fM_v4?LE?t5KFb>F;slW!`0e(sI0 zPU-Q&p=P}7$!^|0(f}i#y`fdVyI@XB0KBw)Dkzyo;v?(fy!)(_TiLxew9w%Nro}{2 z@bUh5Gk*-b_uWj(tVT#CHI_UeT`R#s#|U=e`>D ze4c^hRNHIDnl2(IO=BGEYlzFjGSTkZS8|h?i~~-7p#w`3V9cR@WW3=r{mQ*4D7AIc znWURMzIzYj#!f+QdkDtN-46vvH_}(z-q`D%Ij+9<9185z+4*HP-~VdQnRC0LNr*+= z&0oa9ohQKOqdoTjump`<)9_Kq75Jbw5`zDD@|-hm6rDU3iau%Zud+13Q>l!$LabEe#Ig@dgTQzt}GX`i?0b$nqF*^ zH=n$(PT)Saqd4`y9Pw~nCnf5g0MB7=aLK4YiqlN-$mRgy#{Lsx*@kmCE-nmOY~$hON&1O?;-Z{g+`HNp@0=~B)?+=;a6^@-7Jn5w6=ZR3 ziYZS&j}oh&n(Whb6W?r4hL8`LaB@Kp?)rU~F16LeU1K+H%C+au1Dz@Vv@%CslfxO~ zT?OTTZ+)D54V1?jfkJhbTY!8v#MEkX=qgQ|H{vZ#+I~`SJEF#(QN^O#h}{qpqfdV> z#Gt9tTAcgM6`Y$tQLe2Aopj8E4N8M~AdKS{lh-uyE#uHX6VZ3-5&HRi8Vi5Y#F&ZQ zuw-}_%`yE()_wKZraccclj}*hdopDC?xq!PeQ@paS7f#|oD28wphm~3kahkKeND+g z*INtFdt3n4HJS3Qx2F7Tb3NG#Be`o`rOTg zKdFhU^ZFtUcjv}z1t{1c@U_?;kT9{3nzZU+-^}l@sX-RZ)55{%-4X5)wUZ9jJSMfp z&G579H5di@in7;+1X-4UidXpB7NzqjURI?1df-xG!00zsJf z3#ua=>42{?mf4TRzmKnx&zS%$POTFoG*eh_Rs%(+`~lnBt>ApgnD4b^QD*2fn3$Kt z`I!Y|(7p$syp_Wnm)lA0+&>r8D~8Lpo+#t?hIB{h^7yhGuy)#ln-cW#$T~YxFki@` z{9uUxG?F&n5y^PA7EcYi&%G4Jp^Q$q@OEJ;UW>j#m#+@OnPpj^Wvoqg%av)?+Zc2qW3r#p~UmJuy_(b0ZcM8i|W8vGV z1#oMYBR(C_Ddtbf?hd1c~a)twMEawMLps|4Nm?JzLqA~c(4QGwkk zz9;!fJq^xsM4Xjak#2}nmWIO7U<*9y`B)gRb`CaeAmPf%2$qbIK%ahRg}-zKU~~?R z`TDK)Sa$&acs3I*Et`S?`>)g44=M0w%mA(&5d$l%E#Ui|pJEi5fvur5+b>*?nt{Ij z_usas%&VY|jYkE$r@ELJY0ho>AHd{u9Zh*whEJ;uY3=YY6#HQhpPAVq4iLtJmt8wA{2~ry^NY50#>U^=`tJJ^sR}9jC>- zUH@`9MjaRI?a2e~Pr*q=cWb+PtN=&p!TikLn2!!}MbpdY=~XvT_V44Ad1xEHjL=2r z=+UtCpO+k1ugsTr=tGyH48K*4=fAfGaYMgnQBHnmzBaM zB^@rGvWu-=bV$_J$HSE?7MPxQ5C%+m57{=_xa3v=l^DeG#osaFg9nUv-G|`Lst1DU z(L$P;eH^Y{SV05S6F9ij0jCuIf`YswXmRQ+p@JgZJRrrRUa4?scMLt(p2y#M55iBk z6nM8%4VdQ0G9D~}j#t4@x6+>KElZ)I;S*)9UCwdqlW1{|G8j<&3I=*AQE!_BunPf< z!G|C{QxHjZo{3SDwaFz^pKMNqbA4{D zQ1UyCcNosbT?dn4-HwHDF7rR}wqqpC{icJvXS%SJ`f*+(8OEJ^enP`-6LcJU0b0jD zp_`-4vHS2DVY!DZxJ>ilR>76S=^YIi{tyORTm!GIKA>A3fNg*O2%Trw;S85sC!Ivk?&k@fmTK+k!;^kwToG&Iz} zr&~<1QTfT@X;dfsJ_D%>xz4zAzKSh7mT2x2fgZ|P%*+zE#1=PAk z7h7Mb;Gfn5w0GeYs_HotC92`D*j$RAbj9<|=$EMfR~E;->|vh)k+z!z$&eM0xzvMH??mzV@^Z)zsTB84oK7p~5oO&q!Z%`X8aVVd zY}{8SPW5^PZX3TttHw+6{IVMc=W4T!AXVq?d`oiu*FHKq+!!oB##5nFga>*{9G=juo?sX`Y|-GN!(yQs97u^wJ&8PLXg*W9OZ0KOv^rscA)syI3_j%G9Z^Cpi3>+*o zYClcg%g#41@bI>Qv?YHR5Bw4iuH6&p-u;8(GJQXk{`8L>-M6C2aTUtpi>F_mp_v|n&#rqbt6zKG6g<87|FAb+wjGzK84fcB~zJQt(+6&)(LL;X(IB zkxiPw?Z(3DOpyFw0{GaUjL+Dmz^m8rUO3T z6)mpXsDf!G4r2MCEtr(1hjY_SL3HY%w|m-XmBlf-c0h~2Z84#vDluqZ5{*UM(_yk% zxUi&`8uv&@qtyqIk5~Prwt=^WvMFu&`?w8`nwx^8Y|Pu#?$FNrc3^tNjx9Evrm~Am zIoR?p$=;OX8-9!* zH!|TZX`_Xn=M>nnV;etdC>7oeJq*&PSM#C+r%A?TIK7$O07}hY1)mRfwD-M$8y4ON znFWvN(=&JUFz64dmF2>(Qw-4mBBW}p*3Fvu0dX*E2i7;fi>zj)OucowP(U9c)K4pny$b`_r*~D zM}{p2AE)+tX|&}2A5eOu#v5;?)5ATjqMML}wd*voeQhbO>4@W1N2KUeQV%}yTu$&Hn%~7P%ZxuaTstUW314;OJOrkf= zh_%#~pfKkE53M=@tv-YK^w}i%<)T6wRjs0uYa(uVxf{^04;KaXpdQcE=)ir3T02`T zS~iNW=lVi~;R#`*_b~h&G9EL!jnKkiJ)0O0WRvI|8l8{`S(XBS-FJ~X6P4YgdYq!w zw3!w9ZYM#zk_!4KN=|)=XVVZ>{7^Rpr)94~qi>UVuw)x3m+Yl?J!^z!=t)V#x@lE{ zGp<}dswO5(g`dwI@y|)NVRy5Xpei$$4$A3p&RRKa&Kk;@vpfW65c0MP+%Ln&z zH}tC*iu?br5y~(d1nCmEAxWc!pBI8<_(YEF^dvd6^TOMxboi$41k=LOsoKRFD}BQ$ zw^_oUhG)Zxwfoph!4xMJ=hOt2D`D%MKZ40GE8gv=fEzbWfRdnKW;07n4!ua>H9Gh? zP>ViG#)+{jufX&F`thhJMLM5!oX@%Ks_j^8Pw$^c;oM!;mZUZ{H2AEAP=( z)m?55Z6D!=N}0I7I|u4)s`2j632=7nMR>I&fJa}qXPHs`d4jtldy)r8m*xqhM@wP$ z(=c?sSs$Dr96gXL?su<>`M3wmFu^4d!<_e!LxmRtDCl!@4NDG<94zJywn z<5YFWo65>2@b!B(EYso2h9{+I$-@0u(mw{Hui5dsz42@x{8b3+5dy0XbfDedo4uDG z0o511*{=8w_wicACI7jBnXL`BXlSF}V}Q`}YjAx;x|k3?S5mJHn0RlE$n#_A`syRJ zyFLR}^t}$<@636+ZKCKnW*B-LeFq(d_Wbzn5$YLhSFDpn<%3Rk+4u@n-!|w}&pfXR2FP9#JW405x)jUraRJdLk92N*#C4P7?@5GPz*E}g4><835!(}`TSQ;$}5?J+ox&r?UG#_ zeI<{>pM~(PwCB)oWf<08@WqxCKU6-QD13@KDl~_f;pJ=Z#Bu*k=c}DPIPKar+Uni} zans}7937uQh42G1jok#_s5l<4a0UFYeXbP;B|`3z3Q~D?R;a%afMZ-Y!sInsxG7VY zrG8B2qag!?k2f@+fBHCFsI!eE213`?z2%FQcXqS6=o_mYzM|&M^hEF=*;TA#==2XiMEe z8K>7mt$QzW^ReJbq(BWjE>X+C-QX}u8jqUk@ay_jLSvz}xcc!x9Ce^hn3d%DkIAc` zf3-dKUwKtrP&FJXfy!jUrn&LQJ9=g9WL78o>6g;RJJtrM;d8UpVOwI7y zC{rG%wTYZ}xuRh|bw0c*krj28qub!w*!;%{XZgIPu;Rnw5Ze-%@m8H@`AFC_;Hy|G zGaE%7Nz2k?Bxi#TQT{JERMROJ>hv4QFJcV6F7!py-utP`YzNu?QRbjW*WdtvPbj@c>8BJ)TjK$2T-=jZSoMM1eZ1lJ$rtcTx(19tjKryr-PwNN z6Vas6N*L<#7lvFoCEhkOWY=-q!B*`Y=WpH#-qx)Y|6(kTnh;OL24=t>9U%OP5bTl_ zA*iH<Udyje1lpJ_+@ZZip2*8U?*5LU(8=BT6Vx@aJTb!}y9ThjkxfS;K^FsyPx!w~W zEFXv?yWAndMxJ9&`$AY{I;vQ0LcI|+wCPG5&u~^?wfH!AdMt*D?C;U7HXC+VTE@e+ zhVx{ufxGIXFvl_g&#k))%Hv${aM^oNr}Qn9nk~gSm;2yo_n+di!>1`^x*AWNX+UwC zzfg~2C5V0*XsFXMkyB&!NtryVKSZXXwf9mYu)@kWp$i})$R=uBt4`MZf~ zzVw2K4h1y(dKk)Deu+y>1TKCujlBCE;Q2Y3FkT!AhpSg(-p=zd?5P}_nqCVrzjK88 zMKeMCFo4%cPE%`wJXUwf;Kk-;)IU{|pFQh`jh7E%pSexgsW=zYS6HyFydPh_>&tmf z-SlFdDa+iS1u3K7@QZ>tUTc&KS|fgdtL``q@xCWa(agtdde0yr z7r@5ePI$3ef%7~x;AHQYuxs;LHcVJa^(W$Z#g=`1ch(%TdF751y;>pi?{>F)b86tY zuZrq~J`6>M7xdOMox+EN5qm9>{cEI7% zJ#hL}F)X-r6mK4SO7i8OXkh;(wEXlED*W&R;$ALh*B*-ay+xHS66R7?l@6_K(fhQ_M>GXzaAej-#({+={=2Sg}%}s`ewu{1R?}6}s;wn^EtO4^G zhv4MZ1WuE+2Geb;S+_A7>P?Fzlm2bnD7SDdO^g+{`6#01CV#x0iI7#Af|f48_V<&> zGGGe-+21IZt`C4kH#9iK+8KAR(4bj9hcG@#9h{{aAnm6+cZ9oeUTiCs84cn2sV=;@ zk2Dl0Yw_=Xmtpyw7&_KtPwh3>0gpEHBBNg-)ZmyJvxoDsZs2g=n&HHw?Hk12;>t zkS$+IJxlem?+t*1MnCA4kuH0EyeMQ!r3-zvc9X%9Gt^&UJWSd)g0l`xp{H^26mqu^ zHgtAD)<9!0FC2yYl&;dTQyM~W_;o&~6vp}XrhG!!1s!frKyg~I*y~I*CVYJd#?!h$ z+DIQi4%6gw!a^}IdkkNFwis?VJ5j%2Pa5?9zwSn@5c^Gzvl>lsd$Ttma^49x5x<3R z0R!-+l{G|Z4&?6mi|}4|9rn-b$*w)M;Ke^a4LWH~S9S8qu-{OSGy4QX^|uNTmkz-W z7X0?)FNxEiBQ!j)2F_I4iV~Y0VsG;gkm~J9{NyG`J+7lM;Sn?;@HCld#0ha8maz4^ zG+9Q-qx7V|!guo)81yNg&%Zx{R@b$uE$T8T_KsmGDK+x)9D=*HJr*9D2C>xGI1JA! zrbBOfi{pmNajdl(jyg`ut^YBlIsE z&5xUsK;L2ms`t>wyP-fuzDn%Xc%E|mE~0U*siZPjlXYsZz+4SGp)R(H-fyx1Yw0V3 z{U%4+J-52XV|p9-EN-YhIp(#v&DEY)H>T52z03HqyR`r9px{or(l{Jekfz z3d{bJrtLBnJmvm9a_H7{n;F^#CSOB^9$)go>`DMGHJpo8c9C4M65qnCO!!R$*eyzkr$VQPz6L%RxG1zFy>Rv!nv*P+=O5s+Ln8`g)1(6aak!nK>f zaSmVLo-^OkNr>l5!{*|zA!^uEJB}-ZHDSh$t={k1ydq~}jR`J_U4`KfAG+HYE0De9E0qt@O>(i>C>(3%ojD1H5g91@WzbA+3 zot13PAH$KcNRA!KDE-JroI7qZwhPD6$$GQ!!L^%Cy;0;rw?Bb=%0tm)U~gV= zn)B!7O?2qS2ArI8LQrq%gX_YL*=~*;Dm(v229w9}=p(Oa*JKfWn;OKX1}W74ZpOpo zO`+aVU(|&R^7*AnbBz8&x1{TY4dKFj+f_W*N`~$om4m9;EtCkFcwty1#S{i}aF7mm zUYk$qvbQCrs=fGg;t+~z7>Ry+Z-^5Yo&v41hb())4ehsf3lFF4ML}~S>q?8_`pO8p z*Co&Ox~YStLjDGEt;7p$x5SY4&}@>c@5j9sWzo5TBmZqoH>i|7m$=W?;5x$+c)sl- zRKJ`<<7~cC;s{F|8|^`sGvnax_Fm-C`?hf5?nI~?XT;e~Zm{o$1Mdk|!w!wla9K~l zlQNDp{p^16L|U!5FuD(Ce!N1*%;Koje>H_l)V%mr&;9iCv8v?nY#j{MdO-4jAA^sDIy^BRgpE6T za>~ACu=4z9j!U^xTe2d)_SnQ+T76O-EfzhNoQ(Yl1HWz+H`_+AiiM~6a(fs>^zV%$ zO+L}~u_+MoUJWzP^#XZGK8_vnn{PB`Q`3tctUYiyDu3#NC|OJXBCm?-ksEPk_x@V@ z3#O#|t(g?P*9s0YyXb7na`w}>DZH(0gOhVMF@D=D>~1(Mj*j!eb;(j(u_7DxRqTNj z>j#2*r7NhI9fDVb7D=3qj&jWCUa)_O7KLT?#l?;!R#aq541UFf>kc!NYStFU*zD#{ zo`#f6J?Yiy2-rTOlHNTuhT@BExTG);b;HlW?$T_IcqlKNoNj?L4(!GYo?&d*=+3@5(cFD(t z!=vs(ZTN3t$wFm((ftC(9nm6#@}<1?$6V1RHJnbJ@x<0pXPS{&0v2WWK{?0-6Z(#2 zivc6WYa_$atonygm2;XT#_DWZ^a%pnXMnS1GYubwnTzvTFLo+h>cEAbd=irIlW?{g#O>|+VJ!+;rhC2>b{JyAweU3!XGu=2Ga6Sqm z#%>f_D<*(h#AfVpPez@Idodw8jvn2ZNUd>SDWGT??!P>bQ>>P;$BGlQuW&Cu8$B2X z?heLh-iBNi-zt=gcD4VV>c`&O?P&L-7`}PFA5|q^qeq|p+2ZvL(2(i{D{u5icLOK! z(D+0M%T0yCl=;{=W#zw4?hw19jM;0!et786k6L_ol9A_7+-iIca-1btGC&TT`yRrZ zZ_HVDi5yE5rt*j#HpD8$LV4C0zP7*w)Gzhnrykd!*|7(yEM1KdyN71mToQl`Ix}Z|4#PKMW{wV2y*1 z;BiYYe&0t9N?Z#-ZPZsPOFs_#U7ypo9sTk3_&?O<8e8MF|00bTE(I8M4Z!*oy)>vs zr#+s0*mE~(t`=B!{8!1UEnckt&5B!%N8m)4>td<#5pj)Q9WLIgfy)+r5$34Q<&|UR zfs6cZ;fUvO4mmc0??mp#oaWKIfz{YP$e*`Xdj7ksiEdZ250h_95fxfqhS1O>H1M+z z&UiHk-+IYo+{(pbe8Y8`K4B!;nvCQ2lqWQIRtmR;UV%^;&Oz&Kp-Upm-Dgz5(0no) zf1W4)>Ci#ZT^SRbr0UGJAA}mqAzYv%;Fh1UU{K@_t(iOV?bK(Kx$(T@hjuPs)A%Ly zsh9`xtDi%*{}Zw4=|@t(YmFPD(}bPcJ#gzfB9||}DP3QKJsXW-MPUJq%6KAJ9vK7S zdvjrZ(>Pvjwixe3yns<}b+9Jho{R1brm6c+fa0>xv|!k32sDf4m{rwOruP%hA6S45 z@zroGeKrgl`Wm_o-vj+v#CH`&@RV&k`B8f>PTD;Hv!l+!70W&-)Ov!ibU*z2I!@G| z5rI#S*Ft*LJpSxt&F`1B(+H!1xF|`Leb3$kb^kkXF>4!c=rauZI$p)S30KIgC=47v zP2wFhjQM?VG^Nh&&%dqi^7F`KI3;Dl>9`85byTq?pirC|8-`c6^yT*+U0~!~!=;|{ z$!44nOUVV{rCssjp+_gkf2#?82}^>B3nNf}%O26+>m$ji4#QU+LGawc2qs@iAj{i- z>G66qq0K#xPX6-1<)22NRQ*ssmEuehpT3f2oi%{DCX?J4NJzT|R*xLGUC{|Y`_*IL zoC8p0Iha2_(4~$BThQ#=Emm5_@Eu-;M_p!M(VhTY6>&&(_gKNzBhFFjeiIf|^Mr9W z9z1+g7o9jv7(87DJ5-IydUt=GkR!#Xf;}Wa?~S$PUovE48(7>-0>h zS}MSzmQ+48<0bVy`%4r;$6+s*P6)n|A}JK>VcWf6oS-@a4~$W(U8eqw9_5~<&2}rG z|7}_R@gj|C0)xorpEA?(yW^ z=Q~)tyrUPRVxdfuM~Xdm)SA8nSSJ*c|A;4)d{YX~w-nM7@2g_L;qNrvFbAT>|Ab1N znbhz-O30e=4IGvP3p%go;K~6`th+G*`h~ru=jN%f^T=l!YNW{@EiS@OvrFu0x`)Lo zJ9t~T2+|5HFnf75Emv5BZ`J?8wGwBz(w;%FbIn*P`n?dB`J1BFRKu9pQ|Zd6-l%7+ ziPMT_asU1ANF`zqk6Lvb-V93;MsY(ARWTQai`;J)KMV1}kF577%kNl`HU zerSO~o_omDV=~H(_)bF>FJRX`o#OY^e`!m`E7ZGW!ov;kiNZfju!sBbZm%ZVZHnUb z`X7Sr>U}hLUmncarp(Soqi}LkyO`GN0MxCHBbzsmME%dVg`X+rtgPXR8#_N!Mo2my zTA;{l8%&_xHGv;~^`|rI`r*q(L;2YZDL(Z56ial!llkz&@VspS?s@o5(l@8PRv7*s z&R?Ac%5stTRc#+<^Z;Jm_KV_8*5S+UvAA&Wa=zW$PV%|snJCF04AxzFnDwuYT<1L( zelK6iC5t*GT2qp!WSc;O(-q;vbUl9cF%pv_axrm*3wAwdr7;=v#KB&&G{4!F=Om3~ zw@HUa7o0nV$Cu}m?Ja3Mp%%cKY;@r9V@uZeli_|Bdc${d2OhTy67>!laObn3+;fl= z2mf~;B8po`q3Ar=4vz%?ylV2QSdK03#$5P(9XK=`q^uMdI5H~?{_J(+t_hFf)}NCs z9dM7)(*suO%oTruzADy+(T3981XLiPL`w0+WOVb1t-G}&H*7c9=Ac>5fflWa%&hf~CB z;X_!(PD8x+?XyrdED>x2AA*bCrCN8tzF4)SSKTI?C|or%krZa^MCq=x6lrrEPA912 zxq%YiKJ_G3xr%&aeO1j=(~ax}(_qHV0ld@aEm)T&;N2;e;83E5ookiQ^5b;)+qsYT zo|{7^gY~icxeTh5%%HwKW^mj)RrKvYj~~%zFn)f5`}OXJBX10#@upR<_;(%*^>HHO zMI&+j%29lIyc{PbD?`}PzJlfMp7`EWN|=^03avjD!H?)Tm%^6zQ*#g|Jik zsFC1Id;U8MUF!o_dx0FTSiP45pZ!NIn`c2~@Ktg0pk3^l;LYh8ie%*W6ppCI!IPgC zBm{wQ_JSd=j^5Dv=}!iqibfltlBTft3&)0mO$F&4Pg`e>^p{@TRp&;rog#|a@%axt*EYgmy|B+`||9Vojtb=PSHnP*jaIP^rgBn|p z62PmzC)iZrb)3y!%b|hOJ_H6JYW7fm=Am_13EjJ;&aAu(WB}3 z;Jqd0+&Yhk3O#v;`7|zD7EUjvTgCb%v#}sOnsr`%g|My1gz2H_Xz*SZ{a#9VvLJA3 zswN+rlLkHgXHwzYQDAZWDBPBQPZGyC_P^wdNjv{>i(`X0eUv&UOXk4(+5|LOrA*nz z6L@09Xx?$SfIl7Vjf?;MyY*wsG3wD2JfbmOG?_mcDho%rcjT0?ID0&4h9t1#mpbxa z-~r&YolhK(#N3`XLi6xQUSnHc>(G!+qk2}t)}@M&=&=}*e)qtEPs=F(`$!mQ8iU^y zdvcCL8Xr&}!y8u*Lz8JE@oKdquhBRnM84~bn`0uOI=P%v{9i&}S%HfWToB&>kS4V& z*I|0E!?@71jKroh?9+LYr2UN0!YUrK7kkhb_aQX1)e?Q=tufvpmS##GlUaK*Iwn?7 zNKi3^?f@P>Bm|_*ZOJ(2E$N4~ia)aB1@)#KxYsur9yfdxW*v#9>8p2A_N0qKT7nzD zvzCQE-%`Q2j~XtYk;Cl)!(h=#4~lIXj5bS8(~(knw%k(=rnh3@%0FLg(aK`KKnYa- zU4Z3V4?~+rJ$~-b%r=Bq@j#OuDz4hGf5yoTY6mvy_ zGj>=>W1u(=XU*tOd(ONByLlx*PnGz=R%KQWtg1EC$;H<)TClzK6Zj|YCANJDuCae8 zrfv(@wkWZ4i5{Q%A}5H?hvC>k4zONxE)CT{X#G(MwtHIzLyb*5K--09J0$$uyJJ+O zWsd{2EeAQnv^8Vg9a#J*sFhDGxUh)vf?xy8m>-jdS&5+pp`V|@g+Et zVZ#>&TO)57EmXW7$qt`J@WfUtdg*1$m5x6|IqhUvcz!BwyrPG5pSVgadgQ~#x=p+t z;`ms>9M*4ig{0-ap!sJ#9?|>?V^5i5x$$|LlCFz&t8a0HVI$1*&Vvn(R_JsifSRlP z*>~+CoLc4tcecbycIy{%bWH@sOo;}E)D#SGa}i#mCb9E5*y|{b=fk7%L|+AlCx`f4 z@i*#cS_G3*yzud|6Lh%hET|po2f9zUaPQNJ{3Ti+yI-CIn}d7c&JPEUA6yQ_+XtfS z_!01CwmZ&v>B3I=&D=0Ull@;iL3rY3)mkIYV3^!g&iw0rQalFv|^+elK+ zc0zp4C0aM;5ZqV!4NeA;)VX6L9^SE!RdQ94O3Uekr!9W|Aj7LndM1^8>?V184thW9**1pnI+G@@b#%zd_n=k0hSsQi${uK|_9 zja4$D++CvM5BF35i!W*38w=VpVkaqmwxCbVn^E!hGST-|5)3kz;dE0+&_&$do^gSzd zjtfEeAtoGCBS-gc2Jk^kA6S*J0EW#rqwq*+{9t&WUdz_-&yVG-ex!=~F4}=p)D7{| zLrvUZLPEb@!!cZA7;aqZfKp3l!yV-c>euecRzGgj0rS0}_3E}jD=*hZSg!@Cjehvc zG6?lYT4MXAL`kK$9|f#EL&nF#c~nx}OedFoGRi?cr*~ zXV|vdUb5RW3_suM65Qkt;@k0aIMCLZ^$w}?J-4M`wC@S@A3KU2CwSoaExG(U>k|F1 zAb5d=IsgLzeo6Ak5;sa+q${M<+Rmd8|L?2jDm#`(-O_fIwS_uuW*QmFa&HXEVf0ZN`#$3!Qiwh6ctAg(zaazD4xy* zE1f+{%ES58F%wvoy#hEO!5ZUoR?W`}fvIxHwNX-CXA_?NV$HAZr2Hpc!CBYl=tz+X zekcp5*w+^y_V4G$<31=0yH3OAYOvKhvQ3Kw%pWYED-ltfpn`##5jI*{DSyC=eWhBo z^cEQ>Ma3W;{5fJ~s9v1N<#{h0JB4-FrR58v~+u66uAOxt)J_aZySta2*^(hFrs~ zgW6QG+|%h1#HfBLN+M&_(lE1Ec|wY=S#;7H6g`_p&EGL4uV?_4|I1q)Ciqp~u!4)* z!?TYOjcdi5Qy3Cj*;evKiE~d!IO}&wNXsZ4zJ(mE<5qmMA@Bceg+%$|-ReM6mg(4- zS|8R1JOOpgz495FxLugHY>04!6C;!=g?ZPaDWlo|1v5^#k#>O`kN^D_>`%A*sy><* z8JOYY9m3F4XFnUGqV@&`O~o>Wo(J?7xbeWin-oL3bKTo8f6a;V2YgkcAhig<{}lQE zAkcsC`Iw6rcNZFFYF*iRNGFzDSy4bzL`YdqQG-BKQ9wq7KuJUy0OCI%^Jo1J0r;P1 zry!*Nrj~8s{u_V)FD2R7W8d$4nFm$%G^ZB$fSdC_e7OIE{{Z2?$RotS_BXBVL^NXQ z5m_q6FF`qV0wr+)d6ECOCqRIJkpF1}{2%-uxa0fZP8$E`y?Yk2nXRinKhS~t8vtE0 zP#XJxD%k$NhW{lMfsmr6_s!UP5-*Mf3qW?EPg+1mP*_0e|CIT^ivQnb8tLon|6>XQ z0QkR33hMojynj6YTgf(0wq@UY$DOdan5cZYLVS5SB?)B-Iobb1ATZ$n3i{vQ_1`S` zWBLF8O8yUP002nr|Dlv+#pM5s{;v*${%_@fkS#*szo}i_{|4)Sch`Sc6d@rYf-$8^ zlMRx8m^)Or(vnjT<5f6 zM@hw4WPo87sLPl%UTd8=FkN?mTLqb~LyNnDnGnd;-0^!7=;=osuD?q`gee4GC^Ta!WGQ7SFn z*#p9cu<+azN2@a)WP_nCN88G&e-ZC8pe+G1Og~?3*Mw=BG)z^Ss?y>GY!UNN2oVuH z!w8C4o)4m8q@YED=1pg)Dp4IQweieG%(do^?aSF~Ck)(jE=(%nla|6>sWk|!8CoXHt3y89nswva;eEpq^$cu~@hgZ{dUFIrns1=8>_lanyMR);1 zm$$9uE{7F{$Qk!c#<3U_oTipL1tyT@WvD~401XuJil^BKl4vu^he)6(Qhp4(3m~EKh*;^$0eq8iT&WxF~NpJ^p-+N zYUxF!FT!lg>JTTh#P%$8>Q{&C# zc#9&2!-UodF+yJdXaNd<^(a+96>CU)D*13e4EdO*6pn_W%c_hSE*y`Rh+dGh_7-ZP zX=JyWp#mQ_Z2=_$q)XPjJGnn6aOwc3l%}J6VCY@YBFnlddsO%72 zZ7dO!`|hhj#2s+#0|`{+w+o0sIuuep64StFfVPD^#>jZ=u2Gr2=CnV@7D#qVE#H43 zxTW5XPK=oW1cCn^(a_IuSiNfh4Nh@9XwAINz%uUkxO~A!9@-X8k;2!MwoHH1Ebi-S zdg_xb&|o5Uk@Jdc&RBRmRrnGCulp=Kdmwk;hf}ZsaD- z1IDwfKaGaX>aX7@SqfI)h}RoT4tyhjz>}AdR(O~V5lF+S+FPBb#tdo9I?SYu2y-PO z={kO=F7#NS+1RR#k}1A)^!8dD;6=*}w_{$Y#ow-~fQ}cHK@)T}5X?+hJjf9eNb3iB zVM*X$VGaItqk-IliR`$oq>;5!p`alr`wfCq^p;jT*GcZcX66c=$E-Fzo)rwlF#p_2 z;(U{^oMJ(s>PjgP;Ka??1}!pZsmM9b>$BXDG`|@}c}+~68QmDu#tlK>2=6I9UBr>v z5A&YvDI-hGqaW5kmXs|JW}WOCtQeOfKkF7`PpGSZZ{h~J`n#uqy7MxEpsa2HCvEFQ z^*CRkw`$-QP%NU-K3CnPnYgsiS0F;#M^8Cz6OeMlr(7C{r8QJJX&=id)W~$iIF9%Y ziTUL8ZRP%iu0Y^VK+>;nfj0wRM>YT)i~hYsSyu-wooznB4uMbLZ+FGle_Jfr`AZ3b z3HQ&hr=_VLYN^J&TDjuJZEgHBe{p2I#NDU$=*Ed={ji5NAZp+8a~h6o{PMz|?tNW1 z0yO#=FH%gRc$z}wo^=19d>5hV_Y(9SpW<2i%4@3w5&*=9*%OXuW6#g)judo@K;hZxutz3?vB@luL05Z~L4 z;bGR&*BIeYb=ThDk&gg-uHhM@oxE-A${qP7Kp;t~F{bThdN83kDvvQB!LeK_xoTy% zRr;?TnX)HYX(&1}LOeUT+?UohxJd)#L+6gCtnvwIeJR(WuzqUep6F*f1t=MO%0X0q zT-n&005B|5;`m&`H>yh@Qn&n4)h@en)vVSdcBIIkza!ccXYT9bGkD1DkO~g5m1Hr) zvM*fV38h}^Q&U#unw8Y>LyB&(T0=jE);~;!^!mx_#6i06woWqR-@~`YEh46hYEVv~ z4|bCvSAMe&o$cN^;V)_~wzAp2ct9oU&Z1ZSL%wxFCsEzPR^xCMhX%BO$z@~i)NrKgy-Z|!3Bt!hd1bz zPR*StJkO^_{Lz2Fi%;H3z>k)r$eT1@HIvxHqj9q><4h;ds1C+Q6e!nv1-JJx6f!bQ zfk?(PZMiT*gv;*|dptH`_kc=$UnrU)b#aIzT zP-m2F)tX!gIpX)v<0C>b^}b_73?l&tKk3*07Xu@GiwWmPck2*TqlY1WkDqEu!Oty0?xKXr-sM}tr z*IXL}asFIUXwxbF<3e0ZG)Q(=eCdjizw=8o4-Q;_U=|^Ia(nc4SXlnOW5$0?$3G!D z8fkiG?|l|5jbxe681LVqwly?UIyHam7QVJ&Q(Lfs{jU}9?WRv;Gol$MlpYlZ>jRmR zoA*z6vmfkPf8;+R@t^UtK*de3P4`*jr_V56-UB=-XM8*g1DeOIvXvsmR!Tj5E{2#M z`k@%H7jIf9i3{8kOeUSUmQ=MtCx2%14v>g2-e-- zPl67TJQpvsS*)pLTuC9mUe2oRy7J_bZ)}l{H)KA#xWD*h#}Pgcwita`5N<|G6{JIJ zEoKlL`Afl3#bx25q3Sq>_2jjfP5eI5!QVXB!)XNoq!!O!Cs&oR#TXKU6}qCQuctD7 zNnNv156K^P)UGNoi{?D_70!%H9%Yhe&YP9_r~6>WQ?DWQH4r=ju`R7OI(I&cpvoZ7 zVs}`Vtm5|{5A%FWjrIn~5(+FUo>I?2-y$?AH$Nbhwx8WXUyZ9e$y#v8>&LWwqtR0w zU$tw9qh6xj4P>=ZxmqCJz6bYGO0_1whScsT;*3R^`xa#De=Vtr<#Kieoz5cr9p!$4 zwhKf?uiUB7t|V%QG?&{~+=m|Z)0WGPNI?#$zoX?kj2lA-)WSIXsMKJcubhK*xuCx+ zw{QQFCyqghw({ZHQhDDBD5hq>CoEp5qz_e;@N2_rzy5J`X$OlNJ3h~oV+Jfp8X7z* z)FpFA5Bn-?SFG#GQ^(vDktmZPrCqT@q^`P9V{3!HP*?6Y+<`A18_<+S@%_tf4MBW0 zwv_TgTNs#Hq8NwaH1z10snO$SZ5=E4PJ*LsFfncd9!Bd9^tb`z6MA{#HwKO9gNWwS!zb%>!w&ZKcDhB?$dr$9+TGSV{m7hs zeXN8d@TowfLs`3~koGC_BBi`5Y4b=ibw*d{)qh@SnPJ*Sbe$QK*}z}oy}EjS?)a9c zB!3a6mP$X2LKkvOaa+Wr@m1bin(Y+#S*qUrDk=o8SwkPG1BE4y*Hzvrmr*NB1n7mi zK*59T%vzQG@1TCXuC`aHmDXcGbtp7_^JW%xSpEp1rMfhh*-Z+n8|sq0-T<44#`xH{ zr3_JbPVUEwFlzij*BTNGE3G~bSmpI?0(kb=G`c)3Le>tHjFw(kd0 zI1jWaUV>cSF?CaePzkkp_|7y9{5OMWZ1F&`HHFpf`-;DMp&O9Z8`oa6LdVIVPw37^ zSU7?xlqBbM{g=Z1S-(|eIG9_``rqi>IM9KVH=q&R6!}-)`pZ&}bu$*IgrqFg^sMZg z)scGLUo{RIvX}S?Z-An4Qbfb+@U8t!X9z9g#Ss>mqnkJOPmK+$1(ZbBginaL%;f&FDEQ z$bGr^vEW>u5$Ck&XPWHKV7^u`%+IyiRjVkPAOk~-jqrtL z>*6q?L>_xN%4wwD#nDWc$r){@fq9<^e{Fze3d^LtFK}~MR);gA{QIP0HYumbIroSy zOEe%WAuftd7%sr9+sFQ%;)60d%X^hx+X9U64d8LG4sg9hu3ub!mY*HE18U^ZS?%=%uy9vOh_k~SO>UQ`<2NYr$U>jbo?y>oo#IjYoUsM zd|q+KfjIveEpjD;nH*QV2@za}g$pOH<#B}YkY(9a^;_vHL!nmu_H?%XEr!rhk?&D1#(;x+Gu+A?)TT<}?#qU{P=9OR66ch8=VU zwQ*)(%xpdbNISqFP#0*5JTLs=Q=k2Y*)k~u!xpnLq_dYEL}>v zz@WiH5-Em8Jwl^JohwB@>{}NL`Sqcc;7`>qd~_wskrWZGSy{eiF-R<>x>Sz*?yGxW zyWMBcsZ_|PT~#GA5_v6PGUiszI224&Wa7h_hh1#$D9$L@+*UYNC%KJ55sqXtlm@?# zwh$yxmg%5?hByY{Rpr>{x&bZ>AhhCQe(H$=iHf1XO_Y;u^~Tel-BEHL#Ay@w3z4Mq2`FTWE7XFNV;lu{t)-Pq&Xld zP?>!pce}C}sqE@X-xhpT-XB!rjtd=B+(WZvD3=(kmOqiPMFI9WysFnoN5bt{d324j z8W-zE1U2omNhnK(nCR8Bs&(~4W(y7uOxZ<@%>ma8G5*|(q{a1oD(y1!KF5;XoMXF` zPf-=P3FE5uvCT~>_|r!WnvI5WTdrku9oi()V`YEPIqyp>Kmg#*^1zQ`qC+@-I%jxg zX;cvKpio;$N41AH z{~@Ec1xb4?K6j*-pO@>S7!4IlepR34@OH3{h*$P7h1>H~GbfrMWRkXJT{Ys`IHd)j z`@-Is_7{f_G}t6nuqiEf+A%DnvsCmrvmGCdhzOUeH&$H~18c4<1!cCP`AwWZ!E3!E z+tg+Wdhc?eQ%M%1Sp06#F-Ubn25RVSE%Yb{?Z+(sG&^)N$-}$uoQo*qw3FgdJ-;^0 zDfo>#5$Ium2!>zNVst4CQI{aD;W;P5)+39@Im#=Or%{8G#@{9F9o=V;l5|enT8FXF z^L|y@fw}EX;@G9jOHBMAX0(cRM1aC7?`C+*?MtF7m0Acg!5q&CvcPxp{5bM5U6~Wu zVwzO4{ zudyGyFP6*z_bqMXJ@}T}0WJ1lvK(fL1v=S3E6V)X0r z&3O$a7b;{-d0Z_moY4`=Fho*)cK2LD1o?c$1zrFxb5nHf8t;bg@0Nl?y zUB-pI00%ptVr6k@hv@=@L;tzK#LDf2`e|>*R+nJWngYDbV<_O zHR2~G00i>M;&uE~jlP}Hf00A2wQI@HIw&WahvuGotuVe;K29tcU*YDKS}U+kxU*vjM13KNJvD z4R#TAsd6&Q^RphkCqd2Gks4xOJj*e;mOhA77^MS@LT{gx!f32e@({YLPs=R0GyF<; zEQthS%0wL<)+JniMPiyR>@tcDy)z5hKnTXPkO6crjTV_7X*jQ`oH|rhar6>O!I=`! z*LaEcn8K60JI*hWoQkt7FCV**Uyt?K9PF#sfL;Z-lLf4SU&UcK4AcdPyKIw?R$R=S zyBCqqFRGj-K}gl_DPoLN3^utjwy`juMf`HJee3V;7@LIWGtd)KVs^*FRoML)i0+Xs zp}|>Kw6+h1x|hA3)QVf)m7rlEw(gsr?$|fhjvrPcUCdIz%}N46h49E7as52(LmPAPZ-xr)3o zBx`Y(gknpbULZ)0U3Mv^bOa&{QLs_|cHU_1)EL9iNLF_ifyhnkHLDkwvv8e%YBrHX zQVvwNrt1wb>SB9k!YP};6b;xJ{PFEIM?yd*JN z4$rwx0H5zt?QcB_D0?lX=@eQjD~yTQAd0L!idNC5)vfEscw*IEA9<3Jb@r-TlzwYO zBGLARTYrbNjTJ;makhrbpn*L;pE$;A()o9Z8%sJ2j&M9uO?IzB2_h=0~TM+kb}&w$w_ zT(OM938^PY#c;p#G?d=t3A?3*fcnQIvT=wYWZ_-9`d=RG=S6=aw+-T8TqfpZu+ibe z)}De&sGOJu%k1K3krSL{VULUz1I|EUp^{bpeO$1#R42+Q?h^-(EyKKXc!Qb!Q#gZL zm?kN2H8mRUOL`ILj@MjK-Hg&_+buDG^Gg5A%OU z#4dh4Ha7It@bgiuoQA;DB8wHGlw^xgU_gdzPMSUPZWqAvWWR>Xcw@-6^&i`D?3#?D zqCb+~7%viR1%FF>P<7W}o7w=owOTAI(|(7U^!C(-U4@Bh#UH2Hz59q(_1lNxc%dWA z=*c=~HqVI6flID(Gju=U%?m;JH^eUWWSft?WUE@tUihpi!Nvj2eZRYY}}7^#buKGBp07LB5i!2+zVXlpd# zN(dn6#gG{4GW^NySwN+RUCOaKIa>F4Brvyv^EQ{E697>~vZ>>kHk-`wJ#5jf2vPVk(Tnkv9q!ZSq2lf;=lf&_^FwN4uJ067^=7RFFs-?(K=^CRSAQO@ zXh=x~8(iCo?}+@wf+_=Ewm+^<+!A=(Y_5jCtb~^0?DLvoLjvb7wSEQQaxIH3;-_*} z8}-{LLyqQfV(#@uY4K9y61v5L57*Bq#VZeJ;=i{sJBqex&7ecu+=^ARrEaP zwiF33p(*jHq1DTwT+BTDIgBjmlSD2<1+2~-KXV`?lwmqc{wKcwOdS~_-`mo({SsXL z2IxQ^*7(p_~Z2(oq9KE?-KhU znjh}PrL3}PVGM7oQEn&9d=Kr#7Da@8Uwy{2+j(Y!lbDCpsI1Bu4mfp(Q?D)Q%`aid z-%qgb^JE7PHv`j`jzf`7VTK|7pfgos zWeo4RMZE=8gV~QvcobY$)=Vs2xAr>W3o0Tq{T9`M5jyK(ef*t}eb3u&_v z2eg4w7+XsJqlo9u+Mm^)n$B!}xhBU$0T~+#I}SmG4WWdnv_-(7MdP+qsGB+|)#ODA zhmHe0Y0qqVvKt$AqM`wZ)H`e;xKGk=1oYI7xpw%IsUz@fF``g#(uUo6g+qnF>vgCQ zGbVw!g@5iz*Q|+SibcKY%wU_9qessGicu2kWDKYQi>)l*Gc+YhjILP@r>oVFw!#Dt zp{711;m_omOV8(FW7CuU1+VTC5iK_k?>=Saf7x2YLHr|LR8UDZe?({ph61+*&0|s^ zzkag{|6pV2SjxtnY+W!}+uKljdk2m3GH|FadlVh!gw3I>pVp5>xGrejjK>W2bUIFu zgu-}!hLal`N3UkI$QkSYpiG8;nFJg5coLmv?{dETyB%+9UCU+ z(KMKaIuM=3PsU7#`QOkx`^@LyeyS0%L=X!;Ztq760ao6(tQQ}-} zzTVXyc^tOKvS_754*1PCs>%VdZmDPSD<*?S|D_VnSFz<)_S`xO(O7Wnb3L~-9h}zt zfz|M;MGgLRXEBI>I3-Y9oBdP579WN74X2`m9o#rnN*3;~#hD^%mnhjvAx(eJIeI_7 zCpb)@D+0GPg1E#%T-D3BFiWx(rQ1BUQ*cGUpJc1ckWq=KtZA7;YNjCVoB8R`1(O0V zJQY(a!qXAR2Jqm^oIB($cJTyrY@p}HOfOAkjd{WE19`FpZur*&K7*nF=wov#>3w+J zP(W~Jk5EXwT1~JM+q9Y><}Yfk&hFd7Ro098aMk)j!AonvlnkC8%Pg*3lO^)KA}@_K zWfLzit-uy<$x}%vLg0jul#DM5;-?p=ji7J1$f$O{|1f%xn38sD2u@HWA5lXPFrp?rk=CS$V?gonb@3c>V zL(2wyB_}DR^yJ9Fg7i+?irZ+3XQOkUd1t}#gmFZO9RO#TQ(lO(p_3?)Op0>&C5M8U zd>kai(o82KzCp|+|9EA16>!Xg2MS`=(zEoV%~_7U3%)L%#dk><+@Nt) z&xjn|XY@Q$M1L#hMOo;;1B^OGU0+A4!P>cx0MhT04a;gOAfjueumMn_ete7P0c9#uYAKhwAcSN9t3jgXwq)+H0r=orXIQPpg#ytg!J%H_|sH%3TN@ z8Db9u7SiX}F|#v=dH%$H`R_a$OK}P7DS7ce&e6_1y769o+t;5y9q>LzjSTa0Z?ZBU z(eJcAlKy~oPt0&i2VYjB8zg%j6*hfe$7Kg${vgK)1YB+?L9bh)Kc^QbnZ-Tk<#cOj z0P|bV;AT9-{sN=Vv$#gPiW#HDZ(#wA%9>V5on4L$az(gcp|@mtCI&ams^~YO?N8hcY>Zw3>Kwb$R{=LX{d!-Z_7QP}(S1o5 z3B89(o{cc|1+y3tgAWc4zF7E3J-|PT`Ucg zUGfz23>tUyYN{zVlh`AfjwmX}H5M9-mygXf5HbsSDrEI=DmSWVBK#q06S9Q2hw;g9 zT-4I_jbt_(H^@ePmH&G;C_X}oQR4I$VJDWfMTsPgnf54|s_@AETjSdC!5rp%bcpm@ zyB8xw%!JK^+5#Sz=*gBx2DeSsUxA=&cYs#MV7*^%z{Cf=d;^y5i9m!7u!iy)M6d_| zN2i>)75|PFx!)EQ29^`()#<)*N_&wZP^Gv@*Uxc^8j1#Jcbi|AR!nfo=j=Q>Ml3ZU zf{{D_xiJ#WVl!?u7wL^l_5zI;yM5-%UqrqdUmh8|3%`2bW$Be(Y($e8$0!Yc2kyeK z%`6KAm_P>r)&Ka0>}B7O>zYv5GRk74q`FT`BsCb^hN7@BQw$@-cab($8Zzh0cO`p~ zzFgfExO=9nX}hZ6-C?FAyI#t=#5wcmtalnH&-A^I@KG*kTX1|e#I+$XJsJPQ#23QvU^txls*u#WMx<=Q#4S4n$cnER{Aez0-9JTcT?nj zN>DRpA)NB0$;F%!%*T%?ljI?dZ7M+y@;rR;gQazqCwRqgwgLUH9xlyoG%5ck7`*`A z)m=JW1QZQS@3g$HmJ+%W`>#mJFG`F^BpGdp#IhfDqK(`xl^S8OU?zxm&@wTT>cO zFc38!=VUmGLCaH$!Wg?cDpyj(dx(CzNJroyndugt^dXlnNYr9a_3I%@4<((F086bu zOMb{x+M}zd@{MiDD03syzeNu74Yj!ild(}8XMg5mf7ZX_ozFk)mIiIWN%4o(LKlQr zh_Po$Yi#IWjqrdBSkl>j5{w92aC9dx5+LVPgags3^$R6|x=9sSx@*|eT)kR8&|^73 zR)a-lm-tGHX~xByk04GWT~(p#6e&Dsg`i8s$h`9Fn+P#I+dti4*vu>HTB&wVk;NRNs&$Xl>PJE#w zDN<@nMq6N(64r$`%hm=1MZUNvpPYi&#CB@!(pUdrveF;%c8^HLfW}@qy04$QcS$X^ zLFQ6p5CKQYRPnI}2}Ykf>WD1&zAeuch@}d4P2}q01kUSI$>D{O2s*!^z<$$^rW&1E zsp~_WQ8d}YjEnJ?;HUZOI6ptp(^yT@0X9~}?YJ3} z7pZdKY+9qt*rhg5r>bioAThmk3I5CMhChca=KAF8eliAb^dMMf_raR^aYSm68(^v> zSE6g@db5x#S^8Jjn}>qC?rG!oZLc2|19!kni1_H2N3x^O{4_hS-OID0!knO~MwWqf zCTpRj7$(VD1MebCRd`mUiAH*%x6sm)gTpq6-F4S&Z{L_Cj63l$AXu4ey07^BD`K!) zh4xZLKX&hmJwCgd*<9HvzPNjd>Bv1CKuxghz4sAxC;Om^z}t+MBc#tuCno?6ukwRpCGXtZR~LMDv85Xn#)t5!oAfSqH0$+?HFZ8dLBTd|6L zfyyT)?indx(rkIPSxdJEahV-t))5bf*2D?Suft0UxD7!|+FiT7MyrRZ;1W$Tk+@M$ z-{~>*8+hPrE_!tW8l<_;(a%?*EJA`VFcWT=67f7ec?#kcst<&XB^!vR=B*M41GY$^ zRa5N2r$&#op*e?xf|FUKYpJG7?vI&Ig^}xDE6#ePJ`dq_3IXWE_VdRVJTB-{#AUo+ zPBH`2Zt~Vp{ywSr;-U`lX-qcLH2(TjQO-Q44Juvh3C@J8&K zR#Wv|qa0fM4V>J-luk)Rb+YNK>f%XW+_s>^DcpxAYezd_iJ6vQz4+H@w5s`bZFKgL zq!v{W975tV)rieh;d!^D&6`?Itt#CHR2fj@o`wlQW-$(aUao8AMY= zF{{G0Usr(RIO4ji-(t}^278%xUP`M_YmWBvn3QVowz}_nxYF`Oc^kTUs)K~zsa`l> z5_B=V=Dc1tU^G8|WgD|AeIyO54+beTfnso3p4)KHKJGFVnG+qbI+xXz`L!P|{F>N09#!hKCpr8Cr(NKXIJHEYM`jN>T8pGA zO%rC6qnWy`D0l|}{bcsr^p5)qCHP_F=hhvmc3K=;fj;=euEl8>yx$|=E%Ryl6c#t?1&g_iiph~$n--e zT&dw*iOy-UvcI%~o@QB}L|QWZ!26?&*u|v5ai{`*N?OPk?*VSsqTq^E<36I6XqIYe zmSQsaw)pDOVS2e$P60QU3<649{Hd!ZUOkCfqE^0iOhRhJ3TL+=AiSwxEO2gK`19)% z2^ClIHM#WS>_4cU=oUCWVS?V(&Q$8A$_SI3gh4K;czHTlMtf-bKq6)V@*1(fLDClZL$6|ghWET_x6?OTVfX>h5u~QIB>^Rsh?wp ze=&86kW$b-G8vM?4QkaWh-wM~-}g<<)Zp_GFGx3x^jAVTwpnq_fh}tUkAVjFCz$+t z>3wv?5MefRxhG1_xl7rQ;J)^}4U-o}9kXw8%=~%j_10#ZlXJ|ac^}`+)-wEej&?gi z_Dg^-Hab+HCnnR&FCOSPzkCyocYIQ7SXew9Yvvqi-mUVB*O^BKQVW{Jj~UbJEMOnk zulpqB?4T-Cdyl_Z_oB~EZ;e)WpTYMqK7k0> z+jt)?Olp`f=kcLk#oB78Jfec1klq+@G$HTGdZk$vaxR=xf00uDH5ajuX)ZaSjzcpu zWHVRwb;ES~(OJ*ekq(PRV_L?(_w_JmoDFG}nN4sm^C3d3J)|Z&4{uo#j+OPgeg}0> zOJMgNtw=L9MK{AGeqg3p$g(X_cE7?#u{L{jrod<}g?5(nx#SFq2|a$OtgY^!;81QO zd)bQM<_}_Cf;172gn@RkIC!ps2D_MdkOv{RpnItdT?`B8|Atp=G6kVkQYA{E#W>`u> ztT!Jmp36kf&EhGt-u44MQMz{#zwb%^#cCU(VNK36BWh1o$!e6qV2+vfu3_uU33Dr` z`{T~KY46%(Zu^S3hiods77?cpDPa6fAo4G7?L}O9v^C>sA09W0&38e1&iQx%Ofi8M zuF2ZMKri-Qk09T3Z&9Q0$e$-kxH;o82omnOzH zBaEU-W^%cK+Z4X?`E+GP91?Caal9r*3d&XypWehZidvM;CN>nr0%kMCwT~_irwMWt zdKEzLdMxj4&(D?rypoXGu#mxz$Qs8z1!)3pr)0O-lca!I{MXz2ZPB@xNIY(OuQ4LO zxQ#7Ij0%)inCONHY)zG83s;;8^;Phn%wgXfr{s)PjBH}vTyPoxI% zmMVZ1$p%zJUp|CksP}Er*`x!>PF(rMo6fr!NPEA1^u4=GBwJRC;*UPj&1OWVCjw}P z&HODP&N#zlBPUJ)nu!SkZh3bFOCDZ`FfV-lchX09F^=ncdT0ge6j-bQ3i9!X857;9 zuDVThCBu5s)Lv@jCFxe_GnUW5-lZ+}HFz%@etcuB`#DOk_BpAz!fc+(6z8Td` z*d23*@^5KU2{Gk%DR8-`<7ng*+&%jgtUTcqm2~82MdLx=JXHd(w|6Z+*ZxqYqiC;0 z?eLxwoIl`k9>Y|UZ?n@mj2jojjcLTI<}Ib8J}p7b|4nW23xEQ`tFa(A$`vpR z>+ZRWF>7g)U5xsL)LwrKvVXRk&9bZJC)LVkIb>!iXojZl=02C+U zbgIn!K72@uwK1kY{R|=VvqYGhF>RK`P)OKNpe0Xd;*%JM1NW`f5caDq@9>w@ZV%Ex z{Sir_j7nM?H8e!4^Qnjn6_9%`Hmh+A|H_gh(fcd_Im!QYa1lgT4+jZqblxa?MyYAL zZ{s8Wl@yttf#EE(r%otF_G7IuEeae;ul)_$y!M(2@d}n*KT-CvmeXY5f`ixWe4DOB zR2Uh@(V;6o+03V#a>{LZP_+Mn(*sLI)Xhd1HqurHTuDe&0VrM9=eQv5%xko@>%qu5 zqMeA@9idWomvDbS#!kVPOC-}sV9!Ig7Kj^Wn8#j(!))_FLJpm6o!-Mr@1Dm;1^FoR zn!7xs>!0ofuLGB_vlT(|u*chTUxcmHb9`@q8nL>X%kqQ#3Y^B5FZzRDZyvW6vLiY! zKVIVeFp$6}db>skg^<$EKJm5sUZ4SjOj&XK&w}&XmqTUbYuRMuy(GtWaZ0~=mfI`)$1@#OX4Zpi>67{PtiB7eIP{f^(D0Ajli-__Qu`Q^1~u@4JQLo zS>y7@O7p;|>{I2J#MuM{$!dM3q%?hz7?lnE0hBr8L9biXUld%gR zUtlu_TlI_{E%%l2=ABO#?ki1b4J}*Kn5ba}1-L~yL0Xb#Z{cOv+W07J&x~q;k|`KX zS_a>gLO5YMD^wOlyN%le2b{>QLp)SHRjy}^%x*FzZ1rtT;+^q4^>E?9nq&tx+jC~l zQogF)(3$GLn3~AVBlK!hcadmp(?5L5GNjQ?akFLuLt`~=FJ(XosoRIN`G?DG9y&Rr zU^rEL>b-zfPh^;tF;+8vIe}_qJk{&iG#+eTOH*eVNI%kEwuP^VNNl`t5n>{>e!Ajx zHn402j)f2K)$wCj(mtas!l~Qnb(|erV#C=dcF^euqcs?_W53YWgd@=>%~XaJQwi|% ztnnGCZa{P;FFaU~xiQU8V5qO#SlJ2BeKpfjf@TEY(!v4PW6tKh>%SeqE1zsKZd=m? zs@|V6dOna>gA}9c(pN-enM^FSR{Fk*8o+&Ggz@C$1Dbs6$#ZXS8IdN6Ja(Z{`cFKi zJOOp_43=BBv^bpIDpv#(50?`G*q>wRNvBA9 z!AgFqJq7tmfk*m)IJgpTTszvuw6R;|Z{FpJ7*_h;vSn6sKs zqB)U>{7FN(4Ppr8cg$+)YgKu#;RdFsK?*n#@P@v>_>3V_uM&MwpgRkAD=O}Mue&9Z ztcp~TdSrrS>E%78<-_z26tLZ9wPvJoE^-+{_4#TQQ*I=efZ3~vtU*XdWkYdf!FzI7 z8>5EVKA_2r$*-c^z}IEV44lwG1Q6WXBQ$00cG@=A0VS$ikrgMCrO(hf^UWFbADsCvAO@wfhI>j&7glPmEjm<7qR5ciV((S=v;gtBT_Iun+(@DY^b~0 zLQ2-YrjKsra=1`p3#~7XNs6l(O3O+{Aiu>_V; z$4?OOw&T%ltA2w#?)o@tHCZl(mWI**Sf#jqn;5)}9)l3^s6Q&G`9OX*sWE}(TLlJ* zf}ZD78|qsFU6oW}l4zj=y99X_3DK1It+tGeQ3d>FE`$RtEPfxz{XLe81OZ|v&;5is4S_p?~N6ImwV|XYpqnZM9iWJ3V;W^J}&e{U}{L(ZsoLU-1X^rfY;?zEj5wug^pyeP_6xYD5IQtCu!!&SSw za|Ar=Ja=>+ZG(+FTAGm2fnuIaOv75ICjCG|CyiGX&p!Mx$_Sh6l@+Yqt@lS^D1FxSSs8DFnpKu+GOR-D|@4AF0|(d^O@3_(PUNB z4_F9vplOpW>lA zU?_|TvPFyW(Vn~#-K1{73bGE~nlYiLKOU#V5x-tX%* zekfSK>mDgJ&*SE$Vfv)YvoRjy)c_p|GDit3{z(L&I({3eu|D!>NPQ>K{N|w#g86U%grxM|N0@`x5B6O@7H!R$k{%o7E z)`m|i%I3-ZdLsw323zfL2c3(SX4SYtqF*w{x|QS}(?Dtm@D-c8OFi@Y7~dR8B1`9s zj`BWbF%Lrl$M(`v^;1Z~t#0 zA6=ymq#r}A=!1PPKEDa;Iy>`9aa1*IPQ&HpE|2)s;Aor3oXMcacZ)#v^HuQuo}-8A z>yKCSkRItn7YXr6%)d40h84KuUyfrPwLo9A))m0%&r6g08@Otp)Z*Bhaz(H~)A8UC@S%mHNpcD7LB{)n$nK zPk~X41|?oKYgL%Pc)tQk>eCgem-xYD{(!;E*Sqa945P!#1$~o#8NrY_QcdI=#6FQ~ z=*#{>HcdPz)s2RfsD1$HfEI!~=?RYUHQ&nNz-y+KGwhPyrqY&8LTxGPut^Vv;@PD^ z8z8l$;@s;}BicrB9*i?NVE&Efh{d;z)I2f_?dQgn9Q4FXPYJ&O&E57%KUS6XY78^} z@3E+g)2%AmfEFg_s@X6et#_U(S5zLvO>-*LPnE$D%qK3DS;1&M<}%K6VpOIH1kLg> z8pnhZOe8f-x=f8+D%@OoC<$@7rB?W;j!JwLcrLs({iSix_}iqD zxS8cY6_Ig)w9h$?2*XWC*84UF66}%MmE4FrdaZ$-q6~!;dWv+d;`q@Yo27G^ecZL0 zducYx(9W%(E|=7hLq7%GzM0cKE>dJV~=#RPCXGc*JMB3sv9jkqVWC1B8mVTObvWG~}_HXBd-AImw zAxDfqRjKYh4R);~6lCNVx9jWDM~B|oq>Yc|&Bgz=h2w?jG1?#19(*P5)&kSaO2!Trj&(d9b^ueQ4$wn_3rH4b6XWy$3>)Oyg9AH zG*%`X%kI}ZCRzV22j>~XbT*&pg`oSF{G8+M_Gs08@6$}D6Ay7+C9_r~L9wO%g1&R7 zTRm>AN*qVBd65_|)Zh}>y9=oSPlF_$LsP+j`g%d}K8zue>g?qFt%sLQeciWO%aZzO zi_T#FLiF^VztUJ(s&e6)%$Ee&8Ws9GLT4DeFlI{ z(;icxioqjET$s==KKNe9gM*`<(9&R2YsA?^qz}1#lB8m zr3>d!K_&xUbo3=YQUaL%;RlnS@^%3RJ`wFAes&@!7Yx50GN?LvRJltTP2Zivu!}MR>V@xhO5-Xn1sFMpr^@x%Ih_br|5@! z$y%XKRS9*n&N%m_`FiB~ip!M;bDHK~`x?X7Z7R*g)BbEn3d3@(Xyto@j}>Prv~l?LM+bb*eG71R0ADVf5DqXOIV{JR zSCGS-YrQ|*MO9YWjjmD1ipZUNY7*=9^g2b{f)O0CpHqiOyY_Ksp%EcHaU*}oE2_7y6*A)}7J2F52s#v={qt~bN zt3PYoL#nEG-ljxG`{zy*l*LOCu?H%+V>9GfkKb$hU4FnbZTXpILw~tu?9Yy>++k@>3nSG9jiGG&l4T*{YNn}!pt<% zk$e19;f}e(=fo;47P)yzsrMgeStMvO7#Gb< zgNMImF1pWm)jvJA<%_w$pj{2=P09rzuX*F3AW9t}hSk9G6Orm2Lv`@#pN{ z+n0=UUh?xvr2}xyI7ku*IlOcCwi6oL1m3s)txvoewN@VZj;6|_{_Zue6`Qw{*Q8c+ zAckB@SH$OY9};w*GbxkIL2@`6lGZ1D_!lm7jeXRHEfp;f%+3dN`%4%|S2T`xSB`RV zD9Ei*;Fd27VSq}0=B?TBG28F=JR|zfUnpW`q#BH_#q?YU`(dgn@~t+Ce!CaG?@Xa`t!L6CDULPMh|&3zj&*8V5Yy2k z&cC5EgYS~(ApyUv@=i{}JsWaJ-EI3ZvPM{Rf4r_j+ld!4e*1QgZ*C}!;4Saxhob@o z)VbYc%s;UDk26lfiS4g9Xn`*4uX0)#X8vuVv#YNiKf8Lzm?u+>Cug|!yE)a%ELFH^ zjSDd8jIk!k8u!5LtThSK(r#{X7+>Nn;^s6E~1v`LVO<1e;nE5spUJ*r0l3#KQZP*x}Gdg)#K$zpM< zqdH`l8%xrKm(B&@pOWga@#iNCvi(?~h$Aciw6UGpg@X%6l-FBlP}N8w1)pK@1XZQT z1|O83&>i&D&5CF?31AUh#9^8t zAJs24lb`H$@ED>$bLHXIT=_o8w}g=ts5zT%U!rfbvuK|3b9sSd1EBB}VYjrsEJJY| zAMO|Kr33$ZCoXv$5d$~z3w=vX>X0;h!7g-kf+Bxsu)s=P`a}G*>7oN3f4Jx{&Jw0m zX?Wuguzi(*KnpKRnkwTS=)H)X_TK|TZbRQyyN12C6v1jw67a!ME`eLt&%Q8U+x~qZ zVlbMNe3R3>ZAcU1Ma_ks!5euzq;z#prWyP)DyyX_dxjVvooo6UW^PF;TXKfHOCQIV zLN@CsompoHJ~!@k1nE5=doWR_QNbX4Ql06U)%q7z@>7?Reo6Rr?UmR(g-7O&YM^xY zp6<&jw(dl`*Ihj52${#@zGh%n@xeQ>1#sT*Gu?N{`{@?yQd;N48_l_~F`MVhv-S&j|MdPP}*8NdN?kGxE$>mI@94geBHjW(eX|Im7q9K{#c zP3*2m{~#`rO|;XozQCD97sgtI|6>;l=77n$Yw#YQfoQ?tu~rzdymwzk_Ohs!TRq6N zlw35FmB)K0NQWcWErUHEa**GBgzNjl&OZZ!3hBtS=rATE?{f7)%K84JgCx_BpMUrZ zuH1M!iv-K#MG)$Wrp=YVUAJ0MfEOCYJzq&Ort%}lb5WLuPM8}MjGHcTJ5%v~MA$Wc@r4Bl3h3g?1 zR^`O>>#zJX+O5hu;H&1A_h&Ag1$Hh^V{%fRcx5|lW;@p^m6YMSuZ z56mbRno2nDoRydXPYx+($Z(SGwl3Ey%qF^w&pbCWMItUe+wQxZ|A^;ba29wTE-<1u z#c0lvItmWcy#$?Sp|&6(wg@KV`Xiu;4U?MT!*eTF5e45pzpn1=)x?Z|llMwyJM~u- zeqk0c;(?y}L7xj<+6>t8iSN0&HtwGa5#hWXgHBbW*lMNNW`bAmZBD^=2Y{9??~2-0 zxE`lK5q(`770GjCC#T+Dmr&s!nWq8QbPC;C4I#1rK0T1SP}uC=`V ze#jS-5EsL-s@kF@ZpS{!e9Y_QE7W-tqe2ph7~W;XGWx(Gd2VN%s~EGdu5!O{W&C9g z_a;*%#ZG75_w>}6*3%Ft6J00j&@~dVO~!9%K5LOq+04+9R?b~}c$+tT6|aK+(4Ja_ zv?-tFPt6k}u~^kpc_wJPYI6BCOuM8K1(mPo;4W6XawMw)h8R0DTNX;`(1&%Ss@pj4 z-M6`d`Dv^5aSf2NjlHDhOO(enj7@Q#mAYQ&gVED{G!()scS^Jna^eE+I?NV)(Kx7a z%SeTa<+ul)LHCuC;zJ7;aTiZwq!89-c+|V)va(km#hPi7Ke;|t`|ADXtU3DtiZM*z zB3Ho0Fydl-lrbN#CB%nTBpU&g>YmdDlyg6iM;oEDj&W%(xp^fQqW^4E!qJ;Fz%9@? zz?1i$DCG_XN$CAulKQoaN(PN{GmG6a{mM(eFZXC5$Lg=CZf+RswwfCbeGpsFXCh-% z8u0x`M7M-w-`k@mgysr5Pv`1%ruIk5tBY`D0Lb82K6YFuvx~Yp&}epkP%sFy7U8sq zus%(>WsQQ5-EXN$I%7_ip_$-igTJT7(lxJ7Yvi;SQoFVzwv>V~fq)-#3hghw+1d=) z-=Mj>d&sOrYlSTfG~c;WN8lbkORwH32GxGMtoy+*HDp5u75f zyhOyLjg;5)m8I-N;<^_{&;h-D!uw$S(^~gXWvXd?2Ogz->5q4IQdZ%BDx^$f8`HpR zV(2`v;m<$T=p9sS>Hb`hJ59)Cu|&ba2#0Z#%WTAUh$KxHLpe(NyE?~m>h%J`9JSg2 zEPUQhsq*Iy2+UVi6BMED>K)ot9Y)t#u#yMUoJ|QBtQ0~`z zce?pKF^gF9wsXHecuhNmYzPh?iq%^U_4JcmYYOHXq86h187m!&BtpSJFwy1q^#uP{M)Nuw5M^049+uFbX^=JNU%F5vjTXJ> zIbqp~9t1jU-Sqd#N9=5e#UOUafJ2!Nvd&n6?Zyn z0ftX7pl26JwxkPQ+D}TmO=LGx%FvIz!9fcEGl0J%3?Qun;}CER#^9*bjzGU6x%cE! zuhzX%ZMVK3wt*|fIX0N2!MIGVeqO00y4$1jZJPR?WIvZ>2zSn>H(uc25)Vz-kNQp z23VrMJXzKi%WH+0lZaLCCx7?2rx)6*Sq{ANYL1S9((`*DtIX>4AYTX?e+cnqKB@Y~ z(r4GCaF!ky6>Smtkl!C5XaG=~J|XL~VH)T%y3Mi6JYQeL34o<&dD^w4I;buqu|FV~ z#)_@XUVh%XRDL)QvxyWg6wn3)ZB?BOcBQfu20-U%liT?(ziKlk#fXt@UQy5wBL=wq zE8$L`LI2dTpZ zCvR!p$y`UT@Vhhc=`R?o8$e#%Y)WMjyq`leDqAkyP3AonLTZ}{na-q}H$9>!U zG3uH8Cz+Ew+$OC1HSw*mSPRs#wdLD0!|*82E(_BaH3zh-&*S%Q7jihL#kzja`ydEehzD%vi;$+aP_ z5;M%jH8P=mqW0M2ddK@nxPZCbRtZsh{LfvFyA3%~Mf!@d*h{f=cj_lG>#=Yn6>{z> zLw3XbtFqKL4TYHUSQwI{T8GUi;`Q>MDNGms$VNpGu$@`XRbleW>Hke zSF>U^&-ww7rF~7kP&JmYA@XzJpqY5GWO{OQb3h*kz5A(`#{D7?{5oanb6KT!@(v*Q z%({2rlW6kGU#aoQAZmPrR%SfKwvmkxVNU6IzfOXSY~Vi)IUT4v20`<`V=1%U1$~N{J$-WS zE2C0l497eGZaSl!8Y{x}q!t{*<9~2Cl_0>GO&Iwh^@0_mZgfFNWMeiOvxk z#FX_WKS*%gP1X80TJjk2j5ibQM+};V3xqb%>>6CU<#k@)+F$xyk5sc3Q_9gV5tKtp zIeE4)k&RH(i!!-Rf+Gp=XgiWsGsL$vVw+o};W{G9e+O1!@bohI1~1h#y<*QLi^Mm8!b8 ztZGCvJo|!)6zJ16OC%A5win1a27Zaeh@yGsq&IPLFH)LCDFQp7qd((?b(TPJy~5}v zLCR{gpY&U>X|qYOUCNsE$1T_xAHNl}gT1zCEQy$&vzEFUa6(44-t9(!l&Bm+0nB$2 zXiWRsbcg(pvoCQ-h3G_>p9Y7HSyHog3tmdP8+wyFtI-H!B3dfW0yS2 zS0I?~=60fd%)|7BHaN|im7P#FNj25W6w2OOlP)B<2bGCOtm2+EG? z>u|Mz>^ZM%U0vu1YEp%@$E`DT#JXr27AXX(_iJw^Okg8Qx^o*18LXJ5x0qTo5vk0o zcjg7(MP?I5M*4<5S1*-2{W0nvjKA^kHN3&|_r(Wy-o4$6-IArR4@A%YPp=STHt+Ck zxtzK~Y?5Ip!=-ic)zf|Q(6hiDw@_%qHU)^?FsaNML`b>a#q>u1)GH9ZH{0n7;c zVzMRA7Fg<@(ph}#i!ktgoBd|9QqkfTj5CQ= zqej~I2^LQ5 zD;}!GVR`AcIi4!qZH%p}05O|iQ^RNzx*igJiP;ZtYb38pLUsR_sZO zQ+R)R&EKUHCy@2VY;HH8e^7UQDwm5h%_8xTmGK?0ykUVjC^LlaZMx==d(dd z)NI$Qf$`)X%s2xA8nhzDk^^OQV9JPE{r@)Z1efvc%KVXxAzg@c}W zK4#F3?R_B^dtR47d`|H^%AwOU?6|1!*m31^??Y|EIS#U z^od-RQe~;+r7FZemu9o6CHFH&LvHK6|&zW?6QACd5T9{rLZWQn2*3lc%9m&v+BjRL(?y)C|lPnk_IW@*2bL0IFV zLYn?9>WWPplPQPbicoW*sa@>jCjBDtY0Tr;j6LO_1ji7v>ERAY*p1#nC~6|ZD?DYx5p-QXY>*KKz9$W z1^?~3MKWG9C=(1=wxokVHVPFRg?#^yQ#Hzu$-|0BRcZKHt=+T%N+Op?Icn72JoD!Z z0@bn8G5W*TUg0>AyMfI^fyZs$yn7+mW8fpeP9%L#|}M6l({7@k4zv_BI2?Zq4B$+=>N&J08kLghbJ3yQ_K9YQXzO8<&C= zB&zh*JL^gksd7#Ch$EMT=jdF6mW6w+oAfb&s~2ierb35kfy%~MS6_1PWhOAlkwgYj zN4_ka=isWeA7FRO+uI_fu_P3rGbu?0!x@Zx1RDsU8Z}o4gLlK1dXdUEEen>EVES#F z3U|qA0el1tXsGU)_v>RgVx)sdowFt`U=5&y++qN55@@1j+^{gqFvg(;)-#o_;tf}V zAk*J%XbDsH^(;npI>H!xfzSPRe zB;RE60Pr<85 zK4Hk0IP-6K9lX)56{84)fj4}(G<|j~c}Mq{cG!*8>zu?w4~m|VQ(qKHbB!`2GWDK2)PrH0kh%6l=2^^s&= zzeh`L)}dlW8r;v|I)oBm;7#N=a&EVE5+3}Vy__?t(tJQl!f1*+y4=k)6Hpk zl*Y3Zg;{_RYF)LCzd*}YROODy+?t(?tAjfDdw97qp1hoRPszq4i*FYO5!#uK2_MV? zPU_Vi*_yE?v3LoC%L=PP(96r>Q784c>lDmLeB?IjIEhbMic83tljmHnmZASU8Qhbz z+!&P1SIdH`&eW#f{>&EJc~5@YR>%Vg3e#y&`xq$F1L%W)lhMKjXVE|HQyFT>MLT&w zou~lyBf*haNeF>Rimo>)mF<-hK?HH9Qbn(*Z%CA~Aji23mNZ4JSyg{V^}Mcrmcj<4 zLgEC6Xwbk_7B?Rt1nM6-w!h$)V@PMx`9K*ZbzTI7IK-{xa zh!-m3J&}aT0P_dsQ-6vXkOqap$`hA|FoqQ$cZ8rgnMQ5isG|@v7ow85JjjmFYLI&D zNqwSuWU5A^jDa7~NJVwE0>Iyfi9+@nE_HYq^=cF#CQL^bIy`QTXCB0PjSPI-&_~)X z)+%VJXF4oZXBO54{1&C@t4UtS@qq)%4*X0CC<*7y2y4&tO-Uiy&KAzSMfotOaAo!k z$H|}kjB)bskV*(7Q8e-Mf>IFtuSt%q`5*CZrEd9MSrJnl16=*Q^k{AnMM((mBJJCO zzNXF}IIR@8@)Vi|kY|}9tmz1Fna$534~ybLWTAs~I~8rX14kJ=8diSE0ZH~lm6f7Z zP?~OP7HY+CSHC}V*lMgB0C%+UEBa%!ODjB0UFckr?LZXxNLqIM?*#Nw#(3q=o;CUVOY#@NuK zRo7{YVm&dPx`_jfSMcI}_N7{0>=(KB$+?s(|HMRDF=;}=WwuU=s-*afakxb?m z=VSv?-Emo@7?WJYbI}PhN2V01t_WqgJc2lAEJt2hW_m>{4L=OLa4?sqm7OsuSPzs( z4n0oMT1+s=6bK}!k;RE76e9ZS9tXnZOoFR+Z6z82pIleTC&3~5Lz?|=$>btHyQ-d{ zNSD}5hQGX(Gwipt1VjF`Rb4^TWObi*4#HU@b=;DS>B4m+<6Q-rxP)hR3d+6A?{_fo z%b^^8NvLx;LGO^uG$XX5I&$3-+XorgTrLl=) z(v|*Bg9olSG|U!eMhvf!pi!%~zsBXVn`0t4J@w4h`#mLWgGWGD2Z%T-LfB|zz}eJp z%!))C(MNUiAhxQuU5*oo2|rXR(_{)HY>5U$6`A0eT%*<$5ByWe$uLQ?UWi4Fi6ISn zRXJ66gkmfa5svi_P_r_MueG=%wX0*SPCPK;xpVS<5yUU#v`Ug9 zAR4qNF*U86+!8Ixe6FF|1t_XGSMa@J;##)jh=t7)YZ^SN4O#1K&l^(mfc3Nylm}J0 z-LV(CjP)FpW5qP!bjhzALhvQruT(o*o{2?3oVrDd8Fc&UbuDm&grbpt?1D{HUnNqJ z<+O9jB3PL5b_A82pzm=AO=QPzm6$Pczi@yBV7nw`NI`1 zR&#JSD|+v?O#>ozPz;bx$IFBWv<@8+kEWQ<5xZyfKm|L(IN1rZnKeiJVbD+2Acmlj z&XuED9+?5OxK~(oc1#o#Z?6(Q0ZCj{DG&z$vYTBRFMHmdH9;72RHr*wt26wJ5-iio z7g)1Fk{u!`@~qsLqChervb-;pNLoP^4`jup;bUvT&I zL(vL%$s5*gmN5x67JWq_C9%X=(sFU;desmPGpWhg@e3>6aO43=M(mEeMi*eU`T z&%$N*(kn}oUI?of6$A%|@LvQTc}I<&JE8zBX1I~QAM`IqzIdECgucmZG^HRiF^4~FrN+P3fI7w0fu`MxL9(X1k_cK%afhl3jZ!s z6Lc1!C*muEU_TQ&?8-Q0<3av6xS#;m^rwJU{Y?~sA~)?WQLO|0M9WF(XA1@x>1?_Q z!hJUv@pu*r3BHet+XyQ{b(*zm7)Yv6V~$B(q!p%8gbU|J&1*Od2(t8pwAUUW=Ax~k ztwSkNQwn?h^d_v|9R}tMIw8}-zH9jWyGEJ@cz33~ zk4S=-xjoBJNT}eH`F&~>ij`=Y2dyrLF43zTJj0;_LVn8ifWa;w%{e-^-odktzKNw+Fd)4FE~S?s-8 z*dp14JSnU)>9lK04<;QJ{TrC80%m#JFHGsYX2!6In5v_I7<%ep`SIL?j>l?v4sQbk zeW-Zq%I8ioh9d&-`wS2(oD4qux!wU?-NDouye|_l<#lM9Ud?K8Dd3ZlP>uI2VI1hg z3a~s}#Fe2V5VuvJ5R{xSD2;Yrl59|EC;NpIu|OJt^YUS8gqUTP5(WW7S4)L0{mu$k zNH&DWF%Srg@swHi=n^WKhNgY7?;JB7DMsZ=ElnVKoA7{gq{Jikd;Hj6KKm(Z#hFRF zZKsk4Gg3oAuEgjb@q5QxcHztM*NuG9fj;0-Eos3YmuF ziPgvcP{w`|d!+jmi7zWY7i}9)54B7Ka5U9rLbOV4wh0N>5*!%R+kmnVR^Umf_^2MJ zV{#@z=+Bb?l2)nIDB*s*vqJ3Xy~NYKh6!ppXFT1MpY@ZS4+AEbIGz`cMRJY;nhsXViV(Go6jaJFtWmXMxOTkrG!`_*S5M)I!u`cVL9E)_Si_%hDBU80K<9tXK<>PB(0`-R$!}1-r z9C@zPMO&oKzUdt@CkTLRdy1@p#+uTlj&nlAFw?H z0^S5VFmMA-2xOT}4EjYtrbO+a-$B zh5=!OcqvqQ$P)r+5fNC<3~BJvGA7w4CL#n;RR7Gx>vm3qWcu`{*k;>F5 zS0(x+T-kge-6wr@URWUwUKn86un>Ewm8ehwYlt6>PY38c1~7705yXr3@|XCRq}SZ^Jbcf~%y? zvwV3F%D)^X!S=~@*O8l6uqH7~)w1uQ`rCh14XO9Cx{Gm1v3@_S7!5k|rIQZo_5Hkr zi*n*(`_?F`QXy?2RCMJ@AHkYCgu5?*h}!?1D%LX>?RYM}*tA=2YEAvk)}?wUYm=pQ>oSrHFJe|Fni@mK%Bm(yh9AqjX-ELW<$vZ7D(de z1nU$N?zA{Gstg%SIELY!BX#enIH)94G%~o*V8KZyjAZl-r8X_fP81y5CUWO_9rJRv z7cB&dU*0Juuy}}CA(lVzW>3iqkK6Mhh#Rw zhiz`obO=JU6Gb0#Z%6vN zhK606xF3*%548QGG2aJYlLd>zN7}lV89JYUoN7sKBymt9w^o8qd0;5hv6`EcLL;Kk zZErnvO3unrtCeJ{1_c>X)_c1n)74&ivkDyaUb-t&e43~>;D z1PKG%0fRtko?a23L2=xSzV5|EAu6;)1r1H`xzwR_LLZD? zToKpEFzgEdEJfTivY=NvFElUUpQI{C>$m{#pyA~q*-=gREUc>%=_@oDA&4ia2ZV3| z2G4pVujOx4?Zh`;t<2=g`ZQ`3dDr2IHKvbJn9WjjPP*Z=o%6={jZ|*ABay#+h6htS zEE5EIKi-``$p#3qjg0bw!_ELF+BC?BJ*C9?(t*ZEHMIol>xs3|PksWptCjtp>MTr= zy>pxzPR}-Du7VbD)y?672cGBE$c%qbnTY-i$Kq}`bxmndG|~E8UcuyVr#C+z@Qn;t z9#+-{=gHu%s@ZMDt7vG)=06!q_flYdD%SH%={>2GffvFN3(4*Qcm)?JXU+ghqgL+h z$-oSAakg7dLQA4r^5tVjQi{m>IoK!E&P*L7U_n7HX-!^J2W^llM8t@MK3nVG*9sz! z>sA##GHeZH`Y=70yb`6hVBML=;#I0tLZh=!dikA_4L$`pE5Q3b`$GVf;9FcNt&D)i zZX9%s8cod?QIj`>wCGXuFQ@&CuT#5-A#O7bSK@$bio6LCf)T!5v;{qfXLV3FmsLVb zgR+)^_fNHM_JVr1o5+t^D;vi78&(lIVq4}cs_<&<)|)RVr8?DWrRa_vMTsE)DC?ZG z(eitnD`*b#RC-szthVBWw~Z?~EUgqk>YVQ;1j8jyXU!7SlmVc&3@~$f6>*-=?*)>L8;c z9$fOfbe*)RLla0^C)Q>@9E>mME^?z99GtC0o&dyoj)rQOxZMdHs?J~#DF=fO{?CU8 zUP6p>K9P8vrLfrQE$VPpjq07Ha;55QsBbs`uwJ$QRvAuoFi}!Jj&Wl0D+&@G7J2%q z2y!Hm6}hnHc0i#58`M9FyaFGmE-PUij!U4 z#;~m5%!9%&Z^t=ruP_;W2#N%-J5^_1aciAN5M0)>;IO3NDIK|Y_1gurLUHxLl|&>m zgd1ZKJ|5O-q#|t-?%6s#)-vD z*5|yaJ;gV5m|x^a>Ls=E`gX?#T!@{lY%)k6gakSGCA{*xlGq5&S``HY>*(|cVs7YJ zGO)9x2G0Y5DG;ZN_(w`+3H$MljKkDvGKIxZSoM$|dR25*Vl%Al?jygDh96CjL~eM!~19%?YE2uI)odSLa-}_Yxg=m~X<<0J9sNdEe76>jVcNr+L?qc7y z?_K4MNOwcD815o15~Pe|bE;&EUn|sTa8&|cL~B~bFxE9yI*SmQs%M&>Q<0~`@^y(L zQftJMLv=U5oo=lHR4`pvB%$_zJk;Yx9Lyr0IU!Us%#AsuZ`RZ>B6c8SISB0@Sc0@^ zOg1-W9Jc|2CsHa}waapkDG>~k;~c&4uhz^&bwlh>4-YX*POZU&hAelv83=`8<-I&D zuOR`jxct)^ECd;($zb_h5~QKbf~H^ugjF+XwePeFP6tqhG&er(bc(`0Bd{}O8$c35 zEw!nE@K*)lrFw8C;N^ef%&Y91CoU~PFk7e?PQIe}5H6-bjXwmjD#hdo2%IyjJ(RVOVBP=pA?tDTb zp$RID@2HREj>4|QfZqSZ+rQ_JYC&s>94@<^VJPUEJE3lvVQbPSI>=NE`2f(Tp#giEU2IO3<#G@&GGiov9`yjIq z!D88yc!(_{8z;!A|4~41a`^R*AgMw&Os1!TSazi9u7FYC1K!}K zrq+ndCxVDA!|*`70T@%(6DyR(RaHELM|HLs0i;r*`UwStS4d$6U2U7joK0Z-O__k> ze|`+QvCoyC2~?b6&Zj_URwKF_=yF7_Izl=6(A&?y`E zqb!wf5)+q8#nA*!BXD zsSgA#63+~s_D3X?RLX!JlYw^5YbHe#`Da!ygbl)lhXYV3SXZKHWU7uK)o*faxz>kK z%W%dsf(*0#-=|T%!#nnYg&VN-z}}3$14>oW9vCSZ_oP)Yp5d!eXA+@1QD{-Ep1@vQ z;Ns7*ff6kAfx3e0i#7U4t8X7e!mXJV?r+PNT3)5h zCIUceAn9DE=D|o4Tvd+5ktShkMVJ#peNDYYXWL9EicD+#CX80{kYJZ3-D0A&hU~DB z3lYjA>ttWtO9Kq)`b8V8^B4?)#luM0M7GmHC_F(F{^7!VOoG%K<}(Tsg3*{e>A$)G zku7Q5vv-`Cu#&$mo~e@?t!zR5-7+lg60KvyP6&y)3nrw7*O{eO@zaa z4+z4Js>c8o@fWH`)&ui^YG)!`fNsMT%!DJ30Vg{gf`Fb{*qu$n2to_*IDw%U8~S-U z03?VbSUD_V`0YNLW|ZH79hs+50j#3@VOR53?&Xv#m>Td4J`$sXa7F}zPN|1w8U8)& zA((v0B{#*)8esEW1>`y_#|9xqGvNIq=~Q%Tmx7J`Q?b$^Ku%J)xm*QyHCM|;1Ob{d zNm^N?N&bQw`Z{~M`gv3P%MW`eNi79yuMgEG$b^+t6^(f^n&`brymPYOx0=*7V zkb;bGT9th3!!&Mpo}GJei{ur?M+e>#0<5j^qdwXeBJn>ZC(5Mj2s8NDtN^5mRBWFb zMXVPW+UlAC4q<3I6nkibKti_SbC|SYq?v6ESTX~5%BeV}lu+$4wBcG!C>n6cwhhW? zFZxp(M2!^3RU(P8*=$4Zno~@SIWCe>ygXoR)lxF{gIsOsC2 zsNv6~uZaSWz(y<;4Tha{W-cwFa&jl2E_A&252+^N#v0(IM!jlS%%ZeDRf{=Q`F&Hd zH1byV2hm3gC2}#fGfL%S1aFB1AVNgwkwz5g5r08CxCFmr0juy$#ko#Ak%VxXT!UPmUjVfJNRZr# z1+uabNgD)N%JYN`7)}F1Ys&&0*^UmPMA#!0Gn)7o3QWu7aCp;$4H${yP&`f|gGkLM z^-QxM+@rDwH}%TqK=P0Fb!}^%Ic+GDMO^zN~PD677iR4jJ zpCi=_B&-7?L@uY+JN3FrD7(SH-T1Hd~O@_eMaKk`#-k)AjS~Z4=SW`y(rct$Bj^iJ-BlWRrvy|a%K)`blT(>2u{agq5TcC=6rT{H zsju}%-v4S~Fr#K9vM!gTevGqS+AA5I7N8qQ#F8v2wGo-2%GnqxIsjAx7Ru3CJG?Ev zt6A(65>YjsPRDcm0=v>*0?Bfc! zsHR?KN}=kwAQ1be(`g0B;weABw1tTdOkHJ}W1UBK+eMltMAen?d{)>_J$mCbbqT8J z5aZFe9ie{tfi5XiyTh>@`&6$(6bgdS3mBAWBn^kXIh0NySIDgo$vz5)vzGLR4S%E^ zg44FeBW0S@iJwC{IhbV(MHzwD158TVtJo6zUn1cWb0Z!-2n)!}C>Si0Xp6JbGK@Fuz% zeMPB}%ZuLRX)b%Nh=nOEwNFgT6qN+ru{@-fnxPq>?|dQH(mLw&K)d+md1R?x4g%@6 z3MAPl5Z)w5r5mwHV$n(3$=e)Ei|+IBoQkEJDXlg!b*8i>x3r~z4t+8_8Sal+8NnNy zfP;#@Cijt8WkvpJ2ThC!Wkw^)6jkxlJ3Lk{gcutn?-OT@QYS(eN?XM=hGl@{+S?2f z#MsV{3;2y{1p}N<-!ZW&j+U{Jh7*KK&8Z&fXYCPbK_2u=!8cKv|upG3}oNx`@Ca(8*#pMhDcJnOhY1<_& zrc1zmk!pbh>7vz)&R@nC%r}w1&hf=-MpFhg;E zY?TJpwX$9EY6^)vDy;4I-t!fS9rAZs9FmNeFO5)7ESVB6WIo=)i+Bt6!+pNmUSsd>oINCg{3r$Edb-*A2 zvZTJKwMmk&#pYV<^Tw$iax=9A52$OF6Ci{%vWyb|HhuCuVOvUagUHhj^0}>QE`5t| zW@-zRl?vHB?h0{S9I0ahf>5sx4i{;_6j05rvO9bxSBFe;XqH==R&zv>A*w+G8v;%y zAt ztJ#8i1E0+Vh)2sfs&P@gW4Iv>(Nv33G|G`tawk0(@>2*oS`P#-G}EgTFRdLInyWE=eYXpde`$z8OJDQ}D;xPsI_^-XwVGq77;< z*mcCpRaK-ChAq_SvH6p23Z$SJmfh4loiEb{vYf~DeQqc>81*Y6l(d_RRu*JXEU!{i zz>V8LqTbjiI14pQ8a{umTG9&EVwoh40vx(lhSXOrZDLD*zfqde(9HNL`kPNCRb zFGfg2h!=CjjqB9-)mcmb!6{I_BL*17##fg+8spJ7=-Dk+2~t zf<#jLMR^xFQH(^FV7Dp&$^}JY9TBr3nFnoTqm#QTb@xv{PQv2Rd0`s}fFUWayHg|A zlnnzoIDlfEgDwtu6CYDbR2$mpQv~Iu4b0v$Q*%>{(c4)tl|)=*f2B)h~|Gff0DCy{Hdz!Bomg$T>8205XypiE-6Z>~|pYkCU|c|UPR`2$$l z9yCd6VjGUE<;zM!{HJy+pFhYc2PQp8ziIC5FK+#jNMRMXQ$eYE0J!cs4e)42;OCU8 z1)6=m>|fAD1_JGEtY4y;SlRe z4^5a-x=_E)am}jckyI1$vK#7LUyoKPQ50N>Mm;GR6n`tqoKn!dE5tW<69~pi#Tl9! zqZ7zks~%t#55Stf=>wc(2`L9q#KH*|Z|;HoV)5DlJ1dpm4*|YVbj@w6lT}Js-F9XL zMc~U5XuOO_lYXa0ZAohxme5xoO>tmj3QU3&kychx%89n5#xjO?hF3P$5T0E;vzLnC zgXmE>0)+6PQj}R69#A*g*|e6J7J0775^Lq@PL!nplhxUmaB!)&x&4*3sA#D=7^J~# zp5!1}p%AhcEZq^P0?F9kI^-!B6()}Qj#cC#fO{we9w7=dl@xjW0qD|(%1^au5&a2O z3Cmss$A^$SXL+Mqkhs&s(EUaOeCj$E<6nl1UF_;klrk}Ta=#fH4b&k7F0DNnA|$+{ z=ZPfrs5-3;hF7SrFL*?2(j+GVhv_z|HNl0vF8an6d}P#dgS}2<17b##&<cGIBfe_QknD35i6Rr4d2RCoq{FW+iJxm_0`O z!nesWTx3dCrJzQp4O^|o>0`m7GHpS5d~ zc7_ObU*~F z4giGBLbSMKYsMx{B)Ip~Pbn;C>btxTgh_$P5Cv2E09%(@G{ZcU@UMLp)nRV7Ws(Buv&TiUmUij1(F+)Y!4% z=`Z-Y+nKL*vcnIZ5pPLe(?(&&#gSFuG0SPvTSm>IUeKi75=EH`e4doRFmHBbDsh`C za2e^_j9e3P1kP4C--rvj#XL0VHHRWV{T5Y3$ZmB_#h6oQO6`S4&qZ>SIcm&q;RRgq z3n*7 zBC6b!)RPoQ?zG9h4bkA=p)%qM)w9)P<0p*9mR1+j(O@-=KpuD0_Dg0vsn}fkV8~0S zgR3;b7eY{NZ-YbI7SOGAuOdJC;w;mUg#qfZ$qhAw@QGiWM~vkVYaBvhG`)1?20AcL z8&Jjx&QTRp?iT+FL(Qo3p0Ow9RdRBIyJsDeCkprA(>K0lnj4FcDA<5MKi^ zpHY>;N}jK!xIjsG#l~D1Z=^a&(zcM;Js7AxF4@5nGZ9hHq#~T9IA{tkC{S_vjrEeD z*tHpS==ufri2D4D&pF1rnkBU~V_}#uD3U4$ff` zJ*WpT03}+g^37E%!LZm5vh-#J6q4t#3RkeU%xi~WRY!f2^iKMkpq%AS6CuptmIgbq zP5_mNWZ6!?Hn(0#86GBQa9wtEvQ(kp+#~_XlBWWbB&SLQI8VCcM41ZJRf;(vSTuYg?jgEd0TI-k4;!|o zcAYBW9^;`yzY6HByqOkr$%oJH+0sVkcod=B_*hV-c`t?+&|>O}wos~tU=}r=Eqv1r zieN$NZjWr`RBw3$D`ISkU26$DrIRg4@rMg#!29zhRIdDS1*jx}CO}qLv!(1Yvtz5KE-_^lC*6eIk!N@?r&D0*86Zx6>g;?Js244d=R4o9(uM`VvO7ABdtv z)09AAB!-}Yz$SpBkz7hclIpf_1M-jAcf;QjzEVVBaJJsNO?i zS{gVuQ$cyH4eHo!{C$BBj#VNim~fO#&2U`bNKwj^Gjz|K$sR}w7J$5n9YQtT&TqIn z{x#QkQ9p%tY;APs!xD^7Xzr*v9bG**fB}nD(6j?|O;Gb@OL2Q;KoFC8=TI@qZ(799 z(|cX+Fnht@x-Gq1V|jg7b2g}LsDnt6yl(MtlxvnoAn`4Zh?F5x?md8KT$2nn$XxYM z&MQ&|Vjbz(0ahhiCaAhQw=<5{Cd@XaRp64T{jfU`Nt$=JS`$kl+%4;7&PoYRE>W^4 zOs>}SU!;n&W%@PdRuUJI^h%X#H-&Nx37x<((UmGPW7Z{5@`N8Wh)DFbg1o+cDDGzl zgfWraiganmJPQV(QSE8(rtH|{>M9dpX%7*N;TP4tsdQyc7r45TTMzxB#7x9>M;n3E5`H%jGXid z2hMQkxfuS8H%=?n*| z5Sm_9`pK6THoiqpo2O#qFphpXpkYXfhu!wLK}`%(!GM5(_&I3Hp%>W^0K@XokR&BygK??`pcpsRF+epqamCd&Pmg4w=cxFBUCyk<&vu;QarD=r_B~7#a zmEtkS0_5;470&cJFAtS+5s)Xf-FEVfrVs+BEwfD2T9KWkzn z`5}Hj8fi89r0Nr6v*W3*J1m*@CA8TVzG0fOupU31XhY!JBPH!(}?;mZns)_^#;d0I=vZdNCdAffOTb+c8e5FOXq zDIiF}OzUC;TGTL)j0pWSzVU{!3_&!ha}!i~@(r*C(45Dj?UZJx zxcz`7Atg zmenHYpH50@EOo^|>LoznDYcq=I7NS5=4 zH-WBsE~eX(0&C2^vNYI=ik2q~7R0|%m&)6OTa0S(CD>3fG0KUh z%|yfIffg<>6l+Vsf0DQif-=y+nXS!`4Q|D`@mfoIvkjza!`7*~bRxmI6QdT18E{a= zd#;-_0h04lV^44d2C0W_dpD|`57`)@e?8I+MvGNONkqWvm@$E7RFX0zAf-bhgb9Qz ze%em59i=gA)C}`PH?#KyOP(BL%WBFbl{~dQ8){(~9oxSQU1KUQ(Ezm#lXUQP#sH`i zO0b&PwIiB5)MmpVqwvFTz-F4r<(nRhP*EaEO>c`WrYKj^G=WnI3z&7!B>5e8DoYSN zVVZaGv4-agAI~vVg=|l~jti>MBu0_ZW)>985rqqce_~?HB$@gOA`aI8GAK{d^+lYz zt#keACX^Pcr=o#2>$*8k_6b^!tpJG$B9R<*G842?_b2q=gCbq?E)ylHW*()CpmE7D zvyn!v`6tk}SZvP>^Y&w6-6(2{O=MqOY$zDDaMFytGpQ8f$Qx?q_=e1P7P0Cy!NP`E4s?knfwLrnk*!-lg67iMd-z!ZTnx8ClGm&gmKORp$$0p09_iUc0u5fez;n%-oA( zI+nM@J5<6-N39Pu&T{aj9$`x%-AI+BjA@HaYuaS6m-?WR)duy!R(QC4>LF?gzh1p< z)@7xRL3Lm#GL@OSLxQk}qLvoOh2g|cuCy>D`3p9kd`D2AJ=Lls$^x;ikYja;Oi`uw zN_~gh0sysRi<4I+DPTsVaH8yB z6$Wb_$PB^~#qEqdpbh(0^a7oG>v5%6)vBX_+ z*N(#wk|wZ_OZZ2!B>U776ks|S$$>_V5aYTvqN;&Na4Vt@pz=N7Bq$l`2DD{3p(>&8 zmKD%6BA0>vvfSm_TK2_iD4wF>4DE6SF=1OlQ^iA>Jm3!~MF+7NNMZ ziM5DQYG~Mi$_jy!XrljDNEMfpVdB)c6r&zmh;5s>UybhT61Mpuv@_NEx6q(d`oAQ$ z^oq$OPdd3H=jOc?A;t@7vuiI{24^2SCGy%v(5m~O$#O;t@5vP3T**Fj6ECXM;Crmv zR66{iv|w{K!;AHqRMgKR?0?GI9xW?%@ZXIYMGV4HNe*c@727(}n4F%%f)@^zvo&ZV z-~<3n5%7E>lELj{&Q9mT^3~faSYq zh~R~lQUFq^lVcLJAD|ie%HA$c%GqcDFSk84o{2ZezI$Pc%nq@fBSD`~z%%T>FhPa1Xq2*7hk z%)G^*VN~+ul~+BFz*7H6>SpnUU(pt=Qsi!AU$>-y)vp4e7i3vXQMwoqlpOgR5lfzc z72^3WiDqoGa$GnT(4p@Z%t+&}^`GK57C(*_fjnBdQrU>>3B^I69N09kh3jGyX8WB| z8K-z{v`|w*U?`xib;<^W5?mO#O~Hy!^b*Wluwg4EBB?<;nNqu7q=ES|P}{`~+PMPJ z3z@MV&$Jr!58F&G7SLj=GG(7d9BJx6SKh3!0?YPyvPRQYURqrU(W0n(3lD8D`7Rbp zbwH9cvfV6GYZ)ul4t0{_L2#Xr`HS13^YHSnz>KEQnVf5d+FF^&9S-5 z`)%SFmv?VLV2*%AFhK@MaHtBAGzsjTRx<|DEwUu6(59F;qctor9f|iZLt9T2VVK{# z7*B*AipNy#pqup=@x`m7GH+i0EbJ^kIzfU_JZY~}DAg9`iFl^LkrhCBa-)JsA-pXk zhEXC1<^(o{A7O#|3m}E?1JolLTsaW&k`$FTA_tsx1320qDQIZyAcfh)3}AHWQKTVO zx$bTIM0Gs`zExo=h;)fmItx=gre+|+^$5X{?!g2D5PTV`h^01dW_fHr@9q4I96a%* zp|4p^|!Jh+fQKr5DDC2 z&X1UCLvC4e-plex&+2iZ>;-TkQwWnJoumrNKUkp1ZbUEzkn|*^Q3x<#xP7!OV1L#F zp;lRtQgF!j$H5Mg{SezI!bXR{=0y9I>dP*@s5axc{nK#faK1Un-WhYLaIu7hd7ckwOWItB|Ay& zQ^1r^mP%!d&{u;|r-<=oEF_I#Uk@oK#FBL|iVFrXJ+=TlPqYBi(D21lSQof2h|U%e z=dy)NZeVNBzYk(tgVc-)_!n#_6RHu#K@~XgIu0NZpL?(F8xm1&0(ha>W2MJ#K?!?E z_-R}@Ov&aM&eHvXRx3gnC?trc6%`(r!|5XEA)tIA5-e123d?l(V;`nH#m6@gwOSgL zzUE#>Q(jodW`?RrnkRB$9*I|_2S~z)f%&dLsY0L{#PT2$R%H2qh-W;MsWr3AV&WH;-G>?d( z0;_r`GF5L+DHQ^+#|^k!CcF4KF@CEsj*&#NtT`zKAb0J4GonMp$HaRzw#iQu7V{C=PJ8jr*LCtni=SCvH#9u$TA{ zT2VTzwPnORZJEywa4wK{6Uq`3fkXYd4fytGiT!BQ|K6T9$N zqPkL8Bha#Y}}MCirF;OS3G%Dv!Eb3pb00i3yYdMN(7WuMG>h=AT#=ebb#oKbFr7b zZk`R}I3i6v*_F#z8L;64W}cxt(cVM6%JeX7%QVfXW*oIULkC=`An-H7M z1rSuB3G&}!mj@;h!ybo;0cim)w@qFF3$`p^Sf-LoElmKhGNQ$9gruWbyYYzum$;f2 zH38)=9{7)|94w^ASrW#+xXQ>!Atepa`rrc;MmXvR<(1u^*5@|S9>R-6(vmaetEC(- zU^T8%0!M}b>^GJwSgX79TijsUjhlykiZ=B$3qS|49Z>4Vj=U&_Z8D>v` z{}BTdomlk>0R|WB)WG+XAi2LVW^jnrxEi>-frY$whl~XxhBH2wJghA2^oH&jL;{+u z$|qQcF!1H<(qGWJ*V`&`BHGm>*xON5Bv5esNrb}>Ngp)%T}w?PEb@^kP|9on=S8q# z6GV3_85a`%C`6H}+7HnMDP4H{&|WE03!(_z>`loyH3&~xkiu{xgL4{_^Ay}`7EKXlMHThaJ}GlEaG{{ zF9D^?tx8j9s_U^l5lT`h}Q|zG?9~7O!_xzYK#N=>$@mfriVdcGIoi& z`&A(VC`DbX`r!zkP&u<2pegkpGVy}!ULh~wpJ!3FNNLTIz`k(4&U0*lBN@EIgbJdK zQ2c>hTGo=ZnjeCcLYOvtz)uA-dX=a&IufxPq4Noi%OQf!HO30A;c_nFH#H;!p<=(F zNdgDp7R=+=#tO1zuXGN!UsiBXq|-xKab^-AMneGz%pH!qH0`UkPFOVt%JMwet*3XA zKlOANSlDQ7{;g;em?)v}D2&!nzgadzO0E>mf1(e943#^O9(!GHCc8rT;FEdBEaBj( zmubT%6p^HW!m3khrwff1AVDP90~g?ygk;>M_H)bH273w7Og*Lz`d_F((kh`<$!tS} zvr-nNSct+bBBFRQB3-R|1L%s8k9iQAFqq_&<&{z%pp(GsP+EOS*ppBb!6SqK5M$|y ziPW{b!EKW_RwU6P!oKiW7sdUIZMk?Ds-xZoG}4LqinZh3qBdyK(x041sH+iG(li6B ztw3c_tLY`g98qUbOO>hyas$(iNT_PPE~oIkQzhvmf3?`sWEQgUeI7(DJ^^O*r!l zT8ltOySbs}J6aNsFt0iW3&c`AB|TuFvlh?#)gvXJD_wT229vv1yT6^)?C9oVb@LKw)}%^!?X?-EcnDdTP+FnuW-1LI!4;K?FD zy}XnaZur8MoJ&*gStM-e&M97Cq+DbF16v6qw2OJZU_7W{!>))3l!p!@-&q1J>uP%u zsXkyV$8Z4P;NvM}X4N0SkmdBwx%_Zu=#s0}L8aENX-% zpi5{h>hhe6s?(T6k$anF(wP-UUTw-px-bTVytOSXTt||AXT@BUj(>%A!z6NyB$C$V z7c>A@Y%G&?i$>xTL>x_b!{&ybQR5bn(?u%cfs-_;BovDEiAnzto+W+~MDR zzcC>-UF7n||7p=rWO!f`y}exwS)3nvo+d6CptT4xivnKKFGR;uLt{GxXbpmLga*Yx zMIIGhNgCt5qR;_S14%ZbD*9hnv#ltHmR?j6)DL%v{(YLBixFqQ_X0aUMc30(0)lNj z&~h8jdpAstDK~uE@6iM5Q$lucIIUDx>7l8GSoB9OH^|t{>DiiG=P^u!kV+uu%tnS0 zK5?)t#-o#Q=0q&I=S`Vphf+mW=CEK&Xar5cQAkkKz3Sy_@i6eH3aKGV%{ZSL1|Ptnu@Iu_Q7zF-0v|xCdi~ zwOFauwW1eP#l4`8Z+}HrvrXKB+A7B44>pb^#YV6ZU?R?gsIh2+bT7vNhtP`Z6YNyz zxJ@O^T6{K*Wm*{3+NFaCl8Zyu<`inZB_LX~&n_BnDExJ9BQWhX>N+@08tRCvA~Rwt zdp6M*;pFnobh7YN4{jBqJy85|C0i0!Nn%{yCJ$gk=Vr9e7H5_%uG5|TIx_? zgH9M7)8;y=&mf8BMS&x%vRuParp#nvmcz1{ph8DTC7yXDfCKl>@(bxTFIU(7g$xC62pI zFQctiP~^tdQu{CUOpy&e=bmjMFfeTjTMC_Mc0b_EFOZFI1@zTt0rBop9xC7lG6sI` zmd{mM6y^j;6}m^F`~wpkg?B3vwbm0Z^LN2;5?q$!0Yg?95G{;$5W+y^eAyfk8j8{( zSm$jF3-;%M$RQ$FibkY~TeEHq#Sb7anpDVOUlu@ZVQm28=0=0)f((02h`$_xJ&6}& z+kOS9Db|z{kOJLCwyw?R1MoZy)Z7UuY#k18N(Pe~#>uL~Z8&`?;a2x-b`TTMIiNmL z5t+EF;fNylK+%k#Z0w-xpf{pO@b{w=H-cCk^wphct}zobCD3LaMYz0`_jt3|K%@RT z*yvkx&d@bA0WY$onw* zdg5D~yk<|A?7gbQs#;h^s9u1#v?IbvDfZ`^VilK0Na6vhU<+WDn6~H;1n9^XJlj?* zp*};}YGMs?O~5A_BVpLopFsKN6(}hf5q+y7pU5F~hTqjm3|TWtk5DyQ9mHf) zAzIU@z>rl~O@}PuxI5`t`%?H5gc>8*wLmLpQolTBE1Zst$q?2U;s)1pvBWe^xUgZZ@VEc|;H`2NkrS=oqxr&8tp~HA#xKgdH<=O&BCfYn%!Y+HAq$XeVi0s{Sq!LonE( zwO2#RkS}U?0Q1q5;^LAmkRU7!#umYM7A_$G3<^)cG1b`uXv32w7%pZH zlyZ2sA0oE@TIpCTezp~W1k?cybfT6a!ZevvdF5OZvFbo?=C=~qeLWokgo6PmoEvw< z*FuPnoLq)S#atRx%z;{;HUQ;n{NHMBDHG@r%lQJK#49v_EsF6&^Ym794W8@B6iLdN ztOy-I5BmSgK!~6#W55-Y(pbv5N_~#mjZQzPv(dt2VY2ij%VJ@uG6`{JReJk!l{j?9 zo4^rM*1EXoL#Qf7c#0ucK)emqrO<7ZxfIhB!@4XS;j0Tl*5lE12D%~@Tj`Ly-W)o? zB*CftUc{VK;SCURYoix@YMT|9?wc+>al24zTisS2snP^G*E8=Glbtn`o2Yy&?N?AJsA3^W_Q0o|?dLSq9A`^9@ z{=>Kl{dEQqG5BXMl2+KNT6mf9W?&To_Ps0mB&J>ySTQ-}Pkme=_KFJ8$sbG`5;H}R zm8LSkN{_EO@{fH;2sTxcl^*`UXPG#a)>?IO0Q$T-uvpi_K&!-znGzcUckdoz68OljlJ+x5j3zc+GX=uH!P|Si^ zb2BfM#s2cerydDS^}3iE%Y{xiQeF9DiDQp+!~+WHUpk`Vs`2h(s! z4DgdqObM*tn<&{~VjTtKgrX$<*l4(rjW|)J0fLw7BL`luW3_+qwE_rVn|#R9ibJebYq> z09R?WYJk_H8X#6mF&5CAn!+C->y0M$VQezwr!5Hz1ey}@`}oew z)4ehCeQ}Trmgb0oc`7Hf4z7U}i*PcMcLG*1Uq|oGO&JinpQ1P$;VBn{B4vUPdufin zV`P=zJ`p5Fv86LAoF%&aQh4cF%cpQM3>1D)h5`?21y#y>i6dN=K>DN7rD!xYM*b)O zkd`GK7?SFF<;^2x3*sF(`E=FG97y$PQjh)*nG(2?3I~<03t3eSKFaa{Q0BBE`;S`b zoSv=OK;WWPB@q-}R{&(gv=RBoB`}Xk8rlG0`4Y_z^hokb&3IDwT}UEjM*%XCvX#Rx zjvwsXA&EZaf}O0WO&%263+0irv<|qv8_~`~(AtwOG-(1cet5-zka?#sA@s~}7Hh#8 z@M+N~IV|DJHL&SKyO9jo0=_(uHqo|ZM4F`;NxCLKPZ$+#8I+hZ(3>8(&Ym~(LLMect>o$fAP@tLM(Bl0$H6D#7$`m!yj#dd- ztZ=9*iT`3hnpu#kG=(|2^$<3URfCgA!yQGiNx~;W3n7?e6!=L%w|QSnHTQiL4h}|V zA^DNA6RQQpuwjX^;@wLC%LP<%qm!X$-~nL>2BtshAt)|Qr>l)-6?Xe8jJoPF2-z8_ z;Q_`-kPtYBfEA^p7o%amLA8@YiCo7%VWxC;tpM~JdE^YNs7S_Xz>6qxuy7s(i8Jf9 zODrx+J4IlUOLiJIEWVZlpDj%)AaODjBG=4&pcZjs0h89Cd{<+5WkQ(+<{N|H z4udo6ix5lj)sCCZ$m66UVpog<(R~#|0{aB`RcMEf=VJ_zsOo1Vsq;}wTe5Kf@0e}{ z31E0q1zbgjjmh5&i|j*}LT^NQTZ#ce3P52n`KV~c5tiG+ib&F8>b|;ScjUJsYq^nz zO#vIO0N#RN6kzvmBDUo_76)uIk+!+^kwKbdB3pnGcv0+T!s$N*j{69eaJ)sH#dj91 zo{Zf(F7_M4kRQWNsBogIk^np|bp+%X$P14X*TC&YRaY6YC-hGkive1a`k^T1dC@>X zk`V6bjf}7|AYl-NER0~!cm5ky{K--MxI_@;hPH{f zTZwEg)Lu%J50U~$i#WQZ?W_%kI~6@ph!QJog{9WRB1BZ7DzjsyA21y02|ej8RjQ_a z2KUI*&C3Jw4B~{smZa@bPBgMm*i_6M3JX?#N`NFb;DHN>cVR?ng%=qDYFXXn>#?Ns zGW2+yYt-#UA?eI7?@JD#-Nxh#`{E#=qJ+xjYZxJ%)-{Fj-p;Lfhwo1rl=dja38$?8 ztPCv7su76Yil@I9F8M_v29uZt$zUs>ujb(flgmLIl<>^;fN;(~hmi=7kP+9BP}`Dqe%K{jX~3oq84$%j*q@QU3o-brVR(r-~H!;I7H2P_hE5JW8s-o9FB z768AmaQLZ>VgykzFIyxgfapClsG>I1xf9T$S^($_^Ob z5}O~@ZSfex708v2Fwkc3|4&MiJP_Lj=Isy|I@C4(n%PDNLTxX|wnc8fzJ_qAJ9w3@ z^_A99{7=O6C>|*K(11TN&lG(^i_+ehwTTR0E}`;J1{0jw00lRPv!AvqhMZ{Dpw4gO zX31Nus$AEm#B>MnAXYNyY)kZZ3@Citee;W(;%7jG-4f+~`(T(B;*j{rH#HQ_93IOo2 zVu`%htsFUJEIm}A0*1vnMA;d196*8exTQ~hwA=zi6A6tdc}3Fx-uKfydBIgV%6iD8 zI3o$wc;Co<56~#$TTGwZ_ogI4OS$-59yV>syX(dW6 zm!;7yZPBLKeW|3>O1mr*w#e%f_hb*@wxrD<1YHIvA+xa*Z${lz<2egcx>` zfTpB2no`RRk|+R&?FHeniU-gkMnqdASjyWWL+L#CgGC$@@fO)0^hS*DclFvz>ua)w zo;-kYlRqZ{C_&hds&HM`w01h8-AzWTPy}iUwH8jYIW7^sZSi7}7yE7wgq^52U51-X z&9O5xcF)IO;aaiWXjvhZL;D#+Pz}X=A>BriB+g;0Xi(H@py;m1ENLob3zUSZOSR%$ z1>mcZPHg;^5db)B{NI{=)m$y(U$>v)ny@)mN}wxNBnm@9!@%nC_0TI_lyX5uytdnw_HyfbCt4#@8l5*TUetRjVr_((H68vch^ zCDeMAYk#Gk(%AyuuzGfYFkrl^26i!y+w`l~tDUK~b+%s_OE+MZHX|^>+Y0|vHeG%} zTV~mCOJ)OMv!TXQz=b#;l<6$RKT%1-iqj+XQ^1PAp&Z*O$7Y-WON}%mm{;nF1H~$w z{G~YZkHbQylK*FJU;2TD*3Tm~sFxy?YPlN>glbn~>c(bDwK%9{&+@=*hmAiEjS3NvnJosKNKiagrW?@* zYS-WzELHLr(sDut7EmN%3OaKI*)H`E*&muNnD7&TLs?|*AQ%E9S=5Pv$KK&!7>Ju; zjt6nB1&s{pFMIUOI*5eeSOlXr9_(}yYN26 zR!WHch1I6w;6ztsn(H+Nn5@8b@2XXt46k0P)oL{atIZQ&=mSLNxfEMH!Gh_?cUxqm z8JqEh*w6;%Yi${bTM-PFqZm9b?!#9Dg&_j#W4QF&AV`i*&Nw!z2M7U$PK|KOM_B5b zL%O#ZngPQ_mHMySx@Kifgm9s%cm&K9aQLu%!+qSZ6Pr>m!d{64bvD|JF$-0uPFjRu ze_{l$8*jEztU<7)Uo0|6joPr%{+o6mtwzdWFB>m6w@eq@>9A@fWPS0-QGhb+1z)r! zA?_CtP~x*5zJQU1gRTQ0lF71lc4|vX`=o9O3@chfPge%zEUg$GVp-su9t1R5^%;rK zA`@7r7%RSH-a49T03Rx#mW5Pe4K7$vyi_0|pdXWuzSKZ83G-2Q8M=cqphcZcpbV?# zIg=|sMhS%|y-$cjITbglGH=QW;uR{+&FB;ntSFMH_AqIu}Kx(N<7pku0gu zP;}*;dOsgHQq*lafKCKtJC75cz$nrT7U5XYli|dSK9~AYplJk_#v!B>=cNTD1Emue z?8}lEMms1Z{L&wgQ=PtulbyvZsfrr2X5s_NC+bA_u}MePLF{UxX9htCoQND}WJeeP z3p4k1TrViMEYEB@%>-32A7ZvFNDu}Xl4U`f0_iix#jRs=%Zn)ZD$pRy`IGjJoNj4X z6d5qsTpRTVhtAmYMwJ0U6DzBl9+XuQQe})rl_mN*B@s!9j#^6QvcSPjM6RaH2cc`G z{fgE|-NlR8pu@6F6)zl)exDk=&`7hYVSU%`xOQQqZjhkpW)c9)WSmYW^_$K?Hmh?9 z1zTWG;xf|EvrAeAx_X}Af|{DZ*~}YFp!9GZ?h}4H)Wd%3NW>9O(^0K##^Y_RiUKG* zzkOU((PEgI%wXJz)=YLrRX8h5SoT~1W2o~7OQZBlD3{w_V=ejAwOL$H zc2AglwRRK69mX4JgW0Y{+$K<_$XE-W%0~flmN5@i>+Pq6cR;nYe9m_u6@Q2>*D2PB zmT+eQ)E7CPJa@>>3of~W-*7Q{VnFEya*RBaDn`xBZV-V`RMgaF{xB>_(}zi!>~>su zy?Ha{pf8|ktEdd{ImryDO+L0eS&Vynw-NSx?$?SUQuHAdV)pleMpA(_qSRBPZczMG z^7gGcBIr`2oEO;dfWgju&}|N8+AtjhEt#h^rcxSL?yP+AUb{g36o89Njnpg()lE>A z0HDaR?hs_X9OjRW4U6xuF(*`qgwdmKvgj}mIw!6Isj`cX^c`aai0PQ z&j2*SuFW-qo3%Mz$Z?>&Q<@xQLelw@y*g7;T8mQ>@Mwic&B9*oL^Tjps4Hl>W#G2& zR)7981!QRflV3qnPb>KnVJbvK76Q;pLFz;VVLNhxUJD(JF(@#_Fu1Wq3e&5i;m-&< zpazAoX2=m9%g|L%9=>UNfr5_GDrP+cnOTrz{!rvZiyYVwQBRN(_2 zQd>`4?9^-B=Ht&778Ui6jbY*LHfH|0C61~-1*DLGx)t$HO@bII#p_l)&~ZKAOwh3e zC@?mcF0i9ha+{l(LPVW=L!MKEb|sE;&BhW7HDdfBBiUSR!;-j4v^-TiihC8u9B?Cwj#i0lv6=Vkrih+dp`7-4DD1%Qr zwLqsB7o2X>$}I*X)dsaV4a$2`rVfr`h&gzGCrsmt=7#hj;5{zlUYtvwS#zA52N|mv zK=TnLI)Xs#aRTW8rX*0d>>G^`fwrT8}pT9WB_6W%6r6QCq;#9;!NHYM5>{KASUI_R;M z3!_47bF3M32?pWpGcux!+Dtt`u}-ZR9gtkuemowk%))~K0I}4Vn29EE1u9f=G^54% zphuv4-ZkmvDt@Gjr=aoFvTaM6)rzcqGEujnxEBffQmiD~b#9<`lnt)OwJ6E3z6}Cf=yhE=o z`bpX1B5NF=44fh*iU-4Yz|7->no1908fGHpJDK2xreX<&2whRwKLHuOBaa@8P-};5 zQx?-qO3-m5VASDsDAyDJm-4pgk`j43wXCDkA1nF6vUt|6J<*yKV8hKxH9tMvy6G91 z+^NyVWv7bSa=G290d2*h8F5Z8LpAgCi3@8wV}mG%1K^-35uoY*pW+vQo~jwzjI{0x zKPNPZVap&=vk+-W^DM60ilK5cpSl!;4{oD7p&DB!otxHBSVZjcHgVlmg%g zl{BaZNCOl>)8JXsbyp=;=pzdFkb~VC3mLXE(hCBtFft5moifY3n6!D)3~w@_bU}8; zuIu)?K85TS;*z0~>vV;ou%^-p%zzOT*&wkM0Y&e_!X6-uc$Wj-F6EV}=-}rgn9x3q z8$@$)&dnUHi8-`q)B`W!A09y1Y(q&w;9RPdU7X#7vNxxLIxylcLnP=q!tuaxK;A;Veq$4PQHVH}V2nC2CG@~^M1mMUBNir0w$Sg8Oss9vsey9 zVPBNkaEm{UD`G^oW$>tSIVUMcXf6-FO+-rSK@{_M5ZYX6fhSdrh!sGtD%>v(T7aoo zg1-pd&=9e2POy`oN^lsw(22+fu6F_qX;zqlmULv`JN(v&qrCZ%u^SvQwkNYFO7!qk z<3MhsOl>2r=|&u6@GpMBQcWMxyL%|$M!1q)Uf6+(R9an)Rpz+R%Ar`D)jpWJD6!d$ zOra7Q6(tfC5{)@2WIpQo1#fU_Pw3qSasP)Qz~M&NtdSk^A{_=OHLNz>7&@^aRDl>Ev7`fx1&v^Q^|PEq z0ola-4;n=?Kc^*sq*n@g!kz8KR8}g4yi*{9mj_Pb?F>Y2;72RsYv?-U5k=Frl3vMD<$8Cdgs`-sLg}6K}LlKOTj;+WM{64W-AesqJo0ZC5aS1+|nfF!=T6^ zHl;&YKxSXdqPmK}nyuhQpA4kv?oDzprpiS}LC~<2eI!0sek4+wN7)F)PO(jDL)t<}nKx>sI8_s` zz!7tl4e_L|>9UMY5}BtWx}}AmTNAOU2s#*FBDEyy=(f3icFfTB?zSRCLuSJGk@ocB z1gaARP$s*}1!y$o#hJ8YTq_f0IiGj_Xc}u?k*aWdfsCRXN-&{1XIFa>9E7ZtP1Op9 zmNCE4utY1}-p%{FSMfT?WecDHVSX_uc)B>Un+{74$Y~uTrACf&ec@^WtehGwN&Hi$ zYy#+&le^D19$U*)@7NnkS<>{7jl5Tkevgj5mJ!@F2rHH2#~lD)a4vkb_Ccp^on9o8 zP8BfVNu%mqmJnD85wu2*CL$>T*S1wkyJErZ2OJN=A(aV`RkGwAGztb2Hj`fNs$Gio zL7Nz-5q25UJpfYc`4kF4YJ==Z_uJeaWSD!gi`f>Lq9~XX8l(E#xt2N7Kxz^72_nZY zT4}!@*qPGyCquK$b`jx^jW-Y~%rh(rOpR|=MKBm+ZoZvDwqbfV^wMJ0M%U*Rbj|?!=U=A!iWU&mW2Qa*FalB98Sb~mac|ZYJ$uj zlAWi+P@ft{th&m08JL)K6f|Tslda{rj_B$72~ajKLD|B3Zf!*uN#URiAv7BdyO02k zV^yxKEm7tku^<2~9WdJ!tV>0VUTi3U4@gO8K0ZkqD=_7UgQNsg=j{Q25^3=$r|o2K z0}(Yd2*wfr0%XnW>foo8a=;WblJILGac{CK=UTo|9!$J*0WjHy90X=4Bh(9U4^W|n z7@?-5E<}I^R4kH>S&gQPm=gUJ%ELAgD(o;+$wKibWJJ)e3v(gk z+F`O%7mM?}%*l{_GC!Jsg^bSxMYvAQ4p#5hoAMvI)u#?xNc{k5W&&<7^6^@6OI1Xg zW~3&Yap>>?F}#fx%xJ|;dQ6yExC#bX@b+jhr8_$%nSsP}>m=_dyCZIB;zQO=g%Lz1 z#?ntPb}_IjDpA&Et#4_VI7Lfg#=%1nzqrkSi6FRggp2o2yp+Jj$_#-wBaKq7H5t~$t!2|xep)U)sKKZRdOb8skYr;Qsz#XN=@)U$ zKvGZAQiq_0b_y@+(N1cs3(ZxDRdCGbM=iG#m0JLH{t?OwDY0gMTC&nPQVCk7;*96n?%M0$O} zyY}XmOD|H4YcP4>V=dwcOBz;c$W7(-21+HR!*D0V$=ga$D5IV!;|epqAaF?S4hcJe z(0fCeam0HadnFR5<&o3=Ff-px;s)v~dIufkR6}2cLj$PePau`DC>=aeCDLM{NPUd? zsNtr^Xkl>?OQ}meHS=BpQ^#;h{9klznQC*Z47Hdx*OaRglY)Xv6H*p$s|{v&aLgF5 z;mI(8X@y#8t7Hj7SaOw<62*abYg+~eNs?b{k~Ks{svq`(NwkZYY@myS?Og6rzhF)R zJrCHFhh^dDB37YOBX%L#Ta=*#Spg&R)!BfizF5oeNjLylCP>II24a`>cy$F(SCOz1 zB@J!ig<1yAl63)fBPO^eiPIDZd-XkpX0$%d-xq180VO5WM_Q77G=qG?I)2n$2*?D@ z&ah_!BLmQNkHXPL6drs<^mN89Z-BHWv3Jku8KJ_W`t*d8OCvbDHA5U2Qj%<-Sa=?k znhz-MG>P<{;RL7w5yd%!u-J6fwA|t`j?%iNB?i!hK0Gs&bgJhzA#MKFagn=}sZd@VwH81)hKSgOQQ~xQRekY(Ez~@vz zAd}pcr7Pm?E--4(eK(Y*meGRw_b#N6$0uq5#L2iKcP@kw2Pz1RYeC-;Y0(J+4Hicr zh=U=rniO~jnBFLB2570kU)}I|jZ9^09Na1Q#{p(k)?s===?@tbWSAy+ndX2pV#v-o zda;ADI3GL|E&V(uhT*j!6Cq4l95-G*4j6Uta(}# zOoe1Nk&DC4pp>@#tQ>mJNum@<%1EC394(QSBt>aRJMC0LW++Oc5JDvy zDkORCb3`RnN<;H)7i|rVw?E)~IP1EuUzeE)u1qN5*Hi=EcOpc?w0Qd48YixBOO`B? zjuFz%_=B%>r(~VRHL)(if^uzwh{@zKAF9P;Du7@kl@Xt=dK>^z1F{mfr*-EQk_h{EoZ~$PbZ*g%t9>j3)Z^D(laZz^XygWWH&0AbEchT_KBjXO}k-Xv^VwMzCjYZ^}8@a ztDF0u(oMMV#7`7Z=A zkNYTD_xihJT~fJ_seF;Vp0A}!`QEf@X@dBxB^h4RATlI1lm zP}Xr(uzxp*rj0)XudeRn)Kz&fZRsU=uqQ*bahk#I-wk=B_bV{4ixI6e_rj18KUlxS z4C;JlvVV~=ESDK47|zQTCk2_2qw!F_q4NQx`Xl*+wK?g_7DKP$XTWP_yilBRLev=< zDJ-t=VB7XTx({Iewhp2$%Dy17sbKbO`(`0sB__Bygpxp&+lcjZR|!6w~z9o zc7xuiyAl_PJ%2dy4Gaby;i{>3&|;DSpZB>3=GK0q^SE3Hk-o&i>&|c=lWKT5{<`E( zo{QLRSYOz(Vk&Ma+9x@9qZF(rT!2H-9b`QxPLN8BYfmpT!@PBoY=19LV3(I}Yv1jK zzt7a%$A8ly=amfOe4O2VA8KG^@24E5s4ICDsRi5r?gNJjgKJf;y(X`rmUxdA!|RWA zLj62-IOc5Z?tNnqTRaLx^Y*Jkn`xbxuRcI*&d8?BBX;Dj`~=S}KcegE zt6VeClE42rM}@0`v9NqD>|9$(8b>FPd0%yWoH@XKeX0g7)|kTl^&F)gJx7^WGI(CN zUhUFh-mGpTN=E9BFUB%ET2Y<0K}>mvpwl7)_grs?H=f!+&qYmcZxRb(hw1EE z)2^+xCqJCy?FEYev{VVrUR{GewS&>)j~U*JyD4-SeL}k#eK6^FEoy&N=79JDVcfvi zV(S7$4ADCyo<@194hd5?1n>{P z?U?m$08U&m7lUFy@tA~3^sH1>yk+l>wyD=fozMT^<~?ix)Qzv%G ziQ>uU;(6EiTiEA(035LxPOk&yXzQm}U}93jS;{MM{*NS5|1=)qu7xqR zope$+ObD>NDCxQRqcCg75ws2W!G~Wa3&9_cLA~)eQoTEs+%B1MKNAV&El=b#&s%Zx z#{-}<<2Dp*%_oPy?W9mrCe%jD^X1`_@VeS{J~wGF)uaT79YImBc~u;?kB;O*182+& zu$2y8R4o1~FB7ArmHhFTmV4;jd|va=rKX`_7LkqCEGk{x z8{A5waqL@l_fyx*@N~02XT8&x z-p&tZmb2fTeXw+Fw;`lBrEPp(LY93`m`pSniM<<@&yIrHrlc&P0I2*X#F%Hy| z_i~xZJG}5C5v>QWz^AKAsDH*;X=8*H+V$Vf<7>v_5_?Tp5j78H8OKxXhwiYW?kN23 z3>Qv5+X;&XU6Z(dC+<3G3vP?#DZ*wC%RqO;M!U@Y`pKwKMpSAqRc(Qy{Q415-=A{ zmOAs2zZ&pyXEHV@L)Thf}u+tj7a;)in;7527kjU2aqF}FL4NOzh z#P6xI$n28}N65+G#t>7ITpz{ygAL(AzZy7uv_vRZxBzuyKZ+Heh?d_K*eW`f{eLI0 z&99N-iJg;C$HWcAh1K*!IUVv7jj{9gD3sY)2dC82@%D^rI-7ZtY~S|cBmZU4>h@QX z<>7ZI*mw}KY8%$|2^Atk`m^w931=+NlV)wR#;>#2u*!UW=q5K!*ybCHwE?MY+5B6a zxa9Ya2j1kb9UJB zN*fcQzx5y5{BRSW%lbk$JiDRBDQ)x#D8&%9-tOu~*0m_Hau_AAz{I} z&ooEV1jVSC^!N4$xEIhtPYdFN{HMBjS9$aShsfTF^srHT@}{!scHr zV5+h#_L;p&)JZ78Qo{kYwhDIe`?4NqJBQ$@M+YSy!`j8gy33&b-+XR`xk?VqK8Xg3 zrsT1BBaNOilXsk!BOmL1utM34y%rr5;tn*>o#h8{_QG;{<$qQ@ZN`8tadM&&^DL-em{k2ukFD23<(wwjzjm2`S4r%5=Q@* z29F;zs!ccNNw1&M)SLZSKXd{d*`h&tDt=rx=nt&EHHF=TK)m+Im}lsl;NEsC`e~vB zGZtKg>I3?`{O@OwpY#!S#K@yf+!SoRZ^j8`dxXy=MC$C}Hej$EznkdHF5g;scheVG zuiclgUmS-S<7+4|CIOZIWU(qeS63dV2Gj)HA{NzMEIrIPXeRj_RI9yT&?M6b;;+@xg5 zwhc0D=Q9vrZR!vs&s?D&&bs(0Pyx-Y3TR!$GqKvc0T2CS{VBC(FxKfP#hq#s=LWQZ zY|9qDF>(PGA0OgA@zFgV_u~L$+^*sjPZ1tE4(7!Rd+_@y@%ZNae(|h|J$LKd1NYB5 zEAf1yi>IFU5C)FU7B9^@4OzwpoFA>mWnuyw&3F%;nMGo3*=W3M_aCjkc@nnGwM5b! zM;|hLu)=+zkR+pn6PuSY9 zv3FVMzus=c*liDC!N0#h+J2lgW6kk<;S;gocLd#%kAeBsn^^Yh81an1G5psqVEGey zIOnvDZfg`lZoyrNWl|(8Q1lhQ`rJYP50$j8DT-`mr*q@=MMc0scezsdtaQW>TCcQI}Rteq%WhB{lnmDV-o&okwNdD+odl1`tq*yKAgKUlD2Gh zW*>J|upgTYP4nYK*6)Y4#aR?Gag%V@q==qdUy+XSekA!cV>>Sd| z&-*gU>DJY;9HQnzsn;s#V(fUKA#VrIK_I0`fyeWC)JnZ;cz59byiBhuoy}>vdH4>Y#LE zTN#ve-w2R@P1+{^Mx4Iv74)`I$CyhVcz$dO9JRSDHr(DWriOUZ>lbgx|G{kj{xe2g zx;+3N7Y1|t!#I#1KbU^F+vE3!?b1hSF6{MDjdmuLiam{^aK#dLlwQ9>HSx?04wKp${F!#yhHLuFKfyNH}fT(g)qo7_iT48`c~gjo*AGp8Z{9|Jy%(@=SAb+) zst!ASyFzo`FM=MSUMO=qo3?z6Q-YUA2swF6ezorfTJ$92Gr{xJw7j&_{>HtM3tJBrc3e1^1n=RLD5-jh# zvhnv|)HO|}YcbpT@_(^n@Ui2P%KxUbt?10x0xN`J%lklwQ#jZNcVR|}EvjFc2mAex zkb%#3_KE#PV|wbNj_+LbsX8Yp9hT+c&bNh%d*`49D&D?|@Rk;t=dR)-Zap~j_ATkzbke*#bSxSr=9u*3kEe84uW%i!oIJr-PDgWFSpjUa{SEE~ zCF1ls-SB#(9XjorjknXX@LAe$es&}md(CuZt;iCn@0QH_LVr>HM{{iQi3F!ePoDHL zfIV*&1!2txRA zoVBbQKHha4Ts@m;aP>g(uTL#y6%63tYb^Q7`#GE_C$NTg8?5h{F0@>B#pQvc1nqyj z9yrH_?BccAK8mO^#SsV9YlH54IXqHi&53D-_}McRu3sI<7lWg*xWSg&eMe$HuWda3 zK^vTFu_do4UHUX`4-6i)h_^Sar+(XyiB4JtyyLJ4FN1f$@SBm~v!I$<^bgeJub74% z`4@zYmVx|mUJ?%%=D>p(T^KOd6!#B^r`PN4F{Vuyclq|^AuhWyqc)M-{@rd_KWl#d zwMr=M9t$oXylKihSJWvygH{{udBeDL%AYcX4Nogm@|7nLait%7$=Rd)G%3Bhy93>- z4gvLWp>a#qIio-#Y?^$5N>|S2kURZY)1(}p?%7X`WpNx^y`5tf|4RSb$Ki{Es_?OA zJe=6s8~n6Z;geVS=(u<;-B=cn>%#hTbF@Cn{Mkd+hCTVmi&FajecnIDwq*B+CceC8 zB(6^X14foDP)%dG(D1UPTemf+((|RTa{n`EPH-ntvE4L3$ydA-F+`kr@Y$Bl4rVScxt3BIC{A7{iD`gJY)f1xnD(Tn|k8GmS*r< zw;nESJx+=>8L+P42sC`$K{us0z-ah+;gy*RMy$U{v|%Les_Vf=mR+Z39|Y+1tfsBY zQphFpB$^IA4=+Q*A?D~R9(AQZEPvuC`oA>d)z$;J*l;GUSyx%pE$9j6KQ!iFXSYa{ z{de(_g$u~?s5b5knj_floQppO&ITKqS=e_#Z|?IDYfi^Bh&76t52OO~B z;UA6pvzHd-dWi7cItg}F^b=iw6+&Co4KNJf1CQq(!SMvef@>< zKKJD{rTUotB?q>Cv|=;IS6qLt1GKD)s61yW{?0Py`%B_r%$^+l?%2Tt9BTPbd~X!D zM&S9s-SC^KE18!#!Tw2dIA(iqZZMvOBQvAn)7=Vg{#_#WZz>i_-mb@!ty&y2Ih$Tx zF~uE=rS!em7YLs;k2jn%z!Lpou60_;@GSvydJpEpR1e(Sy0WJ4m2@#>=LN7e ztf0xZgr?Tr+#mhE4Yy5T_SA;^<*fJY4oSJ&bk#$EMq1Lc1w`{jSPy zM|q;z*C;{0tQ!>xvd4}yeSp!)PXCrSrRBM zbhUabEBz7UfMdN6a9_;}&``3SJlgx>-T#11p`E@~CWFIkfBthXlP&z;NdGvM2?aai zQ2$q{P-bO=7Ag&3EX0$u7zSAZE@= z_d6&Y=xxG1Yx?uV!*b}laVNb$@55UDvi#lc8Z3F3$Yp6qAnbGjF8bsrIzB%46Tb8G_Wao@QP)=9z~^V%ps_Iu@aak%uc_ zeRdK~KX8-Itr1D_b2yLbR!6c^4@(=`Z-}uQdt&n6NjPvv7qpCfDy}?UFGNOk=Y73S z(0`4_ym@35y=hy*_6d7AN5;Ir;EW(NB6kelPJTOf@j=TxF>d)vD*W;j?rYeQU3nyojJ^+N75u>G zWIrnJ-V^(dDMd@_ge!N_#K0zdPI`Jl?56*o%m#Ilj;{=xKHQH{QeUB?_d#jE6H^`< z_5dy!YEZ9vU8El#MXIY`NdImej*2N`c*M}TFyTfteHl~%a{C^Lwiz*E=8IBTyE(k3 z{QfXpvvn+5xXPl5^?wxBWym~Bi{j!dN&R{=Me0lsvQ zFH*^hVUT%y2kFLC3M&J%=*`hxcx~HVh{#?8uGZmn?}s&2%O^>mYp>>a%1IQau;pK- ziQ{R*4sdkDMG{|66HR|B!qc)gYFed*v$yoc^Bq57pXE*%{L&wL{5(x>i|WO)piHXi zr9t(0RrEQupM0#xg7eZSdg^tG)p7@N`O@8P-qYscBnLS-eL+n)KJYZ`o27#L<2S?A z9!Gd-qYmHv=_1zuUI8B(&W^q|&sB((JAgyZU&e`r8f0a343GBP&R?GT5y_3=_gTI) z<7fwrUNw$i{LzBF(I?qArJ0>%d+-qJ5oi>@8r{=fkptB5oWWc1%f@$-s=NZ6zBLv< zYkART`3UYEdw}MgnE}qe=gBU5605i-(X`)}d5O9{~k?`McW8T+i7Pb{xLiS^Mj3~(xMtna`zbiFyYhM%GS6<6=ixY8w(0^2L zZvra!9LkSit=Kkv0FL{s2zLvwVqlvo9+Ka|hl)eE$HjcuESv%pz1fr_51s4SSi%n06|&_w+cr)b)bVf0ix0j`a%7rUkfW0&txk~0Wq z^>2#wW9(PKVuCtOziY$!GkZv@PdMSiZ|8-Ul9!;i^*db)%LDJpkEHgFvmo2Dgl<$E zq4`gD!`41y@pJVvu_=8w_k3r=lkV>VtutL9)Ad^Hmk4C1V2wu&^YPT-<9uiFc&b(P zXS!H}JAxF&etGkF+pxpJp=d+MOgKS%EJkt2 zk?EY;?G=4~vzyDWZkLo|2W*qk!$Y+Wc;D!&FxNy2Gh~nP(}f>sX-q1nP4I)atH$B+ zr5@ZmCIkWh(#Eh_vi@{QDmQK$MomnFEL%-_rgD}1cRrx-McQz(Z4xi^`Qr9#S1>x9 zP2dr7uB_lXfy^El!S|&;|2(D-?|-%m>m*lc-IvMuWr7Rq&$dBtoBph0VTvhV9Vun5 z62Z&@Aw+E?9UfH*J# z&j$|JaXcY`G@c=IpcZcpvBP(#+&FQeG9KM_hCCYfz^r!> z(EE!%x46i-Zx}G0=No2X?2A19lFzW;Wi@F!XHv!Ia)`L<#Y?(%=Z7H){KIphWa@Yk z=K9RT#xHxIZuSq*{E!0gO!DaLvm8#o=*JyX9I-Lw5S+ALhvAbtrR~jj=-+(;T)fgw zPR&~#Bh43 zwwOQJCSbO{A`W{j$16AOg@vyDvE=gysct(wDdZCE^4tL$kG?_wsiW9zUW-twKN^n=PQ$b7 zXYkf5Cj{NtPhwE7OlX*?#pRX}{I;MGcCMU8l~s!Pw7v+h+{hKf?z@t9+g1(>FvlfT z8UMV!khJ&N2@`UE&}Nwjun$|M&R=`sm0OR+$t~HGJ1z(o4UZHLzTJg!nLBym5H0S1 zPK|dCUx2?2v~klo3tl!QAKXW6qtAv7(uel~x$NLoELIwcn@UXS!H;|N_y^Og^^c%A zBAjnI8{zq95m>C&1nnnZlG~RXlBXvilx;}?jxJv69gdNw`!SO48AiY>^1cJ3XDo;gq8 zy)YTy=06llY=ZG&&#!P$Z!d2%NW`Ypp}e;DB-k6gmoDf|67^os#tC=+Ww)tz*ar&8 zYT|N;{yLYONTw>&aV(EfF2dPr!!(PTbitjA!+7#kjnsd;mE>#=rYC=b0G}t<`JA7)(V2ku@%8ToTS$kc1^Q|LndGIt{ zi1-dmm)(Ln&c`V@y9pL9n2bO4Qy@L?Ij^dF3}#Ez_`sADRF1huvuDWQoAB{hj^Xev^3Bil4M4 z#tcoAKZxP04+|gVoUy>&6(^dtfX7m0c5R#|@d)Y09#4D2qB9v{%as@kyYLvg9nutJ z>h*a|y9{fdjpT=EcZE}9_tKbuS7?af`ddv7vsa!ZCYt>rNH{3tT&ah|fw zqBt_og7vpWP=&u1DxLNfe>K&ByiY&8BQeG$PtH;|+ZG;DScb3dR?<()AHwSK|8C=f z29Eo%8uw3DW|veqKATXFcxn>nwLOD?hG}ecd?SQnEa=GhDfZ>>rT_{jVhu_^=B$A&SWj=G#YYj96Z{UMHz{4aI5}=#ByI6{L~JG|m$C^!r>;e>9n>~&T1e(A=d#PF`@)Ooxj62}4Z0NQD4za#mYP%llVtr& z18oHx4!IBw_j*33vb-ETvivBma9)6NdCS?}UKW%p-q5!Ce45z19pHK+c1Km)_Buej%X7zep z`DBccYIGc?Onb{UUt@6g%1`fN2-2YD)=zV+)Ih(x&4W}BCZ~Oxl z+0LjPXh&5&tzb=UIzCHwCl3=JuniApP0Jy$SG|JnRo$mm?FQJGyOg>&8St^^!`W)o zUdV|%A@uv;2obS81kZ_K@>hy9fNvH;Eph! z&h$RU#dac_%2}PT-_ZXDP%#QL^BeEFZdU$!%8_ z;j!npXnyS}@yBf+PC1<|SlA80_%J(qQ}rIcv|nadXAQFUljRbL1S_x(jAwkHlk11# zxO4@QTFK&sVJG;?gM7|A8Out3JJ8i>Gd3xcxH{Ajlw$9L{-|Qyp4}hQ_B9I*=KVNX zh>-UGdLF)g4u=BIuYz4rFkLPji8F(zQ+fG$?rHoE?r7!1k`pob+ag6Muv#Y^8J7fG zay0qSw_o7)`U0M>o{s(cR#GIT~9ZF+tUJEzh03W z#>jJQn;qv*YD9^tf#`I95QYb=X8VvHD6^$MX-&CC!&C}6J!mCW2f7JS&1Ych`@4e9 zz##arY7Ty1c}x0a$#&W^<^^33UBU0)`D5R=Ys5<>U0^%rp&)(t3}!EU4bMgm;8R+y zkh3=u^A-(8qvt(Xw=9}guj)k`*2LB*q&af8!k1Kk={oc`{ikfhtf{1C3%m+mCJ3%4 zMER1D*zev~YSYMrH8LGEe4v!dLaK?I{qXsWB`~!!M{Mu^OZd6$9G$Tlh}y2ZIW+nr zssEeBv=R%P{UDL_Z9YMwd=LCls*1bKvtfDOI@Hstqc?}T^RZoD=x>-Bv^bm=itJ8M zn&dBd3kG;TBSq@ICV``M_waGM*(Bsz1+`3g0WAtL7@>CKI z47y2G!9Mil`%U~}l}L$i9H?^l20m}FL;Sqz6+BTrM>0_a=5o8}C+rX%#>_@H>pXG5 zx+CI_d+KbuPZ6`lB08ub&khHYD5z~e-W>3bx+)z7jYxa)oZ^j&(~P0yhyxD{C?+|G zXP1!=Y1bWNl!O!bWVXWH%KcP+Z2=xmX%(;M)zISkYW!aA5i8cuNZV?}FbxINcZ}d` zjmPPVVLq81FM{@UQG(#Hk#g-+aPj$7G~ibn-n^;6#GAPKo*ji>Q^H3_)=-wVtYDE+I(LNb(=j2zU#5?{uf}PYlBUfj&ZW4I@9*eq`Afd zhqPK^#-1wj8IuMke_xBr%~jM(HJY`IcHq=iGT688LvVDlWQ*!%Q7LpfKJw0_-8-{H zw~NWB{9hk#2~=coJx}wNjDn71p~8eMTRFr_m!92uMn5G7k&ev5wVf)^d&Um>Slub; zYF`p&zfxt*6Q*o`Wdxp#IZtcOPNULSpUHTF8Egz|gqqvkc&&UEY<}QKSxJd}?ol)D zt+*p7>*NXnLt07yRyFDTnS^@59vuCt51dU}gRxXgcP1q8q~G1RdSjiiY`Uy)W5j8a znxBOMujk^t6C-J@E8?Kv1~`1qUr=exrDBUyG+{_N-7s|HM(-9;Ep7pZz0`%-{VfFd zUpj2M_5_)ie5~0lA#xx4Nr+kFK)&6wIMuikB7Y%ePD};w>*pwHt3b=PEyvZfWx=WY za`=_{5MGDXOJon!;`*DBpfH~PaqeiIeQ`Z~dRZ#O&Kt)LMh`{OxXa?h;e2Xc7C0AQ zfq=nNp>ymvw_Y39U{8%I@K&3`E{20pe)M+iT0R_=4j6M2KOmQugOI-4PdN1A6S>Yv z5q!r#MATw!OdI=cDyTY-(je>!}0$lX{5<5rk1poJkYF?NHp-umEI5E?n zFGbD3z=AG%5s=E4r)-16LMf`OT!jt8KEgx!#dP|`ZrQYo_FpN_Zx# zDVy={xu4LLu$Pw(O_(v4Icj80y@nq2Dg{}&2^!%z3Ru|19gP%?CIDfvNws|DK z9cG2kTQgZcKb7V6P<6h?){3lv}Ka;BOOg$bxSWGWrxvu^Gxy zN57E5v6Ix)<;4w7(;;!gQ%K&b#LvtvX?|xB{;9You+mYA**TOm92hE9cEXIEFX^xB zN@(sb%NDMaIb?u3H?`k}i=FGC%DfJKPO=n2GYv86w2ZhvY`l1SZXwGZP^H)BpTSz_ zg+*2!Qj_v{(L$V##d4;sU0lke=4_%QcL15l-FSTB3i`7;3RLxOLhYnn!QAE}jPc!v z`LRaQ@!EUD%6rxfS53*n^fFbwG~ntSKjCjbswk zz14Vq(M|Ey?>Ttx^h>OJzH7s3tncS8#RVY`G_x3W$^^+IHO^0uaIZ;%^E46e37&zd!c8adQ0>u~hi?Qt4 zWyxDaAV{ccA#9)zSt9hL1QR)MUEEQ?|p|ocAIJOH+A;fGn~}+e-pDV z&4jNe7SumH4-#Az1&2$4xGpV-H*z_3{D`4he+J{2v8!N|+zx(pt5U+RvqX+hL|*61 z8ljzHd#_-&UzrRe;+{gHSrVm`wZrb~|8yX$p>?hWOdAnkK1^2p9kgwO27_EmB`G2R~wr6VXg+zZ2= zu9Rr`+JZquD5s4K=QbAwa=2O}t~EBq+sd}Ae4z@*+&fOslpcsl;zyEe*-tlE9sT|N z`I1H^o-I?s+mB9yX~cTon=njVGr<%NuDe4j*ItsD%SB4Gkm2tdd&#Y52+vCX4zX)3 z@nmoXJkEL|BpAxD+|rNm*KaYU$2xF%NEEKQwUXT2{4i%mPwuV!9O`FWk!FVa@z9bC zoIEp!0~(TWq^S|xH_wC3v)<62%@-&~G8gZNo;365aMsmTLm4+04$&EnQm1kBqOUqS z#gCA5+FYdln%S`EO)`PGu<45KFi~qQi-mJQ zwp(lg5Y*K+F_P-IRSmMS57r3z9 z;c?;@*}-^zv<6;ty+;NPf_Si@uMp~T02i?WzR@Njcg;x}+p55Su62lC8%J~XKqZI{ zh^5F+NBPtKD15)=5^jDYO6%ENu8qj1UCP2BoXfopOLaalkDI*jooMNyp{y^L5nMIDzYdUAQ)2l7md z!i>)XD!+dNlBzIXZ>P`R{Z-iERk*0_QAvAZf?8d;M=_W_0t}o?r`gh6R;xI(t@x!Wg4=doHy;3PQ`qZ}7#*37#%i=Vup3@xadh9JE=uuMDTR};Uz+N)fkqTL<_F} zO+%&Tsq`+?1uw_6fl5mj^6|;^f{OAiY1ookmDB;Nk;WtS!C=k+k^zl+v~NNYy3O*X;S*L0WieT#qC0`Se>l>d(Q|pCP7@d()rEr*J}mLjLr702 zyKAE{`l|sg+q*)19c=`a4wdwA&N|E)^$T?Jta;}h3odtd?o}n)Fjh>CQ%! zZ?5LFqjR};M-_}b;fXpgS4bRq0RLR!g&vV+SmE+p)NV=PlY6^BCa?gCd&yzoO#{C3 zz7*=m*M}w)Z8F^S)+cl6aQc)yht77Ch$hnt#gwAn?khe= z!Q#VeJY>Xbo)gt2puq(6{o%=u{l18g^>V08R>~)IWU)Ye0{_X(M~@|~6d%1+oY(pa zy3Wm`i-rAJP=5vLN;jax^f|PcEhI1JB|`U;y5O+{C>v@?jxQ@i4_yM?nsWM)SpN6?Z&eE7o$~^VyN^U%=O&8?)vD^YJx;cLa z$_`J!S@ltT^6n70aMyuX_Pq%&jv4&Z6l4Bmvjpto3fN`ZAyhaT!_yWY13%s6oKqc+ zD-MoFg^ni_W)(wS<_hBHl&4hGd;&dtAA;8MEK>8a=BqJ1Xk$}vH1KJq!Ox<2M4K*e z_@%-_)+?ap{e_Z#dyLR@UOMc)H5^HOyWr?u$}0>su-ljYyxycg+8$cPjjOkToc=$* zTCRz0d-ZX;wH)usJ|KE~PsNo=YB*`zcxv>CqlVjUHR(&oip_Ti@#t_b?(=XEW^d~u z-ipeA+!r(X{)%CACDu|{bEue7y9Qz1;)y(URg(BMUyYYLD5G6WEtPz_1N{mg!@TTa z*l|t^-+Nt?jE)i5u-1-OAA2fh_iupz9wiBV)~>Cw81@&AAJ9REuibIgoxb>T{C!l7 z$t9D7ri*Nr#|cnRou-DYxz<{=IF^E{SH6K$Nj4j0D)XQt$6)`bzIffe2hFKQKBYAu zr>u zEqmeJ?v=bhFN40_e?z~F%5Z3XKCfP}hX;Nf%LgZ|0Q9p&k9oP|5xoote@uioI`3&_ zb}8N|9*4amI;io$ES5X|f|~9+;;=C$9C4(bPE{Y`ens73@>)6c_4dKF0Z-w@Sa;f} z7zf8!9i~9nhMSMi+jS(K}g9_F8jX%x}I6N&yZ$bF~)S`QC%C zoEZk;^s;fo%!HaL6ZZyIoSHoiTj zgvH8z++e6$1!Q%;P=tKcd^!8XmQN7DV3H;UN=b z@UYTA^lMwdxdn5v?m{*Bds3X2gHrZPIth{U>fpMIG3vc@z=b)nbnM|Iv^+dc z%+5+gZ~NJ}xgZ;!f1XE=ZC=xYtqNpaGLUCR%5kA}H|l=hjtgiX&q-Rz#PmdR#a=-kEmK? zgZ60N_#&EuH!OjYb&jG`yDUGbN)u=KXkzV7Rk*+CF#ZX4;>UMW#eQ~osZ^-|3c8ww zB{dUS;YbfGtEt1)3r~Qd|2@gsx;zfvwC~*Yr-D#@SB4dq59R=4Wv0RxI6-wAF3lWC zUi;?r{42U(+D8sQPP1nBwp7OIzhIvcNz*>u5V{(@#Aj#E!w>08;$u%k{uX@#3}O{< zNXTuDSN6weIfnQpJpo??Jc1gfV(P*t;N=~`A={EENOueOioQVSpBH0_|9cS3( z5wyNXI|$Q<2ovVnvD)FyXgTmU)JJXLZ?mmfEpQHOoYe?(I>xd(TXNaCap<*Cg%it% zvf;RHdU-t+6l}+1nXNGn9hL{nmiMQ=Fd2^d-J>CQa$sqz1NIoO66HIOP_(0jR5!{( zZ?}cw8oeR>^}=rcV(sdo^(XEf%lET1v_{J%kY&WmL1ul{?2LlWUa+wv68; z{%#q9`OmsY?QEL3r!GP)v`Hqzrg-tP`v-CSwop2-E`f~?#)@N?4#L;3Ho)f>^7P|b zv~WddJ5HET%EqELjv2XEbUgVNo-Lll>k{VnXPIU2tOrt#i0hal<9c(#Zh1#1>6W6<@TG&N!!j$Sd8{Nq1xFwFhMt#Uf#>#*HdST+8*+v zZc~AS_2*2U>V1mjE;m!ss)sN zxe9(>6aoDg9fyQ#iSTj%AiQC59p0Vk#mOD};L@iOSXO!wJ^tQ=(o`+>E*;8J3Gc{t z!W+@>QaVfZ{v-Z0T!KfVw_{62Gz|N@oT|(G+0%NheQdEZckB66+LE83_3;}0%1>vz z_ZLZf#32~A`ymXl>_rU=6zNIhA}H>c!i^zox#Gq!)|C$e)1yW>tKcTAc^-=Ugr0ca z>Kfv&N;yaX4?_X~mFo@^of4e=ZRgEL7 zU9rc!YN%3;mZ+#Jfc46^pw#TbaJLi}%erxI;}2s0>HWDO#TkE>hT+Z+dK|6%Sa_~- zpB%PUfOk0XHgph*uISTIT`4qtIur~88mX`MJ%=w@KWTy57ZOfcamKHAP*_xQN1cmI`bPehMnRukM?4vu`KtK%)`xT3wh!=14$4F z_(u7J@M6jfP;U8mYZ|gSxy3;hgAY5H4R{Qc=9Y}1(w z+Z1(JXJZoeJGvPB!cAFz`ap+0gZr^+k{thaZbVZ{5B8B7?&AF59N0e71pkU# zd1L1f`h0RHDgRdC&k9!P_@pO)U%3f;=j+*poYlb0&^T(9`bgS7m&L{YF1+KwC~z3G z70PRNu;kShc&6e8zqY)G9@YA6JZS*0Pw$1pa?Lo|CO>UPwK>(a6DJ zLO;%|{RYi?-gJ3IkTAtqkprA6@xQ*Uz_o&qrvGmq>f1}d4orX>bDQ98)e!NM^+?SBtw?D@q`oh3c!tNQ}>+O>mU&$|MnrZ>W$G95 zIm@lsIe_s)<6wR_)EBS6bzP-)`rOsHeW59hHSEtMa^gY0Q-VN~V zkw+V+$YW@AglMH!Mq}q@a(ucc-H2KZ2Cf>&_V2-BTdUCa(j1!_si?Xt zjL*s(fwlFMs3mDZguLy*M6%xN%f-mcga?CO0s3?NJH`->&x1~36RRs(08URCFN|v z<3|c9%T9(0_lDu>4|?LAqaOszv~v_@cN1JxE5PkTE~i+nV28K=vgz!ky+N0twV)qw zt1kwtwr7wq(F>Z3;~}ACDe5oshlyhlyH50`IV$F4x1y7bZ=9mWuGiDJr8bt z(jrm*-CBtIqrfSZK^!qiTCxcWIqXi0cv*8RZ(4R1H>~;&zg&8OqG}qu7O3#1>Z#~c zjnq8D1NJ42$2PSCBp>OG9pA50#l)S^*>pl|-fv1x$HqhYlhGvMBOxHwNlD z(+$(7aP(0rU%PL>(|6ye?w~4iXnPI0V{W0dOD>vDn85G)PG=3ZE?O00j~=h`Mav=Q zN#^DV&N;SSFx3dg*23+A^eh)x>pYV8$7$l^uUqNIuc6d^B}H;G%#ABYq{6+Zc<52s z2RGb|rauSXQ|)0HoU=?x7~kgr)@iuopsiPEOp+8|Y1HG}z3-6fw+Wn7Gnz&${0Y_u zuW@ss0qaDx37Lyl^1+g+aPh-38k#$T2fREd_+G68-#;bj)AxdqH$8(!pPA09c6^2V z8t(*^Z8Lb@Eh)A#-3l*tq_F<<1M-aB$EPM|lb-VnP#9hgGX3&M_QrNGyw(hlhYZ2T zkN2@>y$j@h@e)pqAC10i-qEm>G2FXBA6I@VfNWtfFQa29rLI-~EMEp+O9pUV)ktpg z9|x8Bww!&q6E3V_2u=G85|2-40jy<@qK)r zq#&vmOLXy7cQ5`siJ^F{9#5Dahl^^{Xz7ex(8<(d;l@Eq81)sRqaRSwJZ&5r za|IIf%~)=H8)QuM6O8^2LcKKs^zp}UI`bk*uv9-mn`b@d+L>c9H8zbBHTFY#?p|?x zjXwsuyW-0?FR6CNe#+{sK&fVRYAU=zi=)=i$FZ`gGV7hgkQ0&o-b_}+UOPbd)DL09 zU!{g6^Vf0npB!Z&^^?+K6&z06497imcwgl;;qTC6G$Bfww-qO%Od+z5`)EAjdW%la$%fz4+iA4L1&Zl& z20k4cf^Bz?(|{~KsraM*mIJ6%KbBEyi?tDHL90-F?dBOO+wV396 zgC>Ytyd&Zw-1$359A{h!v+qRn>B)m}e)(jOS}cbp@m4&kp^-j5w!^V_)uH*v7T8we zjpuT=QQ!)HZu#v)>3{xtn6#!yF9#P>)%JAk*^z>t5$e2b z*=&wTkmCfQub65ulOn23cwU`6jvn8Pj)PUO2b$p8SyL%;yD!|Ua^nKs)jTdwhF`nA zk?h&v&c}@k!KUIZj(PPSV!t?2>D1-?H1m!md&znsa7_@uzqFIJ8dK=qgiI05PWs}?+Z3;J^@b$!aosCi=-hx4!ZdM0!f1TAa4nwiUqr1# zO35c>2p-C=fxo@F0Ai9!vZEJ=YgxQXgZo>6oIsC1n zz&4eOaoTJ-o)ptdY_eF!#rtG=MbtKy3D(DRe^co0qYkhP2(CXAH3ApdT41%31V^M8 z3IQ%6oh{zXKH(ybeCaEmc(<7vPHO&pcQ`Izq2h4z>V6Jc7KjrUl|sp}1o)9XfO4N1 zQdf>EUhQYW&vtrnx8(}VZd0S{4T?B7OO@AsFDHcyZqT-F7#pvf25VBA*?w)qxrg$D z(89qEujd^kr@k`CCqKeXlLTnJzMQ8SxZ=R`xfFS8J#N(VV4LKVLZsqRvI%k&qo;b< zz5e9RPmV>gTAymNwp)l!CNr_y))YoM7K+L~+u-4erLesaShu`Ph`T%tN2nZd*pplW z^Y^Rs!!=sGvdoagckjqy?R;2kG>wP%uH}{>Pf4z&5>A<$4ce%x3l*1i( zIW&U48Xm+0Gv)Zuf5U~l^-kRVKo0EOYv5Z)E_vDYL8~cgJi0oN7S=?e*x(IUTt7gc z@3Yy%!3(7o`qP%JQuHkL8&ACG!%oB@-^up*7#`<6kN%6P;{|7i;9jS0 zkO>XLmLD3VHolmgO--=NVg{y4)qqLWOm1#jOt)s=rP({=aOFxf{vMhwxjxhYc4Uon zjIq?lTjAG)L1QNJ!`DSnz15ad9!j`L?k@SujF+7MUhd!+Re|m;>+!miJ+0P_qidfQ zu&qOdpcNR&wen%Ypj~zkgy=nG}BL)Zk@F2YAZMb5wr{$s=7V1Jfz2ti^igi+nzvk0n!k34O}A0DflvwC{=oNBwf4!Pk1=W8dR2G5&}cbFPdA?eBr! z3;g))V;ffZ#c*{2GLybtAYZvJSn*E zcQ9Gtgo#}XX=LpO7&goqUM$?m4X+RJAGj&jge#-mEL|Mu_fWXjo+RAtYli9XmSJd> zAKrTE3buQSiA-;k!onPiQ8(k*@*2AOe4m(X^ogZ!=i~h}5qjR)0Ao+i;{zS1ATWJ5 z*6+z6lPVqFdf^l{-sz;@i8}Chb^v?zv&ErlE2uI=lRG3AX~@Js!k{Z&sIG5{E)6sA ze77p=?rjpZe-7Z$$5ES}KfQO#W#~0mERGtA*$bCrcexa{xSk~= zQ3f?$R>PW!S={jZAnm_2nE3l^2rf~=cfpHEVQ~cB9{7%K_4@aBmqy^OZDpwNiG|FS zI$V8uI$t*p$L#5MMcW50^j-fPd`{{|1Ai1^Qf2`(4se3?v)+@(!O(kROTv z?br?}ANyh`t%rBxrFnDi3X~a_KoLCya7RNvO}bx3CIfc=%Q&1r1kAz(s~z!4Wt79; zx%cSD({q$RuMw^+`$lQIPyM@%{aDE+5?>^}2LF&Mw5--=mEw~W92&^Aqc)Sw&asSJ zbsfG&?t_Ej1$?R1l!L!~lsufNhA*x;(Z}(lDWuH;*C`LcT0X+(qKEOpVmS~qTm=gFKI2q-A6mYx$5Tv+0Wbk^vFzahH zP1zwKli9O*d%!FDu~!sSm%N3OhG}GI(@kF`K4kaqGpL?i>X2~t4MprfFMRZUL)x!B zIl*tUL~3#$uu58tF9-Fb+AUhxb=(m;raXd%ec7NeeLYTe8qGW8B{Z*WCwabq4(9Fh z@bUK{8lids_8hy!@&~H%SK4Y``*W`3PS{_PlCOiE(>LJs!RoAKwgTk#c$3}Y-e|e1 z9QEur;5-@`g-U!eA{)Dep_!40#YTUsQCI5fn%IphHY&?^o$kiS;tR;=h#F ztxpw8Hy^5Z((l7HTCyCwHw2fLOhKbx9$++m2S4d^nhJaep}QHA#gDZP_n#f&^qeiw zu98eo2YBG1qkG5{x*UW*Plc?^8{+PRmtaa#6Yjc_Am$t$#TQFc`OC!;vH!Vqop6Lo_L4AX{$95HiC)<1tNl^v~*rkNo!0HVz?+UshykwURXg z4LCHVg2q0-&l@TKYKM04y8=g*+#FmhX7WgTF23 zZ<}M_#O7Em(u)SCl71|F&wyjQy>S1jkMOCn47bPa!B>gTgc^(ILY~!h9y8Ef3^-oM z$LCxi-Cu4ndbTf0)yCNExn##qYe!N+dYS5!3wrx0(6Po2KK|0wVVH>? zSE+jA(?_~os;mIVM<}DayEy)oFg9lYT6b|R8gK3(x za4|TLlj$}1S$q*_z)|#wxlZ@a-I0t12X=PM2Qy1AI^%1{{i~+K2mia`(%soO@1_Db zDrdr)!NXZ4uh!v2Pyijd^_#Rl^uo&){cuHlIENc7;Ft(wdi7or*V}f1QA!J)Gx5V! z@JG0*HIPr**HVn>X5ov?T4?O41<*KH?9|i3oyQvCRCXCQWKZFW(e`*lqlHRMreerh zLt2=-iStW73ei2!(g*YLI8FOBdW_e`2{2d~d)gbKCk^2{qlR(Vq#&LaSwj0x6rylb z35~6#+1x3R*R9N<3w__g$(08vrC<}g)w+jiQr0BQ)^+8Ci7%+uTaUd5)#LWn&iLW+MM$H4H0{+vIve2u zaUT}*vpr=vIddy`Z?EB7bDxsQh(pv;xgM)RjacpdCb)M07R-J6k5Lk~pz<3>4E!QR z)??Pu?_?z|D?J7cjU##O-5nI#G?@3R&7%k3y1~&>3g=8p5^s)7r7io$!O;a02>!2} zzW<$sXZ&?|g!6E2^=zlwZ|Zoutre0VouHtGBjWnpi=f%DTx{y=fo?sVIKf1cM8}Xkh@qE{$2L5FI`|JDHDEfp64H-KY zR{B{8X;Go83^0k3htqP|N zrvva^wE|B$>wv4}mSVx&Vhr@wgXbCbl-7BTrtP-nHo5Ec`-s2?%Px?zd^x#WhM>0F z5eKcfeUQ=elfH$Ygxu`~!fyOS;r`q3`>8VgvC~iZQ&~y7?p~$TyFcLGW?zopGL=R| zJg5F1TQQmC94p2hVSPU)R7mz!B7{yN_JyBK!!R4fUM;df77Q@7JHSSq7HZRZo% z#6^ugmR%N>^>fBG?bF1w8&3s%-l5wEuh-~8eAIbZ9H;20d_0SvwL9~dI#bS3`p0cqYN(wW&J$WqXl}oW_%eAv zjW}40HWtccKU@v_e*Hngp8a^$qI$`(3yb;FmN0($vslQV@j}QjcmnAaX;iP!D)eug zf-@}j0Am)yq?IXn*JTS0bXbAIFKcl1pSzG4l?}&7*NG$AlI;h7TFiYG%*4lwUW$KC zoAK6+A$+{6Kit&pgs&q{P)o`VXz^Ywl((AmNA*NL>Kq7ta~?or>Qam~91b~?Cqi%! zS=g*xN3|`g96k&wdX)tHXDlpArQ zq~1ZUxdWshEfNGf4}3e#`X93zpeJ`ZIF^L-jerU&znBS?KC5Z)k})j*tQP9#NAcrR zN!+Zz9xChPQF=`lP8@H}>C&3w^hbkH+fo%f1Jf~HH;9+SnX{DZ0On=oa5rEL-HEm0 zqFghKDAGh2XDVFKjm5fEo;V?@2;v_6pxFIy>7lk6b+w+O9y5cbO(5IOT9_Ao4pu7}<10B0jB?D!tkoUD+0u*Rv5aY4F}wvjEpL-_OE_Vx zAv@-KU~S(yIPUXF!8JLA^rsBqFlj$A)oB2CO?fZA+%5zCyaVvyS0`*a5rS#HpT$4p^Sb zNl_IzHfc4?dbkQh*U9m_CPN{~piWR(h^%OLg0zb(D0fyeZ3=zPJr1rDTJk_tDBOuI z8(%=##gVvNsT$VT8Q?bcRLtvFA}*Cr5i;Is@Z;U@pk%lu&&yEacJBhx{Fm0MB14;f*yCc(68=q9onj|h+M>j*m4RlL!CET10yi?WLDfc%b1_|WqU4E{C=KWJWqJI#jptKh3JeEWVZ zx7tI+UzJ%eOoL5ad-7rFHbFndfF(Qn;M}G>bT4|0JqsgwhEgY~tg++SvX{YY>QFY= zvw*9ehw*`dW7tzq2G1B?6*qSnLH%)G-g{*kx_^2Kr(c7qB66!^}3OPJf=4A$#@gwL^KDRFKMSZyd1;t#m-;8x9sQMqR!`;INWvTui^ zMW@N*fHo?29KtQR=7K@?LR335n0?R1@YC9OvVQZGW(P)L&78Z``hFPdx&9Q#wZ-A` zPC4lP^cPszag7;M&4DfS0 z;Ey?Z5HZb$M)vnXy@UPGc5XVqkbIy%<7IfWj~Cjn9KbVo*g{j16QrG1;XRMtplrav1-EA{$Kk(ULGh z#07kI$zDo2G=bXodUCmaG7Nm&lfJ9g!t;`A!p4jun8yBql4v-&O9}ftY~-Du2C#Ru z8AG}QW}P%8v+9{J-ggvM-5QAN^YtjvUlo_2Cyo7iALbZYaOEc{Zj#+j4I}kf=Y={4 z&kSI<-0f(gpGAjm%|zqVHk>TjW9`&Xu*uZmY5(cr)s`oqd~iGOwlU;MXUt(@zBP`D z86eqsxs=N4jq&4;x%he53VayS2WK}tqc3{{S@p@N zL2>^vINm=JQ%@eGz^+UxcKImg@2?`YoO_aCw=*!~^mfK{TF{zK@HeF3rs!132JAgV}}&bV7(lpk{R z=5D&M+KNAR4aDxB`uIe}n_h(IVpzY`Fy49!e^1@aySOi#hu;IIi9g}x;txtds!HoYqj!DG@Vc;}7bkp6TC+jWJYrSw9wPB=_Qtu%3miVj|BTq+sarwC6b8?uMB zG?o<&WZNsbV$;IDoEvJvgR)cc#fegJkj6*3TRZ7jOB2Tbx_lhwSTOqW(*L6-(3?ze^M6{To@IEmx!)(et1VLZ#|F?@L) zBDg^YIa+z+eHU9{?+RP)j+)9#N6g|8IsF};6>E^g>~YxGDvyUFf>GTm3DQ-ZG3MazC-0&b?C)1xtxa31j zrzXCg`w~JH-xW4)Jq*=3O5hxNj1rG2vASO(2pz|8mzft9f7BKC88y;+Ehn0-RZa%) zX0zUn3>x^<8G}x(<|wat=#gqlTR-1}N^w1uM5?n*zXABWxCdMe0M>sH!5QOjNZwDk zzyPH&_|l`C9w!|UVCydUw5}9YLf(P$-ubX4#E%?%_>f9`shHcnkezd-$hqFjz{HR`Y+>A|~f=3;D24qQByF1pE$fs!O&oO*8nS}r;W*92n@d-0c| z?BG8H2ddg6L{CRc=6A^tN%KB z3xupu;ZJ8Xg|KpOd?32=y#u!BdEzLU!Ve1JtfKvWOWV~7bLA@r!;d6=op9v_xx~V>mQ1@8z?*p_2Sg`hiUH1 zBP7!qDr~Oy!u|=F=r{j`uvu1(?;YGnS9r%uA{RbVtC;A8$5T41}&fU5l%kJM6HB8X#4gU7Kf_g@tWRn zr(c)--dVR{P?HRKefFiVQBtho(M%?r3xvr-PSSu4nS6KgP&)E06(_cSv|l@JkQlk= zKe7zjj2*pCgQJBN-!cjpa~^F(kn5(OcYD*t>~W-&kq;7up|JN)H${!<4eCK&@F~<4 zqiz1;ll;5zCSRMEJ14W_etjM(?a4ON#eOoZ zdNE!yOl=3e4=n+?IbX=RZUk#l@IMwA$SQB8aO`d~vD{-6M(4?4bX*?XJz6gOgkrim z?jw#FB!gC?$8pPrGt`)6PW84Iy4#cUwQJrS!bc&@FD!tSsBd?oj_>#D{-1v z39tWCV==}@5H!p2&ZaqRU1ttEs?GU*9zi%5l4?;S{do5aVsF^uqpLIUVhlt7H$|j> zrjnGhTFACalT*z)DR237uu08j1+4@4uHO!7YHb$r#z_A0VkM|QiNUnoH)OcrjDwG% zxnx%PA2=v3#~TykVDH{mvMM&=Q;q5*&f6`7TwO=26{c`mWPf_&Jqi^KAHahp`{8JP zv}A$$e{eOdfp&DaP}SE2usw7HOBQ-V)r5YW;M#+QJE7vKU?X_^$Ay!Io+NcoI|>fV z5PUsmhzBcwg5$hS@tu+uX|#Gk=-zHIahnMQy-&j_i!}IB+fXq6wu#(g`rtnIui~%e z(|Or}g|wl$n=F0e=|sl~w%)uSM_vB|5mxgt%;_xEO!uUze>HH-k1#eE5P(MwPx4OH znYhen82FfvDew7}4P6b^Ox$97499#;`pz z`S#sf`k7V%@`bCpsaS_PUTx-8pPoQaj4Q_KDzTrM63uwhP7nT$!y}t&DF4?wdR*I2 ztde>Rp(zQdm!XOlJN7_r?-~5N^CuONDi2xIN)J5!>7M^AVRyS?L%^TALa*`0^wQKH zH^h&|d^aZ4%o6Kp=kNDD*2Krcg5#|p|!N+gLU`o(Mh#sT~!##JS zZI65unpAkl@uQL{{paxpsRnV`cpv^8CV_p=WO2;-3lgi~8k~^m%m2;017Ee4k@v84 zC_DH>v^NRivo+trt9dk*zOQ1-$CL2qC^_yPVT3nL)Y#DYnB>}WCDdvt1Gl;Yj#`*V zbBr&EI-#RcaJI&9xnz1Zu??2be?qEpONBF9Y1lr>9XI}S%%`@OD9~GqpN}6yPv`3M z+{7kPt7|mx^U7k+lM{v2AI$`txFMLdqX(DmeoW0s{7h6?TFhIEev36XwAmwUAPijpOVn83NkQwz zA{g$2h#v(!XwwKDT~a#S}WE5scqVM&assMYghel2>$w3 zTpQ|Tzee!_oxLE%LT5ZUO|ldB{xC*In+#NYZ7;;X8OZ+kY&lXRTV zidSl13X4a*$A@*EsN}g9PR@HoZ`Yopm?<}@|CC(*@Z=OJuNg}{d!+KYu;=2I)ida9 z$ONo^rv{4cGFW){J6thq6ONtO0N>o_U@sR1gu$**{C6lX8&pdEM(G5#ZPa;xCwUCY z;ELv#lx@2N->j2`m%IJM_bt20>8u|feNqlDPG-?S@70v{_cvCC?}dHm7tpY@WWE?F z$9+nSacb}=ZW|zlt9I`}qmvFaNi&gk3?lhf*(6FDF%8jwa8Km21`CuwXG>-fN%GLp78 z;Py|G@w??N$Q{-NKCxpl^RFfy8D}p161wQ(kq6unoW$Ed-KGdRU-Z9y5-dt)p;M+7 zs(1{>Gg_gTQjmkyZ-a!LM?cYxz7ObWgEXIcpu~sPE@FENDIE9r65dqL=cA9^al5F= zH}?hOr7fQ+>A%T**6q7P*9b-Y(A50TKPH0PKwVyGStoXPeie82Rl@Y{^Ym=2qr=Tf zics7WdCH9(am8<0o}@Sk?>A&Z&p)SO*UU%I{XU&0e=HC`2an;*AMdE8vl3sNH4|G} zN(7VZ2|VN3CxFz;z{7QTt>*|ZA_ikf8?Ll+p%Y#8JFfvPH=4iW61yr?Hck1=hAl^RB2EzT;7jhFWJKt>YkM zwFj|Ja1&HlNZ``TW5StZL;1q1U0h_4hc#=a2*d1_(X+oNNYiH$%C@e;Ix}Owptp~D zdq+W5$Q4vv;|5ic&m4}<-^~`d8MX=cXt$FQ-TlXW+n$BO38PHTG+Tg9wtcYBtQ%(R zae?Q)L-|zKZ`k%iA8O~w^W2B+Sh3KEZtj?jx0+q}wsEy&%$#Fl?bIM{{Jn^C2F>KE zK_BU#W+N` z4&yCJDdN=$0=Dmv(BckVe!BWSO@2Cuta6)yJK`zVb0qp)NCvRl%D&b+Fma75$#&(! zy;p5Cq3(_tq5d68<;%vC8>KfEPEq` z^cu|P!_*;NGeG#fOhO|HCUJ?!0!FVf=zH=9s8-nFk${`xBvTnId)W)K)2+XH~k zw)XV}zl7-*Em3!(i9_4EHQSn}rFiFk^k4?1X zC$51g6Qs&ZdTXQFpmTKSLp+&fJQU<__TzxZyU52c7JK+>@{ry#l2g~Lxa7udkUk)V z`$2|{&b;rav9}nuwwHeR*ujzq@X!#Yr7`FuV8~wZ1(@?yc(V@+1nb|M!sR zY}JJ#sm-*<~u>v`#vNEh__`M>F{4 zRxgJe)6$XKJn&J65o_gsq1HFYY4xTrplZL6GffQH=JQs}SQdikQ)Ky~ydxWh`--Q> z%i)=fsnlw;i37EFiX+AcVdDpPHs7%lDve$E(#-|vseO^VyMlm7^=#U|jWsKCod zuMn2@Nnx|bj}BIaB6aFoVZY_Wv1#&7A^G<+P?b&POWW$Xa=;mo_fo*Ssnak#YzpYT z9famavZ!(GDQQI);koTyqUG9WaJ#=N%L>w%ROUyozBbUIgiKl#XH74BdWwN7)bW3c z%ln_}_lv`ly)uhJLXkE?g?OE#NHS8IJ}6pJX_8828I`T5q!QAiArkM`Iiy`O+BCKI z($Kf>A8`M2Kc44$Tvx5hK78(RMeLbV0p7ReIHTr)P+?=r7o(@LP5wxH*;ojU@Aja5 z^9p|5SV+r%Yp|xpK0&!QQCOa&!#{TAl77Ti)H!T})4!VH*4vHLwA_&mmoB97vsL+i zhP~63gfm?BtRMY(V2h(@2AV6p0;R1TrCah*CW~6U^3pe+UcD6buhiTS`7;`X5ib! zg)IMK3!ON+na&lhz>$luQOn*3FhW$q30Jf+a{-I<=X&6GjS9*iQ4d=a3n*>F5TSKp zEuCxBVY$JxL0LZm?nDej2fZrx?QeqCEq%q~&t>t@;o;0{ZTOC27Un)6Q9N~spM5;Z z3Y$*AjKflNx5EKf%kC92&QHa6Ru1^bas_!MFD1=$PCUZ(23X$BqWO6N7*o5LzWwQh zw)|6IRZ~K0Jr1#dt^?hcmEtrQjAEH9wJbai7K*Q+{YE<6O)mk3`w4jG$sS%FzXi|C zlIP-~tI_wOgjTQC=F4hb!oz3MT;6vJTKe9hG4Ix4cuA)aHvJF8zq96;SMj`De}iZ= zF_p|OZs93I9cXpW^%y=-0;k_sL$t{#9@6I{)D8S1DO7tvmf3okb0nUBzjqf(%TH3@ zG4A+QD-T*P_Tq~dy9JjuTc`;%c=7cr!Fx*_cJw#Hs2799$0K`kQ0`Uw^)!Vh2di?d zOap9Kn~Zbywsu&AN@&7l2b=(6HRuJl{r|^k?NrTxIXkdKYDS@Q>NwcKC?+T#M}Oi|N$E zXYffi1uSom<<-5<2)~BdqGH=8&g^#tYUg)|r&NbyVXhG^`p`{ZdkfgdH;Ypz+=EbW z1Ku+AE)*U=17Y`%K;k1Mtf}hHmTN~l2P&P$6A$ZQL*!mu))CLwJB)ajodx%L6hmVU zEf93XX&m}p0sK~%<58tbs6TX3e0O#P|Bm?&)~voLF52;3gz=_)tp5oyy}=o$Pg#I* zYmSR9nIrjX&I#vR1}Si(Z-~>`->&@Mxur-o*8JXnI<<$srYr>~ocrXQu;$QQ9v^l< z)J%~U>y4-L^4I#fFC-4zPFD&le{?u;jR)HueCRdYCA{0Q-6)$w3Q%-TCS4x7NE}$&W1j|!%>08VaR!q*L6;GRm3!x3P z)%7xTJeFZ!@e)c-?GUC;v&M*j?jT<-%fqCjX!nqEvXv>qQ0)Vv*1lpe`>=w){Crn; zIqy33xUhh2TsDi#J+IQjiUdqB*I{evOdh+}hxa`3#3i0tAit|OUoKMqw|#XS{#%NE zooW~MJh~tpzxj#2n#xh>7inS`NDCgx@W!j}1jVs?ah;(I{yC#WVU^`V(wco#Sug|c zU0cRdN3+E@mc7KM#co`Cy?`~&Rbl=qKj_;LiyJ1cARWh0*zh}BC^1RpM8C_}`%8}a zX^}U!+3jPa9mX(K>*+u5yZ`S`>L`A76!|BHlkx2Nc*#EyXB#h}Sd%-VmhT&J;h8Sj zu4%*mdsNxKJC3hhPoTG@KInE!0YhC!3ZKdX`25)|0=#j+Qyzm^d(#TsGcBE(?|E_E zK1FuwI}EQyso;CZH>7teiiUPv5uP@jz^%`fFgWOhv)XwtTOrMQaxD z(O$EiJ&YS^sP$#m>M@@`)@s8O`y@12JxwUn`Uy5iJW|6H$Iwom-O%6qHhgGtoqmw z+gFFes0~&uto|VO9rwfensqLYE3?KVop)gO%z<|%-Jp?E=TKu~JCzo^7NaKiqCR%j zV7+QGhg2G2@K7tB8EKAQfu|+Ix|YG!Ns;h1VF+)2b&aa83h1zKDi2d=6yhXVq&T_* zMrM?Q$}FU+p+`Xf{%w+-mPb7;PhoeE6{@ukriUNyk*Di3agXmmKG&wOqrM$BEmfx$ z|9n=8xlb+|!zg9BXI+y_w7Ayi3rx8?8i%{C!pP69@Nq#iylgS%g`KAY+`R`(<4E4veSOBjg2b z!yGc%Z4Fr_&TQ?N$4#DVofEIgVE_0hT%Y_DY9mr0{O@cm%8i9vW;en0yaT3K>2lMU z-h4XZH*L@kA*+pM7`>`bZC&(!ajDuZdK9gUa*r;9p+yy?2X4ove;pz3H(of>*G?>2 zc^>M$|2qHKb%5h8|AO8_hr*AEDJaw=!|g?uIOtd`Uw^2?yXLjfEYnk@TZM4>gEd+A z8qQm!ui<<7xjg@QGtBrZ&+7-?1E(NmKD&4%&-48(S@_6=Q`S8Pv(LfUJN7@28?VOY zquqwVlRcR&2;Gnv0FJBCM1HCe_s6pJ=$arj#&T=;b)E&S)Ndef|^Q(VS{iCXyi zXe&qkUCNU^hvJd|Rn%GajhoRSV*;poe^IHkpmSJGHqbZIK2y2|71q@k$wJRP529KaLm2iD6O zOvBaVj7hq5IA%+>@tbS8a3gJeH22b?xqh8)D%EkK8 z+Jm3yTHL?BjGByr=NPeSv_9-Q>kMCkHNfv|sF`7SMlGEc;d z#?upUXoClzI{6)PZZ*@n=igw)tqB}mWx(fGW)kIu!IUOdmRjV_J^g*rcUA*j+P((Q z?;9!Z`z8-ReYa4FmL6Z(83rq4GI*Bqzc!Gzh4m-iLu{c1j$WlnQ)XIW4-a;Jt?0mm zSI;B!SxIPJ83~ak7DDBL1p4xyCAeO%7rs`zaO{sGY`MpWHV-Mny!b+>bkbtIIZ~Xz z+X5%AdkF2f4C~SV+q;wN*aTK9&nJUWJO~&z#>v`?k z?Yz@fjUzMM(f6qhhEpjSc)Ss2od|(%A0EJxM|-(5LV+drN~{;24Kt5jAQ}GvD*Cht zXB-@iTT2I_{^gV8{k|A8hbVA+yfqyE6)fz&)hIq`4~ON3NjzY2Evo(Mpf&HubLz)b zp7K`>4mccu?b=tU(Zd|K)tX`c_yb(zIu*zL_XN%J4bY~i0vGFLv31Zlh}@yVD$NPP zLX&dHT6}{ZuTFqzhl(jZC=#mHj)GU|D%`8!tdPH0n+Nxd;{<&r!7=DG$rU@`%O~lV0Dc+ z_RCT7Sy{~PT{U3!e7~^nNHXq9FcX*86~Ob{gCLu5g4No`@|Z1|e9t%!EXEua3mVYmAYwP0}%`JkAQW%#z2g6CJ$W0oQR*liuJ&%g^DA7$-{CPF@!v8YrZ+=$>@yAmC*Pr_tm(qW zSy5P{T?L#-7XNdJX-|Z0L!H@i#~@f6fZSu| zX;?E{pO0l0W3Sg1T$K|82D?;<-3(y<;1i&&7|F4EN_f-CirTjCfDGjx>@eR9eH*(( z-_?5r+3Cgby5pdj`%IrtKHkTr8cu9>N&;tUhvPgCk%RzgAt~DrW;~vQ)%nUe`}kv4 zbPwmCpT}vcZZB}uTa3R-!sy_aBHU0Z5xo+F_|NSN{9@KyEPCsRhAOUTuyh_94oaej zPhxSQW?$|VwUxIvh2wqWmsHYoD26|l;?^Zw==a5=@Mwx5w_X{Iy`L^a?|mOBBq$nP zXZdqu++K0RxTn<8zL6eZ*a=rJ%JIOOU~c`-7xg{gu>Y7PR5Qt#(++I`gSx?Z>DxX! zp`3(n3V;qCZ?Jl`InLG?z&kYk*k9Kl6xz>931EYX?xz=@YPT_BAwII+~mP6R2k5cS-8= zp4ewQ@}315{JFSOusd*)mA0GX^xos4pBsUOWjiez^onNdBxC5ngY>5AD7G<) z;cCmN*zK=|xhse9+Lu3oXMF|vrWaKHaRJLcNMM-;Su~hg%cHC0@YUmC+%oGC410S5 zvO|7@cH>m^%__i$el6f@&#ANMwB6v7lv((Ba^VZXw8{8*Mv zJq~5l=urz;-S-B((~cK2yz^+rijy=oY%|MDxg<o)~h?37P~~n$;sHXc1?9 zEElPMym;{Y3T`^>3VYvgqGu0><13vz;>J`52pLxim-Lcp&Q5PmQBA`~6B23H)Zt`$ z_c#^hJb_Qj!|`E$8M(+;(uME^P+68jvr_(b^@J6YwI6#x<=U0bpEg~ix#^YXYRvVq`%%JURW9@{h!TqZmU? zr%zH%NH*~bTU7D?E$;ToWQ*(ZWVluVN{-D&qexT!`p%cUk5vn6cSf>%zYbz6PqKNo z1pj+pEB37$4;ysXLG-^qcvtB{tM13avIm)hVEByN8;ilA^d}W%8Q}~0-IRY~EU0$G zX6PZ#4h)za6|K&Qq&gNsRru)6z#IB;wv zJTWVv(D`{{beB4p1v#*!!%!%2?ZubsGdSenX5mEg1aJvoi@FZKMLVMhLXiFg$XFJ{ z3Z;8#!SAWqnzI_W-TEe2G&NFBpGLS^^#x@7wR!wRLm)R*{%n!YdQ+`=`jDr>T$NP3 z5v4AS8TK8tllx)cbEf#}@Ik^n74EhyCaK_F;-2kU@cU{V9day&ktctQZ{L>>Zi!7) zw=e^LNc|N``;128#ttfiGAc{?E6%^D!hf#x0rSv%Y`kVKuKe2%101eH`ImltzcQG& zFOR|0={KqGiCBE)Vav|_PvMrnwtRBb9vD-)pMQo80O?alA+7kiXj8Ed|5hP~UAxPn zbvc4f=R!Q${8QMRq{1KK{OUGtPQfcDW6|4Df#00);Ujzd|J$_=JgXao*^e~%{JDD3 zH*p8}NjHK@)mLbX^T99jy&>$sN;-8}mtPn4;F>wh=oWbFbY5nSLR{>!2-S^#pr#SldFA zcRUi#E)L-3Z=(5%+ij}N@d1sF2^fDd9ik_VKue`kh-xnckGnPys&EUE*85Ri+EGz` z*9gIM-a^6ObtBbSiqu2lA!tcEvG2o&u=~vs`crTVmZe;!oUgXvX(EFo{G4gM$8Yha zd^$IZBk+vUVAdUOfagu`*A>l^#tYL2;Z(&beDg@T@X4x!n@&uiV}c69&_Q_b>n?bl zv>7_b`J%zwVtP}#A8ociq+vcOTsCMpFYb9zoU?8oZv9kFNyUTFcSRP=(mIQO_MGJS zR(Y&S@#pO3Z2XcrnWhi9MnnA~#jxcCv|!pHkaW!DE5-}ZyV;Pu6-S^(xf*|RP!<<| zmyu}YNO9@qgLwALcn%$W*ZFN-A_dmIhdF9Pz%+O^Z(OznHfZEq#K}F7Ke|{!)wFEhb`2MVG|-djobhzJsy}Sv+UfUph5s zDv!BjgJYa^xVd^UY=5GJ9sY6Hr^FAXE86JJ0&~_#kzvjIy)pE26D^i`PEHD`;*@dM zB}pfzfLhEnl-=7Yph<*ePuM_Sb$+$vm1aG?dwGc}b#>9OV4UQ!NiCYm>vKfwL8x$8 z#4-lwg<$<`ipXEUyPO2tdv_zpZyH7wTf)F|%v79KuY$6rj^a1Vum74nfhOz_aD&sub18TVUnkKic8B4+=WiXa<#dmd?xa3eL9Y0nh7>%x>E3rnxoD=?R zSK`T!^XuXC^&WJ5M>=0R+aJ$Pa~12{zC&%d4By-;O6ocdQDw?(Y7L6SK3*?rSkojv z>(Yzgu3P{)cF*9MMG~pq*(}UH`5NA>b>Y&snXGwe2hUos54)7jaCpEK2Cu8Fnvtym~l{yhW<@e%xEOM_Fv(F9PNa0BjIb_s=%=c&G6K3@4di%?dPMvi`r zX%cCSln<6n`S>3%-ZOwMpU?o6Up+Y>>;jzx6};!V2Y3G}MV;<4(!HrJR(}ZMobSh| z^>Zu_D!fNO=apcYp9;<2I*2Y^li~!8N6=@FL`Y?2ZXGAhGycRwY;<1?c+m?zdM@U! zt+JfB@{Q;jZ;FXiCrW&?nDf@J(ZH9QSP!YduK;v@m6jk!NAm-0@iZ zP?x%Yy~btde+!iZ^0^`SINPmzMiVa0BdtXm9Q-E%wjC%&-SGpk?`$vTlFuaf-a?dJ z^%`FEu7O-nbM`p=7UrIu4ACDqqNGQbm^I@vN8fx)VY_PR>S#aI9aTX7{nc?=oh2GI zWaILW1Mt}MRy-d2lqUR45z_sl`Q_wB5D;$HqT z+JZ-Q7L!|4DJZV}=X0T{BK%s9kI&k}e#1xbS2YtSN;FwgT?)UGwb;VM6*q5{fyz_X zTr*yzaSwk`!J8O9FgcPpzI=p1L*j6C%4Ha7Y)1iM9d+xjod?Ow98R^U8%+Ir6UojT;8_mQ>Gc72Yb%f{daiGY83H-3lmC}v&!_LDpXdk7DE!qd2SGxGZ z!;0f#qs=h3HEyGeasjy3)*Q3Hr9=MkWQnzV4`D>m5_lQ7gl8Swg>{iz;Jce+qEElhdM7=UdVA--yve4D!Y7=!a4I^(v{0T_&(ws?AfXf zh8@#*W8)Pz=ra@bj_;>QPc&i1njN%G$pt?yPsO<3(i|0Qhr5+i!7?S4|7J<(M4bhf z{IK48|T@422-)Yn?C&(JAibY9zk}q$kqTS;> z%5<-TM>CL|RC9%q=@-QH6BKws%W~(lDHkZyJ|9%JnWM>n)pRu2MR3ZtVza&qSh2>E z|BKs92Y;Rs^_FC!+PFe6EStwm=2p?Co*^8eCxNj0<~$?4k8m$@A-XMcL|i0~mz@&0 zzwS<$Dr-z?=lpPU&QO+0Jt_!xxuCJ`Cak&jjWqk@hbxQT-PF zWSO&U{dm0XU59=bCyBZLm|zUn)WEigw8EXyIXn zuBiEBjBvFu57Wk!lb(4hg|w%ELbo{&>~#k^)g8&uR1yCa?c-BhuRuld8Tx$24&Rkd zqlLHT(C=&w{612dC(TTzZohP1aet@iZ=3~f?_zPxFDD$F9}nJ7OJUgIgHW5U!LsI! z_~iaV_;A^-_UAz_J~T+0U-2N6^ETjDR4Uf&+6eLuJvjbqkQg6*Q=Bj{8D8wP2g9FJ zNiU`fCcn8#Lv&(r+B0|FbZ;02`}gE+J>p@Gys2~Q`WDL9^@Tv$xmbB#n@wpK#0&Op zxV;kWj}?ezir!RLwF_oB?GjBpXVbum+99~$H-#;)9i(_8#jj}>#uamCqye$GA z+$t2_Z_E+G3X|~l*PX)nE#Y91t_vQ;-aOK8jWE8K34a{d1QiccM3sIDD0}-Ie6P7J z>I4Go$4|zdO&+viu@*>fn6r23KFNpazhFk6AEa1ykY9{l4`0G6#M7lyu;_D#_;{HO zTdJsGnvw!pW{t)Pef4l`mkJ-t)aE5-bLhRA4k)=vVeP;yI=ny$-;Ei9!KA>&i%;^q z0XbsX3@P&Xn1&4(OzG${Pjq~q2K9E=p^r=zT)8y|4%+R5yd*_hdCHC4s?JbBo)(Ap zXqSwVVX{6m8%I1^%t@oYSt-$mH}V3AyrPeOWyk4RxE)5HtAcrdk#(a?aKhYWICFRu zCZ66&X)jD!Ff$OQ#1G^BKi^PHaV%FgJ){}RA4vN37SJwB6lb12DuX;$b2a9J*R|pO7<=@}(Z|o; zSrk~Hf^+gdi(LmV2!G0Lp{PBIo7{cCd5S!HNoHU`@fLEHUJKC%L!c#iE{)k^%~yaSj@V>UbFu>}IOl_ptBPQGZ4_=C>&L_A zE7Mbr6-)tA^=l66^LrSKOO%w+wq*$J?@Wbrj=6Y4XCHb6?B|^crqpJBKyZ_n!a)he zl9f%aeE807@VaIp`Eogq@12;<2WC3ZHHU?gN;SkUJ<_PkC=pNVDr3N!?c;k{YNC># zF8^rmFWwpxK@ZdZfSKo0=#zMvBtLW@YU>_)^fM0OKP@=%;{h(0e@Fw{^yt;9<2>n( zCr>jK#eUl6Ft%p~4@lV$N`vRHP1R{wRI>?O?kI|mvC8<^N1csY9dWa`kL_+Lh`UeD z=JnV7vF1<}t(@BcR$sI+$MPAhZ#F}VQKfw5MHjqpn~xC}USt$=*haLa}}{y|9-eW$cuLW_;)*Ndyv&7HOxA{5*p6>bN+iBUfZjabmbVz ztJU#b&ML6DV}hF}bqgayCg6mmJpA-E0_VKR{@0O%+3L16)jaj&iXV0KR>_Tjoqr9J z7P*td$V%?vKa{H*?~2j;O!2+;EU1&shMvlk(X~pEEzi&7zS@g9)IA%Xj6V;iE&({` z?I{@EQ6-dp9s)3@5e{AV!<6eY#ikH9nm$aA=Pok=`3Bs1{A6V)cU*u9sDJqs;)Njh=|6+HNd8!Q;~ZU`p@<8j@?o9(5{$)4dcpV&{(~)|1Igy&p_)(u0ldw)D-o4suE)@Jq8> zP*ZS(h6M3i1l%@&$n~pzSeK<>X+9dKWZp z48q9{5q!|!n=kh*rG#PWloY2SEFU(X2QAUXZJ2-`+@mpZa3!7EtI18~)ikEVP4M(q zr|{8N$otGl^j6Bl?j^a{L(h(L74+F++W`JsHUysi{Et<49wDQ(u{hvByYOnuRJt$w zjf#^?>%vEb3$lBgNZG!Kq%7CK(m-p>U3myLZc^pIVb>|V^%q4faubV3|8s*=<6!LE zp18Ln6BmRWM%jDOROtzvrz*wcj*q5(>n@5tKB)4+1*ai(+;hsEbOSJA8`W!#fTOCp zqTMoQbPm`7vlMeEd%LGN-N^yR9M{0*TDPzyDw!T9HwpNJjnKrptfi{@77fi z=U@CpsWWnbX@n+_qWz8ATlnS&>sJkiLgkq;UU!5gz=*c%z{WlHhp zV<$wrkPOUosHfv*UU+4X51z0MK&!jOlvdPD?){v^3pE-Xt}0UUMrRh@?!(e&2@+SH ziXp#_QPVJQc%&D@qr8{#tdoIMbIE621n&O3@Z-v@_oPLqAuP#0- zi=-p%utLtA*RL53ac{fe&|zC)pqU3A9yAA)zLg29PM@I<3##dj=XS9WRrqkZB6)-- zv#-GhmR*=9dA)ix+Kq^Y?6NqRbNCn(UvtK$hVAtEP#Ml|tAbma=YaJ3QCQY@`fXex zmd{wsm9KN1^KKrYI_Kw-KbJGa!4HmOsns1Qzq$mbZJ*8o-b%Ggrh3!P`_i1~c!zH# zM4G(87=Wha3HtDd3XaBZ$jJ}8bV3gNp` zq$sdhi*-?&gYRwTkmeC|(xX}&Hb(;onmdZmhh&MGPj?8mDm|fp@eR0kBc0#Ff}4N-v6u_2OoD-^eyQ zeJfFzVF~()S=^@RhkkWPS)&4Rn&%7Er4)6I(Y`PUqrLKc9CRrZV&o^{A@OT@){?eb4@9FT9WryL>!Dm9j z%43|T-6<5jDB-Y(yW}CK!t0*DhJv>rz`$z|-tHKL8$XnbR=zRpzAT;#Z)LJpN+sNQ zl;|vbx-W!9zks3M>bUfq4-P0Og4PYnE?@rMAtgv5)fIDCeD6aZTLIT>i9>lXxBB-cO9x1kX z^P}ROkZu;sqGmJsNiX2_Cs*N|Vs+m1Jp}99;;80_iFoYmZsFKzBR0Et8}5wgqFTFc ztp9mC*PQearGhna@PKQu=}`}SeMt|Uwi;vS%C+2;ZHoJk>0qaV8z#{Pq5W%+zWVSvv#|sNj~EcnUs$lp^L#$6Z|-sQGL)J#fy08%pVVWDV;=mb3eG zKj`N>11A0&i}}X_CI5{L#Nu`}jtz9iZ64|3rIG*`qjQ;>-BT&+^>B2$|Ibg34i#2R z`~eHr&%?48)?&qiBlKg7y12t(mZW!~j_AJJhF6TN6h8^QYy|Li=1nTcGob9Y4d6BIW?5T~BnC2b#;qkV?!gI8~~H^ChLM-Ev<%S{jJ^XDSd$JcJIY zfmM+^an+~(=pQSMm3dRaY0y@_AK#x0G7>P&MjGv6by=#%PTKX<3uc~Cz-e17_>0aV ze(Vv<-MeG)&YIC^cG(!)>Ragjky1#v)e^2n=?nku*T*-pDm>4|9%Z9`(yF35;ppDM zT)S!?J^E-2WoyI9*u;&mcbBoVZ7lSg@)%g9C(1plhE-SNg&o7ganPr}T=#4XhE|n1 zhYuadu|xM!_`-FxqT5%{F8)YYH0@#6(-=s0l^3=>{YD9gKeJ7a939-{0Dp$3z}zFd zgbP^*gqxRkVG{J9`F8JkmdQx$8+1cx*_w-KBb@lN?n6rc*Pjt{w!?Lm>*Dm-09=1H z8V1BEp`Jz_tus#|=_p-R$gtsgkt)zz90~UBKR{uhH%Coxp#_~C!q;!7;m4k{!q_>s zY-w>GlIN+h-$i+sin&re`;9U^|2Ur=&Y04DlEnvS!uU*rEIw`73z0LFIp^1AJgHDe z-_L{!-mi-2;`g;+>jQB7-Ux2!Oy?u-$KkqPEx7)S7XF;xNgL7vIraA^*obQ=BhQb9 zJ-bIzz0XqArf{~kDiBs?6w|L%BQ)q+1b5F4!p-+T!t}0sIQ&|tzWt>yhur=PHyQ_` z)Se@t{8yEoZpGoQrhRaFe;lp5wG3MdeRx7@7UUg1CcYftfT*e~uD_tb`$AWWx16SO z&Wm@L;FQWXcmU3}Z071QS~&T?TktZWKTTYyh*veQFuxlB&pOR#Vb#e ze@q3x&Oa}72LyA#hTRb5lmy9gG0aU_q_*CGwSUIKUyH9oX5a?rQZpwUI$a0*Stnq~ zdlgy}BPXW)?aQZ@oRAnQ8?(Wh8D!BI1$TCc`0!dFce_So@jykEt#=oj>lX6gWFPJy z~2; z@}j@^G|U#OWC}=KS`}Ya4B_g#soZ^h9tEz*7i-?zpuxH8bWf)Z5*-XM(5*!BpPf0U z-(HWYHKvfgTo%(ZO}HsKl3Fhr3(q&OsNef48$LA>-?cIR)zm->^$N+kzbekgvZL|s zfkvUqJD6vFNJg`Rm+A4@0A6hPl_FE+P=3!?Y!8~kMyHT`iqo7!EBEkpO<>DZB>P&i5hs$VKa3! zRgh`cMBJhA7e>UUp)D!!rk}3dA~l>JhyJG0dtc$5{=c0B=kmN0g_P?$mDAS-W8}`Q zkdZ3|dA~g1^onbcbjcYfK1qaS2P}9O?_uMYx;X5~X{bHX0DVS};hnvAz}P%xOsWhO zypAqFJL3!-=O)FtP^9SGYC3%SJv5LpACbR9<`u{2=hfLyM&rXZ<3Uu)BS2vPd z+8Zs#U54AAYK3XrJ_>7=#|T$n#B=zH1HxR53Gndw0+j0XC%=<#Maf+R={GXi+N})M z8F3ia5+;T{c_!G!>+u7ZA9Q0tDS4!+vgKwy-t!|xn9whu{ik<>W1Bo4nWT)78_ZWxPP!6tx?C`E5i5sQL}2KMFzo^}aOj37O4#!JD{SF`M3Z zc*B#gU*Z0KGIKUpB%OzohB6fCu~78g?~2un zo>9L25%k<=!m*cQQERn2ubPnpCJFxBd?kjR%3lbNI=aRC)AL}z%WIZWdg^>aW}LX{ zdH^mWOYYUDFOBvNMUVL!*nA)ud;9OlOCxi6MOHGIJahPW%kJoKKY&v^HMuGde7CSZe z3Ri8_(BWh~ecn2XmsDsWxQ>TCJx=pP#RfW&a#P%@HyPSeWVl1$2+ozoqxqZ1*zi{1 z*!PC`H%Eho!4JT)=pa3liRU$OUxnE9t7+__Ys_&(IK<~#J?l+3$y8wKsI4V+mN#wrij zV0+hdSm;m*#;>kGSP?;OiyFLHzngdO`3xJR>$%HzHQrmgg!Wf&#}6j2X?NRvQA0(I zuFoCMrONHlbvBPf=KAu|KwnZ>JOQ`cZgK9}wTk{O+6u#!He*~`G2Al#MeP^t`GV6P zS~x8l7F-^KWq)P~vnQzIx&TvhdZ&c#Yuss>@e_#MKb@4kJ0awIlQ_Femt!^*IoUZz zz|7z?9HZ&TzIP(fdVL0VXYB#KaW}|!moDip%?FQuuIxB2iidO_K2de7E)( zdRfcuZZmtpBiWxfxmDXQ6)@4M>ahV#GZ@DwAC z%#wnCh{FSK{qek2GtIgA*ZHVaHpR53iSte*!l3pAJkYrv(szx9Pg-SY`ldvZeJ&iI zOuI)Tw-wO&538x=o-G+!|$8=v%agajJ?pxS#yMj?iWxJP@{OdA)N*qY-L$H}b*eitG02;ho2Rly z>o_j;s1RyVj(@&*NRiDB7%d(mM@tFcG`I;L1Y25uy+PQu^#}dzZHhg-4<#pepef`VX4z-bvQdiz$aUyy_+kGS!4k7?x9(MCJA?1Yv{ zDmZz$DHm_mM5BbO^y!Q-Dn_MZrAsqt4>6XU*7V^%COZ6gyA^kRK1Vy$z6(|nEoeAX z6=VZkv38jqUm7$R9~)n$Pm9tyXX9Vmw&D*hUoXS+Z}!AQ#VAfaWO+Mj==8V zBKWCp!daW8F`c_%vYs;h4*2JO|9H3ANts{!R7-qgcTkYa9QgG+lE1CB=W?3}ayE!V z)k&?wst-FTP~yZ6hm6sAnjGqWN}$_z%V_XY0o^Zn;kV|GVAt;vJ%6jkZ#~jrRzFit z+AmE{23Fu3)$fwJGY&#ijVC+x&w>v1-Y_aDol;huq?P|R`|_#*FE~4cO5U`J4(X?1 zWsg|6zD5fd`!0r$?*_sJ*+Ma^t`Ag(4@OEWW#0|af><%0=j)Y&<78QqT{lH6-WYqx;(a_K?;ap(5^TW(%@TTAg)z}o!g`;a| znC~n!e;6vBiWrU!O{%E5q{aFFT)UoYO!s!31Y_kO}Oz_3w*yGg$DPK?;V>8iLjqL z(+u(4!@+!Do)?&}>~i`Fn;ehf4+;tpA=LpdJGbGOJ73jnOZElb?#fbI3IWSK{6{C#JxuPuwpHJ4|?;oX6eQ=zRHoO%Y+ZMw= z)8jJp*MfexRQ+;aTim;#3se?O18t)qAvw4oYc!SNo8_Meh$Z${;hO#_@Hi&J4r_I(Pjm@Y8TP=$yB?%E`LS5q zd>_n?yW(&gJ-(eB!=GDfXiAa_?nq4#CQsN%F|+OHK;b-mcqa&Y|DM7tJwFTDKXfU{ zX%a3>F>=-)Rw>C;AqX8(Ppap>LD+)cOqzzQJ*}G_%iaf-)Ot9uPys>>ro&^W^YHD+ zb!fFT#~4LJUUSV&sFWE?hVcmyrrSb1av&wQ7K4MFHy@a0!-WHz(Msa=tXH51tKmU&c_+ zOV&KhU=;-AmD8Tr+qod>srcJszS#S}23RL^N3<%t1m9+7f{x^waI|R_zAf&HOFB$Z z`tAwZZ6nVKMm>4(NrByCN5Nv@2946vz{?vSbGB~}ypXv9%*PPeAB>@^PsXy*{#fki zX-d1wf8wvhN2uzeJG~k*nAbULqjFFn74|&KzNbG6&-d2|m;6ky&EB4a)@M=mgtz45 z;EKxvcGH8lR0?YD3tPQau=`00hH(l@X*QgX44KG%1HvKaL^G`vhrzNB@_7Hn4VZnj z51a4r&+=}@nBSvWL*W5D-gpI!>g4#~nxJ~kt{voXd^10MR}91DCbQ6V z25erQ$Mu(8uuKvM_r(KTT(kZd^s)eUe+e0Bm1UAv8EM5XmTmqZb!4_+h;{WV_F^wbcJ z2YBLmPkTW&!VjwozEVk?8_J~g;hB1Ipg*z?4~yzUb>>0PdT+Z}{AmyxweI013Xh?0 zM!C>?Rey|F9tb&IC6wU!@7;l)l$CZ4BR1!Aqq!%pdzQ@h8-`(F`g3{?*Tujm+o1eH zCuJ|!5oUa_7qyKNaZH5?1UuCM&ei7@MLjZGagbu0e$t1%%Is#g79Z5T2C1Rmnom}`3j z4(1X)O};N#cqRgrej1@pT(z(%bt!*p?G*gX6gjCo7gS?L^6|IxK<&%_C_3+duHP<> z+pQM@dWClB`OFRFX==mJy|aN)j!Sw26G)=j1DCYG|pn_tIXs`yaR- zkL#RsU9ac!m+KmVQ>S%8WJepi9Qh5wS-#@H;kT*O(~Z5P#?#4}>$qGa4;<$2;-O8! zYquS7Rp)%$fyB(nlfTn;akL^hLvysbElK&gQAvlx>+xqYgB~-h)Pb zz_UV>JK!(MESJEeWh0T-yHT{=X!;w86mu|CT#_=4wmmiC^yL5>T;{N$%{Ed`X~u$$ zjyN!VD?HmbhgOc!1wWaC!nMD-%wyHgg#=ya#TRQ)FSh{2QN>>W%{S)rEiyQJV-C)q z8_5QZhsaee8h>~D^2JX@;9K>Iq~c%DE5or=aLa=K98zaLBYVmm_k*S4kLQ!L1nxue$JgtN+IQBeKr-}$;`u`q+{@`b`tMfGMi$)0W~i3qpMN!ysb@# zy!xeb^nzu0+Od=Bza9|&1>K^x`%>Xa%_7`sUrl39{l(Hn+OQ&26NwHgQSd%Y`gXhw=1y9k-U?sexC%HY6Vwtf-uBjJ=?F+isIXlmD&#Oz~f@J_U zKXT!U^%T+f+B>LJx=ET}ALG$OX|&2Uf{MQ;@&r#^z7yIX*j>; z`m=WBKOocME%eHqz!rBcuq*Bu4(W=-=g)7k!hIFC>0L+9g3}SRGWgEpF6w`C9TY9u z2{w59JO!^wlr=G)o7QqD4OSbRV~jJ&mbbU&6iqe}$S{ z_WVI(ajSFyW=xvPDr#2VcdfQk=GQj1D9aA3O{mQEPQ zyOz4s(8{NR@`v+6|y* zkN5w@N`}^nFk{0tL$3$%)kXX!rThYP=@6OKWl1_6ZPkG@C08w?NADF`%{tQ7YUE^FzA% z&f+Na>J`Grj2cPVx0?$!w}E9~r?5Qr66HPk4wd>M407lVdk632({Zg{r7Obtd7(L8 zJ!lTq`6tE4rFWs{iDRD0H4!+~N+jP+wZbFIMW`1-P!zUav{b7mI%`5>tMdeprz$+l z;5uk&JJ6<*i(-q60}ZQLOsxq1Z$k%)_b*9vN2DwoL+RCnp+d5)#oYfB+nXm)yG(Hk5mG#*%VIO;5 zn}RXP^DwkR6&}@fif&IQOFD1N#H~hsxJSD=&TY9Wd6!Tv4tsn}4BnVS9+#gATUL(Z zpOJ;aflJ}AGkzyemyAHVzJQ%(O{BERwc^FJ{jhw=5_GX{q-Ot5FnMKSw@bRQU@y(( zcVzMGhS~5W>JgmMKM1dO?S;BoUI6o2z`uQL_x=1ysD2zHvW5Uha-|^MRhwTa86qDo zqNu?i${VP1|5e(}urs86B=hg>qINv0&dqxhDb#f@} zQc~k3cYH9-_b=_x-NXg?m@ zB!`nKGN7w-20P$uaoqfc;_@FlJp7)~DwX1i;iWLZ zuO6hNBoMt~2k&2ai;6RCXv~l$sBWVo%ulVLpv^{TxZs^oUq2pWZvBS2XPr>JTBLXR zb{xFtCn=Z@<;S07;gNP0?fo~O2Kg=L9EC>8(pm*t4>fSZvQO|V;g{rb!UU-D*#)mQ z*Ms!7YVq&!qdcLZ2Twm52050)(KIR%%Ivc!p~)N1S&Slg?F+nkTpEX(B|`qCWIWvW zBuq{oOIK&@2hB-Su+_~0w`?@yiCtUi$g~=2aB#u9<-u-_3K04#s^iy}z38rP z0B`=5%60aCXt?okU?l=6-HYI=rH3x=Q}JWZgS`4;Jf4x##fgK~U~tC)I=56puT;ta zXS?!S<7?u^1ZEkPo^+y335|O%MeU^>P<5-4CZFqxr?a}fHSZUV@RZ|=$K&CIRU|LU z(SoYnMlg3-3uj!ff$bD+);_3*qZHr3w!kVnY}d^U%RWlVzmE|OpNz(l<=s70?ttp5 z0i7Gc6b))g)ZZcYgb|90y~!b?!w`J z4M{)AkT#y&! zNw-Z#RMPnkFOP4L#JOyw@7JEvk4M{C@ymHAx$cW@2?^jbR{`VB<hr?w^s8(kG5VybZJ5euRJ=xriOrtyI0ftbdh z#Ps9(e810Nk-S>qY59Ikd8PsTe|~~EjMun@MU^4%X zaQk$z*HBk^Hnj^wyHiKRAg3Rqk7EbrosagMKl&Ni_BH3nNxeaSOfdg_(}W3mu5ihJ zJ-i#Tmczb(6os}4n5(m&{zddb%U0n27fV3>!d{Z?Qvrdy=EL04In-}PJSeNmvFzGO zxKU8zGZB|y%p?i*AN3q|rG~=FmI?e{oWD@JSfA6fw(!=6|IrCW6}D{a2ZKXpaL0%P zFm0P@=8nh5kBw;6i5-OzPV$ zS(b%x_reCMelV5?o^PgadyA-jXf|D*y#*{{6>)Y;5q=)u=iISwpEOJNBCEqSSa|dR z#jHtX6-awm>M;%XJHO3#AV z-|xV~mEj}qj)?{@wN?D$)KJmQ#2cRMl*1PzLTI_uYZ|<66Qqip*z?qCl=&%-18jSU zPfq`(hJX5S^wR>|JXnDbX!hgyqZwH8X_GjnD1|Nmp7I(MAqxqXJ#cMuATK%78+ytN z!Y59tcs)ml^~=6d{IZ)8Q-cst+bfTsbw={!hA;@1c!|fel(@d10WRO02=(WFODfvB zbM&Pz#h6H;#<(Ps)7~q*)={N{sq%QID3NoGizOFlog%GC#kl$8F3P$aOmkNzz_l6u z&~bt?zdTxiAKpBpc1?5ISh|en&q<<>akhB#z+j#lJ4yWI{+ewxys%(<3G7qaj_qp; z=y%j3S}JuKaHTfu<*Z=d6vvJZ=i%J)kFa2_JN`(#B}#u910iR&2>G9%QO>8m*rQhv z|2l1ftTvu|8{ULN-WlK%ZpPD-d<3JG`Mj{}9K79;&AZ0*AkV&KVwKlQ%#chcMX3Yg z^;v&l#%cqM$~lP5!DGl@Zy|q;EukiBOAOGHMyu>)d~9Snm55j2tgA1+nXboYe>7un z{|6L4V>{!r?!y@SmkA z4m6fxw<(9D=-yS@sF$@EChVvw+|6p1D0G8fz0!n@D z;Q5pH64P{J{AM44U2O*VW{hbFf|FL+b(My6Sj>;MAY%G^c1YuaYN~mzIcAk z?`}tEqCO)^VUcl)IP3m0^f)Gc_eR~G( zRqI4tp~w%PUK2H*55;TazmU;TdH$GYPgCz*LCx{O$hCVUFZx7t-PN7&_r-2F`gH;K zJd(~eVmJFJ@5G4cGUS27B-f=Ygk9;{oMJ5t&679q@q5lJld+oTsn2J<@inB<{0;_| zWeKuNdxG|(J}A6(!%sKcg_g-`$_{iw%vpCgL-kBn?44&ms45CVww=X z1LvMf!>^r+XsJDhn-@>u_ZydURexi)+_awp<9Z?P9L+D1ma?i_x1W1kV{h5PSohL` zCut547i`EDK1H`s(x5pUxAX)p)!$Cvi)_(lc__6@y%wHl{T8AI-T})wr=VbEAx6jS z6BBwTqGVVMTa46&3vcd_N>5e#5|=D->1L2^Z?t*E^)e_*x(~k>>B8n!BRqe(=m`%x z?tzb%KW*09Mvmomq-A^pQ(F=1j}F4PGB*iw6R4%;WD7u<&t@Ab%HYa;z?d?WO-3lr`88e!(A zo5HJGaiVdK7j2zzj8^wr1uLX=*}C8|HYA*epKcrY$lrCmj?2MZdLlNIYq0eKKaRPV z07>~<*gvUDJZ&(D``inIm3=a(z~VD(p6`q+`+tQO^`C_v75nK~sX3p#4%nscL04YM zVPJ~DIiCb%=OvJSFOe3Ve<3WnxSX#o1&GM`E^JV+#YX29bUNIP-pW?Prs#{FZBij*d7G`j+H(GZI;zZBfjgXQ#Q#zb36Is>QKG1cgB_F6WSlc! z-M1d~3LUtQViJ6P@`olaJ4;(blrS-3BU!~b;!k&dzPhp=pR6*Km=zM}>>A6j6KArl z=VM6j=EIWr6M4;?XmIZO3wx(|LT*iesx4z55AKP5MeDxPPp1Mo} zQdH17uLnom(m@^ZJ}m2<#b4SDVWws|Jy?7kYj2iN*HJ&LI`7D5mYs*8#fs!Fm&}TV zpYTj>9eFtQfxq8USk`x+5O$YI>!Uh%#7D!cJ0+0zW&x|u$!4RA>v&#A7~T&~hrED~ zLi5v1$nF0gdPgll>xY3TzFfx^;}2ng>S;1cn2m;6_o&|Z7M1S(Bw~6dZ}>SI#=bwv z^|52P>P`*KvNFPA2RHhakt(iO-5<}`rQpm#!F=}2GW0b7QQ?XfxK0_!pFbLbvjw7c z4=ujn7EY;MhdILQ6g#=yBHd-vF#NkQ{`$~C--@&0#8O49s|dxv^`)$5w2BUEIdFpI zYJ99`3h%mPp>u&1G_7?Ol74nUSBEaW_lW1Cyp>vyZ5BU#aK+s(`oX%LBPF-ZMuGQ} z6L9^@I{uR#gZs}+Ce^;LLE~#S>Bba7=B#f1x;37gI@D+oJ7G?F1KaO@M&;VF{NO5} zL4`SH&2%NhgjJ{swbZx``RZ7Gtgh9@c;6;r;QT0Ra@1wh9lh|aZx=Z%HW$wfui)dM zC4A&a6gp31FjF_iQ0<9ql{E#InoHr`Ocin2u~Rtvgeyj`)W=G%fAp+X8efj>&vjjM z*yl|wN4CuNa=0aj=JwgV;Oi%--+hjp-|OS9=>9ydyzZSMNHPN!d z{wzP-n{FJchQ;&uK*lR=&knf^ugus-@E}!!UyTKBa>%DWT}tHg=pLk8?1BZo^7xy} zK3H&7OI(vOnhzSK@%wxU$2EV4Ei?*qoK4ZGZXfJe{X`-L_r*E+voX6cpHJ)5dxh1H zr#*XKgV7R0%sW#^bG0L|Jt~kgCdH9)NH*?|_)I>tw7}AR9y#~h4zVqP!nNK3yiRqm z`<_D?^wbo{rC%DCT;2jLpSIBQXiYqB_+Ao|Xa?$K&%r;)6n&De!Z6)q`23Lz%^!c0 zV!FQ4>P@}bu~^ru^7cGFIIae+n`LniyAb@VYRq}h7UGrNJ!$H)5{kWP35)(l@~k8y zgn-T1r`x+mz0M=M_d1;M*Nf&XP@zflztW|dE#f=62&Qv7N1UJMk1uPMlV`+w&%4Gd ztomMozJwWyw-n9U=UfHb2HCOH#3GRYWDKjkr$N}hc{Htb9k%K#fTO;QWLsbiO5Yxi z6MsGsD;gFFukL!X)tfM=*G9IeJm58N=rRg%ILQAcB!RWu3y75)hNKb-PJ7k4^zIRu zr(8*MZVTd(V-Ilho!el3xPe1M3VG9yVsU@SEx0x7yqDpO8x&Tv3={vm54+ddN?H%x zVoi%s$+n2zJY456rds#r8NN>V>gZ2++;C3_zZuHDuX1s~>$QYo^KsY+S>AWX2d17? zq$Nj0f*}(r>hKi&`tv@yb?p~7b@t)%nTQ*YEEfEB$aS;XCCbZLAoy!d=kMA{>~*TI zpckNphL@7@it&5#fulFn6pe3?Z{C-dI%Q#2<_X;=f65csl$jhc4VmE%$ST3o1*oNLmK_HB?gP zCm$SOC&!CVUj&y$gJ}H3qr!5DSvMy-QOUy^81bip%Jr4#yj3$L4mm^DYxi-dr-D~Y z(IIegC+J*}3bn7Vc01q}EUK-giK9k}F{bu3Y2Z#SpRQN2tQ1>V^!@`{#{;3OS*Pb z%W@OU{cZsHLC71YJ`>WPs`C9HZ&cJZ#|y3PkQ#QJru<#bUuTR&`@DFwzR-c2ylVN0IoG>WSlg`iT5(k?*VA$zxT%8`mPRG`9U(<9v6Zi-cM}*)u zA8kt9oDK1}_JV2ws zhm?F=LXB6IU}B{-&eUt7S1-)SQ)i{{{O2?b>$R7&Rkg6?Wf1TCGL2IcMYn5$wt+hpS1dC_l!T z#%i8|N6S~Uq-2fIq83FSZ5IH~jD}6wHgwSL0vO%gKtrFdL#I=t*)K&+$TSV-Y4_dH z;6V@-zd1^|7JI?MU?*%;%EucJ&KuhQ(u0ekobcThhdl-8e;|k64cP!7BZb4;hG9sf zfOnKU1YOqRB-umsYPKs>uXHBOJ0lg|8a=FFr3YQ`wRDPq_BRz3AU(jrV;!EV!TpCwU|$UCFJ=$dEWAotBO>VKt5lq{&L0O>rBQ>a9A3*94QbQ$#Yyk>@Rcq9Bx`3G3p->J zP{^zSxAEFAdyYK5)Q`Zb)T1oxcAGAL>&3qFEU`e!5C1)^r2)MK_@xs?eMf)w+NZb( z@2@(*C5EOTvpI+lT~xrnb6v$Kk7Sx?KOQHBZR8*a4O|{|1pZ!9z-PN_#C9K1V; z!q*6rjYsUUHWN^9@iAe<=m30%3Vgar2lL1Kv*Lk7_HUNrDkFE?FgO5wU55+TebvQT z{d~~mzvI|6dOT-pd=NE_B3Z6>Iq6hP?JNp+fe!WEsjuyo)HObP7C_2qRu&_tbk33~WO*OnF@naR*mO5cwA;>HJ8 z$YF{Gp380%tw+BVtZl2QxV}+bTS8DU_Wysy?UbA_R^}qZEBrXhj*R*X!kqR*Y#vZ9 z4!E)##ss#4?8;z>abLmeCkmj#dMkc2o`KD|$U;89Aq)e@PlfV5`{BdGLqz8+ zI9}!Kk3CyEvVA9H5^4nd-+k5JO z(h>>$D3C`wI2nu%{T0+Y7h*u`XOcf0EG{TX;$43FIG+4Ktz8Zy%kR)4)jeX1$1Jpc zUMM*emC9<9MOr*^61{gj1|)KABP4q}nqz`BdFhs)bik`h__jHl&KT~78|%klh)pjvO>~AE z<9FhzO{a0uw^FZwzh}gcmvZ>JiU-YYEMWOYY2IT|DuC)?xN>Y2Zk<<3{rA;~f93je z^woTNppzW~Yam|IeaQ+Q{h;1Bii_q9#faMt^!v+eSb3!nPK)Y-UnU!P zhtg14%8ypL1GFpu33-rfJx zk+EE`#8e!-Oc!@4%)#g1ZqvMR-F)^n5@OYS_;vh0$Xzj!-BK6ArAyWfe-tn%I2>~h zIg{BX5tMf`7p(jUu5YeMHjC5n+2}ADy~Ug-s0_nY`)lHm>L*~i>j!08e*t^zd|s?D z1-*JUiep!qG!-s1UIFiBJ1$u-i!#|`a6?`g zyg0U-(zI@Z%!>7p9Wor=4!S_2S7Ev z=#=mr^b8lkX7`P7;NAw|_531MzpKf;Z!ahHxFML><1J{fCWssiet$PbEUgiU_en-W&e??TOkuP0)7SE1vnhP+TdTrs(URAy7$;VZjmV zQ&ET)cAf*xz=bfrx{QfN^@o=!req#()H_0H>sF&Qj6lt-F!1~So*rfmZB*$w5LOO`H>KkWh)RV#$(S7li>`5H^;5hVm+ag)@X)u@iPNB#%m9!;1jL$?p5<@5a z1xK?y4u7)U>z&_QGSoQ%rpy1*!1h$IQ47Zs-7M%4vk9i^NAsXU6`Z%^m1yNZ8l477 z=$ZK@x)Mg#yuZeP!Z)VC z5*G{c;~+KOALooi_1<~qW$dKKv+iU4Sb4UC`7pt7BL$WT(C$B9s8CJkd&|NkO4fD! zVVJ$=|`O4c^Q}LXT6F<#MxV&EM?0tzBB<_J5a0h(589+zLNr;*wOSgZx z;DOCA$bNYSXSye1{F=+O`l=nafgQKUxI$^Wfp~PM1qmB-LAiG}$Sn~uP8^N{)AaGy zX(kz8V{vy%Kk6(g=gCvA(5H}8PQ9_6PD$nli3+kHqhJE~3c~74DN(h<}pS;-jC(CI6Yu=$->Vg3lJN<^o)!*sv{J~f}@-+=9y^E>V7SK3A0srnR z;)aoz$+_Qt`tbW9?J3p+xpTkajb}2j^j?1M!nAEwIE3l^v11<23vUG+zEd0 z!PkZP>`B}{R*7$Ibip-}v-D$%Cic2$Ln9xVu=Ut)Alv^xQhD?aZ4bu^BP9cHiGLe; zez{BwBHq!OKC3x=ULXd=P2e#lPsC@d>uAq3Ta=QV6+8TIQF1rW-dWjK(6wnN-^58g zWv?Sni@5~zZfB ztIwVs+~cByD~|>6;m|Fhp>POF66ez+?VZ?4o5ZfU7liD&`)O2$5;pXF4~sW@vh$7E zG_VM`BUzvOx}7Df*(YF__eRLf-YWhHbVAiN(}jxpGN}JH8_HF8qWTR*PJCVl6_(qn zaKtgF+|kVw|5Es`#bF`TX%!FJSO*(wmT-b}6k5rpkniymlEC-Zp~hwe^_i}L#u|s= zmzTh2{$0i4#{$XbtRbELYtJ5o>Lrgq>tonaUye7=ro=xJc=}#d?}z&Lptfry&XSDf zhS{O?;K?HzEFHj+_w#u0*`@5eJr<-gc7to-Y}}i5mtswwP{HmcC?B~D#~lm6tL-`k z$i;%DnG9$gF(qH_KBI93;&ulUbh9w!7f1GSwBOzv$>vjY@#-FP{@_tYYyM?YPrM_O4&}cET=OLoOAfU|y{j~qyjDKP6P(G~Uzbm2 zl_D)%&SOSog8q>Y5N0Ug<55?zc4ji2c^SlRbM?6i%_vMJ3>Ftm28ak=5oa)j~Q{}dq9Iayo zC*p^T9+r_fL`@lU!u7;e2|YO?KZE2|8mPkdF7^2+&-cfv;_JBc*r!-Qu-ol`9uHF~ zp`@PXNO_QIzZed74il7|zERNHDtzN{knK(v;KF*c&G< z37UZM-_phC3%Q(`6-*^cMPT%AB(g<4l{hb;QFX6jqJtwEbt&=Fmm!eSR7KMkYhXv; z`()3x8zp@Dwh5}eI!m?dE%48+EZX@>4z(WWpyt50MUVn584J_lRw74sjjYB)A#2i|*jhxRrXQc7khAM6KUwg0|X zr(`kZJl+m(OiOUCTRZg}seu1In#)PYN+_|Ey~f6UAti|yYQL0a#r-q+>S0r!vh5&O z%D$xWL;s0~YaYSl0i)2mS`LeMkHqwO9z4+J2JKxk3h!BVz+9OuI{v|$$63$7f6YVj z+w4q=`>g_ci6tEU&xlWWuYpS&I-tpQh&asbf*4&g8l{S?@W0oN;+e?Z-0Q9q8dbW% z+qZ}XCtdknprNQ^;D*uPYM{$9A2LT@7CsJq&KsjngRa+L){0a``ABJ2nw}4P0@h-9 z;6%xokx%GFhpv~g|0du$_aN0eTzs-LUeM0c!s3IK;=>cs$kmHT zrE>!Pj#OrI=ZEyP_8feCYvHY+Fo};0*$yU$x3j|UDz7;86L9~=D5g9|ym8fJL}5-l>^SKsT>5Ct+oh{uO`ij>&Ezs& z!cD0BeG$z?HGC8$&AYD5rXI%KGm<@mJC^RmEh)~tJYc%0@l%BjEnK{o&Ob$edVV3f z&DTK3U^$fb3qtYNR#qwQk4xQZ>BE3fco}I5Yd6fNElW0_jSJC})K(a39f}8f|HOxS z!NPza!K9{N!f{39e84QxFvXt(jl)EV$x!TSOCy`ZSA_S*hgtifEB^Xm3z1d?D+>;L zMy>fJ7`>Q*y$ZBgzH$bw47)Af%?Rhg4+il1#>?XKnz7jLON2OgcTWh28-&9rJ7S9c zdR7jW#^F2qV{@z(PVROvf3@voZ2K1K^&XSvh?Aros>dxQr-Xe`Qr_c3dLYhi7Qc3E z=FDMZ#T{2)2<9Cd==?DWPJ9r6;%^hN9j(QRzP9{l?pE+o-^}N}*pr{-X}TyGjDbtn zp+{fj9M9Wy*ifE}zu8L4uBOr7De=7XiXk5Fw}E%84&lBvF^tms7~E701H-nTHB@^9 zPVc|M$znPVJJ0|nGHkm0FXUm+!K0MGY-Bm_=vgq7hdK~Ca=L;5+0!#j%j##%o} za??ds!@l@6Xrs7#{zO`vs*k>Bib?zEDaxxzqS>j*Jj64WPF->nf3CU+^YUe|k6#E( zF1E)vjiY$(kV?LnvI^gZOu{x*eR%sqTXbA&4%Y4KanHW~TsE@}dLL7Q9%ILHpi_}o zLYoI}WZcDKT@Ox@^~BUq*I>808@MH3q=^QFV&tNcI63(U>CD~tjJt z)|zYZ6lh*_<%Q#9Ik4JO@at;jK`(4^U3|6VQmP5)n;7xUkZs}#)z#Q*?m^+8#{ix? z#fJA?wB)FR&EQ!62c{o3fD83!Aphw=_$a#v)Hi&l`l7L&fS8ZJgKCBHZnB3g--r<+Vx&fOB`z^v#)K z;ifVQ_Z`RM&fNsBt26MhPdQA@nT)n+n@BcntT@eVDUVQ_!oFs+#a5dbnzCpDV&O23 zcl;psi2g|DeQi;*)DClZE+&QW{~+pb42}LJheJoY;fcnJ(C>9FtyS*Hb&HSDfL<0n z%LQpgXtv{5D{nf-*4uq=*fV|AVT>mgH2M%i4GP(f36o z$Y5R*ROSSW2agp(pPG^Qpf*Y{a|-5bZvA-W%SVEe%V+SKV+kpjM$zpsT^wQ30UADu zq7~cnwLiVEwsoy&|8BEzEU29#rd<(LzP*4~U6)9Cm=u&3spHoU545TdgjUT1blxtV zMudG6Z7&pvv82ic7cQT@o_LviSA~mtWpR>J(@+fmy_KAguLr4_VQ8C}Bs{+e^ugPQ zvjT0fbzY-TP_hLY*A&w({gJ}(8wO~;;v-e+=TMW82^Xm+Ve9NhaYuhOT<&7bJ-uhb z!KqWhD=dxfelVtE>bohb-*=&OwF`Q=s?*QMlLe(o^8BmlCu|NV6f}=6rZtyOf_?S_ zA@5@Y-``m+-oK^@??0yCgikrN&Soxc>XurQ?M#5(yw z>|L*pbKKU#(q)5S`vg~tPTh&~ue87{ll7uWR5P{jJV0a4$-?B;FwS3Ag7+G4iK;g; zX+rfG>YDRFxb|~16s}vvb)HU8I;EFncyfa{tYj#DZ(E9o%Q}QVzHVZ=vK#xX=^;F= z(C3$jU05ng5te3b<+I1kpy^wcFr{ueeu|3pdeW6I@fdnjFwxDTMDF70*VJ(Ox-o*Q zjS&VpMv|kFC63O?!=G)HRMzIm&J%lM#MT>RXnP-`zAAB8^Dc?%tKXzzTq=H7I0AuF z%EbpC0$K0p035RNG}i>(6byH&v$)X^`+85qwDtjF8)%{5dtVeqLuv~P<@LWqDK7}< zVb~HlUe=p=r7SKEHAg+Y7MweK7cKqcj~-X##n9frCEx2;@V8?-I6&G5hWHeLZE-Na zt1QOmyi9s9#z}NPKAR=WQ^k}FUv&RmL7%&f;m0sj7JIhBEu9)zd9NK-`aGuI@?Ma= zLJd!KZWWzweDV@4o`}c0YVl9*IJVyI2QpH@^iXvNRPV9y{9KmE*U!sg)V@Hl`f#5L zhU|u*g^M6OP!YG8Yw)<;+8j2^fugBeusSf0lJ7Wi8kzuTxNF!&d6m{1Pq> zE21TdLF_)Nf|m{4Mxc zq}y2%SgiJ9Q~fLq(Q*RWpG9C|n97S<8zJgk67acwW6P&)(AvnzgRj`SxF)PypJ2Eh0vZ-|!~#HCKnP<=#;TTG(3F>H2}-+?05mX~b%nS~?7j4*i5D-aYBTTob-Jcs-6^E-%c! zT#wVI{Dl02Hey)JD_Yefn7;Qnz&USca{l)F;+r2jtd+O{+m$PXg%8z9UF8jZ>vrGw z&P8H#ni;EhUW0=Ud4h6U1jeT~Q|F$C&~I}Q9WZMJyA97szP1;q{5#}zX~-18w~M ze<^6ZKTPq7k+f@NB(JZkD-S&1dg4;KjM4 zDWT~tSPZe^|K?s6KJ_)HEiq2qV?_v8c#h}a+ozFH)jtS%rihIX65-2?^$^hdPMG|3 z3`NE_<6q@aY#;EN?guX8>fkGaTzxg%Rs2k&?o8qyBSt~S#zgWcOW-G}7Xi;`gUO2x z;G~mJ9*5gt^{=^@qxMz|ALq;gJ*7DG>o!(Y&_(fMr64v_u+s-9yy!AB`v1_vYmN)A?xY6izxi2E5lE zgVN_R!roI4z^1o0Ui_8B{{9NQ^W;&iYw3Y@Rkeauoxq+m{BTLeWVHLQfTkHs!0d&D z_dgl}-!#_3>LqqKF7z!OUsp{|`H|>`{$iuLH%2CCaN5U4&g>_W_FP1jkAvY%S}8s3 z(kJDa@fcC*#mR#r@gZJ<|2o}hU5`%EHvLJOv0C_K>wgq{Ca_Vzmk$TdIElBW)$-fb zhoIqa7I(!Pqv8^Ih<@k*+tXC=@1Ldo;_oF2=~IpWwix5~01~}7PG>vYK%t~e9ZkLz zl1#)8%$a(f*0@%n`S~DLHJB)>8tQO(^k?zO%6`)P55>LO~AJa9u-Ou^AcqC>K^%xPs|BlL{ zMZO{iO&Li@MTr#ke$L4#Bn>NNOI9i=v!zK|qM;&`N*P(9@th+e zD?((?lK7a}-@gCA^TTtW>pHL3FZa#WM%QS@^f~mZRSzR9-GuMcUXj$(N5ZWIYFup? z#5u$Ip+j>Ie5v{$)ay+W-yT~cE}!-u9!j63p4uAFYqKBv4U7|o|DLp?djbD|LN zON~}q}E1SapIA1ET&$V|H_JIezNB;iV^s(It!lfQ{+2JHFO{-n1*BqiJ=*$9O@!N z(X#_k46%lVU_-d>4(8~0O5WIHfqAVwHC`A%Ji$SHCY{8CjCyj}e}7<+jyL;#&xHSa zS#j3cPtbpEs&Ly=6B;}#VE?jI-W~UWW^UM4mwqe`&qqzg39F3gk=zSNs<~BnMr8!l zIvx{!ckjo)H&(ND`)0}=6~+>wFKnocsk_^fM6r&eFy>VyTRgc4O;^oC-Jdh?v0pYg zy!RvxWjXY?W6eud>_D#gfU+a2(LK`{!y)P#e6C5zw}1pKQSMN zAJ4+B#%+*Xf0a5W&fv&_y1X(#or}}6s9ISQ^UgIv`4nU9^K~i?m_Ax~yt_@O1;G(TiGiM5B_Ug^q&ej-n*FcOt?JZ`V zmc>0aspP&yfjyj_Q0vy3+Oa`pqRh-%@mov{BwNU$L!%=8{5p%P|DA?~joN(rjxmHT zFBW1ol7u?}Zn!?mn2+0g;N&CqaOlGh9QqyV!dF}I43EXMRL+oH-KWB)h10mKeIoYD zQs$+v+$mlh7I; zDS0w~ikS7^M2zw*1-0|u_%d`5*vOuu%`aZlifuWNAiW0`+^?h7EvG1GP=TarpewdD z%3^|gF6G7^rCGn)X?>q`uqjR=+OLbE8;fqk%tk}>>%9oy>>WeXZ{^dY#hM(l_>|=B?=UzQdXknHHwi1M zHVQ@);^51qK-_p-nw#&`P^#N;3h+BDXqb(lJ<76dyTTeLm!Jp{Ct z^{01^Qgv24C*hVc>NsQP*#F=rJ+Y!o1i=R>E_go&f zFhkgQ=_*8(=wjegTU59tFK)f=f+n}V(vgRo=+13twt#Rne>0A|T6*ApnQ>&c$qL`T zdIGcNKBH;fg*)G%4|-;0(Ah)F@#w{mLfmNWI_38c>^1rcJxJOLvf3?V96gPvURZ*u zDI0LCrwYo@Gy0~nlXBj+ibHMhlXKTG+I!yz7Y)5kM;;xJT>cSAQ|bcYo8=cUsxPB1 zw{Vz$;IVk`(lJ=86p6E1#$ddfC5)&Y!Wm|N==mi@{&nRexnwGk*OmYr6|3faOQRRv zyp}-zR{p&6p*G(7@P}@1iR4bx8d{fn5Vb^i)||UW4SwHAYu!pP8YN*voin0W z;4aA65Q%yEp*Ztnf0oU{AUTlt4gR*eIIpfn^IS>>|HnC{Q*7KRs3$RJr4fKWHxgWmTnHEl|}}9R4)-e z4Ayae>NAetHO%Kx2Lrj~v^`cemQnldrEG2$MACJxm~rwenXZ&3qZ858*W(i0#G7K| z2`g|O;R4oW>bUUJX>zFCPF*U^G<2pPO0vh`9n%|hyZROd&DX%+wN@CVuR_V=b_#wD zTd>DRBYe5p8a_(_O)AW$b4z834a4|({7t$Dx8P8+IluG|WP2|c7?sQ5Z>fO0Om>mM zlsj-^^j#?T59fY{2KaHrL~c@CiP0_cESx?qIXLu%kTHHzU9VmWcjsdL(t|$~o`619GqFZJlUuUJQRdib9GIekk|WQ_`?V3J z?OK6x0|$b6;RL>KHUd0oU!YLEFW$IH}GOcQ~g)PSI9ecB?mACEHMC zTP4X3Pl1&&ZIbaa->GH82ME`U;-{w`(M3}?zFay8Wp>M9@x2Oh?g>-eKP#I$7U^S{ zcNT11l*q{%*QqFAsgT>R3~b^a!Ksr2=wh)k#y7-BbPoA)ai<@0$Rj9i+6C`ro?b@Y0Si~H`REv0sR>dQ*{HvA*SW@?bL+-4qm>nl9#l0pBt#dz*+ z0Ed3PL>~%fQ|3@Pti87vRP6te*Xse2`5SY@v6_>(Z(bfqeO!wPM=pVfzaHOc(_-=a zO6XYD1M-Yc(7(#>AY~}S8P!9%-`swD;ffSK-1bel6(A#-;nFObHq#a#N|{3e$JTj2 z-_AF#+@|RVUcteXM3{ehFkB2yrf5HB{ALy>8Dr^yA9gRp(!cXSs8i%aAD6L~T^Zee zU_d@I?P5^t2Dr$WPM_;fw{pEGKWg8FKzx%O5nGf}y7>!EC zZfG<|la^+`qh_BHF+A!Y7%g|0$90 z?z!8Bt#kL_idDfpveO(VUmr*|Yh+;j^HDTu>L`}69e_0j>-b28Cbd8XuAP(u=y?i; z{$0sotJJYdre0LAjS?fjrtt8|tJt}wnf}h7j6*jy!GUW#MaB3%V6n6fzHc3j|9m&& z=>5g)@!Uk16*7d!?b-&XUgXg6fZn{}r!U?#=?m-i`{M&WL-=*mosIX%b5F-fFuA8T z#!D%Y=AhMdU-J?yx5>tmKY6r#>k3wD+fIJA()hBa7IfYF@!wu6DE+(%Dj3#6#gtnx zaLh+x;`I_TmbT>5>Z6ha^Ip-Fl!)4;R*59Bn}nlut63N@h|QKOIF-x0qO5BRjD~4E z`Mo_(`==&6P>RLVhv)F%;s|`?Gm<_v%?#Dgj*7M!#Luk?d8F*nu6^vYGhy9=L1DD#KxOPx)j=P*J+HHI-ShFWHY-bJgaI`bP8 zcnVHqCZ_V@|Dx&mRA)4&}}BW9Y?=6Vw``jmxKKV#TXwD)rq8>ORsu z<;ED0eP#)B{0gD%O(^wAtR$s(diXte5G~wwSx}1Diw|lWxXWZBhV@>{3Ulwm)#57p zbian6ED%#(4iOCwS%9Y94-9F0E}k%xk(3yjaL=n6h#m)MSQm1zV-uZpalxla1+2B@ zr8ui46V594MD=;m-5Yi?AH3e(LFS1h-@gJ@N<9Vmvz0qEiYR|vCp{ZMFuO;T*#C32 zc>0DrUY{FG1IM+ARS8A7)iW9fW+@BFo6{&>cL-cE)c}=Go7qIk0XN!>VAYa~kUnM> z{qVR8?@vFZH4k6VnXS@zax;pvb}zwE=1yeZnGgC~M{<*SnNaPf#_8i#xV8ELEmd}< zZ?^ViV}p3&O%Pl!sUW#x2hkz9P&{25Oiv;r$k(D5>$;&J-%@T^A|d>On~to4Y*%vG#;*MY-VEGDTB+F0TA8l?Lx;G+pjc+uzz6d7gEgh}n3p>R>0 z6}T6rteoMieixW5h~T7NM=&VGpKQ(V3AY1wVn+QoI^DVeXSF}2mhE|PN5zE~RH*T; z?_VT=X{#x--%Fl$Sew7+x5LIhOK|h82a*@sk#O>@4-VaS9u#{^bE3v!R+Jyfhf=I@ z^t1su)Mg->x!LgKR26JZwH5cdtOgImWpKLj13WN{;Z?b3XessQ1-jEw9!|h6+nuy9 zb~t8QHw*5%X*@eT98av3!p6h7Fg0F_7GCh9^C^)Sv)qnH_jbqB)zVP8uZ4a&+t5>$ z&tiQ@1~eY-$xD?E*9}&SrK6!g#gdC@{7h~iJadQ?3_?}0D%^%wJ&7089UZYO=as-$ zKhrgX^O%}vA)I@oie;<6kXnC#di!`<-MoI$ylt4gV45gPca{{0n*%HOYLUIz9h%_TQbJ!3 znc|6~vV1zVH%ARGpuoKZ$-e~NqhSSOGlNLwQoZ=2AQtwA)KaW48z09@p^M2Aw#nZq z8v1DSDZ3b)S*nQZQ@7Jz*;1&z(UZ&7C$hPF6<+qy;QMoJ&|u;;+L##yEf)fXuNP^aV`pno~*pS%O63Fkpdz7)(pSPBzjh z{);HF&exG{?j7U!eEbMj@%cjiN3{#fDtB_l;iEiR7yz-~PQ#3X=@9VEoEB<-geR4o z@Qs2JM|l;Xa*qOGLAeud)Hp#m_uQ;|U{FhoMsHx_Vs~-zgmmg!s*4ld9Z=!@d2o29 z4!NiQ()~*9y5A*NDSdegbv@FQboCCPn)AE)*Td_A|D|oT-Ea-sN2ZC3cK5+)e{Mor z@lxzH*N&S;F2DzCFOx-x3`|||kkTx@FTi}CIfRJ%9;b3W*D&MH0h(z3w~{gZ_i^--)osmlsDL-RD{uwhOq9W@>aaW}1atjaBt_mjpqmXieW_(n;_@bYjIzS+NlwZ{UiuUaHFD8}OtS_enYZo};chA`vvGQ9HL2`{ZW z3?El6r9m;hIDYXD`Zuu$dl&qnYp1n^;XA&N!m~hbi~Ro^Qa_-}&kHVny$^1m(}WF$ zI;d)7jgu5M;?0VQJg0XZw!N@sr|$W`_$ZVgW?c}s*V^Dyx<>bgpNG=id%{D&{nmBj^=_$N}xnDmZPYMxVi^iewX z$%yAK3B>qrjv0-46sM!toee4K*LICs-gQ!adxFSo{=wn-Ra9wWEoL;$#ldYYV5r#& z#ygp;za6E7`}@Ga!HmC#ZQ**O4LD$1Z#pP`g}Zo)bVu$ZIfbJzM&SxA`N1$SNru;V z`QYu=N}g4n1n-K6irR12@K$T_@$F+9(x z9U3*K(Gm;Elzci+jCD{S%2sn??X=gD}>>xj7GS7TlN{07+C zsm;$q62blWOdR#!0WrYW0h7Bu?Pc{sNzW(6l&CAx+Kf|T%$Y@;G5o93q|$v{W^YAX z^YrQhgY&-@76tLEZ@MS)VkRY+i?F@E5Y{1Ia;h6MbmRz=~USaC$nK;+%Aa*j|z7v)iB1^+B%SHip00ql%9M>9!lbecRt$ze+q#N-{Z+~&#JV%~9at#?3#n8Yfsbra` zh+zqZqAEv2c5^UIbQnOpn@&-{zK5EQZAdfk&yD^Xxwk_{rxVoD`#3U1=gW z%x$6A+w*z(y%ECIrC;FvM+4kaV9$TX*zyrsBib-V9)EU3gAU}8cTyhc44wxjE~WgY z(G-UbdI^e8Jn&_|>+~>GnNz=3gJe<>DegUsJ*6k&$iAy__#A;v_a6sC#T{h-QJ>cv z&Ej>LO8je#1Sf3&kJ_L}@SXFT7Q0`DPhoAe>1!TcIkOC^Z2ky?-A3Z1fvHGMb?`Lw zfjGmbAL|^PD^{G)=2*!)GCOr&%+BnM-`Wgt&g22kPm_+*@j822;C7IQMLnmBulJL% zE}i5=Gt}BKnbY93@NjMeZL_)w0e4=)f;BfN;G_&59@#*X%1+gtT4;){HWFOXkwRyb z>*@YkB_7#}z_+l0X1Q*oO}(P)DjJ;d+8;+GwPoO8FpN7@y-9Ud82x?xMO>-*A6?tE zotrd%i|6K6W6aOlSU+VN=v}%`Yjbj-?f#iMTk~zaC$F7C7WP1s5A860m|$?M}NuHWOtm4gj=%JLuZq_+`_m2<*%^~N~BQw2A*x{2BQD)>sI z5naAj3ghfF@LbeFczR(k4SW=cy>s@{731m9^Z8Zr?ZyypnW~L3v!dzy?a|bf(D^ zS7mLb<0GD+YWIA6RSLv9@kdn#Bq`h@Lz}BqyVl8Z zQA;e$sO`^7++Wa$^lC6no{PYl}7(e}5!c z6h`3iMaQWAO$7bx*hd}<%;4>~F>q(OCwq17fFj?KSZNi2TO%5AWQGp+(edN1k)FJ; z`W}6`q5(&P^x4?N97iU`(b-B@bY3aVR%aekZQvT3dsc=zvo&$iNhzM2)`Zq4WSyP7 zYw+@YZIa)IHq4HZy(zXRn;~^dmk;x9r^)6oOg0j$p#3U)=il10Ez+FvqoVUFvet&qKzNREYd`GJ=U`G>t8W4i{))AcZ z`DP3^qQp=vWX4M-y zCz0a;8piak^95P1jN{lHhS(xK6@qQ6mpa4UKqp%mLna&XCj= z6hhI}Y$0+)wD9(t5q!3Z!uh|Za$~0qPCGLj_pEvVOTLX~-AT&qXV4DU{*%I0!?w}W z`zf$}q}UfxnF}svL7=JQP3;?fPhHoG%oa z48!jp2XT3*F><&WJ-YdnpO_xvy&+0CDLoU84e5oLI)YZ@=Hcx}FWxKd4rgW-(@&os=%|~3)AXN- zpGWx8{P=qm=zd5D9{!y+opj|DlnJ?wNgTgdpdnt)9QSKH&flsei79&}Iiz1%xAKG& zWKWoft#7vTi`Y0^-ba~4?1%bq-B{sOE4&E%1U?50Da|*Q4tno^Q$@ zznkP>`2Av-ymEm!`gtrHeaeQ3&$fYu!cI_~Z^#2$3MAorg{9E+tV2+ior1D0yT~;8yr9$DjDv1J6r86D zgI!~xpV|Z{3|k4VpSp8XyayH5UZ=cnrc$|6Ri{+73!2V0gTk&zzVac4Tl+ckm}#SV z%pz-yzOz%D`=AZJ+-j2T6Bb6cgK9sN{1z-?~2nmk0h8I#g1~FnBl58mz;P z+LNHE(+vgu0ax-w!8z>*SlOr2&7vaSnRgmB6i-ot&uCo#JCRF%4Z$V7q9%ry#DX(CQYW(X;q$I<$7ln{84{fbSXJl&9!B#Kz| z%?kbR8)13aWL!>w2S2&s#HZU}<~R>_{C=MHDqj=F>~JH)sSbYR92H6j?`S3f}H}0&;aKh51we zO77(i#FYj)pl_GY2`N)qw#E&Lr0mdUk0JJb>dMcRlEJV(4T2XB<06^qn50)h^4a}R z%6=UsO)D0H|CB(TY6sPSPJ@ZPhgsREKRN z2Z+~=3(489fIg?F@z6)TXwBb#_;31o@SVR=bTQWA{wt~}$cAnLDxo~ck9w#qP#vP_=nC%@32KAG1|BiF4*DIa89a-4FXB(~vaf8gyZt$sX zBA`sFsI+qk+X$b*!5aoFp^Ra#k-!CTt%;g3THDD|_#)931GV17Eqjs;vDVF4{Z zuJk>25DUlu(MAt5_Im9CWnV&sG*?r+oiH5tg{Q&P^#~uWZ_(k3pCJ8JO6XLR!M@$C z^ev*8R4Z-Zo}VE<@mUNlQ*!In`^502wWslU`W4z_IRw4KGFVCfAS_TjArAPW!e-Kw z#I12RFzst6g&C@|x3>nj;w@0~8;P5whwzt78A0o-4BFibM$-=}@H0)B=N2udEAtHC z<(djHMD7{w+joqdYb$Btmlm`dqKzvwQ^l8~f04%z2lhMn3%=<%@RXoM0vZ zM-8U@rw;Gs?ul1g)i0J<41~tfY1DUJJifDDNGZ3B@KmM)_I!1TGnB`3{s>n-K6r+x zJTL-{X68cFm`JqNNESCJodKWIU39i-KmM3efR0xUP${k_x3Akv<>L3cg;vhIDStRG zRgQ$Cu5U3+HB7V~W`V06iJl$wp+v3G{3hO$RUh;dtg~u)M0ZC8nQh}lZDUk8Yk}8_ zN8#V!({Yy4J?c{31O1<;!h(q5TrK?wj|uR+jxybwNV z^rs5XICRl2fFbhMBt3T%>!|H^s(gG3jE9{dXBlt)bypWB+CHK4S1i$fLvQZm5(Q@R zIWS4iyDlN+h|p_91LixabJ#F>-VztXpH~dPJeeaT({-By^goF`eP`ongAlwH_6TB9 z_K=>{8rmb2IBq$vhouF>IlnEBen>iL(al7rO}}9AM^D6__rdav2KSNgpwu=Q)NZ~i z>AL%g#v12fQ}Y>WyKw`??@p&#qt?}aQZJ{9FaE1ufigca7m z1kFWvAP=p1j%5U|>M;uT-nHUPoypLwzl?Xq3oM2_uCvG|!D2=_ zK9QG$n~^J0N8#%|f0aTV>5SEWLM2qrM@KE&$?MXNYPj-H-^L(a* zmljsTP=zOyvhfnxKX+tJ^JdCE>nU{g8cwqA0qB@IkWvOL;u+0uto(H;Nsqe$bw37E z-;O%S``iUWaS^V3caX1aEyVsuSMaKwQQf<11P{GeAS_<_3lbeyb8&bo;*gE_DW*Fo zD#JN#+*tAan0jjIY$Uiak>43C5zrn=kj%ZKw_Cl|Q3Oqo-sonM4#hYgc%z~V&Rd0XrZi5!BhSCx=T0@TRs!|X?=#1<0f&1%OtvBGgfGy z>5lPxifX&IBssov{zVrF@bv2uXfN|cFTaK8(Rh>2*Y6OAT_93A zn<%z6PhqV_BVL;@o!?&{OR1aIam3BPj`#2vn0}vvs!>kZRq|1E(c2FSpN@mDu9-HJ zL~*pvK}e{13{71l@aX;CeCX?I@s<5ru%4SQ{ytR2QY(_{erJRWkE;ivqQ@dw8Qjgm z$Hw8c79DPrK8AIM^SPJQX4v=wIcIJOq!~*%Qu-|U+YH0z{j!)msuB(B=D{D?E$p>w zJImSkhO=jKASu>J$UXEz%-s=+G5tr;k3$F0@687|b#sTPuzNcDR`sDJd;P%aY(6bM zZc5)@ouOan_fgNGjWj2}52g-@gy|nV#hJk#5O^sJKF{tAQNF4|o7O)5EfZ9?|LcAD z-jD~rg)hbNj+$KhZXnJ&kSAzt-HZSJj>1^e{k&?;X-ZKQIRAnv&JJJCsk=+zQJ=@4 zeMb$q2#L7Cbq5@bYoHP1}fv=w3|!DfkW^?_y0fI z&A!v(qH%k)1>K6-MsF*CZH`5eosy^c(f<&sY`Fr#G8r81u#T1KqVU>i9A;Ep0F9Ok zGV;F#*XpfMSu~E8Viwwrf}e`RLA|zpGn$j1-)4CmhVYB)Wn$O zQprno)Nwc^%$$`ZsQufC|LTHi$ClghCGZTwqym)kSOU9F=8_7-itgoCthAJCpR?4?yE;2fo<(oHl#K^1Abn$z!Vk*TR%8 zZo`SJ=b?x_mq+2)MP(BA=09})^9pp`F&7OM_;b6w1&+8sjC;SThH(}h#O`TA;oy(Z zF~pCSrv8F}g$AsuWW@zjZIF9?fJuD_DjPP6{T)yYE~$rew@;Cye>cbVA}DS+PuX@1 zy<0rHcd-Z~z5c<@vdiTC>X6vE*^wJ6d$Reu7`&sRfXfFxq9J27c;e$6;qb}Pc=Ayl zRU6!**iD+WJuirtO?HIItP9$n9iY=91I<15i+_5XKP(-E=Tk0H)q-n4Z+5eH)h;gGY({@Kd=a8eb#eX9z2ep09;o%G z3sf3iATTM*>All=c)NZFugQoNrtez~R#)utQr{o2uB?KV{tbn_Ikhw_?gihPZBDa# zAElp_!|nb zhHh@|?;PcSg-X^f;((vKc%Rl88ahE=P;JfR_|`gD=<9}dN)@of#2bgI#c=&GmfQ}r z;xQZlK)Y)>rMt>AUG>BI=@N+jx)UG!Y`|8tN;-SAk%~0mixd9D3huurajC*scD{TV z&rF-l>0eVp^}8?M{k#vB&6ouh2juwmgkgB9zZGBIlS8E@FZkk|Aj~h+!FY3b95UuD z%^0M>`E&0KylhBm&dThTxC`ENT>!h>HQ9Pc2_Y`VsD^edv#o<>EeaRS z(<-p$?Il5D`Cb_OESuxH>fy_eR$+Zg4CxQ4#yCBH+EF=(50>qxjc!S>D`p^;e~adO zZK+VwxlVk!bP&w{>n^cdSIF<98pJ5Kcf#(Z8K{`mDK7b!O`ZyF;CI-E2fh3Q-lnzP zIH-Z=X6Qkw`3xwjI|xh8CQx$!I&$yk`W@lPoH_U`j%zc<59RXal}A2ecc0Jw<=M)@qch! zm?qYEDe#i=W>}K67LU2TVTuz_*gS=gy1HRN_+jz&ykrP0J_vh{+#}2Rl~`ag59{{G z^O@fdDCCSS`@HJ~x(_l~oG=kKT5AX?K_|&1<$T>H^#ZO9{|&EJjKI)hJ?vb3Lm1Gd z!g*gkQDsge^(~sj+CHWHYWZPdYJ(E>+OZSmUS~kkcpJ?4vr%%aHeVd7`GZteoy68> zE6CbY4~MVp&nu<|Lv!O_(L2DL)2dVW+CCd>x;+84W`v=)Z+}*s{Fkmaeu68dQNr&- zuOvlc1AP5w%CBnI;kl_7DB$2OSkqTv-P=!vwX3wSV9f$2?X01=;rDo4{`(9r*;Yq? z!^}DJ-+2CKXw1qv*}@E!wH!5n3-4(8Li&EmRCBm57Rv2{Yq9%aoAE$|8RJ20yF}l@ zPO-_x-=y}mQ8@C{470Zy*(ZN09)B*lPR*xc~Nrbd9 zlSLUH544TlU3)F^JCqDgrPG0j=}){ZJkw3$lNY;-{ag$s?kW3f5DXy!8r z`gsF1a&%GGp~FO#R{@9MAWlJzu z+EdcgwGyU|oy`L@24hj>1qj}pPmROwLC#oTto{{(zb9W4|BjBMmAl=!ypXBPd>vh@ z*A@@GyGHI_J?rckNPy&jXElc)(XNYrGmR*m(jT zSm+Api%e-IREynn^>$GxXX?$rmO?5V$Sbn|=iDDSFMU7yZfJ&hz={cn&>M;r9qRY;pgsNz6V z1GEvh3PIz|#Of!t6yaux18w8^WKC~0IW>%41Zm=}tOFEkYQW>Vx%_S=^2ziFc%bqG zjQidf)*n;hj`T-V-E%y;Zu%>Z{x*)*RGRbXkBivF_`I;B`2!pdlEsSbi}dv28o_s_ z45m7+h3LOIbofLWSMB`_+w?}$rNQ$sKD@22W6?@jbMF5)#p<(1kN>Fb!(7}fznh<& z{0v)f8?umd38EIM!h?(xlGNe$Xg=yM-;gPVGh^on>uqANueJu4We>nW9)|fR&qIEy zH_PsSLyLbK!hYF2&eAuBLkqvs^Nm*cs*juCwyY3JQdi(w7ZXfgE1*|j2OLw-3rfbF zq=oyYbE>H?Pl`TD?W<4HuRVF3TXR+PteA`)vQ~KJy*gTMG~vP>UbtMM%(p8dY1P7b z>>cDtCi-zW@U%258)>1tz7&7&_GRfOJxIOEh$~Dy(WS3D_qpE$agk?e+!J%qHabbO zV*gS4qNkvfrwBjk7SEO2$B~&!xlhkZIJ!LpbIMN$+1j&li+3O_IyMFmzgka;*9P*; zgdh%Bi4cz;ghgNfgN$=kLg!|4eAfCCYW6=A1+`sRv2Z2LUw2Z_k)6(y<@dujVW5yd zqlSVX3Ux0vYiQ@wBPcz~fR|D%RahwV@xwzg|E3-WD^F&Hne!;Tu>Zy6DX*Qp4!q@- z9z*cbNLPHlxF=3+S&h2-nbfpf3R7E}xXD%u*LzOHmwJ)dlz*Du3>m@tSLWlw{Ppl> zOD(>7lDRO(pWQf4cLf4Q=@J)B30ck$`DM=Rp%#h(dw(h9wx;V^ zxES@qnsd9rzDAAn4kYsWQC1+U@)AD$+y(h(rwKErog)7$j`+TFB2B^p@O+^u-ai>D zl$hRuqRd1(w`hm>dUymF$=;zpyB9 z=$Gg0@ZTq`w6t1*bHcAlUL9V`Uc;V>Ir^i8>24dL z;hzGXwU&`It{;T5v+slI@{ep6KNwR>3(0n50uH;K1<_v0uxGpm_Rdmb<@?uQpLaS% z=%3)b!<|H@WJgHaJp;SmBRH)o)2;sP!{p| z0QNR*rrrH=C~nXZ=v}^r>bF%whuQ)(Fwo<#>J8%Xt{D6pVn)WddSR2^CmPo?9a={< z(8}~7ye6Y3~hf4q z=_2HPfCDy(b;t7MSRt7?JNy>y{=|amuLzV4-b=YQ2SM{q9}Ja}VEdGtlAiB};C!J9 zOuIMvEj&CG8u=d2W zpd&woH&hGM_9>cvww}g&?+r0=&2+f7TbskDo`k&xP+Y;&FN(Xn2X}Y3UEE>u#U(&+ z3l`kn-QC@S1=z*iAt3}01a}F9%lF;?_wKD%_3BO4Io&gJrhBGN)znD$ugmg~Il`Oc z(hM%zVX08tAnDztKL$1EUsC+3q<^`QPRPwyZ z4`%#8hW%2uA$pEtogk{gR2wurl1JsEEkKp=tv;0STCZ=+l6{RGNBB6GE8*Pu-MM<% zRXl#j1AA9%Ydun~EW_N_Y5+HnLH1`O?SU%e(!M3XE@2>e zb1jGDF%U+b)zgwg48JyTC*FO^y%;Q)rp3S8uRk~R;1(hL+6Zsz(!@}wZnL%6okze* z7rqEG3|wCx;;cD8y)ME16~s)074KLKnbP%HXn_cGsbV+ib{M{1YpwRMY=TOMnW?=)*H6GM)aO{v9NJ{e(R~fI2L%XVkT_l5S4qU(`T?03gS3=?aC!@;vf` z=lnC5Awlj^(MdrmLQdh-$+Rah;Z1-p1Z)Lee+AoB@vzaAAN@+PAKM#g0+@g#sN+&wBorYa_(- zq=Mvs``0zlTc>ue27XrSmq)96gt~Trm)JFFF*g^E{&8`1lV;()smT`)C*HV#KXZ^B z;6pj~3cKkWKFKujTIxCXi|7^q5}J4*N4Ao@H7&E+VO|cj0S`&oBa*vP;GQv9bN~iI42a^}Q+IlLWVOfQNBh7% zuMoz!7-HH+=9XNg4^)puuwR}638+5XK`y>D%C1Y%#mIrhC=w(goDjhA?ZAiauh$sk zYa8#rWSh>y(NOJ=#1^D!ip}wG)NwDHkg@>pD?RF4eQjU6y&_FQU&I@p46_ z4(vf0s%zJY$xrvP4!8Xn1wA|FD+J@c@?`TrpeC|58#002eCd=IMvHbMUcz2)Hm>U+ zBwqVG8s2N<&6g9|N$kI6|GI1*6>WuLY>khK%HwA5m|@3`uv*)0OaFfRrKtLS?aF;e z=pwcz6mhGh`kV~=uk~Kf7ZB#?8;kr`5<=}S0VEHOO(DNao~!SAgpl*Af8_?r^T$ekMlx_`@HGM z;UjXma6YPH90*+5^Y7jQO}`1I{84wbKA9B>IA3?oHgryqkUYalLM~5!K5*7wHVgmM zQH93#FAkdDhtk(?4Wq%UbD*9@)9enEtj@?x0n4+xkW+_|{`HTUd9`F2Jqho==s_!p zvqyf)#s_)%egI$oKutOeTBYpSi{{&JaI-zZO|R+0;^X{TQugH^-G$+(xT#ELkXiy` zKg+ea?J&c{NF6?P*(Oe@1_iEq#X#j}^!?*4{F-E5Iz`f#>OwPhO^-~sUaJ2J-)uG)X8kOb(W&oL z+naHl440Ts5Q*`M;NtSq*qA|q7p3~bjzZ)%-^^O4etfGC)0>odQzaM#W@ns_eWCt$ zq=&eK_Dv=5K>kYS#=Dl>gRpY>HLTrC=Csxo$+iitl4>J*!)&aD^v?F?Yma$FmSPq= zw)ys|k24Po!F8{1m(GC9rSlu6ztA%p?=IM};VS&G{`ZT;7g2kMq{HX>H^f9Zw^ub_ zK3Asf1MMMTC&>;dE@uJI5uO~jxHAKW&g04E3y45EI)kCjHZl+f5*Gk1j~*n<4R@H- zutT;=eoGd?6dBm?MRgeNAPyqHA_%2+>Xx4HOND5KmqP5e3}tkn9l&CTAmHeQE&zh3 z3>l&`gn}v)hokuNpw7Xr!_QaFdyk!vtGciCq7gu2?gpA5e$@9co-h|1_N;L;Dxpoq(GpOvw)cW1jrlc z6ku;p2`%P`1S$r>0PQ~z0W1=&puPPH(3L6$pm_2IwaG z<&25|?)DCd`}7!Ky-@;U9?J&JO?QNNvh+Z&5AOh=gEiUh&j{~kx=zq>u!@W-b{dfT zPXvJSA`LnmV+zsO$$_Z2A_K3^X8~vO2mr4k9pI!yIiz944G_QfL3Y||4RR3K3n0oJ zhcL~fL;5EBA(KUe07WA@py1fj&~ub8v@Pr$FiV66?Y*)GcKw}}!4|IoObmXOmBQkO zLegph!xTfZh#q|a&rww1KiglB;EHF+KU_k{5DX0PW0yCiiti3`DNF`*ITQr=$xZ>4 z+;e4>KcPa+4zZz$#rKfGiF$yJdH}RMr)ijlMgVwFmkagy0Vn&bhXSyS9s>O5RWe+L z0D>NCh5?rN5}-R1o6rcyIN;}I4j_ZbXP_}ZJ@hqF+$$tyVM*yc|Dr`y~{YkFLq!7Z8)i9veQIye?`+s@@2Mde(pGNTir|~;? zDfK^{wEj=IPrlgqU#Ek?2#J&2KIkOnfYJ&_w+8~zehQ2Dj|WpRYJ9fUH(Da3Xp^N{Hd5BJ6~4)&$H zts~XZU}fwGHEv6<7P8TfXG}25(}u}6+vI?dzo#3zZ3+_H~^G=ROohFteTT9orC0^QBXckJv z>a#^Te4mmsRhLGXXlB7pGibKqJ|g7q{}oo73xmp&1C9q?R-~;sKjLzprl%W=n}n*$ zZAI{G3}~i^9j?L^EgfNES@X2iVz_1?(?~miTj|COa(smT^CpCRTJ6!K^y|AD-3YF= z)FG9SyY4my3M1ROFdKwKlgcc`AWCOX5)h>ucF()8~;Q zO4q%*9+!b~MbodR+jXri>tL|Tj~<}^`iX?`)}`t7lP(dFkJgc11+g9lU+$VY1Zi3u z3!_W8OOlMqjFD^0AO%WLUlsPxnt%5rET!G#OQSg9KZFK4-aqrg{raa|>!Bz=_bON? z`~r*nA$gt4XVqvtx7bTvtl0|FwojZONW<0laT4cX))Uvf=eapdwh~)=ZyTW-U(tZQ zfEM*9PF6Z2)?fpnVVeZEqoc6-9ae!)WBIy)q_z=8P+ss;-zN;L4in>qgXjC7rOOG$ zd{a?Iuzpl=W0ZsyXl!DKC}KglmELq%q~O+e7Ju?kQhi;xjhh!$b+6jRZd3k}f?W~4 zT5dg}Asw=o#?ro!x5MxK^pT#Q4A97I3L;mo6?r<7DMVPq^$i4RDZ+_XPqep?MIyw}!VkAU`nT4;(5@I0B6nLJ<4%TJWkKcc{Q`UCU zOn+4=RGPNd#*>L=i&kX&XE|yl=3X9h3r4Os-**_4$w9eSAn6&~9?#}o$}-8;04z!b z>t)$Ts^k7nF0JOa-aDub{@uaAuZpcU^SfB69Rz2~+r*@9LLX@Z`{1 zZ$-mI&P$cJGW_LDWV)O5>+}MC*VISo4OB79DO#RofO+4xCKPi>okUk_CyQ4lnvQw~L`95)y25{AObuWlP~2~GgH7tKwdi|=;niuEDiidTAXI6i5Q zbK1g&EwXg|Er+@7MJxYy5tWK{IoRs70t4p#M+>(a+MGZSzQF1oRAFa91S3G$!HI&F zo)B3B!VxJEJdhw_EVa#})NjHYftd>KvN>K=#g8bYo*AxO; z3I&cEeOn|G&XZ~#Jk@^jsf>B89p5Q+;YDzPl{po4ws3%Wc0ujuU3sSDEOW(4Z^VAi z=Q#|93ea{2)~DbCc&zJzmj$#H3=OzOfPmt`b}RP#rh=NOnka2p!}LZ7CR!pxIYfDA z*~YPJ*^KwHjcjdFn(&KEDP;u;TYGptXR>>92>zei^dg)^RibJ`00qR>XVQQdnk5l# zP9Ce@TMYPuiUXK_@d{p(K*CLKL3O$LcI){W+dNsZz3!J5;!IpLp5}Z%ITl}^F2ivO z$~mm9!We<#_?3$~$ih835082e5v4?*KJYAv*C7fK@4n}+Mb+{KdkF~k)Ee4S?uljU5roY2~QcS!P zw};lrEoYgQikPVsP2(w?;H9jgZaK|1bo#@zob=N5M5`ekHO}yRzB~SEcni%>96dyX zDPFVxXxRp$~!<^xqTwPY#``O**Ga;C*fDl)xXiI-AxEqqS7bB z(EGtMG02RscBcYIji{AXw;&5rkCgvX$25vmm}bu_j43)9PZO>@t|o-|$EoHVA6Iat|xdahuiOi4*m~n-O?%VSSZIjfdJNU`#Pg2 z{6djk>Mov$6!0Pl;i7N_>XrnPu#DX>o{2Id)ywF(ZH#LCnv{#pw(25?bitc~* ziGlKQZWKo(6#+N%SQyQT4P1E33olku1e5C&71Ck(-(?&F9jI}WxNUbG$j~SQN_#1m zW2EOFXpV8HuOHFQC$ z+;4;5qY0;YU`Rm&I>fP#Wx%|zi=eow06BzZ+0|Oio!gv@^r?j$aCYBdqt1!cJ&_VB zt&@3)SpLC9D1(uWMeI-WzpL_7r|$F*O!MXx*E|a}O*lWwtZvw`o6Azmb4;*^_qcKMLU@)e zB1Je~@;IuOXl~c#nU567!QEPV#cON^fM%%XySOc!{0FIMSS<*fZV8>X+?}IWY(I&3 z22yrq)BG?e#1BA{McCj#qxR?hxg1-R&%vj}06%ZiYl{CpDxF;=a>Wq1!saEamMt_{ zs@kA^TbzRlV`=4^&JJfm$6cXJn6pVFSvJm#H9-sQcBi~#ve;%KGJl36)#xb6Pu*!RAfErv=PY+r}Om*Aid&#S@)&% zo8tF7%)YhiYflV@yPg-Ql3%#~MV7=)u)2k}_Gv@-T-e_a_D2adt7t%)uY+3t0#%~c z=VFCf_KSxj4|BJTJZkZ|kRN_2acB*;q%dq;i1L|CM)Njl{$VRDW;D-sEjT!f0Q^YX zmIGWgOBxe={S-S2Eo?mSq?v+fz(yP;d^daR^*L;A1O|&l_{^_`rgmMMt>DVt3>D~_8Un(m#N20uwoF&3X*>C^3AS%vmMHab$acA-Rq%1Cx#!Kt?tFU)SG>!dy>+5Fk- zy0TdfD#>(tH~cUU3~`qeyf~wDDD9O{{B*mH6@PuPXrCn$RlA~dkgZCO)wLi)rr^C* zo^C7)4Ys$7_->E)9i<_3FI{`qS;^}K+ru1{PVgS`D8rAS(;1@PZ|vlTm21LzZJqJ) zBK7xugpRbU30;up7{o~dM<&H-!MPNci^(nZK)dcDneku6Zqrx zQ>S{T-UCC8{5+${K~843AUtrLl9a zS>aW}7Z9fBD&10RNx?N(R@6Rl1hrQwC> znLuvqI$MseXG0s7*UOkCIi&Hnv%-me!OU9Pt~jBJ&DG{$B-O!ysc_Z(I&zZ zgf%+&bT)$2`#$*2?M^nCvh3kk2LG;gAw12TZ{yF2W2t0^xN@A2QXx)uguZngC}PWJ z@@i!Sh+TWarQ7K`Q)mb6AdEOJ{f}DQPwRZ~c*4H^S@5A(M5wr^{k#u`{?E*VB=XLC zI^Ebhhl1Ifg55I|ibNw+^jKGtL_bv0-52;caMLtrhP}4gf|5_B-L+@Nmkd?Kb+q_N zv!#@@N{Xe9TDy23;l=DIOUq?JR=ua&Qe`l>`zJGQ>bMTKu6kLBt3;d%*npkR4<@mr zHi|DXgmp>Zy{Z$QTA0{k(ax~CX zV=$}c$312F7jAzf`19K)<m%dE_-N*T}Nkk1kDk*>@d6m0GfeW{|W^NpG&XjNlv zO+x6(uYgL6Xv5ArQGy+{gPdXc-+o2-lXnzr*Sk7;1~nK1W4$V4QypK0Z4tZ@Iu}#S z(k%?H{L=ZOJ_j>fT|vl3ge^@Ls7N?;Yp7z)-vOD<+Bys{oaPx@)bW0ij=9zU!)dJ$ z|H+*)PnmVktv!=K9zFd~`fSZ2D+EInXB5t7*GI&=q>v=%3I>PJ@&BWC_5bwmc)2>H zY`VJt_`te}H;U-+qwAkJJQ8&6l;!Bwmia>Mwly|cA$(GK(27l*{Q(7g^o;MKHJrok z14(HKqC0nySxOOTdJu&p%3$kb7YBWVYLvBhkuo8Yz=GBp)OYWeE^u~?ZOEG-k=7dq z#WFAaSHUJzs0ziAR0KSu@`R+n_^6(P@@eT&j5CHBYWzp8gVc~47gP0>#c6W0@bvms zuaul$meVTghe~227iiBZF>2eZq=ZjHI?l@qb+gk=EgJ9*A)N}G7No%jZ+#G_cnYHM z6DGbJmN!gyR#J)p32fqs!pL>$TUm9U<=69WK_!+QoMc%^DxK8v^ZPYrfHa2w1i&KT zZ~H?2`ZpSm7T1F+4E|=e;!*r|U04D#GlSW&lXcSqOP+X4p*BA}!>7CWZOE^DAgn77 z6D}dUwb;iG_}y^u)##t7^l&}VC;EI zhZM!r2|hXI$~|`IK4$m(-I3^2v;|vIVCLD$dxr%4Yxke(y6Wh{kNN2bTIw9jn@nYSTnvhNmnEwAzg) zq6S^{Yj=aD_b)=y^5pn<*m!sqVw+ZPMKc~JQIm-o15Ox3@`R`xnH%toHWyltF=0BU zPH_`-cx)-Vr{X0StE%(>c6MM5MAAM$0f|>yBuH1g4Tq0sNa9zS zDJ0{P#Nla6PR(EZ?uiO6{i6E;t*Il3i_B0xfrvG19jn^g>aDU({~Cp+mZc5^Ejl?1 z4fT0`4p^S&hvYadG^e)qqXXrMV%wW@$j7WO-_H#2crtYZG=_NrgX(c;vLPOV!&x1s zwmgs!HF!k3i$XT&yw~XQc`Pq}Hk1G18aHMK?6M_-m_WUsvAa|x@m$FlnQ&o@6#8=H ztWJLoBmp+hX~qG^IHx$>=49n2&X?goE|-dH3h=D>^K1fC^l?|UwU}Iwsr>u4LP&S! z^$*2Gw1Xk*4ePiyJ7>^{LP?IuCxSFzu5ng;{?uK?yRJ9Z)PVD5m1X*b=lar1cW9#! zcH6SHRYvQaEYTshLshtV8N8@sME@rkA;T&FPSx7>Qsb`Vkm%5G?ozX;a?y6+T??K1 zIuGNyFBNs}rw)LDxmW{2tEyo2l}nAXI?uut7;QZkTxLcdesR4gE`Ng3v;VT@2x6sk z(?j`sd{%h2V;oD2CX<|a;s##wLNs6@RN`&e+ww&H-XYlLYWHa{Oyt!;i=q8yK9J4k zgZo+(5F=Q(D-%)4;2o-rzIXJlLn^8@$Ww(18C!X~+(M0;%{2m`Myq7oqd5Q3CU}#cLu?*l$@(KnnKOcXRtnHBu#fa*e@XnjLYFF%$KFL971_#OV?tqF z)dv)kaaMqUKC%5u=gFBeNGJ#TNNe(-Ca}{~+R!*mqhSE6iFK6vte}Or)#cjm@8lUa zo7fmL+xz7D%Ld0t5*nV8rCrS`IO7Pj4@VAO=E`)cJ9dsS2v&P&F)K%of2)HmaT)!& zP+D$O{uDBQsxKE&&*WW7yJ=w!0$aHI{6_i~xX6{o%^_w%aMA=rLB4@V0%!@aE|^j;v+Jgx_YBT>jb}hc;~VXwxA-h|N3qNg`;g^-D5%9BJOHt3L|S=%HhOY1OC(NrZE_%8+I;d!zH87EgNLN=9h-beleUzQLE zLwAg-;*IiEDirH*@y%-J8mA5enhJby=qKcv%7Dl9N>5L(0~YX?Hn zTjZT5wbaMj@Q1&V6AX{YvS!Q^`vq^W53SmVKTt0g5Sii@bb^qzaF9B(%&QHAI1o?a zNI}ISlH~PAZ}#a0sIy$BV{6vFd6Y>wRp7Afn$?A7YCGa!Te5g#`;v)dPk|w23fY_V zB~I>e8bo0hKGo}9pi}Z5CJZGd*atWMQ!2T6FA?zv!==(Db7h8~Emza8t9i!^E@>p@ z`$hBhuc*H==dY@D|}p6YL%e+QeC zOt(~d`B-daKDsdvoWcIBuIFd4L<^%+m8cRHOtg4{Svia`dK_R;AfsQ8m;g=;L-=K# zQ1OW{Kji8O3FDS|!8H^+a)2njujQIq4h8;YcM=@%ihUEF$#$vFtb(NwBDCYLx^=9j z3R@~OY{TUGeMUJa%m^!2Nu1S4)Z$~DR4TB7_$C%vsffyh2;5fa!L0ELW&XKJs;E}U zEWFQm6pz_vN2=1;FP$MT$Ev}8a&h*P@rv712e{-1Hf$o53+;SgV_7hBrw}@ZZpZ7s zP`R=gMqpXN=r=mFRz(?6wOK#5pb`jZS8{{G)nR2+qu#nBZM9sTZmsfQjhSH5HVaFn zq1q=R_P_XNvrk_Z)G_}a;O0{}x~iH^ev^!rkH|`R$EW)Cc_K%zAvra~;z(Z(x%N*I zEoLGj;2ApHck_mt95XT?t??+%eq^dJG7sVx)UG!&LLc~jpd{91$ zYB{6FrpM@?u#0?W5gqv^DD=2LVLQ0mk0*H})MTXE681vtpslOkl>9Q}xuZ4;OQJ36 zxV0Od=9DzBBK6k^D`-R@oh$|ARZLxYK2PZ*NE-Pd->O)j0#Qnw&OjGLDqTmH;A7Qz%iG zhx1n&SQDvz)SU#v3+K8VlC%T3x*ICyen&A{2ZxEzzH)QW`uEm(@)s+`?H63+18mlq zMx@bKafKWxvnVtLD%L->am)Es`$7r`pOWpZ5o5h_(A#L2z@ zr+zPg-%@&?Az-6$VKRDvOZw;YP&{PC_o^w0o7nh!keB1u0Cu`m`(e-$7Cp&v3Ylhj zKGqX)AwNGZ#!#4A*HP*bqbn+0^@(H!gwLg3Y7#HyT1;6cxnP1qNM?s@$pXhd4u18(qb{49pfZ z@D#VRW@rZcx}4=A{JnrS9~MYNGu5M`B-44ge6E z-Y)49P$a%UPyRAPp~Jd-2EH-sjSwN=kAD%^_5`2Kon-h9Ai5*xeMA7aHq;& zR=QF-@8`=_tx6iLVcM|%1V`q`Z_#@l@L`a&eNzUy?)?$PUjb3lYPfhPZa3Dvn$!Z* zG0_MymZNIyLk#64GY%2+>%^8Op`3Qo)s7ZFo78WaWXo_|n#~JFiwwIeyi=+KFDsWI zqGGG%9}O^fNi-Gb&1aY>fGkr#Xh|&AItM7M!!`$&0K-SagLd@WT&f-ewFz5D-&9ex z%|HS-KHPQWh2T9(v=t3hy1jn%=`av9FTA8h_`XqoVn$%EC!v+=E-EcO6||RM<#6B? zCvdfMUFONe*iKo0p(?OqFI@htS3#E1o04nLKlG(k7vmYE7Pc07GY@#G1wUtgr6VU$jS(&6w7Iy^YU zn1l5fB_PqB4kg2`5Z8=X&jh^G}Om@Hbpu5w%Muv%XjWuis^yq1hszotOAA@6dl?E2bmjg^lxHupC;!M;ulxG z+dwYT1d%6rs$c!XzLL$987G;&E(O)Ag(|{`CH%SXz13_GvmOi}=y2)2j1k-&+wJ;} zXJFQ{T3v{Ux9d7!$^;-0BX#62d)RZ1MYW(pc;d_AF=!OLnL(k|#WZstcYlCM-PuHc zzjqh+9?UTH9%F3TYoS#X=RQqGh^aq!NKwac3~xVWG%8GMbJ>@!4=;BF?#>8Y%>n8a^s3Q5MvVH9(_ot^jBW#o2bbk44J@|y@*us zZLvCB@}gFr-iLd9-lcdMmC@2$*%?ny@FuCoH*b}dc92ZKpg7UgaE+kgXf*XY93PCRE>Z6=u~7+p${dMtc$8VQf$XsjN(Vf)u@UyE zoC)ov9oV`&w;Fv&`DU1a*-(^u%{O)thphDnOPbO?@}>Q+#P;(z7Uk2+I|dPH=HMXL z>7IC99uEsk$)!wIeZvlLcfzB-m^gB4`g`Y}TP=ELv0lfH6E5gj;FoH0GxH9N@a23~;>lpdWFyr(>fHQCn3wM7F8;cR zSjXnlA2k>xz`YT4O#LhTU~DL{q6rf|S+Z=L zvT>Jb2E%gA|5?27)3et@g9QDf`;h8ZM^mg9?rMcD9N{;Toe)&db>! z-N+9GrqC4_+Aa|ycV0_BhA^}1`5M)Qtlq0 zGleq#<8FVvB1w>77Bd9L^>>hSQUsz}3qua8-ckY0XN>?yVQIM-4O8||nJbAU6>FmU z$&Y&K^)3yr^=rTWN{y$;PVlN#{49PA|ACKYnp&h)?<2`-^vN;)`Pvk2Z0bEE$nD(a zv1YI%e%3E4*eotxLnERcI!VRflASqHEsn~g(ykUGLjzX9q|Rq)hh4Jcrn2w0IaXoe z44arYw}NlrF-`5l46TM~nlKesf?Euw{RFNrFWZ;`0%39g%0#UQH!I+%B25j{^Z79H z2<{Nsd2G5QFnkUi?)*e$3Vb7LSW>0!oG8)lA?Ha3L^|?0i6dVpkU?T@7 zYvZe@yY2QTHpH6w5RD@bm`EL7{)#0o6 ze>K=j=a`zPTIbF40w}>tNQ*7DxTZIO2e4{ad=A!)aRno@W7v2zUNF9MJPVH)-3uSU zsdJLROt*MWGH~1{Vv?1H*3HEQ97!fc(!+42D{S50G5i>K=>qMvv#=0l6Dy8~WaDr$ zYG41ib8=26X?W`$tHR8Ouv%q{&L~}n4I4OLhKNljQAxgwVW#KW1Xsa$29HbRN9NT2 z5GoRTB02c{W8$(XG=a*Ts1MvgK6b@jxD1zZsvkdL(bA1nzR0puyz$A>?_msg$Tm#z zunLy7l{VoHg$W;VbC37P@XY9a-p=rT51?q!aPCS6-*7~R61Ts(N_Aqw7cpyP-#I|N zX^GJprM(?VqQLhyBm20zr4q{X<+J#MvJYk_bF!mByE;YnP?rIe+Wk9n{_;4y9BKEg zT}iv2UW|4LIT3aX@$M-~Ajv_iJ<(6sw)YdOL7L3iWXy|I1W+n>I=lW2p0}z!EGsX> z2(!(P%T5qAo5WcdAy|Ef1TT3wqJ8?&GY$A;l1G%5_j9|8+xHJ0E=wS@4N}&hN+ZL9 zgh_6v-az-w@w?yV(vR0%u4PN(<=jkU0#+5V z3uoCwLqTP0jPcwOQbfN9=MiEM^+k7$u?QJ3;-r2?%fogz>q*p{;U13LuG(debXhHO z)`cSP!};ZL|>ZWV^#kPBpPsM#!`G#K-8i@)B$= zNa(g}Z22vd?9nhjRftnG>(~);Qo>RY6I&sN)!*TMSp9WckoFUOH`chXeVDpg#sbd* z_hml>bNno}6D7vG?GaR?KNxj3GndgInZ$&&7nw}9^@9dph$az+B+l*=ljsUosQCdj zx=#qnK(0?~RMU>Gi(kHTa%d`8nhw^~3nTj1iV@tvl(NOJU)!T+3q72i13f~Zp0qx_ zow?;#>@O;$Ks56|W73Dx9|O5K z24G`^ZKV-$Ap-f3DwYs8w>B;YLfZC!!#$JKI-!C`xbMKeij?v9*CT-ikf|Bvn7^VF z2STkaT1=2N=QPIGO9L4srBDEotfC@q4=bg!W+X+9$2dO`N}qqLrN3wX`Hx_ZZSHG+ zXIjmFGnLylxJIJoV@hE<(innAxF&3-Uw?6waO}n7p+5Raswpn60>( zXXGVI2CILME9{83wBkS1puw(ohs)yQsS*6iH%$`h>p0CQiq~`T5xs3d?^yU%&4`M#KBL2# zmcE);S}nxtHYz9LM&?S@5brAH6(mGV z6iOz!A{D8TD<1@unsYXZG|>d5DF!9B8GxQGzd$=aA3t8~?mdc{ zGNqBHgGyuK6r-`A4Qed^F**0xWJE&gW`?57uwz?vglTvpZ(Sx6sX<8hswuFcj&QX>hqhjk%C$^Yh5;RmoX(ZiKzABs_Y&;+@t9t0k4G(@c@gXT zp$nWfkWfKXBU$-j6CcXs9wPevqdXBAo(;S&=;j?2R#O*fE?9H64H^)0Iuo>t46FJ9 zxB4&M7DL1_vzy#%Yk2aQb_&Y7?G*kq-`<%xng$iHy5a)7%~lYsO`tUWo+d~SvA&!9{}0}4+U#sC|Z7-Tw>Fk1TXF>qQY7mMzN|NQSk@o%Y32*y#f&i?L$I z++C#I&;YkNJ(;ZMQ1A+UjIbF^#-MBJ6cQ9RV;df$esPUlzNUEOIA9)$U@ z;%vGocyCe~E=P^H$^6KD0^N)+J~(q8wS<~RWd5j zLiBPd-TplU_syARW|_1|PeRQ7QWJ3Dn~v+!XZ+^pGpXnP2)msl3hg_Oy9?G`+pHBz zDnQ3DCep<;S%XzP*%S}X6y4O|5)8*LXQ`6UtN+DdF7arL7b&w}qB68i>sRKE^vGf_ zlITQYg68Pa{&LC8;LFOH~F@HNdYL*PltG{*->@0Nt>0Xwf%BGZI%{$lO#t&lAT*!qCuqf_kc=1G=Z;fVX!IS1Le+&!XMw9pp@ z_6I8=YVbnJQ}xPIix#3N6*$Y==ZE&VWgWQ5RG}w!L5uGiijca*e%A7cOoQ8!q|MZQ zSy(N!!HJHGW$6lO%PqNLl8d*8k{@7fHwafN+N7szcpi;S?K*EMn4eL{L!-3?Gy=a}ORIv}$e<(P7 znP-DBgr>=jnKu^6dM?Of+=#VDO0|nw?wjJ0+`2y&-kJNt@=qw^8^%|8B!pU71QU4h zl83;fpmH#v=ohO6FvvXhS7Y4F1oU!L!SlE|)aqP8)Ze2k=)uL(gFmMP5^rj?v?vlXi#3iUA5BAqW5+zChrNnh9b;ZhpN_CX?!gP-aJ=vzK z30T_;^uUST%h)3xeakbdgd?1i*o{IvEgZBU)7um0Jdg{YRWuT-zl0urnyGg`x15w) zxtW7cQC}Zt*5M;X+a@^{{lY{XEh}6DtZ`y-5l9hu0_5c-P*Bx2vT0&>hns(H7RQKQ zP3CNw5ZIPigO6F_=nOe>yjF;hk~d9Zttz|-0` z4MD|ou+`_FmH|p7PL%8DnTpe24NWlGmw=8>Hv{dlz%({StL_d((s+2kvX8r&+sTsaxHZTp#C#S>;B`MiKxTTM zcvRw~XbT^A_Ul(9t@(mzI#7U$7a=Wj@Pj|CT#s}%h9|h2D!V^&`c~t5FaNmHgn&<` zQ<kuVN!Cmi9R3A!*%K5%2>OLSLLUAUCc*MS zmiO%CI=R>pHsjgxM=9Eo@E6OmY6D0mK z<7F1(5B>GB_OP}#C)dUOxXD;kspDzn{_pi&Wv zm4tLO&)s>WccXnb5d}?fx-`9sdAq}2;8`xX2 zP3lvM1nmiB_d|x3+rhF^lFI2PqC*{fXf^~K!8Sp}e0V%}(OZWNq#7fX_^duG1s(@3?gPrxZB1CGSQb9egQj_5x^l49#Sl8YO?@*Ew}5 zS$#TOg3ZITOnd^lN>LcTJ9t%}ycjWX3Y2|g=UBi7E@>%#Mb2R!>l&-?u(>-WFeO*r z;N1)p4@-{?35N`DYZlm6_PlYTyJ2gp5Pp*%T~j9(MV6Ve{N0+;>im8e7QmtvNJ&Rc z>oqJeui9aIL@LN~kjyKmvn0t_QM_6Xtmt2hyHzb01MY#A@!$Rg-$!?%DjP}^A;+lA z5}sIYAAc5d!rZ(WP8us>*ICoTU`Yly8H{KHB&`%JdigytQ$^;iQ>Ie&BcZd)=H8*} zY6_riPPMA$=g4p++r|@gPG}YN{<40avDK^56Z`r`xSssP-8oAt|H^>OUUR%|x)H-a z>G|2hFzM+ne}Rl53iv*;PdFyE`O))eDtsD1`RgPdRT2AjG;3t3dZ{%{H*jULj$?>7 z>XLNp5r0b9<2|>~b* zjKqe8W-u-maAR!XfK1e6Si0BFQ<6J26F;SyMmRQGzF_PLeVQNGLAc|(XnaFL0>0P) z^A^cVOwLLOiOKN~-l=*9KezJkcQge(lyMZ?xo(f8sEHLG{5I~Ynhqe>iWVe_I#4Jb8`2-j zMp|&};aoFM$j02t(+chgTl^d#AbyFSSS1k`<|&3Qp_m{_Cr7v*Jc2}w{9RXt$EaJV zFE`C}*|qUgV=q|FkL)vJ_cL~AeJ=%XU7y|F4l+UI$$?PCB7Zf`T`l*FNQ{&pc^lx1R@H^IFF2HzQpirrB4X`qbIS!SUl!m zBDK^Im0}L!Qn!??ORmXJPTG{nEH1t#XtW_wR)^mF6HrR!pPs27>X9jl8Vqx*w;Q>v z(JLwy)Kf3oLf&Qra)v^82z#2PE%FGyFY-|0$!C2W%0?ZoIbcI5@wk^q;N|DOI5OWc zcuP#TQvr3t%hh&4RjUf>U}|7tPRA~PmJSRWc|q%`1x6w>8N4mf5k5y5b(s1OVp$>l zz@vxW>wA#-jL5(InY$LxkLu;G&3;u8_#{Zc`&>2h1OoXe`O zvqX)qed4}Y2v+;DyLzs6sQQ~%_sJsb<@T02L?u*^;JfSVFvoEVlY!D;x#j1NpXsVz zJTobNTZCX&&vDAcn6fx{G2g*+WIgqawu_;ue z($WT+jEOt}-V~@weT#frHRZj-pgQLT6-I-wdF@UWxS#fUiBSth+@ra&HuplL){8SZ z4c2npcG=}lwJh#_4HyG`iLLx0Gs7M@#ta*h6y~@@(8c5&JZ+z=g=WgRvK9w_lbS#LKhy+;@0w0sMhOk9Sl|&&NegE? z2fIs%e-{gfRsmzHXmyFVF=U!s7!vJj48tXr8V@67;4V9S?sDVDb@1K;$t5#C$bjBm zd-8^qh{(A>!>ra0tH%_js~hlNBxu6=zr&2H=&GioW%!}*3wS!q@MN$re2vuTO{D^# zTNLinlXJfb3f@S-nI`vPq!`(_BZv*xB z8w?)>jbk~pl-|KNg@>qe3SluLLY7Y;TXM2&HEr87CjeP!pkQDhDN(NQnR-;z4l(gC z1NgGm0(=XZdy*rkBwjkoTmxlNCE5lBNsEY%D5+F+Nl{LP86+H9@qgLn;%^Q;P_oUj zp1E4X5eG27L*CYxSTB3Fn&wv1Bx?$dr91pMvJi-QcmxA`ie>KCI`CJ_%s9S{);2!b2D`T<+o zG~@jPjJj66ewf@#2T=Ng`^(T$VvR=K}MVbfbPX4hiB|f2k2^Nd3cC_F(^^w z-u5@(%CYhWV-hxO#mieLJ2*t3_K+Wug)}WQtRx&nr_bUX3vorUt$LsZPVg!DNUzV( zVQR-;4{!bB=p);3r6GZm1B8QJxC(ocv#FM8oo7k{ZW9-e zYf*n|HlYjB_vQ+V-HhF^psj(+m;ObZP9qOkn#^D(@_K$MHuBoI5>A30H*P-^X$E?TZ~XC)gjVj5!wh?3YpQOo1d zAS^5HQ$aT(Bvkn zAJ_tjGBArE^^if3k<<2&dxK?f-efr>z4?~;mVDjSh@t$iWl-{6TgB4##OdJf<|^tI z+=B<0iHG}UscUaI4IeUHRqHj_E}K;3bA^vRXmxqf_ogLt3s%e6t&cGlx3-^(2La9X zBikDAOgk&@8|kplM#g6+zK!v7wa6yf(d8_|@<|o6Y~HcRE0bL?f53JMP1P*+LEKnRil5tNMw?`la(8X#6*LLg`rLyn7t<+*ChKx zc;#pEVcluB>)BFN}i%5}oFfhiob&H~vPlwX|{J3hz8jXAItiFsWyzRAOg z;NX$tZRD}jS3#j8po|7Y^C!e}cIObjxD~gcJCU@|XAZDT!1`xFp|N)YG%1(|?*t|> zoTCz|)=&UaO7f;|hb&9U?(nejNXt3WEi7zz-eFM1%x7}O$!-oA(iQ3Ls5H^$p&_gHMFX;xmeTUZI$a4$Sgef#81c<&aP*-L~FialN&gU z{coZKN3YFW`7b-0pc_?P?t>L869S8`m_A#u+Ss?d6{i_A>5d3juCV1Zkk7}fr&|X`lMzuv~ z$`8E{hIBzfuGBQftX>dhUX5C$>@c$Su1pzdG^j&?n_$>~ExloLbjxT(a;&?AGc3nFUa=M-t(n{*V0=quhbf{A0R>&CoA=Hwh4URY z$$MJpEcY+5coa30Mt1+JN{=QvB_s%%N2b$IfTJZ%DdF$La5Z41ZkO&%7Z3CcVX2{z zRP5SI$$wf_mKO$=3&Q1H9P)J>yx}N8KU;JtZRJfbv9{qEskaqYMD`(_@KUWZR2f~( z$&&@{lI@i?1!94bPnPgGE z;%**)GUJtZXr2Dr_gO>keL)b=_rzvMp!Gy~w=b@~XoF-S-$yGybj;A+2Ec>*GvbfDiS0heI zJxZWD5S$(nD?5L$mvv!lrJaLva3&Eb7RrBx>5o^r(2P`DWr8D6a9`d!Onq8zPcJ5a zbe86>V4n~6d={vz$st`qW^i=+qp~|HRo&rPhZn%IGGmH5m5m}figEX#Zo&<$Qh(=BiNK-$_S+ zX~*SgS>JvVjXHV{n}LOoIomU0V7DZ z>3OTx=*tjuX*onG`Q=#8B4?WkZtLpd`_S|B4s=4ZxGjBsIq_T=1IpLw{wMn*x$3;- z@uk1K7o5Bhqs*GhVLdu8{%=&&#n8}4j}V$nxq^CgQYeELC( zCYKqhn~Dl$2|ElEicgCQKlphqx^iP5JQ)oaw3O;uq`g%`>-eZhq4J2JkJ-KB;~xod z!ZoQHQ|v`#w!wW*5vgB-UGI@0UYNnKb)Ns*}Gt=#H7O z#ySWLg&_ZpI8z?<}@3LOGA5Z8u|H}M@&afDqu_9sMWQ>^7 zkhOb{?h5JUAW=G?R1}SryPxk=UgAkFPpHTnU0|+bp*uBlF%MwNjrTFo9yKf-m2v;> zf&JS^UbExoNNcex*;Km8>{DvGkwd*1Afik3)9^ouM=3ONAJkKZ!DjItIuoS7=J7=x%;%x=1xn91z{`5!H7oC!Y%-k)H z`s$DS!owYv+$7(euqeS@Q0ug-7*g~eiRPIX zH*KEBIANeS4*sfDJ872klR^9qzgg)UpK!fO|E?^qC;Kl0kew@v>^1AO4d&b2A@Mu$;D2_R>cg{0 zg$|&8g{i}f)2<&1k9jBO$}wU1`?q?x%^@Z!cL~2O(H9556ZJ+LF2EU$o2wOL^_4tzftHYG#o= z{)4BGn9LMo%R%Dg6t17%^CU(q{HoYkA)9Sc7HP$+GrD!>0bg2*c6}P9BBqBPiD`=8 z!)ht}^!Oh>`0%_eEE7(__3@M#3xONEGlnRN#1gx+#TqlE3P;lp<^Al-HUPDs4KzLUJIC2K* zN!BZY(GOJ%_URGQ{JVX@G&2)>wfaI2JXDQYb}Eb2WJ<&pp)SYnS{uM2r2b&^b(A)I zU#8Es1Z0+ti{R5ZZAV^qAepB!I6(P(Uf*rsl-Q<#v4qSkHW3?p_S)aUuS<rgP_u2rssyFjTsdBnb0wM+{c^;YmT)e2?IOEBA+9E+xW+8t*LR3?{F^VXJ6En^#?E zo!Ba-;a&OSZA51In8}a+1g7ADmv&y7ZQZl6^e?h5!~^LjsNT~eTMdfVd5Ctk&UTl+ zaIba@q0@Gkt_rdFpA!{U%fz*Hg!THuz|bE2Nl8DOY3okC0d-y^+NzUrS64(=ESo2f zokRk0r%7<0MbkPA`<+xBToh2L_bJ!Pv6qmwM7$_1=g9<+S=x#V|b z)G}+Q>D_8~{}S%1z@gb3xepV_KN%<8wEcyme3?}7IV@+f5hEF16&RH1x4~^~xs6yN4F8Lc-V2G)l7VhaZ6)jvqm^ zeG)mB;u*HM7>507Z`g=TK~&MNutCQc8e-5nmIpeyKZKhES6rJ#x9{fo@2>0)mW@+Y zeSUWmA_QP)p1A?l>(Gi45=Ne$qAPUkH{jw(5mVnK9L}2Wcwif(PajoLyAn zDuWSeXX;=f_jLp0%NbB7L*~H!r1|ge_<`Ilk$2_=*xF9$FcSe2+Lrm__HN;!$@L6X zxJ`+xq-v_56t1*pw!Az^^aW+!=+t>o$c^cx=Ne;aD4b6kw4__DaWMIxaoCU98=*ec z5kNvUUWs-twt1ro-GioLKF#ag4idFFZIAp)Wkcr^bAp z&bW(`fp!bfWg`EXtwfev(qmMs`?z7HmQB$_i#dWcsiA*?zf@RF^SLkiYl0qa6>Gdg z)rqaJ5rDEF5ttN&t_IrbwXW*=@SxNV+&-)5>^E^1*vR?YIXsf{aCD}{)F(e|-eOtg zxx;(wktb=OceZKY#8q}=oVP&S4hPfm5=0g#K7fZ;TOVN{y22)94(Ib7KqS3MZlDcB zNoy223FfwC<{r1i^TS1Trrw|Z2w9BQJzp36$wA0l2Hl*H8)fp${mz`;2aNx<#$Mx2 zZ6fw<^)<&(EeY@6aGtj-1D9Y!HDnF--uf;x7A*K87m8u{1y*g41Gv2XT9uWY_Hc66Xj1km@Yp&prOX({I zX$;hxS%QA`yCKP8R3>ma@(;W0d7?7OO{{e%Qqqr9|y!*Cz0w z`hy0mCf>Uaq5$quTP*TuOsBYk=kkhzeOuFbWsv7{+e3@@iCIn{t^{dJN6rooPeOohto7%i6_~%D*)v5qa{cy zs%y81^v-*p1Rbx;L%PyY%9b?*(gIz^IMEMCYPImjy2XNHJ_>$b(4Fl;z)Ue}5K$#V z>&B-Kl4(QsS%v7kslk)BKrA%9J^m06Bn?$j@qUdZM8}PPfxdK_QnGh@@$Tjr4JuDf zyFN+8kDXoR7}SYr{VQOK=Cr$Rx|Lqzrq(tlRM778FNbF8)xad`pn>+fR*Nims5in^ zkk4TK#bn7+mlVb1UV;eplxjqWUuW$CuX~F#l;R8<2XWB&&Wmxhr+LlVVb^$56IW!T z8dZJL9wpTYHF_NwlCNs_+Z9}w(?J!^vULGxM|}@50#Mj5<>|TrBLmwjdtmE|LK;Co zKF{y41`u(mz}Eop4S(ZmG7O|Dkv~F1a(VYU*X)d!5ay_9{I7-DJ$mzTu=bpY=O8TJ z3xKi#$SqyGDRb7ku+|enq)U3L5g3wA5`%5a%$oK~Ru~ zy-@EGkSzXcdAGL?fuPELynb7EM_Sw;i^P@NH#_^}iq#?<-9qC?Ah*wLjq8jPGFEOH zz>e%q#ZZcGp6z&ypL4eDd*sPt=Z2I zYmlGp5m8?+tCRTjg?)}FnBKY;+$32WKf5FqzNmoRwt0`QRk8D!a1SkUkzgEY9)CUoSEW+UAGF>M&S=9 zhYk>`!3!UQ>V!FTDyZ-uP1-UO9o{rhbaw=2vWIgdaE`?2ML>5SI(YS(`>}QiaC9sm zp}otJRR~MG;=PzVCoI^3jYjXNX+}dk#Nw^ut<{w>$5wOLG1kyS{0G-XB zXhzB7=x+V>b!?1({&aLE(Qykk=n6C-8^hDoiBMm+tpG5+^uPbOC-XY#nRzCbGmh3D zWIe#<%DMS2!L8YAxxX$@PTEW1yQ9X-*?(`t$3X>t7b4=l&5Gkl1wi>9TVvqgBuCPqpqWCRjEpf7$FgNsa$S88G~;4O9hjd=hk` zhE7-(dTrp|J+&gNxvcRJJg})iLtei=Bh6<44<~g2dM0nj?|crDz(nghv{DJTy2=uoqNbMF?#J&=9sK z*>HrP5?}37=IbguyWl5D+`3BcDjSWCVt1;@w#i);o(xZ7-dLz;Np{=`mME(m0BVOz zueMHbP}6(DT*Y=Nmkc8aT}UU!%Us2UYvC~npW;WDK<;0J{sPSQdCoV;9BYF-#z_x% zWX@_*PBF|#fZ^zJXY9DcY9>73>J)r*1kHY`X>wfli?9}8Hf`f*dl!@mN>Xo&r@mL& zypfUTF8s!?b5&NSn_gLem=^kGq!RhNcDxW7`3$;R;B_p6y_r626T2PBANzLCvd&`8 z4wb@?r$g2}npa7%0-M;rrKp3n?NgX;S&ghHtL^T2wN=+x-P)Xa1UUb2mwkQC$0GtpzrKl72^&79 z!-a_o&H+=`kq~ymy*p2!IiV&6R##yBNeYh&ACe_rj8k!JTm2~&?DgH>J2{|Y@kdbb z7_L5(Uy!}%_rN7Gf!@SFDJs6lFFRA8G^g7i`cD?1BQ=cQiL3!{g`JwxV+QDLdJRVu zg~L;g{8?vvt30hW(%W1b=sV6M9q-?R>h9yd%TB~Oj1kwKo=g}Tb#z;g;zb*EjsXJg zDR-&7v(?5mUDbTow+OGM;Rhx;`j*{6)sx}ZUDQZl3WY!c)%s|{y#QMLQ^t}jO;LE( z@LHgtI-wW=0Rnf^=(78i{wXfVZw{^B5hZ3>g|BJt5N#Gfz8wSc*2jkO_R-HYb@B|*Gy#Oa zJ?t&G%U~BI&f&ixFgk_v*X4~oZg3~>C&b$*fi9})yEReI^`}W~Kf+!2jDchvJVCEQ z2Hp}F`JnERTaFib9yBupngUtj0VVXVRT(ASATmWFn8`__B*Il|;*^5z{mfRBGvU!v z56{tzg88h0E8s(mhobF%L3ORixN!IyEE6!af#%rVxCbIcXJc_<0W3W|^sXWRxIQE@??e%Zb2em0zRt)ANP`}g;Hhw7Ld%&0C1z>95=Sp$+Y63pGbG&= z;0RCM03Guva2UNLLr)nOp3$`6ckqLjG~hlZiD8J$QhWXq?{M&R`krgBvKhvqrizn?BH54<_aR?P(3ffdlEN9d z7GK}kq*Lq7BC`P21%@AR#ZV}2T)?{3AsBiB00s! zKt=MJos{gT9JPvczT7=siHM2Pd4$tv78P-+xrI&@$70gZS7l7QIw3$L?&XJ7Ly2<9 zvQP3~`0J>XGI3Y!Q`v)!x+&0BD#w44j#~{Ckel#e`sEn2Ql3njYtD{8PB;g5ap!RF z1fu>ac__GgCZmrKGG6}KVSshv8D(t4{HY$FGu5OH4*q zc}hA~lLtLD^>nziY^N7P*l@WPKp9mE@DDjF$)jgkmR`NM_$~Tcf4EM(6n0|Or(J5# z9Qr2^(=Z$z<_o)RN0%Jo&bO1F9z^aWo2(t z14x!baN;k{9gLaTYYvFm2X)g#C9*Jy%9n=`E^$szDcbG77=Nrh7D{+{L*GSe;{oNy zp4Rnw*}+j~zLc6?dzCNGfjbisJag38dRiZ*W!h6qv;Cd*7xSfp=l>{R&F4jw$397a z^EL|LUD#GDX+31{Y?9abuN9ylN@&oKD&W-`COp}|I?Kh3Pinni+6JCbp`1VQmUb2g zM#GwQE#5$B&2^*bu0pKUUb;yfOAub2o&fj`@K$6xzf9g z)$yCE{J69FswpNR>7KC#KH>cot9Bqe`)JrYM5;8XAjri}+jL0x*B6Vf_o25ka%1W8 zS)mf*XyGrAZH$;!;qL&B01DTD-1t=my^yE7lulPnFwbb;Y>W987?ST1fxQ+Gpt5}t|KeDuLn2F)Eq84+Z(qHRSSDY;Pf`;Ld z+}*y9&!^qhrTV}qrmEIx65#Ea!EMPjFfDNuR**$gALufRT9jBAh<+Z@HIanBU@J{s zX4th4VSTJUBe`@z?Vb74E=+2gUTIz_LTk=3#Hk`l_}C|}Q*38(i=k6%76geWlJ3`9 zNuTSYsW#W0_2LJH0e%~Q1{{R)#|@uAqPg)@{A0_B-tF{V^$vccmf;Z?J*03bFH-Sf z57q1lR-nrk)-pjV4HH~0VY4-R(L_(p$%;mpxj=*mf+F-v*4Ni6mQz#kyv;K1X72B0 z%J>*vB(mV{z{E<^)DwbNqW>L%edV_iMXUSQBYce40q*=_k+uaf>>gUzBNEPqKQhbH zKF}{^y8GNIsFDlHaeQa^Fak%qT71qk_}g-E1Z`ggh#G0(=vo_I@*K78p_a_DI3Z3J zf3fPvNcctMA5U!)<<~*B@vhx76fJEg?S0g`fuP5sTj22(a&VpmKzd}@Id8Wt^fTJO z#6|69c}sz7f4{Cbu6S(6=dSuu^X=b#Wb@{I%=(96)z1@^`HY_9K*&I<@l3nIp2S%` zUDjVC6NoSzkylsR8d*)1qMA6_#-VmQYm8U2cMfg{P6XaZJ4aYvy4Rs^JZ3y-O=M6~ zrbI1Aq3~en5VE3B`J_j2FIGnHjNj0Uji31E5OFbN0%f_zZR6k_m6-Er_%R3G6-G|! znt1AN@Whtyo`0y%n6?aBiY4FUL<%c82-FG;Qq|o;2;JfIiS3Cum+J2TIgx+>6cb|xQYwQgWdP5NUI=Rq2`vfn&M8h$gQd!kq#y0M#@UitCV1?( z_(eOuP?%`dY=OhZbz!pbn?kuo=g_8B{ApNyjWWy>?3kuDzY%jPZ5t@C*)jyrVq~^@ zyL+aY4Gl7Jr^;F~QepCfc2dmoVIs!1zQ!$5A=zjmC_J}sWw8oqfeAP+^qgR z0vhrDpUXcr!GC-PT?)%&b!-0bol6@~h))~~>SD4ABL9pAV*g)41NHwC8vM5u0p@?J z`0wNYga$_csfZ>}ohH=Z(!FkBnQTLd^>B!gBcY*tW0NllBNNB!Dg(YrW3LBPzS$)R z7m2CD1e8HvitwYJW0^RGrWFPUoh^eftTlShn5NobPVY59E-apPb>uKNxH9A0+R0W3 zsXeI>bMEL~QbPKO?Lq<8P#OrMfJXj0q`2%NLW!asd-B%C1P72X{4bFIFVw$I!C9=9 z4kNv?(cb>{qn#a!G07~|Lr2gUv=}@H26l(F!N1#Tpw|12=X5qY&0I%EzBr!@(Dv{N zR|8de0F^W!I-a5t@|$^^z!l7m15D@N48XCmW8p@!WDzZ_3h#{9g9wx0z*^;-7{;MQ z(AXVliIw9}o1jD`r9z498A1)hHfljvj2GEP%ma0p>Usu#n@_LXg}8ptn`@rfKiJg8PXfCnLx4j{S*=QDGaN0Km>hPq&N#bSg*B>}U(^ zh|mZcK!G4{Xe}(QCk*#W1N!X99bv(r)39=-`PhKm`CIr9TLSfuI&u{DY?l)Nk=J;` zv*H4M;&KOUzEUNHIX92L+Unj?=X@lnx_>(8CoI@zmpF`a$fU(ztAqnxs%->umQtiH zz-nk*-6So@VXZ5CdadojL-PU8`jIze?6B6z8B*Z{=j?<1_=f45;6=PlXyHOE?KJ?> zw6@>Sz3asof5k3ftXzUA`E#F4Bg`@w2!!NcK3~Z!Bx$^c1GU8(9}&)mOAI`J#qw}6 zGtmQRVjH3Y7wcm*ixa`}%Qya@{T%@)58u$B`U+iIRdG37e$*6HmIS@l9YG2$@y}}d zW}of~Dm5L*8b{o+NQw{jKp^jG6skw&sWEhrtkm$kZcOEgV26Qyk)n=&9mza=<79Dw z{kvj)Mf#!K_$NO#Gw9MEJIx4fcAgo7A1eTt;xHZ;63U*k48Ib$vP}uXX)c9(w6|%W6LUJ_B96EbDal$9-ZwYR z5;`h8n4!Xr5X40Bu=I9E{E_fXBHM8pB{1dJkTD=$kS9=sk}fIAVC4XoEu+KGHAC$z ziq^sP;8?c<1^>mfyosN^Tz~ZfBEL~x^RZSE7O{fazDU(-489VUmiX{fqB(~5H`6uZ zMZ^%)1g<~-_67kk&Ez#~l)AQ1dV6qhp0|rpU&74^3F?3)tYOy+Hiw!7Ew%Y5M2eObflyD< zk1>s&y7+1^dWK$|G9Jnu*IZvV4r^>i({G&`Duf*LMFs z%0)_&i5e`xT#V8WBuU{Oq*I#?T{+B1iyo3*!GEO70PvZtxnc=OAOuZ`YO;77B|UJ4 zfcG5hmd8seCM@4R%A^Fn(rk{1|3`sE&zMvZM)KFKtj9sRGQ{5wNdIli1)D4wxt3jY z)M3G37^q#iL`M;i$~1xyp(86}F`A>`%|~>|ZI2~y5-rER-pNpM_9qI9ZPEh@AFnWF zl6ovE79P<^afPb&9j|z{p1Bm-UvREU=9z3ffoR{fxS)#iCA2t|Er8vg77hV z%bdkPXr!J8=t_LFl58Hx;$yZ!eXtimim2pmG$Ua!mU=XuYWTQt0w;vu3?{pWl~Cg| zN6q&;_>|col@;W4@(F42Yt<-|hD~*pr2GK99A;qFQp1WL_^FPbR0E-kz9>V@ zkCQ--#mFjHm0Dezuh%h+1lMvCK{G%dt# zZ&b=M%JYkcKjQ)y`V#Xn-XMwHvO0TFwI7ng50vUOf0|PB1(PYBubaU` zdmCpsZGhrz<9f1=1Zu!!_76Nc{y+ z#8AGE`fVlXHU@fHKm2eZn&A~ zPy#>9GAj;C04R*Lp-nbeN!7t~-(tP-eM1ViOupFA#OV5Z2S*Bq6az0v>kb{G>Vn*@ zQBQ$jd1$^zih(gw5fK*_RID^tTy?lg!OWCzO+ zmM_C`h}@zFqrFA?#USz+^%SMsPQ|B|=tIvG8Te2tdm!XMBgHnt&KWchgy@F@P~TxP ztIFW%Ytiw30@HRVqiQw?;4P)SA+PEnWj`PWm_h05@mr5`E6J2(u8W|USv$BKjCW>W zuV6{2O#a-SvL0P2WG#;9AAt*PLnpn=aTIv%6QPG4dl;%i60@!JR$ek=;7yLSXYo|%L{w3;%jT{SRab}I5P^l5;sF0u@h3!w!kWMMpi zHiyCksey59Aw30{g~klJsveK;0|!)B2h3+&n6@CUgywUEP;?LdcbS#rJs zsg{>rU~XbBL0grJJqcxJ{Ms{E`}-#cEc?8|vI(@9!>$|-YZxwV#5L<;Qv}Gzih~5g zSS-vUdftQw78E5?7LJ4t7ZBOX(j2F)vHa<1tBPd-9lS3Eq|@bM!7A2s&FXTC0S#1k(O|4`3kzF00mH6PV^ixef7S}jkS zzUoPuQutnEYU_HT0jttHKMai z1$I%)8Y8yd8^FUMJGj*n%o#X91;EUN0NN#FRw1^iE_Vj2;s;q~AeS=3p%ULF6hy_6 z_Unzt_)vGV3lVM}tll!BkdfuLqF)z#$50DCTd>JcRhrLu8`Lj|2YV3@MO4Ez66|RGIOVge{RiEL_FE*mDEQ_CBpX^I zQMO4{S@Lfka1!CBk#>qmWQ1kHAJk4OquE-IAgzrS58wJWHo-BdSu=$02CpVSONiD( zCORv_878IiDHD;2G^fED9Y`V_!5dd5%VZ4-9ZeC_&9t^lzcIax5VyJbF~Tv1%(z|p{CfJwN1 zTIsp(gzV*gt(|ZYG+LlvhWdB)Yg{6=>Q^KSXsx=oqU>1z1kC zaVg_Q?4WT&QwYeS_@f5GL2C!t2qMoYGTZF9DzSWkTB>*wELV+|^fG8&zL5VUrBFUx z%2amcFnG#K@F7sQp>BYnd;}=f>tqx~<|&`+N9332T>9{f(7a2`+*RW?zgFD>7}YSC zMDWF&2^Vvz`1$7qe&~T3OiGe5`Q=AzzX~LVELYqbvh_JV zzGwgfOgnlg;fhgRgwsiYT#$8}8XR$RRr^Qp9NI9mXdPiieLCGZHmodSeu&rc+IjSK zS;#Vz5?nLET!*|hLT~mxqA{17n6xUuSn8s5{F)BeP7;tfN*x;GANG;anax(#S}h45 z6yXLxXjo0@CtJY5gNvx0%Nnud4Wi#gDd^=kTYBpVqEW0Kt={>q^WJ3KTnosPxUbJg zax4`sk{8nd?j$t$GrmETI(tn|-mk?F+-qIRMJ4wO00tqfJR5xGt-gpBeoY2H@y`lJ zHL#%?fLNO)fB$b|#fZ=eX$*y4@r&B;kgq?(bY28<4$5Qr?-!yF5+4mSk|MUSCxiop z6>07&);s!1B+LK8Z*iBvERT9zN^Twp~DtGYRY0ylkNX zZn2`E5y~ZPRQiOwISr;}p-lt1-zfUdH1BKF`}#*f{;R{LQC^QrsR?+5NE_`J%Xfrq zqH=OUv-b2n2;Bi+WPeqvIjXEpid!+0f%Dm9fD1%WisDj9nJ^S^&Q|e5=aH2-^wWHo ze5}Ys6IeK#NS+(jx853T{f}}r(DD_fB|)0K5If)FE4i|DOaUIT3ASWkW#9gF^|0P+ zZ;+93ltok4JG6!ZGQ8;ij}lOg=~?7c(vTXfu>d6+%RbHMFCKw_S-#k+#RT9>Tf6}l zw2-k3@IFFDYH!y|WV*lytTxNkSaCcs;*5kJl5J}GH1mcA>D6@*U7Y7-B)vZ|_A2O3 zs3k?oLGg_XnnKAlVRo7qR;9j{NT`OFRm+&OSo}chT>nO18SsDS@9E%-Fv#fldS$Pr z)VUKdp(#`~gehcvK`nEn^Iu%MP=JA!fon$q%Iq=BTuDgQ zP7B|BKwIVGA%J#2sarK|pNQKee_@YX{zu};YeJ_n%>=WN&|Y1mKUD=l`-{nXO*j#{ z(;6@zD=x^auJRxzM-BU9Wb){#7&umn8}Z@QGw3hW`1gC#u=wRyox^6E@qlYAZ@`$;J0HIS1@UVav=iI<~9Y;5IRh! zj*^_sRfn1t9=5|l)F!|ms7Hy3NF~lh8=!Tqz={S{+O zYcx;%jT5Ze=^bUR>O>r0KNTis6^~7LCs2^CR|jj-M2w$cV31$y<2YO4HYY6IH3~s8 zgxwO1dWO6%YUhxy0v!nG$Dt|I^bW4SWX02o@*l8$N~yX=$7_XPV|Ci%qYebDQq6n9 zD%NMLdxf*rRsejvQIg`{d9>fHc37%maAA;4t`cV_3raJN$1|Fk| z`iKcjM_zmnG6uIlx;ToZfLB!T&YxKNfOL7G7 zgKa5+htY9g5u;UQCoBpZqiS~WT%bnUL_3zm@*BilaZ0+c91S+Zr^3?e32-QFi8O=u92UA#e@FcN!5xxCKeiBRX%h<}T{8#aX}mL0z-`~IqO1gVDQ0kL zB#P$kkx@JVx{<6Hw0X=M6M}mX0fJ^SSPe5D+H0cPmHj~vMa|z0ag>s5-OV-KvJC#gFYN)8||jL!bU z_k@b%X0&ExntJ}(=R!PlA0dqDh(;sPZa4xc?xC^>IFtHD^THmQUmwyeM+8&0pr=e9 z(BU99GLBmgJSYa&@Hvw!DY%r~VgMzByLPpTjWn^cyX8rSZ%_li+baHLF$A3g9{;_KxExSMXJ#BmqTD?Z*!^DsJwU?0;v$CNfMTqz@(@J!Y#14& z%ijq4M@z?J5-UH}a-%+iLIp~o{LvyPUNgpwX;FxGa>zfjdK;CYkPQM$>~eP_%ls@0H-=I!L_DR3wQzS zs}F~>EJTNN#pIE{xy&o;&|$(hLU@BzfBA5BY%E2yM$Q~<7AP^SX@aByx=vz13lF1} zxJ@AKQ_3`f*8sNwJno|tS6|Gm*|-ku5B$#6=7WSwuXPmiVGs6P&A?8k6p~p~Wy{ zi>w|;{YFO#V0Bp{l1(|r)IbYI2FR3DRS`#fN}eP7@iv==l=Z7i*Qt@}Ae^QkrHyd% zG1W?hx9b&vEC*wsjrmq+U6xIFK?BaAqk}FCI^YFOthTaOV2dzO3Z(<6Naqlm(DpN6 z6J1AQTZddqP_jRAMP_gtUyCSGV+3fUhLq8`Rc7^-N?%S9*D2k6Q>V2@14dxoiN+M4 zLyReK_|j%KOju^pSIzE8*8`X&C?18xz=A)cWD(i{;ddH+V5@zO0eb~eZ4wMJI8nS% z0bAhSGuqAsi`#)5q4+4Nc*aBj7!e2YeIcMCqMj+0<^x&q8-sySNGUDbivknqY>d<`=x1DzP9Gtt(yB%u*8JTmJz4V0 zeCc8|PZ`1|AK%ZUgt5(+W7L{3bj@0qE8?=t^0^axONuPy1b~ucvhy<{2`2Fj1MmxM z%`H5Z9onuM81*C?f{-Nwu0;IrtBZG&u%jzHfz$@4f;ZYnB^My%(mwzMAIJdg%*)*T z9+!SA8#4nzE7qa$71q)6JfPL%2439{-JoZb4-3W%8n=>|rm^rjot{+(Alfr1Rx0At zl}QbYi4(oZX$3}A9ywHbp`ieolimxu3(bTRgarPkRr(3FyQ~blGR_M;`9(q=e4Q@b-=OD+-9<-ak_t@hBWA}$h$k@i zUV6bqu=on_OXdTofn^x!j0mv__0K1GCGbGPOF&=nF$fuGQh+N7cYDted z_1uleTxB?W(T;)?sF0Gw5S2d&g6=?sBAzE-2>}qM24Cj{WUWp@x$7_40&k4kvCT}> zAfGEv%P33`v=w-zNVP7t$eE6D!X)D((N1I`S8S?mAA|^53+X^|kc@0q(>^y~MMfQ ztw{(^=vW;i8n@UA*sjwXQ8JV(O`u7iOoA|QS7g?ZLXf@qE)9fHG1WQ?WkQz){}OfV z4~1DO@M>yFR)Vg&@V0P`6D04Mc5p9O=IKt%&0w^!n7d!3>WL6NH-USAZiV14Cp=&S zq^3L6<-;Q(fkRZm#!$PcXm_Zl%)UN9c;$T1MpUI;;c4!EaV%YoGLU|Z;86o!p-co` zVs${;IO#B@++&*(I%Yu9Z>bu@ViN|NtN2a%b_1FR%)y@pUz6?fuZ{!s*}79Kmae~QG=GF^;iGPC)Wq>eF7`6lVhm(oyX9FG^GJiqK9tn zi4PHDG7OA(sYTR44jbhNqM()cc8M*aeTJ(4l0ovUF@Bi%=Z+5V0XeQ>n$=fmNPBYy`r{6Rjv_4-rcz zgb;+FWd={rX0{_KFk^(WQ~2JWSF5D?BdF;yqR2eJio5niY&!lK}v3roiw6jXqXPfdyj6 z0L3=q7jVN3PFn;iBRWR|h(hEQ>WB&`HUju`>9Yut2j(qQSIOX9l@IruWql~1KBX~L zbs7Q$G8yTBmcj)Ad6JcL3gem!ScLAqLLOtHAD>51!4jEU=AE)pLkrk$Y_S7|$3(|K z;CwSBl1C{PmQ>Par8-u!FynrYQ%_aGry}TU4y6*SZ3O`>QY=X5axBt^dR91#D4lM?s z&{9E2L@Nak3Ate0l?b~v2E!a5Q5VLNDUY1+sa+L*EnOw7Lv!+1(!`Z z3|kz~Sc;D!y%RtvL-7NwuIZ`3Auz$RPJl6PMV6T%5d*(5r4J0^jolMN8(Nv@eP%B% z8C)esn{qZxs>+T7ZPn2`i9P|w)p@sC`HK;Z8#4Z#XEF^{mS z5PZ4Xn~SDW2x^P@YC5H+E`T8EjRu4o2khaf0^?&qDb!|Ia^P6e&hW#XhvE4| z7CDelvx(5~GXd1nK`&JRWsqC7#qmG%0nw`-+dr5B8tOqw0{tSQsi%QBp9ULMpo|OU zGHo!j-9(LzxTLIrB>;3e0)q|TBIQGp4%Z=<4lb&QnTOn{r2f&Sb%NwOoJLd1h1qW? zc8CI#ySAWF+l|5e1JEvotAesfxqw@kb;p$m#@wYQd0)|)Bo|ISctI~Is8Qk3!_8TF zX4NIuIFJD^T%KYz5`=KXIjO{-3*HF*ml)~{8bOl>1kM*ZkIu6S?^qj!45vi@G-L<# zDAi{-TB3VYD?tk%2U^4-UQ??|SLD()!rfULf8nLfGZT$Fk$?arH3F2Jj--l+t5nAV z3Vi0MXM9a%yT?_DASB*heh(?dDD7=Y6Mx&nGLa7qIdUxs*qikl#I;QIn9X7#8u4*_ zSRMNVS{dbr1uq1D2aarbBo`D^^+N$xOBENxwley8Q+F|jF_l)KIV7yGMG8X@Juf31 zQQV_3fMK7BwgeKo10d-ppE7>KUmaw4m7O+x6s90xwd)dSTrgKl1g$(nU5_!`92K z1F|}t<_&mbYV^H^84yclDP^wPODqQ<3NwSS>FVSVx&gFfN(mk8V$bV|WZK~r6nHwcYD5>fYKq` za5MlkBf#ED*h+JRP-p_w@<*Hx}N0i^_x$QfaxbxQ9r?=^-rfibGfjtyzcN%;+zZixwC z38kQ{Bot@J2TjC4I%sz|D3=t&7QEAfNU)d{kscU|BQOAbii0%_fjgOJD)VY;c_EOj zMcptI47Ai0MO5ABbta%p&JlaPG}Qm%1d<2SfNY*>zWriDkc7!jKre!qLo3<>gUB(2 ztSUJ+OcA6+fpA0F81!W}C-e6=uMx53S)g_WyI7(Uf=feR$1$YE*2N5?``GAT736v@ z4xu&(-7sAGpe!16w}>!_6E-)@$BZq!@7$mCas1U6shm4Bq?C_nG z!)uU6tvxREXhDNTi1~Y5UKifi_^W9pGT-xL5}S zH|^@l0Yy?|2=ZH4(Fo{}l*8lS)P_4MrA50Vz~IJ@e*l#kdD~d|}z^t$RpeTzqDNQ>erb9K{O4 zMPfWY>2O+hvDTN8$wizlBlqy1#Wz?FZ8}%zXNu-Ptw*&ut4MSvc5>K+ZSU&_Rrz$- zyB-84W-64zNZRW~V(5(HvtRHr&q`I7Ditqtk=jm1YrJ)+0Uoc9TL+vhO(4=13zY}e z>EZQgms&v6;XE)H5y2^DK)b>ZI9vIarNM}3D_j8!7NKuIOC7iKC?SS3wJ}iWeqpJc zjF$aKlUrSfGo#~{f4nN0NRW58YSEfbfNFwaSf0YiKSdH2OAygmo9#hCRIhjp=~1Tf zwt$FUp>WwOdk~I$QUOPMLH#2{R*y>Lb?Unx{TUfGg11U1h>FW$ zP{oySY>ETO`-#F0@iI9eV`h#gnLAD12-Af0Fygz1pziy2Ynju0L1Zu5UM^HGk%P1V zB3}?qV9;lQuP{#y1_ehc&00$)Dx}15c<}Wn+bf5|Q($tHv6=0xb&P$JgoBtwXojI9 z6?R`#(zGKjps_U*Z|KWg6U{9MFR*GbF-uU<(;?`?dpb%yW>p?g;babkxhqLyRWyYX z!bW=QZ4rVCf>V+|R0TAan952BJ-)f%O%}C&y-}A6(fbC4%_25%h1l1 zXiEwtin+n(qXqgDE^Pn#m=;cAY;x4WTv4(uh!MKE(_uqb?LL_~P!CFD6O%vy&|Ovx zaO9n`3y%e%Hh;XsPz*EWsuH>Qpex=0cY|7@Ksu^Zeh?MyD6sl80gAM=156}EWE%vN zq@4s0n*uxPA6Uf*#|ALE+mDg~)e?S(wW;J5mksB@%f$ink-tTUy}~?&gatMnF&$nr zs9C0(ZYHLKt4AH$pCCemS$B92#RTY(UCLx;fl(G^g`_G82}W?kHl^lc_!|J4f6cnG z08fK(?C4zxL!eV3tDjW-&Q}#$muNAUS<@#0Tu@k={O%?291&tOC8J^fu0Hsnj4C5% z<4U{+VArOMW-psN07Y`d6c)ik>$C>5Oj8}1i~XAR)M(GXzL|6~$BNuKxb9g%GuUno z0aHq2v@(vi_5wRziL(t_!;Be*#eG=ILnP$n*NkPiRYP+PzA6oe(m)rwQ^mqoIuOb6 z3kF*e%EWs2>T3*VCBY*QFhM1!*^jH(s0t%pzBOth zV5+jKSGOPoD|Qw+Tj|$L_8fpyAr(lhsvsnA4Pu4eI3@TtLkK@5FgU>|eS0u~DF)4Xrhu*n z%gkFbXa^wWfda?{Cu!7evU7l2(333eHr6{TIc<=tp&+caoW|fRj26gr;8&-lTjq+; zPzEEgydkG5#1~QL7@IrOBwFMLJ-Kyb*rD3+d@iJhHAqykq5+;whTW>J&}Jcqux!`8 zdfz7Jpz=i=mBQFKjapuOxKh51Kac7L&Y_r7JK}$aqYNGkEg>_i<=vqluF~k_#StZcK zX)}}PSf1#L1~z$zh+ZTnVT*h!VaU;4i(r+q416zPO={O$LqI-CyuJ~0%M^Efvy+&- zh|tvoIQjHfvbMV9W*DJ%hB7UXEHYDCiS-nrCfG1Svts!iyZGoZ#({)i_KwWiC1%qJIxtLIfAM`C1B9!rH0b zv`QvdDn!uvV;T*ER0shro(U6xDIne;|Avo3c_EYrG1eOXcFMGwYK;^;5Q=7DlLn=J zlrPoiG@3$yrJLrScm%)tB3S=<5bB3n_;)SdN0=Dx1K8#;hxI|g>k)WW;r%NR&7qD0 zvc|yEMs*?vwh|_Q+CZsq)D003kW5?c8A@2s1ekfp) zD43wl`R-7C-QxK)8FmB4r-8!JxTNNpJM?{HKZjA#K85SAs6?wREYV7>%96{?dJT{v z2v1;1jDUW4A)y>5b*4-;poXASi?)p%#Q#>}M7&QjrK$RewP$eZ&bG5q)hFJx0ZqQpICUlwavS zP$Bz}#aJ3>s={P=bZKZ>mr!QOW7I3sC3p41z_5qFT6WUHfx%xFP#Uzph!^%0B9*0( z`FLAis8F6HhJcdcgc2pc126HcBn!|eV$K<00pAW|`MTtQDt#RUn)hxJTTGY-^JCfM z5k`ddW`AqsLt`iGk1^EWLHv!tQK}kgLJ1EbDdd3Voi6SQ{$(XFDJR6}%auC0((IXa zX|I^Jf`jIqP!VdJItaq_E^T4>EKuur)hxwkmN43{dP>xB4?x^U_#4BC?_dlhu{3IAFk>`+kQw5<1P(xKjEfPm_ zfN2rffLsG_)A4+LqEy##H_+TAKii3`06DlNbv}a2dp*L|m%MKzs=$-dQ4j$0fgyc; z8+i;xrdlEzo|+WUpXWt^@Ts#q4lZ^N4N-Y3O(aV!N8~lnrxDRe4TGY`#Ge?^3Q=uD z?un}+!@^s>xnvBAwF~He7?0e$FrAOSf1%C~3&wx^s3kG1-zxJn8k^O`JX=J9XNfHh z`Xl69gMJKBI;=@^iiXJJYVgZOkda3{pf-nKqdbepxrjT_0|eqq)#(f`FJv z!Qx0Q-*l{p+#ttZ6KHh@%v3kzT!z~B3fTd4wr;{~IU)x;;J875f}SxA%Y#OBm$G$YYfz`Lzzye^!{sY#_;R_OPAvN>Ba<$Z zl9oQs8j9FXO__sLnHE$1FoV9AIF(cQereZ6b{19ul8S^}7`xo9t>6T-zv1h4eF8YT^ZZ`FpE!DlSYP;7gNP3HKSMHWxQxx`p$ z=?YCS+s^u9o{YtJ&GNyf#x8I#Sn)$^z`oE|=xk#2HvB=isp)yN+^H3QBh?eZn8s=r zjF8b#!Q41#Zva&$J?YCP=Ew;6ifJ$ooIQfZF*Y7Rm=y>8^f@tDZb1~6{n2~2{Yu0n zIh52Y;ozjhm-K}ge7ZtflBvW-Yxayg7BYfHjG4~&t=+;Xv#%$xpXADO$?O+|PX$JU z1v!u+P+7Z41C|TI?Pja#a1C%NnN)~xB^F2Qc+9n3^K4IbB(1pMwT9PTO>S-Hjn~Y3u+LOar1kH0ID|F|?<2|Va7}4$A`NJPKffe46sqbVL*I&LG;1pA|aT)QJV-U#SqL zIZGVg8E0L3Mu3*}RniA)1qyB{RaM-oXuY9IdH`+9o(!MLdB7l@1~4ZQ6rh4fC~~k6 zo(p?UG#|ixQWZJIu6LqeA)m;QtMKYqRr3Bm2!zXs;F$TVs*-E7`g_9q!pwJ&@KUrG znUIj82ZmO0P=zCkg^Msq;CO-n>#{8%qBcfE3MI6!OhWr77tQh~fR7-JSl?}LC8zH| z+5sRumFe`0W->gEBWMD07%;p|1p)_S!x&FIV3e3mwO;Grmk6YOlG4}?*U*|@Nf?7n zO6!FzmKcB~2lqic-aF#!*dd;B_ebk#4O@PhvD!sZv$ilS78eY`OS;Icvxv@E?l&^T6FSRAR-Fdyn*fWhA6lPbc?u0gL~V+WMnNjG%1`i^CS zEyP5DUxEA6YCJWpq%8&J?S`Yu`$?KIbL6%DXPAc2#W>fi07*P-OD9W?#VoSk@baw8 zY+}@I&~DMCSZ2tTOx4m_0$gH9K`SZ^Q_8@0>_FHumPb}p6< z*`JJO-awRGZ4xxEH zC4iI+NDJ&056({9S!5NtU{#XkD3`MBO$pLPEu&Vrk=w%|-FT~`E2~y#a8L}k3@t#d zy9?)%=4dJy9RUu2o>ajuH3UsLN;cktG!86MhPwaItD8|so&SYlqD`^!Oi@`OkdC7; zoe0h)Krr>jgx*?MCSv?U;my&lc2m(R@z+T#5aDsC>O1ox1Q_+1`Y4t%EQwz|Gc+4i z*FGdSeLI!ZKVsQ}rF_w)8|;tlhou03Vhe6YourT+Oyq!@5Xd?hh>^Vi5o(LIr4&`rk22wz0>eGzNrym=IC%$IG^TQ!3mziLSs-UETMi3C zHwMC0ptCv##Dk9$rLN)o#?nFqY>Z}3skOH(SXaD_uFb0j)YY;%wjIcz4KPmKP-Q^7;m z`(^V}!#f;7B9*hXP8fJb2oN&0LJ<`uha%X54sdm!k&P!2ErdO=AU~5C8ATdSQ0WTX zucy`wa2}&IVpB;Tra#*Z#Ta&!Qttu8O4aM$I$P7s=t(3{60IvJ>w=UM`QxE7I=F`b zrp=Eb)PmC?Nndh>UpzxswA%nb+ng*oW8C*8;b%M~rv;%|r)?#W!<0PJircz0u>#3p zJMj;&U?IJyCkQcsg}yvJ-CD~>2Tj)&g_4$ijzEMNrC4PGN;L)-VhF>JQik9&S3->$ zQ;^}>yy4e^`hlJyBHe+p5LE`aX-Aa2EaK5*q+T!A2fwzwZqRlQYM%md`M+U@V&W}( z1eHwtXp;X^k}LLuD@iOANQc~i*SaO)U=MM8u4z3iXjko+_#6@V7BfOL#!?OIRL<6&Aw-a7NunLgM^Z^s;L_lgTe=^ao%3vE<#|t4627{>X1p~QdtWm=toE@6{6v# z$6i=ii1i*uKs?dmMigjHL5>^7T^dDhgm*q@A$u5~z5P)wGi|B;5E(9@Qf38t+s-I$Xu>h+=JL6;A;YO!TGo( zi;Uoq%XP+(oIPfl2@WQi9acUTRm-;8NeE-@MlKe)GbN;7h##Yh){&S2W*wvCl*=6C zOSKBO40L9Vs+$^mY~)6y8JVhAAUxFMx=3dy7A2D9v%eGnvz*br2G~0qGab$ASu6RLA#rjM@tcV)y<&m`R?>P-;;I8y7(a>e1aE0Q z3<%o+AkZ1);-Y1*`dM7W6?D8x(<*(C<&f!x&{}dcE}XB>R$UxaoLKQcT>g3A{khN- z%Am6q1SdWZVhR+nAJ{Nk%Y`dK(R}0_`BvnoWbP|O{i67V?F?HFa`O*7RG8qMJ-v+#dtphYdTfjXFC)GSLP8eRlD4--`dnC*20 z*&wR)G#}-9c*TgcElG7oQ6qzG5w!A#b*x9tb*B#WHJTYCpo`HY-zg~LCy4VBrq98c(Su(f1l=1;lf zc#{HZ9yPPp4+;b$WPHY`N;e4{e6>b_)+3d`Ld#m5Z(!9$n2L_lC{mLsDMz(6D-g=@ zYZ{s;=?{3H15T=|&hj|po6Clc)1kBSX@Qk%z~k7D>Wt2K??X`y9_0G`gV1JQ|N5F1 zG%MYd(0JHYnZ@o&DSb#B(@=+6z{mQ^UL;zDkm{&hoJu&f@-O}hW?b18Vi1u01@KXL zZ8|ex^Ep7W8oJqD?Hyunx9+1`ZEPx*r`^zGwKg+>FHCTluYy$V&PH30a*>$yV|-K2 zu7ZAa?u#VNeU`uyGyhBQ@wEo1paBU00EOZazjD}KI?0-a#hunPp4jw50XFD}RAu>& zD6R0U5sg3@z955V#~P|_sVohN4ZW85Q@~eRZ5VNWJ?;>EwAVpv8(`RlZjL-M+|d;d zC1a1KKGiy4D;oq;W%#PhCK`fO1W6+(bmcNoyj3_7M)s)3N)Fhn*2oE20&7Yb&;uKlqO9KHEUyGZR_TP1r8tCm!FpnxOEi{Q}04ubM z3z>0@y2?*XN~KdnQSxfg*M59{`U~dNib_rB=yI=F5Ce zWu@WA`?$0(Ac5SNxdu(kW(_hD8gtD2%NzO|b*CM}@(gG-jI!MeQg` zEguK{2GG(IeIKF%THtE6EgU}SbO6&3h>{yXCkGJ}5dQ00WjJ08cbJxtnRJ``U@!x4HrkOsA+~oT*CIn$mS-=0G6?m%8ju@B7?NX9rQ#v&ipCASrys zB|AxkbqcT(%l65wi5q+|#GxK-nK;C0-vg=U=mwKRCNes(G2Kyo)$VT8Y|;|pb=caf z9x_*+tc5mB>vqGG0*NSy!K^bK2~asUpcJCCAdB)RmPq9*MS4xGzDSAtEt@R~rWX`R z9%oRpyOqEm#5sF|Vyy5UBnDzX#imc=BCl&{LKfCofqkhhvkbH4E1y~g!WsKd80zrf zBn!gw6PX1n4M0Z5OZ_)DrOa2@DZ?rtWhCX?f$SeY3gXE;KASfWfTd?MdQoY+fmrM1 z(7BsJ5vL9x$9Wqj^-YD9a$HaQ&xm8(Q?7pCMa`5=i8!32C4 z6-n+sd0dZ{n$UB~%t6?qtTH^@;j_UId5jJA2u4e9)`1wI(obsueIpuaB)QQevqd>k z_;#BMPACi*AtW{W_k!FMhYlzeMabhv?oS#Db(;}-CG>r@OmfkUmq--T6QT!Eg<8@7 zMzImZ4W!=+oELYC;pz#UJwn@cg!&=jZ>#?vTsVh2CWX^zxY4bLu(nO$%_#3*BT-EP zIXNpb`p*F=n8eEHUH!A5oXdhxq7wF1G&6j3q=_wNv&pg=T9+eP;^{-e;5{b+FPAk| zu)%X0$C)Tni=(d=kpZ#$7qw_RQeRFrQrnLV@DbU}?h+2cqryO$hOI&kSB5NlV#@o8 zHE^>i3C2;RtLC$4o}ltA2X#e4Tww9naK%j1GsCrHxfZgRslX0yL(TW82$Q# z3nrAX*BCEofg1S2v?5a|8u@!hPsl0nhUUais0EVyWP-8{XR_pc+EGEmY}8FLyi~m! z&?<%w>J6%(Ck`XZKm8y_TLer}1|=#QB@MR3vtNKs_P!`(!ag1(ZyQ+jCUcv@gB$;j zDj(Z662smInpA+t;%od;yfbRc5tjAfb6P;^8A$Fj46qaeK?qxE&YPCx z&XJrXZ4v9XdXu1gi;TFb1GvL!m@00QA#X%S^xL#Zf%6avmAqW)Ro`Y#Yr*|!g94>7 z^HG#;a@{>Uh71hEg3&3Tc#r-$&pRe6FCMlj(^)bN(%Fv((ULSUR_4a+Jwrgl4$^l5q3S0H_{PpL~amSrBA z<&^=R#Mo;h-zFhq*N$jSUq~?aol)N*=rfCBD~8@2;?#roqt9eai_zY2!GYRJ^n>a_ z?$Q%}b84troa@Ziz!@ZYHh@9ME9&2_j(D^p3ec{q z!?rr1P{6TeX(DpYN3Kb@5sZmhJ>ImLQ4f^$0@C~vLVH2G5rapw@GqseX)aL ze7O%t!s|E|RbFtqG=N&7>=6M-xaB7!4?+A01L%!94)bm*ce!Slb^6R~>mm3`TWGGG z(yANyLQaasbfV0M8up^PgS(hLQsF9Xgz%KvAxBw`kUKts@Y4V#vW*AUn&&i!9DmZ= zI;jfmP!t-?i4Jj;#+K~yE^a$`KgGf`(CYe!MNB4JjyPG`>VkzC&F&8^S-OxH>Lrv> zAxxVT`0mU>9fc}Nq?!=5NyZ~!YVV+$JjyeCO{!kOfPwn23FDK(o87 z3#t;OO(3Z?pgo*Iqisa|o^kFg$d0s@EE|dEB(v>GC8+`MDP=uU?+Lr6_R(SE9!Wi^ zp{Dkh-xbqX6;#m3PZCxN1+V)7djdBr4^2|aa-qD?BMM{a)XNNw4|Zi8rn2s3@rASu z?n0*8QQ=>TVl)&O^&`y|8IKyUpn}>Y21Bkq4{eBJG3n1s<^^gYrF;~)Hq*q#XlJ!| zzN!ifeUR*fm(nFL&j+o*uojT3h7dOb@K!`JQHpgu)GjRJkeY#e+!r9?O3=y&v?>63!jn4#$lx7-;?nz`NCB zl(3PNl_Y*W07S;Ui#)(Mfj;kJ8kEli`f~oXMgjCU0tl9-i&8phu-;cnqJXf@mq22? z=7aEJg^o8sYJ@n!C1zpbK-oYbjH9&)O+EWLq?5EWMDO{9jdmzhRfk5MD@GCWzpBFI zfl!SJ107|1637_~FvoiaV{OrV;0+Br5+W^+?m>SmjR263*IP|c0C%Bj9La9gO227& z18KQRohxd^Rs3+*C{-$D^&N$vRvD%>dQrv$&yP?b@5}2Pou!Hu9yb1rCZqYBVfK@AHczf^hzsd6=Y0;{wwp$sD6DMG~npQyiqu6i>gv?1Dpc(jgY z%JDIg;SLZ2H-+a~%#z>`9e6K`Kso|1#<>6sM|;p(Rl^DyQ`acV9@2Uuxq|VIFp)5C zfF{7e2t&H<*c*!wImf1dIF2(Udk7qq-lK(;)Oxbx`Dq8>eIl(n#ThF^rjQn*Ut$ap zA5lYc;qa%Z3GpW2P^8B3_<{Alx!4-7>}ANyY|kC8vh@WpNOe~8*e0-omub60)ljz5 z=5?+TB6_cQt3fEAO@t@*?;xY?C=^&~B3}jt>hU{2Si~AsvT@t76gRK-}K>@>qh&Lp( z*_q+}MvgJ5PFXN8Hl)DxxVAvnkCG81-*WoLxN!~w(vujy3_^CoiejSp;DGsMtFdQ@yzW(Bqs0_!xeJ|$dZ7m_dS11 zaShJdiD=7KZz)Io3YbhGlk-T@%7XLA2w!CF z>D6NqR+FP7nmK{c87f#UYyecR&9oZmK@vv9jvvVrFwyNgN^2ou0VQA-RV<{F^C{o% zY&MOuYPu#d1e=y#kejPo5ipmdGt$ki1nb?!tD2e4Uc0!U5QBiBD!S^QWE*xw01ydG zr5QHbz2E9_TN$1!&)L9KfUMS|(OS%dG%V#s2uABe5PX)05K<~@iuPbZqLk-TXW7Td zrD-YA``{fk;k-hdt#weIlnznwt|sh3D~xNQh!7@fZhB<72FYLnBd2zCVJhtEKBqQP zxy^km(3W?bnsnqyRgbU6d+!%rB7tc}0+mSyZa4g+2@7ji&Bl34CJjgjYn4N`V|a}k zG0OGKM?`I}5uzBl z9O##l>c1#}dv_uTt`dYoY9n;$wZ-EFv=oP#8i*4S0BZ}zlR8%_*r3v*gjHw{70hLP6DuLUU`5ne)uQOTaAwAP>k%c9ihTaa0!n1?knBHa zu}`1p#pgTO^b2576u-Q{qLoT4e#+=5ZC9apRN4xPzU4jO3J88|8KwZh5S^7?vuUJ2 zY{%P>cy9{ar7qdRE^3Og8i}!eBPp#4V@nC+$ucBnEPkI=59cvyfO7EKs$DH5xrM&v zM8M9Fo??Gst0R-7eWkG(l{|n`#3!oHM?P|!JZvyF68TlCQGq|CdI#vjtFtTJaq@O` zz+kI~_=7>Uo}4DJ@mOW)Che(?2UH zL{Jf}M1yC|W2j>XDIwr{t7H$m zNB1gW55hz!vATp7n$?LqL&TbtID-{8yGD~!)LTVs9%T;pvxX_C>86Vq1#|9d*jCPV z1X*8}qF$4#w@Psy+gK$=Od-XLKXB znC!}6NDikY56fAgXq}5A4xw0arz!5UgGLca1ayTO?L|e2#}tc=0d#ZK!_CI08mzMl zc$onlORLTS^oC4Vb7cfLDAU}bfAc)Wl>`FEBvynlg@B+$0n*2>frtuQt+>xv7&J=f zb8sG$;f&f7eInX0SY`lfzo=p|t@1F(k3cZifnw^wk(vnJ5ABm|FG8g2B;ji?g6Nss&RAXr!R3=3o=$?CGQcgoyc{#Fu9 z(1o3BApves*I*NU5_E|r5`ImjkGSI0^kjaX-foEvU7~mzDQ}1fs|noWxb%>&?=Zj>6MW(6E(mIHzlNyLR^(~ zAPwiW6PLZXAZHvku>hc!o_A`-rr4sU*Td=b-uyaL6-h|QY=68q8xGf{rmI&IBSgXF zLtb=n`Wl{ys}1n6Lgb`9Mi)YSt&x#33x+P>B814Mn3r=fT(@wOv6B;#HMglb)yv&f z;E}>kMuaJ6p^bYx6KtTx88E>XkPttHt;!yp05V@!3bHF7P=K|GJ~y4I-)K?j2aSW` zrr6lk(VNCk#{st*$AU)OM7fDMWSy1467;Nh1wBVlVcEMp1F3NvO8+bbDUDocVoacd=Bv`rIGw$% z!bp$Q3S4wSe-#gG!e2t&j~13nK1gN+Shj3FMRTMQ0VjEmWmJ^u@H&;bA0Y5a4F#$1 z59OT+2N5j^OzijC@sjG0(<4wd)(5`DhIuJv-}D;Bf-ZN8mK>knv)?QE>E>riU zz}W3Wz+eQ~2$TwDiSQwUF4xQ4kFJDK>Gt56yP~mz98cqnD%sKoaaAtM$G3nyqyT$B zguim6op=^i_1iCnwraaU3mmb#=%V+wFPWN#qC;@Sw0@O3zB{#3pcU>K!6YTlNECW8 zxGcxyx(>~RnIScqjm!We*0YV_;9aH~hT#+y7b>!;k|tTM-Ad-Da^fJfr;gty{eGnY zu2lvH0u^%`EQb(uk!3wY!Kh8Q4VOxAHD}4{yElk+%=Hdye;;yS7`Pdo)1_W85*w=O zLl8+YB!i2((PEjg`B%hv7kxDm$?nWDtJYL_A>iyD#aW-c7C6&2+gV;Vm;(y!G=(J} zvvLjFi5swqI+_f7@+6Vor(g?KF;iuhB zkpzm_7yoThK1$2%k#jB(R&5rj zcx6D{i8yXs-{KzT#s zreGpeMJ6IF;>{Uj@@QG1=YsTFLQt5HctB%8CPIp$Ur8CxQp-#;qLB!76ParJnF~8< z+^;@$=WSzfCBqy+GX>HO7A%sqfJp@wtvF6jWbZ$ynbq|Scqb8(p!uMrVC02`Mf^Ao zZj`vRdL(Nj=7ugI5XFHEn3NB$Le}B9J;WQCeQ}Q5miffEYOK~T7-X^&5(2pe2G;Pv z6AMzPnR6r6;1A`f&t;>lQxQuyxdPeR##5jKOedsLAGpN~SS_u`x&=mw!?9IUtaie7g)uaWE zmYSK37Bq%vXOH{s4mjk|YWc!IOSoFT&B}O?h%gdH93i( zkt##hJONA0yPN0|Zj=5#3BY~#Q#(It2)kePwn0orS zPe=sGBRmAVWoqV3axP7v3n&Dj!DThZvdA67o-R9pEA3dn8NOoOq3gad-62N3;ZG1OJk zcHkK(iW1OY3(H0ea@)i#=nR!ATkA^)!7irIlo%^Y@H0a96ZnoTMvmAt=@R38ibFej z&M<>Q&P&E?jUp9}WRg$=t!GoXB7vEFgV8J}hDC$WTw+U78bYd00!|RSSEo2q0Sk&V zR9h2QsZFC!OW~&qScU`*jEyO!GqccmmFqym}cDrNoqp%@iaV*t=fQ z45p5-k6nx&0f9-#HpB=UvgizDsL)4U;4tGqewV1*F(9F7%NQF5MnUZW3xh}$y^U>8 z$QvyTz>!1|7vVk_%!7fv>gHQ@gq2gXuD*4Y5?|C^ldp1mVxJBO?oRV zyV7-L)ihdn3N_7W)9L&L!;-2u|DJ4dgak)0akmgJE3%q0vsK|mzF41((G#%>R8$$c zLIsDWY*0T5aY$i(uvYiWUYDvKbdw^%iUrBiLS;w?tE^QcX|(GC&kHD+mmNProF4HJ zbQRIY66KOfXf$B1tyD9%BJzDg0UE%5drKLR;vh<@O7_v=rbOh^uZe%03|Kb}n~BK0 z*O3!~h<`Uy3Hh>kUjtHrM|0ed}Y+y$I zNlEpV>Pj}*rvMX;n)i_CY-C{>W`5K~kQhw6ukIx$w_mMYWTWDXm=j|vBxNvpx=~r0 z40FCWQssqu=NT?4$e}J3aa;Elp-aeJ9yOAH6-!(ADx^;w*wso!)e0meJex2i79T4& z__@`xn<1g8q!|7HawH%g$f9CNXBY+RUGX68ykb~2?K8xC(WbW4A37;@CxkOd90=50 zMH<0)7U_i*g-Fx*uNm{2W)Kt&en{Lh(CidA@7)%f?3|z{h{GEb7C!f4dX!1bAG{bb zyj-|*12>ftQ5)Kv ze7^xScaxZPgv9GX3cL*SJCGye9Jas_ki$Aaddt+3DZm7UEfJ|wHLdZ7Pf78=uw_Y6 z=zqVnBpd!JLu_%`fgq1XmE;9nZY?LW<6;oP^DJsom#P|@|Nfv@H+%IDyr}>Lm zLi#wO0?RakCg34jy-fiV0Er+Y9qHs@$C55sgM5WzB%*9fkEg$x9`sVFW&ic>GgK^|ZTWjb;Qa7pUW;sg8!hY~~9Cb_sr z%$BR70y(;CxedSVJ$&km+m4^iX8uMX#MzD#x$!$)WG=+?s|K{9w6O38hmJ_ll;)bc zh%j)WEBTdWN=v2uqb;|b*qJ~_&Gf5R9CF>O-l#qCPrZ3|^A2ckEk=u@~q2j0=BwkqPD9sN#25V>d7s2$e zFJ^pfDPpxae56o|l#n}^%z<{x7Gd-tDybY=7Oc$98UzLcpZZs3SkpA!Sx~chV8W18 zZHk7gqC$uYx|&5fkl$@2TRuQAGRhlquw#-jD3OMCEDlquhs>wzt0#St#n2_e++3nPw?1vNn=MUPRGH!`h5adG=s|K? z1_izV*QIC_K>F*u=tBP(;SUBDv5pALMG0(9xHem<1oG zolK|C2vUlZM<0jC{JLPwZh?nkI^$QuVU~eIdn1%({?Xymf@Zb#6afj*^=3 zAuZ!@RC+x~GHsMt{lX2TA+KZ+keI+8#z@Rsn>m7XNI{i$Jhpdm$C0^1W^`EH)FbB1 zRvGH)yhOGraG;f9o{}qf>Tj=-A6^xSLJ)$Fspcv}RUwK+vK^Ej5yj8=VOV4z+TtWF2xG>-P05v}QdAZ*|(RxY@d z&W}MO3t_4|t|%o`N>i(v0QTlGC9O&N7c1HPhAssKKn^G1&vlUasRz;p_l+4u8A_D| zphKVozm)R-FxDo@pZ!gpXu7AYDznWDsIa^H`o{(;0AiL*_LNqPc$Uu_*PD z|Hfq|B^jJe;9C*{45J7qz)Twv0Cbv>SYX;haARS(fRWLhQkfHAxn;*ee{%|=Nx^I& z@G#F6PYe4&}mJ-J+yj@s(*rUk6DDHCH40S&{dcRt}2YY0|o#t4+`CG zyE-|Z0g=-rWRny-C7tz=qe!L$VupF>`)j;Z^&El+LKMtl5Fp^El_o}9IltB6-Q~yUko2|)g`535>UxMr6}r=3_$ecQ6SujVR0~r zr2?8e*EdbquoYjZ^em8X!H&i5YDwv3l7@3EX4u1F;36<{g+@(;+8~SVTfG#@&iOur z^JJ&%dZ5Qy*iZ&3T439{3UNC@yM*SQV4uBt?z zMzyAfc^etVdz&H-Dx$3=%rfT9w(?2{6JpWFBGgF(0KHOUUNt^b;C(?JiFRlFA)T^b z%ycDUx`O_f-T9LUe*lyxa}@KfU{b)AvUKtxP*U9N%z1(~TR@{HGKsk_EmBL0{cMSc z?cV)^$y9AhG5GLa$m2Fo#m97fsc7Uv4W^|gPuV!cJ`YhC9Dy?S)JeIJwP+m&f^DZT>lR=+4DQ(ABB7Hi5*8$oqRxE@RS&}zB6ApJ%Nrxfh^P)z7 zN*9cr37Tts5B3a8Ul7DWSKGe0DMXj7vNR;xzyv)0GzNPYx!2w7$n5a5P@R1`_nH3))0s-kqD*BWsX4%FF z0M&}tCmBKF?_<`vq#wWyZAB5Ni?R7$MGa8*2#H8|ECDAP8A{Hy^KrtD;`&=QF(}0v zH%qypKd1vGT8TW|l?P=JL$-g*VUY}qAt>M5^+4=!&>A*1^M~+`c*~J$R1o_za4(Ps zoK7SiCl^yb$aCApq-GS6%hj*TPWYnw61&09>5)v$mT)-sPvoL zNK3E)3i`!KqkCc>{2bC@}07vhc^$ zIG1_bvChcTdi2%D;9K71*wk#IQ392}wftjHTE0ds3`9#R2Rs0pfc}tIf&OT4j{CtOL8dnRT-^dNhCN?D^;1ER<^O^iNM@(CABDHz1^ zT@*}?&@7?q5drdq$!n@0T_QiP#7{>;ZK%^BnXEZZGH-Ci3~FdH@Un)NQZ)ezpl+Nn zn={FphM>sfPi-$afUdM-;*fn6Fu(-g0>P`)gs9T}3D_!ZK%q60&Sci1NvS?w7AElx z$&1z)a06)pOBJnE7`_tY1e|)IVo~CmaUtX&CscR?V+g}?hNYnJLKk?F>?Wgqq}CR3 zfZ<6=dwVOU!v^ddNkKlArN!Y}BL97bM1q~aEkXw+F^#y9Jf0;LC=#>mibstqxmvDg zidW^?{}lNT5grUT|H} z<%Sz(!UzN{E4cmDd~{Wr|5%|E1_YB#J63*>jqJ>fVX~x8zF{kpJ*%uTa(~nFwF8NPJaymkas7Fo`qsF!XfOd1 zh=XGh!y=pMr_Xd9pzW;%gjI*a=|n7KVwzDMfUV8sgg5F2M#AKVha$dPNDx>P_TA7q z20Rq4N{7JBDY9XPDHc_F|DnQa*UwTUbOHGX)YL?@sl|{O@_{8dwqQ;`m^d4$D>`r- zR_+8Ss2o$;3?V|8)RXl_EF@yM&jtW5ATl5ad z8~074mgaGb*eS#`5{3i1U}bSBkY$U|J0}#IzI~Gd>mR@ZE_qVP!XfrYG?$l5_;7S9 z^}fWjE^i(@I%E+^)_x$QH(!0WgQb={3`$jz+aoy%~Rn7kWo;&e2uz({#C^m7{uL?-@0+Dy<$`O8XY92Jr*Z0NO7df1NS-ynGkr@eOW zX#Iff1C680O?2@Sl>nqQxDt47$`GGN1eefF^ooW14z;m|d{oP%)?5`_^V?}VL)BX< zM#ivU%xXmih$gg#{cwQ~Up)Jhx{!upiilr+Rg0n&L(EYlJT4G}jid15E*|G2Hldyn ze!Hl5Z(z=zC3tvPjYr|RKoMcg+dgCXqgSc&zPQQ{M8&Z4e2y9Ex;v3SP+Pn_V4bv) zPR7byZ3f)|AZ`X1FF1FZ+7)9klM1O8ssOg{B`wc1+vgiCbFQc(Wd@@~hw(*D2s+Y> z9uo81!3VQOk$xveBu-Fw(3aw(y1}=#8pHaJJx2o}V1O-e3K;rwm^CgtHL!RmMbN6e z$)XNpu<^sZL~`6pig|O1ix%5&rGqN9KS&x8U~YZo`WW{}h*pl46dV>BTw>>(+Mx8N zg&zr&&@w#mB9vn1S;Y4OH1Z1x9r-KV<5 zlP3dB6Yq8m6(IwpDXoi)(C%QO23 zolH_N+zGIg+$z4`?E?Q>NKBcNAW>kgd@mgkVlN?s0tBu3hOsY@sU0PH^Ag14l%ga; z9F(*$NK7Xj^LK32xD0=|V*eFK9uUdJ*N&P{?9i6~s2!CMp%h@#q(aYl&WT*g@IwIR1m%7rMY4;VXstdN>w(DBplZB1V8WseLMkNEv2>-RfqG_QNV7g4 zxP7di8wehL%?k>R`ZR@gm6`rJ(mIp?J%Z(9mt2(-h0TBj4=N+lM&;j{*iM2JrMA57 zYmHw>AF(tLY+aW*h=H)8h(X4;eBTX@n5s%L)bcE9Y-+$}0d+a|=_vus31N6gDoZ}r zRdLM*%?>Js?RasH;2jvKehX0yIL@(Gf1AmlbXs$#^+i*{Z7z{iVfQ zPpF}wfF!J21}!Kc9_JsM2XjYfkda7Ns z&KXE3O*UZC*Iyj*ebzR*97PPt5G2@c`FL)EaArqq?u!B8on+;@dW zKaRd8l!l*T0f0^De3jT=qOC>&gQCoec&5=bcZF*LvalH&p~86A1&RT%WX7n5t1QZ) z1fLtrH$@u&dn1zoXt`^8R*_YCg96h;szVlfi}1&Q8L(()ygW1=odC#5LK{CrRt+_9 z(h?AOLqb4U>&@o{nPsUk0t2J77%<2T+@}@83{{^`hAjFkt ze3|XgwOllBk}7MJ4}Oc{>bu*7PJ|s zlt#(}5RE3J`V)3*YZBqc#-d*0*^{WrCiF&HIB6KDi)Xx$n1~K&TR$OU$C57ihy7VN zwkB@EkRn}JyuW_)X;X1+tE}Op=Ri=9;dTg2sNM8dfZd;)08B_!qQN=(MRulCN;=#} z1O{*gra25Dt2;z4Ql6Zzl*93-;*$Db82j`t$j0e~l2vs{OhdoAK?Gy@71&Lr5v6lL z3P>#xZE^B!t&*A*3~j4;6k&?jhdf!V(nup{mlL`~oKz0+DM7TgvYHs0N&p9O3n2c* z9?8h0A8cAh6)c7ch!8B7bI6|qqekG=L^GMi zYQvt0ppwDJ;IN`DerPS3RSL>s9+6wq46uoZs3wt}+m?Y?Cr*=y%RvG{-)yKyyB&h* z1_nO3VXRErW%~#nf8asKF3~M@K||O95oy>ao}LKxH(rY4}?gwo7) z=*v1ki48nZ5-$NrXC}$K7EKl~FFNKZ?xYNB@M9iRJLP~cPy}3xG-AJ3khn7F#A5`! zbTCxt)Jt}r){+_N+inS*GCQj0_i49)B+H;yR0igx+2LTFLB_7x1lEhjSL_xHb;QAb zEoDzH0#9)7i3?cR(@k#|VI@I>) ztV)EFJ2z<)@Y<`AKcEU@u##6Rou9Y;eshLrkCRZ-W0Zj?srH814v3PjZN*Y;jUaV_ z50vr|FDVl=S*b++A`|6G(!Dnuwa+oTSyVPm%DhW9+;xgF4#pW*MDZO(NRfI3bvtYr zK62n8waGOXj^Lb^KC2V9gj_UY5l}Kis%BkH-D~g)^s=BNkcnRuT@_$`vVhPZ9kfc@ z9s4l+V{~eu8V$P4c4{S9nuCBq2uD}C^hGgePCjkrEx=M~A-uyZR2U4h7oWsd1OHR{ zFyCg{`17HWa-?7v-5m}UrgD#OFOkm`U<(8b2j-r8W0tz&A9O6?OJr&)*lSrrp8|;G z|2)tI7lXE_*^57enk))H#$B0r7ZDx$iMMNb0%(*zKu`kP;}zRn4Plc}C@P!oL~Zm0I)L6|o?=ga!5}vP00000001m4 z0RR910009301yBG008#>T{LC}hzU>7!EG%F5-vthQbR>k00;m80000000IL60{{R3 z000000{{R30000000000008hm$gcnZ00000WB>pF0000000000000002^#(a^=)9bV?K*++i-P4>$>%D`l`?MxC15=z;2J=uQ8PHcXbhpAV` z3d>LYp-x;&nccl`x1nW?=ny#xRYATGE{CXNAw0M^YgKs4YQDxU@$oFU-xHN!!<_1b_ z*CD241md-!GE{hfyD-5?3x4lS<7;_mdBUMy=sRBzmpKo{EZ0gp|0o{<*Q>(Ufeoys zb&bN4r0`%%2EL0pB7JbmLf9i3!%?ldJhE#x*H!FB^`TvY=XOytF0I0OjZ-1+j(-3? zy|!}S*YUi*#fr;skCAxbPgr9-6X(yf;~`^1giHUGNPqe!0x8WwgWv)fzA02#`8pV_ z3wpR#BnD&L=OYwgr%CNX0>*|cX2s<0HLpMPt!a9F5Dv_q4qMXV#q9-y_)FjiC{MnM z|2?10L2t&3BZmy8CkOt+6^CcRpaLb{bLNfolIjbH8Br+&S?EYRH-__l)hojKEr!C4 z&#vN*9eIMP{&{**X-t0~tI_`4@zm~PD6DZvgtbfcP)jiuw;!6$E%Ri^#ZQ$hY^Pw> zvkg?8m&C^vil|qgf%wPxiX__qI9+Z21jIve-`ZYWkSarc%r&6wth?Cf(LHc(?O@F+ z3n=|MjT&vX!+)6-G^*{Bu;E!Dj4qu8f0gc#ymy%xH1jbH-MfqiraXcH!;8eU-$yW} zb|30jWnf~9Jzkrj#iK3q_;P0%olcq#Yi^c8iB$~$zNL=c?&@N~bTeG>zMhWu%A`=e zDi9*4^T@Ho`LNs)QZlU(eHMNZ3kNO4QK9mr&=3h9M|aSKWd`iB=svY-DhoxrbzJNIvY}_OVkGfO1_olzBKJGaQrTa1EPXfsIjYoq5RY(sB1;del#pUOb(zAwO zoZ>vxda(z;?D-{3db^uUm-ON{ey)O^2ZBU<)tO*<(}1e#L&Uqv3HWo-BGlV= z7@p5)A#qJOTZgiE&ael5sFJPOwLe@qyyqUsss!T18YfbE7)KAq8XRc7fu&mR@G3in zdiU*){hxdm{NCxHPv<9?*)RkAOC~|GrLtIkc|KYFGN?H_Hw-?@53bR=bO+22f2C~w z2wd4vD(FUx1J@us^t*BkWj^}C^e;aldcbE%?Di^h{p0}8bfek)(LwRP|1#mZh6Sl_ zok^o!_Z7c)H-qN-1bF@81sOHJqm}zq`Q0N~JRkEKwpAp8#-Q$a`9(dr>QBJb?FBq! zmol98cB6S#LtyD%H}U1BR`}8qi?6Otz?1Mmd|M5#-lZ` zZ%`_!Y;uHObCboPj&lXi_~)>pxRR`ljzPn{41l&?*z>6h4y#)t4k~M+G`I zk4N9c0%5{VH4#>P6zpx~=)>sY(D&guF}}-MVA*`JM;}9BS@|41W1dBFy*tDsn#I(< zRhK8#3?)>HA%hux(Z1|o&J)`yGa?_X-5uehf@RI0wrg0|p~4A|vaz?1i*(B@Z`9W4 zCv9pe6=vo=qAe#D!@JVnwC2zku_ZAIeIiY{cC~8Ft%?#+FY6X8Niv7$8*}-j^Z||u zyC)v3x(pU)N5F@7SHviZfAuNM65}857q1-+gW|i3YhEf^xsLm4$UU^*pwrF@?)X$F z=;s$nD#LxnBk2+RWk|YE)T)cqnqt6m&}ovj^OpL3DWRwh(;@HHWbA)M8j4%3L;j~Hpd2F#dYpUd9dcG?D zx80AvMVZV-f ztv(C(oLvJKH(rt4so5)<+j{YbjcM3ldlc_F{RNCN{JDSHGvRFKXkpXGxqNfb=jz<| zSD|i+3Xe0tBK9~COmD_#;oXFn;v^d_O2KWU%iG>%eq7w|4a!@FC>cV0;43|7arqJ zgD+#wvF-3ep#nm0KcSL;S(a&e4abMA|cCH$XhNW)>**z6(kwD`1nat!si+A$@5wgi9YHrM;Bmp}%Ql z)!kMXJeqJDGBO%zTv7_%yqbmcf2!0-E_kz|(;-^1T#afs9Re?1Wh&p71j~K~W4+dK zeAaUSPI!{dv7z}y+PXabR62~D@DeSDnFu;N5l39rWa;Di;__}kAb-lBnvb)qFk62X zj;OT3{f34dXQ@lQ9=xL2PfcA<$1CxZmB!LIrA6dkXHBhzw?L=BhLtk3z(2Yd_q-`v z^I};PX*vdgj&Xu$-1C)?t2<5N_xFX1#sP`6f7e|I8SaB=KhMHU?^AF%q&scAwp6e- zR+L0eJpk6Wv+#iJSAi3T(767u>Cg4)bUW*t&}^M2H23``%)8wwyuBSM<{TWv^3Dq= zd2$>%-i)C0({4z%Y%GLb&n@uBszlltcty0xPlDxwA8m|zNd8WJTzBW?63iQeY-K}F z_l@Qqm3pKT62_6+EMa)s80y;GpUev~q0hui!hPkvq<(cCoL!~LI*W|O-aEEYoLo8P z*=5tURs&3NSj(AOCZgBZr6hM^18cs&3HP*AD05OKj{R8(tQ$!GghK(0{`vaq9Q8)b#AUFjeSI?~Xlz3k`PsXz3K}mlQ!~ zdx}GGpDe&OOWw}D;>BAssd<4xmjbek%V|q7Z4g6mEO)62jggF)I z;+xa^S#wP?mz`Zs-3lMWbm#T(b{`wF23DljYY%xH3*gDyPCz&PNpxhtB`U5PEbiFy7A&N#FzWhs-ZRz%j~RstHZ6dU zmRNCnWGQ(0ZpJ2K6RBEw9R2k*5z@l@V%OuVe6%V{c$jigGHGNiF8nc?GKbi3?wLyX zwRJU29G{GH{j|{Pnguj!%5kswYO&qNfG@j@Wb>jf^19UxH4jW-+pH?s^k1Yj?BD>T z7eB>AH`O@&_-Wy!m`gdwPxAcfL0EmbTx>X_hhq=;@i^Oq5@`eCmhXopx<3|^!np(Z zeb!S!(y8k}SE{kN9ORl7LTbEYL_+X#T=jirUn@4=n2h+}Xw87^tM8%nM@lYpj+&ut4ruV}6 z>Gst3$Z%1i+=MTWDFl}WOV)hTkK2ce3NHH*{$6B#M6i z3SK=mMAcw3Sh`^WzW*>;xbn6h%3fZi&cIF~dX*8I_{PHb8D`Kujm5rClX0@?Y0|pyz|(?sxI%|0aH#@?oSjGt=3{WmiBw!6 zv676J{-q=5fE$Ko!Mk6t$m~e6X!zWS-7Us)LB&r>AF+%7duD<5e|7Np1V_}bbAUScDvk#?v@%TP!UpcjDaxN_c?RQ`URq zjY-`#aQj^;DBs#5$cj4nZS5kgd{ii|tWe=^Q`7lSMKNT_pA}6k!a%uV9O?cZjSI?# z;cjIWEc)rg%O~3LHrewODPII_X%S-S{(&^!bO2r{wM4tKNDYDMxU=mSEO~kl7G&tN zJorFW>n`e}*PY$}y0gp4XOaKTAHAOJ*$gAt8thxZ`nthEgYf6 zP9;zhd|uqpwMsmBSq|$mp251hh3uhrow}RUiuErYU~qjHNj39Gt#A;okygP3QHCAu zkD{|wl~wwe!z#}O9Orx#X8EUxopW7y-{T)_s1wQ0#+c&Jp$zs}TIk+?nBcLv5Zerr z;0##u=+I{BmD+>z{{Gyy%58Oqw6}>kBT^G}3p&J+UB>)TFM%GkU!?zp!7N6; z!NST_Xl)jP=e5%KcKUld89kO)d5@sHNH3DjmgkRB1AY|VB7L*LkIiqmfswlz{F&4X zs3{$Kq#My$yGdC8@-=MSYR4L~Z(!2Ka++waj!Sm<2*v$1sE?8-bjr%}%cLfFqIC}o z)lE=HcVI&sQyzYP2ya$@2li!~d2F-?#TyL5mKDytW1<#1sLrK5KL+Dvm&u&|;1iYU zD`Lu#f$(zHckKSQUb5uweiTBta`WwjWT3c>*S=rO+GZxO?nN!-NFqVm{0P~b`?K{> zOI~784rVtKV8W4!V%qCMAune(YJLl6r5nr9cjW~**4Ghr#>Me$|85j{&=Wgd@51ib zy>vHxGJ2Wp;>o6;DgR>xB_B3J-&wP%c|<)0cB$axE)5*CERc>d-EjP$ z(b)a&74BMflFoW^z-pVGZ~=D1Y6A9bcotjlB-|HUxe{Ef@k;*1=F>`l5->f z!fUT>6xs8Q7@4{k-nSm1PjBuc^iJi0iDxKsoCa?xJR^;12!tYi2Y%B38z}e9$D0{# zk}~~zF{@OS{~F&W{*+ALR82TH{wj27E*G}A_eI^_dc1yEBj)cM2*#b7P!_(B^EHO> zL(_0E*I)wQzM4!PyZ%5}5z!J=Juuo`M_cCI6Mem`$S@3el6F5FJ?aGAQI^4N{bsYi zWfz>w{zKz_OhNzeO_Yp_$jMe2n^zvehGW-hS)(_rE;HloO|OK)mic&OkqVF5Yy+{X zDPr-iXPB&AE@^LgPj@XtIK-!cx@o)-JNq@!L1%sRJgSWyJFg1MZYSf%D^Zlb;3xU! z4CSx?^}v}CQLufS3@aBts@B(k0vp$QvO`WduCr3(J{$T71BL{1b;Dnxt#+8!uZw!W zn}Fq0m?n4hL$5_!Y5TAbLjQrqqK8E!&FLNsVS{>ekN$}ibz0y8!%!Y&77sDDfENNw zpj>I65bQLY%<^6Fn!-37mK`fNL``O^<^b~8mrQ@w4#OvBo>14=JuldtR~G+HRLF5LvGg}4C+(&(F41U z6xMqOwJ(eUNlOJDyic?+We-`8wd2dba^UryUNmR9BOm0O;`OWkd``T;!MDt$d&_;n zplb)_r|*HY{d};W=_1G;?8teQi&!tn0j)p3mzwDnlvfIm+=%kXoBKkCbUqrmxlB};zF z(6V$d4lJKZVWGFMBX%c#-xkIf)Khu9<3PTh)Cg0aYS5xUftsoY;3yq^EDv$vHKz_B zMEP^apWCAPf>rFIJrMTa9)ZWDi}_)b4|?CeL&s;##ownsNHoR{fB^@d6Ml>5>%I#> zAu!p=ru~mt@OU}8O@Q)Le~IU3K*k|bDxIt+tH_l+a-qt?|t@k&Eu1J-+nsl z_De_WN-t1f5lxehm~#55lT&V$Yk^bo5$ zYAI@FGIzwalSjl(*0XWvn?W<-y?Pcr963e!vTLfi?Bg@=s9cJxn{ve+(l03X*@V4S zN3hnAJU;fe9q`^DaC(Rj@2Um=h;I`8-0axY$Q)(Y1`6AX&I$Qj1H`tV zF%pA6CU|a@w(Bw97O+h7!MAq~@#3yC;`K&te)4`Wd#o)Z=eRH!cH|Umjp|FA&shIs zNHz3%)k_?#vKALvtihG7d60hksVHY}k3*luaCw_Gdp=X5p>va=X#XC`y^Tcfi#2h_ zuM<$9^@UQGMe(T>^I@&rOStX72V%}tiN{A?fcInbFT@Zc1pPT)KRcqI++?}qtJathiF(~!#n&Q zu#e3|ZZxlil{52k#h9a#mK}LC`b)U5InNDu`uMY2wF5p1eG6$GfWuQOU9`?;k?yfn z$%YO+o~_hV_@O)??BUT5ibytY_(&WEih?4n~KfcnbyymkFt z(%KV3>i2SRaL86#FrAA--?*4GdRfTjN+B1ts6yxtCFMj`mcgvk?;1SY)dP&=|Ly&ze7X^HMaXXP zqqpK7nlh%2CNI^Y@8N6k&02TXR9=UdGe`2z6WP%J#wn@isY9gX2Mp#Lc#Q=1mS$s&RD8)x&;v|QnUk~(N*q_FI%7O;-k4e6G)_%Xkj>=*8b{CP{T zPJS-*UgE@&&yz7U>mSQr9;FS_wyGWI8H1*n3VUDf|Ef1=oSm!YAV;;AieiJ{^9a&%iquT~BUatp}NBTZOgVIw|jJ zoHVfZneb5E1^4^O@Cl_`;^z2Rv9q=mvU|@G`pKKHnm7_Z->Jg1n6Z4Qr%1U*Wx$rKg{ogYqfKko^Y+EZQ{ zXA*>y@5^GdksjPI^TZkT$FQSg5+9L`pn;VRT;yK|@hN|)f9YV}v+)=l46;UP+FG33 z-WTIbM&a1o%Is~J2&(UIP-OEhapneFZj87>KMKRRr^hZb`t=#wg1*3v?`04fElbL8 zKERNvFUd0ZCe038%N~by_|W9VY_LQL=c}0Fkmc>5uqO(%o5uI@PN)q&<51(|~05zY!L7BpC=_q+4a38CRSI#Bl!ns6>$A`d=tEtrECcyYu zeZJYJgZBMAL8mlFg0@W_S|ufkku%qVsY3+6-c|~gwdcqpX%C%Qb(n4CQ|N8c3FvNW ziMo@wi&tJ~Go>3Lw}%LiP4|Gp@1+Q}y6Al7H?~aC=C)nirMn|{vHsFglKb}NY~fW& zc9%x-q44GSy{!m)W{szaZ9Vw&%QftuDM35aU{O`4k|rEBg_mRY;*D-OnAFsj`L1h;bh6Tl;6_C76V#*T^(Fb-Q?k2%4jY|FZ`V>gF|c&!JaS;F4VInS(S14?D<0)xIU8h{u;`@$ERZ8zQ;mywv5C&C6C5- zM8PX9cRb|XKn~E#M}j3h!)P$wX-ma~jwPsg^)-xGISX(6Rik0Wbv)>`ZxwctuK>(@o$*>q&Ke&8ZY|ZkHH@* z!4PHf3PM*MChvt+*kKuicS0+{u-2F5{|@K>rri-g?0ql3{Hn^^>jf;DB*T-2)$`+D z-FS{PgRV7hMBi6SC6~13;h!WBDhBVz9;SQ2;`(|}_3qD)>zz4mu_ujB?#)9KEui}V z3owknOmYS_-0N~0RA1Nza}%1u*g+OgnD->Dz6)`Mpul&E3wcTTdGe66=DVu}oViDZ zZd|s2O#|-2qQP~rU(*V&4pkUaE)`j@^Uy)ole4DOh9+_2$s^G6k2f04@^r3bEA}=>!YaLs z!o@X!N+Ew~Vd^-zU17rKIy|`GzA}$5&~Rz0UWPv2e{sjz20FiQJ|F&CN``)`LB2Fp z%*agRSH`u%*^uoxy=F3Q4(v^hww3g1T^DWW??DR^6?l4G4sCi_1dr^D(X5IoB>$h! zTSZchGzf-1wMCu!546U5H~99v3qIRa`SGi0@LZOJednBmtp|^jvd&K$I<5=~I-3QR z3+DV|RgPdh_YOb(aEm@V%>*^Y7<_uo4mWJ>5Nk*uopwGU`GYHj$jG~#r&s{d`wZdT z-Df?w3%f>rt#I8796}js$VyV!n1! z8Qz&xK-S+uye;seXnO1=sIRQYrknMc-F*ZP{VvDzgZGej_`hz|-H&@@&*G{7GCV_n zHNR7sPx9X?C|IEz?z&qHWfr}Kot;l$t$U(4uAefVee{E_r60xHMepgI#RoXJ`6yld zsx3@C90XdUTzTOgDa7gSr`Iv5__6DqAU9x-*rdCfqlWe1l*b~Boi8P>T!v=@oGHO1 zlkU%1!M;Q0!f@LHsob&e)Xq_qw|f+(ey@RuSBl)XFpHnZ)l*7VHRQ%x;=|ZTanrAB zk~a%R;>c}@*!}QeG4|mCUMB4zkF$DE5~+!U+%0)(UJuEWur=UXyo*zYJf%r%r*Ngt z1sMBb8V&gL2ZGB-;Dr0yNEa_dWM+Rn_&|@>_qM>azsg+DryZ)E=h4>MZq#OQMu_n| zNoLdPF>%5f@u1962)eYMYo+;O`_qxa`hJf5Z#II*vLSr3{%mw2_CsLYpoUG>_6U^1* z@b*YgTvTyIJaM|6MxFUh$tT8%ugcP?ef%j3%ZY@S6AiFI^BIkBE$8KT6#zyJNA5J*T z>N1%bO{S6N$6;yUV;FDj!}8Nk3I6e_uy|Ske%a{&U2*#SQ~iQ){zbh=VXtwy+&%Ht zbYo%f*PZPC;V)(MFQgB*b7}MsL%gCYhmq10oE5i==hVAVsqq5VtC@p$pEQH%I(@o0 zz88+VAj4~3%*TS9vn0OSi@!@A2&ozKp?=a&3R-B#Er#X7tMdLlwj~fU;=P0_zZ1M{ zND2kSIKyu@UwnH$PuLY3Njvt%KzEZd!kyE5(Xi)j>EYDV;u_!4eBJ08^_W>A+_>IG zZ@d#BqAHT!T>A{2)Bj`r(qj0sZ4{q)90HH?PzZl8K)8EMf-~go>E*pN?58*b4lHSf z>Qf8(gGwFk#SZ#YzLcDobxLOFUd6X;i=X}WqGzu}et*6jdrULu$#?DPR<^QWZC5JF zJn5v?-`eaPR}IdmwDH1_5s(zP6u#ZtPv75JqWQMhRH~qaYf3hA$^=bZxmS@R=Ifxx z=%M1B6cyoZQ58hZDlL{4*F{UNRTLXU*hQHxNDcTA^a5HvahP#JBw`#k;97 z@LWHbysIVr!R7^8bTh?Gd$)^TEz{Y5_h6RsT!aZxEBMHv5DKw-NwRVMc;jky*LPo; zrc65`hQ1FW*U)jeAyxsu+&szu?b#*iCF$ns_3SIOrmOs8Ya|ab^dOy+Env_?mf!tN zgI@J##HbY~U`1L654)>_AiEpb!;4Ok@1IN>quefbel}yh@o_@fp_jbhZwRVi50$n(?Td%Q%*Y_w6E+#R zV!wr#FkHnK|BJ{*AIV%!9e$i{=V|h->qANQ`y5^va-X7(y7858DY>nW0gJbKs9|$k zl6Fs*r=c|(FO|o42c8NBG5`93{8jE%U&-gaZwkAkQt(>j6kH#&3s?SqBNz@ThBc0( zVR^zr-sQBP`~Iw@UVqea_QF9p|B@nhAFTkIImuu-R+igsWT~q88_%1ZL*B}{u=Ym? z=6(JJL2{)O%qIBp#dzL)?*>-3uK{$PzGyl36Mg7kxvx{ym zDNXstQ)(-P=IM&O{^W3!|8WES2dSfX`)=Ixz=q?#u7#*i>u}DQe%P=h0s`jNleeW0 zba#%X^52c5@aHBhc`<-@jc%vy^Y+5jwiuXcH57xo?V|9@y-=evT(q{lC(6Vea*5k6 zU!(oxj9_(RCOYSh!?nlEsriU3N6(JOb83O;Y%-E2Z789jOD>$+Jp~Hp#6we?Jg?}t zwEFsy<=}Na3ENUVS!>#GYJFhIrtj_xU1p2vd+;B6nFVN=P!A*n} zM#yRS=W|W>>20JAila<<$a78HGND$yaKxM*SN#8Ns51M9YjgCz!}$5dG?;Fph zpfj-tAxf`1Zun3moalLlj?K_Qg?`InfrG7({OuvMTd&1Yf0X$1C`ArOJ=V4i6TeGh z0Q%jdBSJqM_-+I{X-2To^Hn@4S&bAd&w>_wgRXDp*ctHyYBY4P#nlUE?MdRnmYFVa*JMgd-h3wgm)#*8M-{L^$)c> z=Fs?{Fh0A=i0e$N*#5Bu$DH%TraRAI!jMG4aq1@uF?YwA?K$}J>18S(qYUG(RglAq zR7vjzA&|LXI%`L&;59j*imDJ8QME_7W1EXw%O}AKyIZ6iW5A9kpUCj20luE3z)roU z@yPna_~-jby3=b8MteI^e+xaKdHiVDm7KutUrZ#u?ZT+z?`BS(8G`@8H$kJx2vt(j zgoMFy;$|}oP`nk+@24H2<+fEk@9cRP=%kISul2%-UyJBZ#!Z_3b0K={oGUrfJ{gB! zA5U{$s^CulK0@HFvBKp(?X>vHYz{x=4te8h=)ll$SfXzX`M>k2?`%&BNna+cnid4D zc}RAP%*fpC4zy00heb59gKhl4`6a|(D~0YG^>-cSe8IGDGPv(2WxzE;{qN{fbc6|;+r}3&}yvPex9?T~9*|)$sG=if8cJP@g zMUtMK11Y!b7;OLNZA-6}bLO^j661himhU?sMs4{{<66H;L$=Z|DOc}$Um z&MIJe^l|a-%}^+t_YJ~7ZRXmV3eZyO=Gx(Z544|NpmL)ldl z|M`VqmEWLs3td@L8j9*OR>QQi9m1p#T`UOJhCz3_3HQC~_}m{=G*oe={gpjn^6rg1 zu=g>+pd$ifr|gB{(cx^D{S7)N9Kdz$_Nf1LIV8R~C?2d#2fgfXl)KQK(~kek+7(0B z{{{@DuII05o~%9%e;OctW6b2%<0NkxvIb@dl`Q`zfiqo?b6%brUi6)gJsJ-Qz4sen z(8i{J_eUlM^r(gdEz2;n&l9M+_DPf-kwdqP^hmGOO`K40k!pvIprzKOeCjJgLAL^& zI?@nJ6r13g*Jys)VS;^PZ5R$dCHqB2?0iHY%U9f#8n^0-(`^6Hg62cg#rM+S#~*hd zw_=dk`?oXPoH2!OJlKot=6S=gIuHCktUudy8c~d1U%H&yjh8CV!d)isc}s($(DcAo zw7M`EFZ6r?>vw%4oxIg}K<6}3coqj(NNM}#pOC3F3|G1_#AWt`Nm*~8SnG_$+d`Q+ z$qM~JjvqDmtm(M4h?_So6C%FMz>V2DSpTUEivBJ_;ZPA(oav7{0#0M*!!=O(APm$E z#&93^cA?eZf`?A{N~g2m}5 zTS~d_Pe_VVtoeF^okU}J9NeBdk7XZUki-es$Xz`cz8;wbk@ZEKson(Y?%S)I(j2fk zXArxOolG5a`q*(+n-?}Ja<^g1xS+@eZywT-*4CuZo9zD5vy%qm#I!TitKpy!UFApp z?ub}Cxk->djiMgYJ?N%n0_5}x1Bss-@3728Nz`IIyGDv~Y(%y<4cRTPRDAbhCNJ9a znR3U5u}Qrt-ppCcHaC)7UjEXe>UGbdzqAO-uXmC0NF~&qyOE~O_2RLQw&7dla@gXK z2+N!d`Mh|9jOivMn^{o#MkSD!lfxV94TX})`?$C74O(2#odVRxK%5y1(HqT#7+ntx zTY4FC?L+C%-*s5JI7PB~P(EPoE$Z!|&9m0k2tR`IX~BoXSpQ=VzmuN8%Y{yKr|mzq z9Wk8BdM{<`sZGMvunlaoyRWOvenbn#yYo;pLniysIr33q5zk-S`ve zFyewx5&0jOB~4`OV_U>y`?JJ8u>z zT>dUhjtD_@QG?276$@bd80?)r@!5)Eu{1YL_%yW#=Xy@7c0T-&_FbAoUlXEH+fa+- zh6JPAoG5;#p9_b5FH`Oo4T^oUN_5Xlr^1DkN%lb_y7|uFbqg}cb-f9Hnm7puWIN$) zhpBAUHXCM6@P+$*kAV80Sa$n4Ls)gST^L~h7%(uChPgM=h&hIsa(f!#&IbNsV+)GT z;pA!-k9Rmnuw2{;18QWkWa34Mozq&jm6zcg{u;RR!2!r#%|hRP0n+tOu1G9D+UECktX;O<+UaDd8iIyhS!Ob)H& z)7Mj={DK~OT{nbx_l`^KGh?}%`U@JjT9*}ELWH4Xo`G&C;=8N>bdD~Bh3)T!s25IH zmY)i(l2jqmWgK+^S@DzR96Co5FRKwfT&xrHlbESh$Ehg3USom$(DjH7IJukfvRH=^R7ca+P zl%)aq_bUgxe?I@YUWH5c7-QxVbJiK8;+nnwQ+^;g{p!w(NKcNE*ler}ySZzhl_&%^g^B zGY3vxd?5@78G;`yGeK5sFuF7^XM?9D*z)@;eUASR9-D-)zW;gg^)9c-KL5AYcetD zeH?xq?8at^>)Ggjm#B8lQmnXd&KmdBSj-rSCw4gCsITF;-R~2b1`p++&z?-$zahD> zLHIH5D0QoSES{{&g=Gbv{OY@aHQO#rf192G=jn&ZRM=0JogHvT@_-yib>fe7M zLXZ2autJmtcPvoC>O&jZs_q_Ly{IFm}t|jfaX4*I;;YIVq2>6)h*mQHktz zShypJ9(?*iR<~YAcH>@{P&W_*D~mzY^`V}-6}a!-O_FZsJxQ|GkoxRa;^99##RVIJ zq2~NqoI3Ug6{lXNgQcys;Gu_*RuUlHlj6@hj~;_pkAWz!H-qbqKpSE9wo-@@e6vnfHL8$g~KJH6Zj->Sp# zaPT}aHorUH{kP`D)&p_cwx_VnK;UzJ7IdI2oN61s3q|rVg8SZP__|5~CLUb`PDu-) zVu}Gh&d!FF@49h<&m^vVltgdO*$K5O>Y#o_Lpaw<2~)p$qTk_3JX9_lfB$2Ho|7t8 z`L7iN%CATcd)7dm_hug4BZK^&h4GM*F(m1j$QKkHpx@I5Nc`6#8XM=Jo!(8+^pYO- zdt?YQ)BjfgEndOR?>!4DHSXh3B|c~fq;An8 zvE*b2HP6-I+kr>v@Rdpba`gkwK6^ms(<{I)$5D8EB>`W5&&8n{b-a3Xm6+Hl1Fiix zBW6$Mp_iOk{;vo}qdyD#-|xl0(U)n$@JnK40@3wJ(=e^QP0ZN0j*rfcq%8(N#7E0o zaf;kRdLbPJgCK#Gt{8J}VK5~vd`}*myfE>SKhI2*#l&Aj!8tx14n7{h^~b8oX~{r5 zSv6g-$@(TJ-m0UvVhhyY7snG8N=5eoRi6KLA-4FN;;p**6!++)(3+*lXDV&6m*Wnw zNIwJgE`@T7KZsGqD}>%JVyG=KnYJ&|;LH0&(3DT*3|k3mwM5dcQ%!=~;4o=@V0Uf{ z48h2#DBQK`3Qa8vWX*>6E|1H5iN%e+SoC5zYifRh^_%NKMx8HukJRQvz71fKwFMMt zKCIpIf`Uz7E7$x zC2+}#cDTL&qA<}-z#b0PFueRYtq5L?M#EcZcVQ(bx|{QAAA7X38HX8X0&qfW0*zf& z4EF6GX;9`q^0O;|;5EO&&D#{c4b9o9aU2<&9izm+o=`NQh-QtIu*`_n;J+h+X8Y&h zn|-BXV^Ah#UreWY@w4f%-%EH~F`KtdXk=;*yPvv4mmK7Wrs!F~+ zWGQ)WZwOahBi%bf6smM%F?LlmR?GFoh3SW&-=r1%*=;#B8_Z;k)?;zcMA{qED17R< zklR$Y)Ald6VEs)Wbd!4F1mgm_*V7g|W%^OTbHdxSg%EKk8j;vm)NX`#ubB@tG zY|zz!2fYu8R-a$Mg|KWaHQ7x?qk0Jqs~bpRO;4KK9!5w;{SL{bO2csBv;P+Kp2ooKfaH?Tx&JceF+M3s+Q zsj5Cw82+-Fs>h$A5M5VPNn8UZ>ju$OX(6dBaTH|Rv%$gJnzbwY^6RW=yfyoo>!Vi4o1%r8VQuj9uMU5VXa~pXe|h$o{+Rl%J9a)*$9|PBh5Dy5JUHwU zW_&w{IWu%Hyka2N=-sC}&ka0jhZ=^|Y~bRGY@zF4PwP{-g!B!%X!*?Rd@=RBaOnO3 zw1~CBMY$mEeG@P6@3EL_@lklHg1F+Y3SF(uzOr3 zr(Uw8fE**97ZZ%3M;Lyn$f5k39_Y9(0jCeP;x%Uk$hjiVnTh^z&(e&G`^xdgnK|Iw zvk?L+lUaG`K-heC9$q?{3wzJIum-wt>etOULo)-EPi>;4i$5i2OjGgtf$4n2`XUw7 zbdhtNinzto0_yG>^E9x<_HR~LYP1T^XeHvX4m-Xp6GHhXXEJZ;1(9`Q`28e%a<|$Mhg#Bq04)lQ-Bvo68KrD^c?k|MPK{0g7ONFiH2owm*H&MW0s@g>)zqDis>KDO$M zu?n|fTKfMeI1j&`{x6OvX&DVk+M*~SMJl1sJ*N~&k`WP=j7X7@k+fARqojzUok~Ks z?m0z>WF#|GLdX{(>*x0mydRJIKI8R#KJI7~S4%!KOz=^xHq(=S(8F;*y`0o2_L`!Gm7@n#-RL}vHVRQZvU)I;Z(7f_$yqQd zqZ0Hkw$REOn^57~GM@G9GkqpEtW!*egU1cQZaMO>aaLHYqKHe3t_ENj1YG3*XbV5>0;h-%L9EJ)pv zYKG0cU z+c3zfh-hUDd7ZI`^kt?PH*YFCf7RgI!_veYxk~Q5V~Fuf+i0`TAe?aUvv_TgH7fU> zjy*?T2Hk+WG+rZ`SArI$F4`%0-wwmp{R$KxWP~Q;mVmkWS0Oa!IQ{i}$xEIj(#Z%# z)czQPv5BYQW4a>+rwzrAQ}a;iw?MJ6uw*|Dp!`?X8My`%UBn3$^&tkh#!& zVmv>6yPmzSs&lV2AG-F%m@oTOky24lXxhCOPW4Iz$qfa_a=r?wn@vCrT!i}Sp1dyN z4)t5`iZ1VSz}Ln7{^by`$%~7^{;?y(?&fva^4%1~HwPp^FCtkydtR&#KLQEaVbo}x zOAcH1lHZsFR5_fApI$+6i8`bTV8fAc=UYgrQQ6~}UKkG>c&T^3*0^upKeFGcXzpv1;s!sFn# zG|ck=TZnyemB9!}ug7-yuxummIn<9HMU{c7xxe7xxfL*X0DK6~5R$`RQToJ};zHRS z@XC89XpBe@+ii0wpgs`}o=As?<|ORf&_JHod&7q=;D(>!qUUd2R%pFU`M0HUUhvW? zz2<8?_i`J3z+r;asvS5p(+lCV^0`S9uO0!;Wh3k@q1C^KIg?au8JKP8@6~PyOup zPt7%m576!4;&6X}M@aSWHve6umFDR(8zIB3R>vrMP*vZuI=@j}CYRC$MYsFyw5!koWl*1%Ft8=8Qh4Ne# z`aEDHPH=xrIf;fC4Y7DUu0hzQv62c6JaOyII|K=F7-4Qq&dJ@hV!>~E9w);GKMu$8 z%P&Z#%m5SgK3CO5CE$eOTpAynN#pgcxZ!>l%^cYqog%N1{!>MJBV`$?x_F3xnQ!2P zV?W8me;yv(?aS|bIO6>U4?uPJYq&d20r&5+px>US$!)1btg3d0>r?)U=9_@6Ru_pj z+xM_;&7Z3E&Es)`i$7c&po=jJ3aLbUDlR|oLv@+QsPxlt7A$>v|Im9hc0()#SDpY< z?Pjs^_El(E{S`XnWwAl~q&T{VD}It)gnXj|mM2~zo%P#k(1i$Uiq56J>53eACyqQ? zlzG7$b9}aX9a+^_;kMdw>}R5lZZ2M;;($8Q_jU>znv{U)_Bp)v_yoRvu0{OsYZ*N3 z_~#aONYYyUam?Q>G<}g%v=tgk0B=7JN3E$^=x{xS z#g}iy^h3(@YTp!G@9)jaWu$oMw(&ysIX_Ip|KP&4jp!HTM6DW5WOt|s2q$DX?OQU9 zQJczZ@7{;^IUlHP?qhnTtO>)8#|ky}FJQLUS4z|>19=-o2$aj=j5CjEZbc6sw5}&s z9y~&}6}tH7y9E|~{g?IL;gnBZBtNMVuLU{a-}72D>Tx8OuH6Mg-f7{qv(ve(ayn;U zEa9bNQ+fKg3h+D}i|e)IA?t)R_~g1_)+H}g)Kua{4j%Bk+#TI5zwsFqvOKX-DxKKDvTBZJJiR`7k@j79LhcI&^V;oFlo>DGG1!fPs^I6Sw-$K=tan&|4S3LU&;gT9?3YiQ64wGDulM3pQs~xC&`jFU(xj8?$j5e(J7Cr8;4CP zW#S7QF`|_7PN-6+*?jh06^^q!lHsAVC%Y;uP;%D_!E$64K9jRU-aSCrrrwixByMM) zt$HM<>cGQ}#8&z4+Q75SN@;NBa<*>K#510U$yxa#c+PtOgJ0U>LF+3Z)2>P;x+<8K zFc2F;4hbe@JE%*e2YX3PuhMw4hg6@`iL0KL}=oSmP@j%CeaaDHF7vnmZAB#yuY zv)roGf_s9(;qe?jMoWAXNE^|n?wjB?B15uj<08!UuEY(+DQwYfN)BgsaL=)h7`D@vl?Ua)&C{j` z%1&6IdWY(tPsQ&WzR?jUc|m>NbqZO3hHN)?gZuCf%9OZsw1YX=+w&Jiu%_rN_GmK6Isi33+;!AteO@Z>}YCSS`I2P)kb zT{VtDs-+HT%J<`E24f)T$4)fqKL{QBZlTTfFU0u4@w8!SZ`d0U%!9sGQo+qvwAAY% zxwh@%LOx8Z_G&|q-uv-toy$L-9zfm-*WlBY128Kv5Y2Bo;l1W0;Z{v5B^r(7-{tbG zWA%~-P1#B(D&(=scMeBOFXwHCbXfN%L)mgyda|sJO!oYH4!sym(Em>3+N98;)*GGQ zsNwwpPg0kAERK2~Of3mjdxCosx#~rp8{FwZWHtTNXaoDuR2pucPItrum~^R$%4(bKX8vfTT5CC66tacP&e`z> z$#b!zyUp&8iK=+SNr!94pF`hI2kDrH9W*_cVIN52j;=jkmIP@ zk|X}e8O@5l<^Ro;K8H{4A#B?o!41{HICw@p#a<8Lb)zFmk$wu|(2+ROUX8EaeJYxE zd(fZN>p*tGdt6>*i;XRFIQPp4-rBK;rhSV8iS$u^moSpA$|bYS-4L)oHH4?%T!k}w zeG)=njv<4rEa*c~q@F(mcP=P`0NIWFE7F;53VPGYSB|KWv0G5wlu2(sSN@x)5x6>J z1#Z?0<7H<>{-A!2O2;~2Ziy!Lm+7Fo59QP;*20SE5qQZmUXpTqADF2eqEROI#1_YJ z68n$*$FSj|U20!QZXO3iMju1v10|w*_gEq3ffCo)KBHkHSCa0MlXR~^4oA-2fFtYT z*sU&(cCYTkEz9R&$1Drn@$)bl402~7I`9^#- zE$ZJLy@WZP^)T(l7}97h5cKyxg!;`pgnCC2k8CUfh@tPqXbtd5~Ip9OC=GfrW4P!<@jeRnrs>@w)pR(Ag&j&bV9QU)fuN z?4A@VT>TlA<$WgI{zF7(=^pHz7sx@*{aB}0fY8)i8ap~w@KVGxC zyE7EaqfErE^ZP(iUXkg@AgnhF!rpbc;@?e*t~HB4#;{A^FD8eq@peCykMbNKew1mw`B?*+v5IZ zktaHi8-XSVhryK}1OClh3z$SK!@)Yg>A{7Mq~z*xiNlJF2*G*Z}mK z-6>f*{}g?3UV^13)yZByjnn%5k<43jiX1csVoFvpxHa`hrI%x|cl`>=-*idPn3Ihw ztRuKi?hxI^ZXW`s4A6_)GFUn{v0FM+Sj9it?e@$M|v}=0wbeRlBnC^lp z>c)Ki!#cdxe=y;Bc|1Ge0H5BVhsUMXknN^N@H3*72AE8txktz0u~)-6>Cr@VS*Hi> zJyme+wG=vS@mCy{VJs#sSLZOD;K`GwMX-rDm30mr=Iz~UpjYNyD9W3OGndW6F=_HJ zEP4Z2>+GO0(pjwe!HA=O?4^B1qfswl6{I)!!>-BqVU|$|tm)U!Ud?VGpA9N!$5sAp zH0=_7H|vXszph|AXAe}K(g(LYXQOAKCpx^`4;IU#IHtA_44I!u-j8I2>nHsA6|AS& zYi-~@x)S>?uNEg4gbP!bHq)W=p<+W`4_-GOcw3DjB)D6M4O<*YYG4HSd1_4tzjq1~ zXGOrNQFlN;z6M%u48rs$qj+MA8fj_nqc*}{$)ScUhmA;SXSFMF;qS}*|ouALMzYJ%${q^GX6@la( zkw#l^7dXrK<7II<%dQvkI;o>+jjf;$^8BCv6Y-I(9O}8)@Q;LUdMZ@Yvkq$%AIIRt z=~tmLZC|%(cgC$e(5Psl-ryAs{FXZ$qp9Z3Zs(g zjy$|0mFJ$C$X1_>aoV*UcoG-^9?gCnTyBrsKh1<^8?q&ijeE$yxs*d9cJatx{c)6& zJ$jS}fw$*uDsz^{+p79l+o{3{X;Bz(VV^i?zdDZGX~>R4J0*vo9Tt5D`*Ot(7qYMI zM;-O{^f@XYXFhkMv9HdHyWfrChIu2vSGFe(%AL&YEX#UY{&2E*CLh*04j-b2!o|Dg zU^3)94BS^k!P}+qz5EiK`fEB`?!1Woe$>bt{WrAsp$zZef-I}-#R+2{u)ow4 zVZ){&5-3`XKSsQU!_!(I;w8Ya?*l2nmnPQDx(40+F z>WcQ}Ts2MJ_&|kw6$jzGjh^^tqZK|Knn(8r)RSqy_0+s^1Y1U3p$AF&EbG#n=T!Tl zziT?dxR;P#sla8uozQLXaUhc`v^exO&r+}Ekr~~%qVg-qZ9fe|4Gyt%#z-{EkHT9U z zF`|L}2CA>$j&r~2ap|)r_$a)f`W$T@z2PyM_Wlgc4Gj>ub`vkYaf{w9&;-j9_vzZE zdhm#7#=Oy2>CrST!6KuR8jN&N^6np(Jlw_OqU5UP6ox{;4kuFW6@)80eZ}vEx4?ek zYkJX`K-LE;X@guf9a}et&RT?_#5@RdCyHWBpe8F%b>{LJC&kJUI{cz#F&HP=ii>$4 zF7wL3_1|RarTGD|b?{17-QivJ>5er!#eStl0lB2~w}8uy>Y&x*fSA}7g5yj-if{9b zP(7gq7Nz*n=hE32KlmJvbKlN??0ZpENe)zYTj9jO0j$0|48Nq0foIX_tn0ai!)^@Z z`u9um;b9xN`9>BpK05;+H^lcBbkKWiIFvuBe6wAFM}0a6*%lM<$-qnSt04?` z*11x6TPY5j`37FkyC{s0Good66{KSyLjF%u`Jiu(aCEaP{I(g7KDQ;Dq!7rd-Emcx z>JNoN$1!-_ZzzwEHNy4dEMbxf8FZp4k$tFEZNo#5Voh$Q#{l5>2 zTJ=XEadR1rNjcB|%~Rt1NnP;#(=xob^dPkb>F^38Da@X>8cz+aro55L*eiZJJAc~9 zS{r{+<9i?6u)7m(ez+{IvbiAyDJo#v*ACiLdq|AX+J#qUp%}ATLZ>nh(Z-%F@Ga^B z*kz4jU&n8l?7Ig~wfDp!`p4+oKwCC#P8N-XZEUswOjYeu2b%gj0Z#;0;8A7ZU(aXo zWX&b)H=_+Qb0cV-Pk-)ibr1@FOyYv}VFE9@0%=!fgW|9Hs`#(kTplQgriXekgFY`pceJPSj=8Y8`~qraKNoIUchHne zom8pgBTP`_$>EJNc;j$@lL|8SCZp!^K%a4B_B)pq|M)_Wk=|ft96=_*_3-!lL)fD| z8QuQX?CJhTbn9B7FhTI=cpZ66avIMW2cpU3zf4R`>YxWBwou}&k-RN>rSN#-4)~*f zn7*|;z}$r+A;@wa9sIeMFQyjJPWK}4mzBrwDgRaNe_=?$hQ4SQeF8?;Pv@V5B;->( z9aoN?0TyKhN000CHMbvd;G7_S?N*@Z%OctJ_O&}U{2aBR9=2?GFG{)RLQ|q9#hIj2 zc=%D!&nqJv*+ckc^hSI-P9JucTqJKVTYmXnLfa1R;3sEFMR%XRT;m;$3te`itEL-G zSGM4-;zFKMql5da|IiPG3R3YY#Me82lDyYPC{#X0Z%p^m@pyF_e88DwKbYXC?og8Q zOhUCuZ*YgS1~0iciofUuvx4?)bp5r2ZYr=4{Vjff9qq)OVWbP)C6s)hqAE?6om8`dDgw_d^ukwl1u&z?mDSSyp?9qfe=`lE2Zm$Ny2lJ0{j&%z z*bXMUQfn@d9nOzUop`?AUV0+cT&4T=2tOQfjV;a9QF+#6+&yLluDy7hg1rpT@5W#} z`Ok4L=uO5~U#H>o*o*M->~*^0=FIu?OUc}P04L}bi4zV+ieFEZa>@KS%z6ETew?}s zPg_m-iH|=WoxC3NHuzA#b;IzU(=%vQtH$T&zlxSNDZ;$H(QKl-k{(^?Cew%)G+i8u zZwFLJt_NSolDcmc7BrC_4GiVpTnX>~%7OEgc6yzDTxhtugH=bQ@=T4RG-tM(usFp9 zy(4>ofyxwAT9GOVt&u{F!ZG~7bqGFPT?ydVA079drLFHSiIJ}+*=>G0f_ufRBh~Fm zu>N)h^!2un84Jv_6CzjF+T@t(d{vmardgwM*qs^|7 z5*Rk0>Q7}tuO<^5)PwNyi4LkYQ9_*tRaRW51F^kT;G5H0-u`Ak$d$|TqaI^$_B&P4 z>&0;7{|bb?e;uJNM1k!mj$oN*)o{t{1jUX%N8i=^;{5aPVWL?x9HD5qAK)Q|JgKjqreWk)^qqU8BBD#NtfQph?A?| ziVF_vak)QX+-wany?PD2>I5DyHJHCCgD%wjdnFW$k)srSS)D>R@w`yJf5a!;7*KVIm) z=q;?-e@~)+XQY^ClZ5FHwfXJ!I$=od5?0joLFqH8P`x0Igg2{%)H6D4J=lvFAq=Fs!Il+ z3tuTUZx7FiHiB8ZU$LItLrC;Urg!^RV)!yS?%wSMe%9vbbS@M8*6&9b1r=7mq`;de zdGm|~SHwd@t_#Kw6nWCSshEGM12)2`!J{~rDto*X+$$M^2w{KQ>+ zQ)K}Dx7Zuc+9=^6(-vB~Gz;=#MxvbbE9hLak=@+4LUE!ZH`cX5u%3jLIRGqQ{u?YE z7ty{TB@8QTf~Qjg@$r>J`a18U`0GrWSU0Q7?x;{|Z>^FH{Uroid;$#mqxN>B)n=KED4IQ^YDd7MGqJ<@}AUREUOp+m*ZmTzdy ztUlymM()4;3sAWW$+;O4y#X#0($WUCxNs_jgv)v|)E$#i(LS{u9KJA`0EJ+@NR z=Idt*1ViaQpxWyob*Nn6OV0jmH9wZmpL53XNloxDE*57TGR3JTk0Gt@o4DL2pI;q5 ziNB3oKuhWeJbKuN_iYaYIUg-d%`@U`KQ%V%Vfl~a)k)vUoc)fb!1t?-^laK^IA&Y{ z&tux*r|mWIb3q;~QX@RQD-0h5KCMdqJd{mB_wxR--aLBvOxD;fYj;@p0$8g};Y7C{ zxXgKqFuhMAbXAV$eVzBI-7W&6{YJp49X8b1qX15IOys#W*G2D~B{VKR6Xs-vLt}P~ zpgA}j=KkJ|WlQvc%U|*GcQaYF@grPRFvq0Q2vVH$hl-|}U{L7?`VLv}=EYz%`y_)` z3R5IycPH`BYisG2)p@b}#uI9G@)hp7o#Z`G!ZM{$o`gK@>by_v*Sd^!5QqUbiB%-`v%M!bQW?gH^OOCJ#lU59L%;FTV?C;o1P3F zh_}z*7fc5)#!a7x09+o8%Zr(`dbqJdLkSt5b>NbhBd}WkI#d)Qy|dX(^Y0Ads>H!C zv}ZF_MBNqaD-#66TN_cbeH?2S2jjHMDm-WMK=f?Y7Yeq$rh?(KtF#6=aEN_3IH*6R zs$WMi>S}NPdqf3e*Qv4eiM#ZmbRWsL%;zHkowRIt1?WGny<)089*^J;l0Yp@?pF!V zL!L^8ER!eKBSZ0!+&rkGW2mDe%O$UV(T?@99FRGH^JW)8L(xQbtV#gK(lIpk{8d)3 zng?fE&GC|V8RT4U5`7}w$fR>2YTi7A^1WHmJ$_&KV%koN2Ck>D@8M$CF&8$m8Y^^Y z1WDo!&%o1%MvFxYC$eQfX$sBl#|iBO({J_S@g*Ag?RPpjH?83^$`o=YZGq!!Ga)GM zH1xK;Dv7BuM77t2^z8B)Q8WA;24=0~h|WdiG-(4r3H}Q8a|Td<$uaRw=UZ65XctW1 z@dpYw^x)qEH7M)8HFx$kz!cZR&^M@_Y~r$E>c=76wcU&7MKt2GL#L=B{U&5LC$dt} z4R|-XX8k z7Miwt5bnrP!(+NeC_OZa4A*M1+AkUQYN~>MeDmiOp0>&X zK|71u9z?NYYBhZP-IE9Zw~XEdx^UMm;CD^qaaxuX&s(R4aP z`;qtg+rW&sS76PzeYk$D4;4AI2s2V`p!4hx`1ZGoj-)KY=#*7BUt_G0r>Vpzf>rs~ zsCa5FYoaUVZPaOZ9{Tljf$Mvc@U8PcEU0M~qIN{^tA_#Pdis|*@%B_ozq_3^--bfb zm}FKJr?5*b!<5aF&~>l{`Z^kM*4{Gka|r?UqVKe9s2ra>orIbH%@gvnE{Hdj+}Uq< z162JUkAvSxvF7L4SQe({&IDK5xMulSZ@^5;Zgc-C*|cGNrtdh=toa z!2duK1&2T9xM%j5lG+JV=Wj+WRRbzJX-C5^4a9`=e<|lePkS*$29vYoDewL_8lHNW z)R!2uR7o^Po9n>O`cI&BWI7uz3Z;V=-eD{--OH_ozsY8NtY8yvzZF0oYk@PnT1hj` zm(_B&;!EE?!i<~a@zMR)^kwf2*mZo0&>pJ8v9_nkz4#xiF0kZh6;1FZ?}2#XkS|!R zkr!q_4E*%C3zH^G^OLQ>Awye0S?3s-YY2GP@;Ma`c?Sijy~L<$d#X=R+|}bHNi%7f z@DM)u&BODJIymuJ5kH)!#Uf>r#$$Vw{}@hRt{%+cuA?U6+m39({ckqa#AH%UN+Ld(yNR1m<>E9)Pg0SU!9AN* zdF`qYe*Y#Hy8F4aW>qq`*KV&We&IyB`xijjnUOSafR`9DYA7z!JquY=Pr%|HdvLhz zUw9a5NEUa~$$V)WwT&HKRp#W)a}^XJXl{~d^{fwvth!6VVMa71=OgrJ2oN>FncSxz zg4X!6kohbPR$nfnfd7tgcG@c3YF{A4?y|zW|G9E$#2px9rHS97?uoCDD?|6{=kRBY zHQG!Y4X>Uz(B700%#GPp`t6qJ*f*Zu8lE5}ryo>Oa~S8(?t|Zs6oc>56Z9*6S=DgM zEWs>6mk$+%aQ*y|VnF*exFd4`+KQ^h*6!()BqxW_$p*sOwV#C-6C7Z!b3Hq&m80qC zt+Zcp4_bb#ptXvlgk3dH!0zoXKH(w71r4M5%lZUMz6ibHnF;_-#QC708pgfGhXg(BHB7=3vv=h_U#VIfI^n(-98 zFY`?_OS(ws4pa+Wjs-MOHUKtBDiJR{#Qd$6yk}rBU0vnMe4+>Il&L>Z%Bmiwo4?%-CKEoZ7{i37~{uk3tX~9nR9cb*u5wZw2cpg%fe=U zxGVo(Pp^X>=kp-_<1Ds``6 zQ#P1)U)msX2&fQFZ#^eT&pypJe;0LRnV{$o+>jL!d>r6Ki`|yd8Z@^}ck~r!0A)%|$Prwt2tbDW`rd*Z+ zt9SR{|KH#q*%^IVw@3+-ACBgV0R~Y2#(>vXUZj;p_AEPgFL)n&B<2LfgIq)uSV)}( z#ZX&R9jk;*qg7b%d%1W{TZ1!4pB2wGeI|ADOA?#EJ@8BC3=TbgRoL)g3n#lo*tyFW zi1`;A;ECgWyoyhR-?hH*|MyN^0c$XD(|VLK>WxmtI`l~2h)>@*1Jyp({Kc@1=2>^s zvXIMsHh8zF9B>Y1o|=ir6UIS#r4bdBsN#{$NU}1gxw*>+<5w;P&w|I0WYbE0-x*O= zX#jp-Ih*2EFA+YZg`&lUlN1?{%^sPqY`T;gka2A6;4{wmj^0X(%-uS$>gdHR`vOc@R66o z;; z*W^x%Ng112wrnZ{auy!cNuUSRpITp9^BLtU!s1SOj6E}qzvb=`?x-4Y(AJ*V{W}zo zt+M2I$AaNrgA0!t5DSq>1XAc+b&&0Z>|=qjPF>|maD z`61=5kw&HdNAOT+0LE186?_Bcab}RMpmKE`1n8vEjZ3jS=I1-gnc0`^vvcrRS{yv9 z2onmf6;W>T8;V)61Ud!}V=dn_NC@07B)uAmHHJPk$>oJm|4fz%{u6xzwJ9%q4@In0 z#ajoC@~Xkl;kH8tcrR>+mJtr(dA)5A)h`mSr{~g#A3Lc;u9VxxU90-svKD(uAHrMK zX`*pbf9{Hml%W0*u-&S{n^sG(?WP%5-t$J;4Yx#V&)GP1^9#~EIDw~F8VV|Yq4X;3 zFYg)ilHXs>zyTI3@KMhhU~1{kdlsjFyG0UKjyeRUUw;(cwhcufH=NiSfI7RR*;}WBR?RY}A0HOM zQ;*)1_NW*Cjv33j{RTjdg1PANa4%dr;~)ebcB5wx#^JooX=3uKb|??&&p}QMV%rwT zySW=AA2ry;YdW1hXMp3h@w{=R z)d>3C6pCR@&q-IQl$LG3B})C#7cCwY!)iGPKGLoVWp}n-QJO9adDGHh?%4vY%{vXt zZXTtkD;Fr>`3KVJlF)yBz4+psE8_jE5xAu71>Tx%1~1MGV29_sxoX%I(SCP7I3!a; zEvGiqPm@|o-JrzRHoJ-KXRcG>5GUNdawMIfn6GW=fjIVM!;V1qX>n= zkZLwvNKHxrQLY#)zWjwfW>Qpq!3bq)CR56fBnVY9qjZ&U@lXv?muodm&EJA%x8e{l zUnZSPTHKK}iRWw7itA3#qDOb`P*alwh7IkF%U-)fxq({K(%i;9nK{!8b*e~{WH3PpG zO@!`BXwB1xvVjEV{g#orn*%D9+jHe-CDwKAPf@|rg3L90d^lc{?~YJI1D`(P!>ge< z({*gs*z^fF^++9gTc^S<$58q$t;15wT18f`BCTavoH*|{WgK`bI_{f^_teJ-V=l<@ z=054LGNuh)cB|regJI|yn~YUkBVpF~WXis}mi)@Y#Zy0J$=dn{#r<{=b|y)&xn35R zH4Nl&IT@g^AQA66bwX+J2e{`n5>ywL3I4m^!TiiDbVYaFD(s5Dw z=TN)Nfse)B-2-u1e@hMEwqMuj%04?KIlo1s;CUCeK0yGA%+wlROlO_=4r87Ji=3JsTsv3T<-`AkZt)bDbvXQ9psN1fqw zU=B@kHO2{Y&p1?15vv{RX=~6~m@`#_0{1K+CG#{?86l0AeX60dw-k79S|RpNOrh9< z6QbM}Lq4!+3EAyR6Ml_21XX54p^a-%MR5c?u{Q*Zu{K;@sm#rv6k*(KZBE}hQz+>g z&-_%{-gwCZ=!&@lcdU~6$;S?HMO!z-F1bLqfqU8ZlQOqjt;1tJy|9O{8xG5^7sL?_ z&`@*=UbVfaVfu5?8b5N7w=wtEHR0thZ-vdP4nxk`azXF)L40~G9fV(2=(D$&>wUEO zsl{!Yvd%qOYDmXSI7}pnDz?fATv~c?vZu*)ij>@eR z)kjRH%VyFj_3|fNj)}w4JJUIIxj!jge?JG>;4`F zHKV2Q`)wq={g=JB=P!h1RzvaGl5~=It;FrIa@>7hUik8`k=FEy5xlRSh0__&X_Klx zp4nRleg8z_ucW6?@vs*>PU+9PSId*sv@Tkj`H^h?rjuL20d$#ze1Dh~JCww;;h<*% zI}X6?NHc1ia17#lb%2_68d}8Vfodt9I?WwER{a~A&oI)Ubx2&neen)i7r zW2}<_E}v#B(SDW0)60)@xK0L`t&F8OJrz_bk%y9o-8d@A24D0lqA`mO!JaF`QxjES zN%l}4v2YvWk8sg~uPyX$!xF)4^=y6~X(!Yz9z}*v^?|UJDhx(p<})eGtho#WH1|;d zAxkJm+>3tAvnXywH!LsS{Lh28!%gd*bn5yU(hPYcs*HO;CMA=(|GZpqIdecvNVkQ8 zv4iPJMLQfd%7u78Q@W=Ak;N_HFz3A?uG0@k+h6shJ0U4JNXXX!sAJ@ZyOilPnvrD z2EE#432$8zdDG85v?y>aPRLq7BYlrT@&S2@YYYa36+MLH;gi@vHreis{5rNckuUyC zuf@z>J78Df0~$9fhs|^)|C}ldM(tlg!^}MJ`Q~+K^Y;hL%^$$`{_Vu&ZI#rsUn9kK z4B)&nH*r!#A&&8OL1pbQR4Pdq`diBJ0Tp}xJtLB?QxSFb4`(?o5AII9Kym)2 z*qOCM=rpns&8M4T#W8ghWaMzlc}@O0>Ifd~uflEf#*1&JM)9@B0#-SwV#11L^hZ4a zLS}bUK=@XkR+Y`a4%lJ$=;4^_lMl0AN=QSqRjBdZgkQ(0q2c&i>Zpt6dvlz5LD5SX zADaX(=Wd4Z3#ua6&qiOnK(sPe!}sQP^kj(=8?+q~&#EpF<+`p@PV#qhm>`2CE>lQ8 zM8|HExjw!u+$72Ccuz9D+}Pa89fvkwgw9R7#Xwg*dcV~ir$k)9gCBjMCZmuN5~s2Y z8c|fQ81i^Oo^4h0#G@lrIo8yW6ZRyDlg?{HT4ghYA6AF277yTob(HY;s|~$dvy~=| z`NVc|>e&1`5xQ$Nv1dgQeK+hQ4Bwc7o8(1K5TbDLf*Dk=_6TNv*5T)P6MAU`qpnhY z)orQX+;3eYHlO)ycdl=0mG9F|%08MeMoALE{lN}aszu4W7mLY7Ru`YOTk!l1A+&VV z713YU9ABN%|Ji-_z4b~0c=)>_Kph-(XRro~dOIG2ROkYZpi{soslR3dD zjiVN?qn|e;VQJvGf4ndcOY<`zCvzA|xs~z9dD`sJ_XUKEo{aPTCZoxK4zcm06yDkG zLuEazs9^6-uHDlh_9?BUTLt~lKtolGxo(DIj`hN>BbUW%e&5n$CgE?D zFEl(+=}OzBII@(oqzK0n7${vv69+ZHl?y%5SjLe1Oc_BL3N{kC_5N`Eq$yeL=q9i3 zLvX!UvAAiZJWpS9mZO(`7q=K1!?TDXF#pm4I9}r@G+3|0_mxBNaZv*8PcMX(FOunh z6rA^4&+iwWS8-=D^c2#q>Pk8q7WGk)cbW#iR>Ao zY?7Io_4WM&?(4em`#Se|J{~`uTgv`395LTZu3uY(t5Lq7w^CX7Sq#+Sy_S+LM&L>h z8}dgJb~SoOd6N*P>TH5qg;o63vI2g#C8Ph(xj52UjpRoS87dilz!4A zdHa!X#cia@vL0i`uS>#lHN~*cns7+t0$Q1{oSa;&;QD@hp0xL% z-gb7kiwg}KNF{~f_hAWjt|3m1*9FrDHW++I z1FilW#T91>5oMF$0tB<>^t~9ZX&-ttID0% z|Ds=(4fN5E!e@ogXy&F7;EP+y_4y_auR26OS`;vQcP?j?uBRlK5Ym62f!8kXar+#e zK@Q5Xg6z3{@JQu3p0Lbk!?sX(=(m)6w)lf~We17c{+u&l2`)Nc1=BBWbf0S1jpM?C z_*>yN@V=SEey3;9ldkJz2xIv0HV>?t=R%+MY~y{Mt+M@rcDC?>#wRD~Gh!NvP)KUAM@Mv%%XxgsTjUQ19|>^j>fbtnxSEz13+{ z(mw;NHSH+l>2^+PpG5Y@Jo){$!pdGJThqrj+Xu)$j$130gBr(ST39tN4Jai zuUvWYd1(y#{gfKBn&_&w12@<%;+5gyg3+{V@cKXz6lI4(L%@D`^=iz&_ST;Z?MoRo zWa-=0889+Y37b=xs-lfG`k5Gugt>dWqV-t##eMOejMLTH-xcc z;<RgMvw6wI&v<-Ar~37wE|T08Z53 zE~&G=BV0aJ2CmV0pfJ!7>b+0HcTZ3HG;9g#z4GO$>kGlmF@zVNDT9;gij>v=w5WUs zu{bzG&@o&jKGU(`xns?_`0XmVzrq)JsZ7w0VNsFYC(SjrKS``j5@tEVD!J zzk{)NR}<|w-#|-Om~+=yJDhZ`o|5N&6tfjA#0!hkF=wt3e|nKaTLw?yF{ff+)F&n3 z>LYcs)+~gwngme2C50PDnbWu^tuc0n!|LZxnFbcF#9i6*c;XCQa^CZf%Fa9jmp6-P zQLp_tu%(gA7HPtyNwe5%ZxAf@pDotK6w^+(BA$M3H?$6SM9up5VBawWR6ba7WQ`As zfB#ap?oEoa+{{VQ=1~4EfREoDjduU)tYvi>>kg zRzP@n8=RMU2?t$kDJp)xBxao%z8W|mTYsm*VK_pTp9C&?{hd5#%5wOanq;NzVZ?2rl*3xVFxOWD)w2S}^aV$QzY@~ie2BX#6zyJ2O2A=#rNs%+w zbL!T|@IwA7+{HTRUo)9JI2kH+Jd1L~B!=Lx-~9{BZ62lo4FAcRQ0p-o%1^1Jo_ z`jdjKTjhjeYNP{n`R1{I{^rP?R0-CnU%-^XgHU#FBOM!Li*Gi!2{nB+a6{^F9-)$j zS09a|UhU&hR^Nhs8kW=4vKn#O05!gHb|-SuLd-bPw;{FfYjRzs!Bd9iV(kkDe)hOZ zm=J{O3vos^Y=mV7}m|8G$~ly>VK9Cu%?4kCabbg)rq>yt#NE^i5Rf zYV9t1mSh0eik3snfPY@^`j@tkI)U3)T;s2vlToWHlz%K3iB;=I)+ep(Nvr2*G>vBo#aT(OnFsm{q?( zZ=5bKzu!V$f8r^}XuvT( zykb9T6ukyD2f#(^f5N@iLeV34w^ZP;gPyVIPdxeid5JGvv*XGVq{-dR?tAR;IaJYWiah{ z_5lXxc!H@-Ka@Eu$IUWBQTxh2mpSS|t#hP!!Nfasuwow;4;Y3!cFSXj7{=PgR$}1^ zLvha^CzjZS@l*YiET^am%Bm^ilB{`nU-YFX#Q_*m{Q$h~oAWZ+qxiWlAM&dHh%cO^ z*gE}3-SmhyxN9(ti_-(CJ}ip@qVHlzS1pg`C*;g zER5yCzEe5HvIVY348ec`Rfq^L6P360!>|+wRGHI3?b8L6-W^EVOHZQto%51B3me)H zGL0V$6Un^$1HAvqU!>-FhwAWS~sUt!}W+rvr9l-h0x%B$McHw7;2$6G; z8ZI#m&w2z4)AacC6nlOe8iI10ro!fAW0W}@%BOM;L8Ts0#*qvv4<3eovpm?|KozYj z*1KmFW?}E`uSCBdi};;-DfE49!<)7>;nA13gsL<-Zj4RgBy}&!zM>7*3livIiaK68 z@(A1~Byr13k)EGOA}=FV%nmyM7OOS><*pR|7hy`)gBOb@&V^!2m={c)7lIDjo*b|( zk|Nfx=lEmNY~w8F?xNHvyxez+DKV7`MqCyh#$=MKtN|`0El?Shhy511f(seIb^Qc% zocx&@OD6G%i&pj(B>2Bd(3h z$E{91;Lg!Mg0oK-swCZom20Kx(8p}<^!Wv}wo$y9xrkr#1U5~%CtMzyinFwxFhJ!z zHoS9W-(8LL|NrGKPM494T{E1v^i^m2Ad7ZeDmW=G23z~vvGqA$K|QsYn!1LG;;pH8 z<%lfTMy`iBk!iRi#-CHF%E;=r4PV)y2iLliVU3_b7y7B;)+O~qXK*N5?CFN#zkMk? zc^oN<7pcy)P>gKVXAg%L!tfdmoa4|NM;PUy?ez#q3e*#?^a$hU_lv3aF_YREN7`?3 z8xA;Lgnk*$eCLKCOGX+qMIV6NhD)?PI2JsgzX!SHF_h|Fz^@(a;rje)m^m&P@5N?_ znSa%x*Qz4HedaMb{-_G;7nrl1*D!2!`69;NzXi<;r1`khVm=fjK(&1dJ+S_c2DulY z`e!P9`dH0*9fhJ)%O#0A{-Uf6>YQI-=3bt704~~B!~T=oS>~ZJq}^zvZ@ngB#?Cx= zB)3u*+M z_ne;~M1^fb-`=fasB1kmJZ>PTnuj!Esh&7P-JX|#vGLC2WmUMibv@-jeeR!LBTU1 zu=^3N&C@`SuB%`)H&u*kdrb=9%Kg@s@JhR4x-PE=UoYk3w1G=Rxm}}R$Ps_~7S|~T zMen7W1~2|}btOfNQpQC`^H{C_Gg#bfDGU$OMRnT^)RlM<=FhEz4Ks7dFiVFobhUuG zi6X1~2uHh;PjoA>A8zWmmnLuNNy%yM?k2XkXmP6>CXC4C-Fb#&mvBW==J5kW3ug#5 zH{(N#t#DFtml&pZh=z`6;)7j{K)$Pmvbs<~S>1;}4lRLR2|l=>XbkvY*oE6|GSOn$ zPAI;$fKOj*q0UT8X!N*7gEy^Y^N4zK=&MLp)%DOe#f+2R2SZ|%8s8OP3DLGI$i(X( zFO0qchn$pXPwjjf>3N#Z?hAuS-albp+#OivDow51B-AB|M7^`=I55=-)Azpw+vptf z4)o!H^A#v=xhD^bdO{acWO!QrOQC$z2K1YM2a8M^#dCRP^n7!H_{|`r-twFbOEvD~ z=gJ0b^YN3Q9O1;-skP8lmm@^|JCE<00qAPmmn*QnZUU|oyo~eManfb?(T~+h&NLY( zU&w?jKD}sD&r^Vt&y$};3wA|p!?I5!xUIsSjk>zYc={Fis{@qc-G`GducMFNP55)+ z95J}zJ|xgQ#>JVSw&#iD%2g#!`dUXZf7j9YCtrp5mBl#2>k`C<%!b6#vv~KQ{$lOp zN96lhiAQE^p+DC*qn3>|8up$iG;RDtVR!Agu4%NG7r23h;xJ);bGz7}rN17kym)&#UX@U7Tk;&m+v^%#(X`I8&)M${iDZCBzQ zim9A=emjMg-J=ZeO~UuL%SHM5o8WK>W7P7I&^cFGV)pGI#q1eNGYlN*;>_h7J>w4V z>vfja*uE7K^C#l+GIM@gsYI2d)}Z2F0cRb_7ag25ac5=`Rk$SJpSuohvT%^3ts|EH zk+Kl}w25lz3FN$U3YL7^ zg*QGtf&7FdHXl5IweKOlweBa(ZcpX2$KS!{kIv$rnWJ!u)*~U;%P31d>hoW#-8Cwrz z!+4G9y#IIx=fxS4!p)tMv*8xF+WDq1{k0AD3GhTm`NgF1HXTz!WXQnfk#Nm-6a6`# zMYvBRz7R$`paQX;5x&9FjJU<22j(9?&0;aILvn^_ktsv`JTD01v z7>>-Fj$KY`ct+|A(v6Ja-477PuI5f0kCP4-a6rBldJLS#S*yBXvThm(w=RpH`^>}2aW`P+ zH*0P*SA~>LWz@Clf>)R0#jTw)xu;kQfu#c=+Db>%U!aAr-z-I`UgqvP%fHjOnzuAr zOGn&U{6&0 zX2vP9@pPYRaMTmTZP%WYS;I^|6{ky0(?;XmSatqx5k$i)uknZbNJ@F%) z%@;T;qX;T3-6_QD3*A1P%}(d67B8@d(%k4fE5MyFSBkvortWyzccU94Vvb#{3 zp~rF)7Esp9WO`+$#Cjnb*wGO!jy$h~Gpnv+#~e8vQ1+gBd=z-mB}=}P^FX-qV=6CN zvt0P4I*2!!l|b9lTufP~h)-URCKu^fw92+poaK?=e(qE_FG=5r79%zIJzKHdpqmue zxCIV12GB|AEA(3JKR7Ns0%J;YNhkF=wvCv{DzA>f;LYYNAGDtA2dY9*VG4iTr-3pa z3#c*W5+9vDn#{Kq3!les$EE>K#G5x(fVV~wSXuVKyHCA%&%{n#^z9Vvf3g|8(o#vz zN1y#$WH3)5h6}HhirXKh3$cc0DQcn>_q5z5ys4JKS>4m1*YH$IRMy3=A1!dOMH{6W zWAMY$6BPHrjosxA(x10e>8|SndK)!{d%o>~wtY5md43W7ckMChKhQ^&wg-^w$WWOa zf%}~`>8I8xF=4qj&hql2BccB|Y4;b>`Q(rHF6<@!H9y34Yoq8%zBK>J8_mlk5BN~R zG@L8{3tr0f#NpH}x>jVvk7ZjRch)r4O-#njhd=4=ogiG&&ym0BHcL)9+@n9n6|~#d z22Twsqy*YS(a8i?^h*f-<&0(dFPhZS4)1H5q4m`Qw}g5H5c`+&n~33T+~@^gL@oR= zLk|lNuBJfCCFnKT9(Kgt2Gg3GH1cU8j=tVVHx>;+vx71umReBxBUM!X}q#q?FkQqsOK5>qtfJs?w#awV~LywG?`rIf|=} zXyK}F(inAPtNX_D3HV~158aq)D_PU5%_9fa()x~}6zMUCHb_5$qAyy)q8X~#ci$;6 z>#I(Iy4|#PL;{$6(-LE(Si5N{O-<6Ig&-AJ$b(xZby2S_feus-MN6e!uw}FiZN983Snc=*mCH#SSg;y9zelrX z|Eaevqy=+g$=^iAq&w^ zCWB6#DG(>7$V0jDeQ=z-1xj1rx`%(=2xI3A$K1bNlHS%EgaKs6<=GE17*^E_~8Cn)@&g(sy+h~2Q7tV zB~K|B5H>fMVO5?ppKjLSJ_#c^BJu**eocjOT6)lKTIKp z#cGzAxmXs8Hc!EedvwTp`YZ6r=_^b-HHh1{hYP;t5_Yum;l4`pEDq^_!w=*!$WQ|P z9oFH(v{dMS;wXL`;wspUDk5`yO*^gANFlfm^j^+m&wb;-YOyITefk9)!U@KW@#EcX zTc}{690Y_eg-NR)h@Y&ysPD0PI37%Kmg#m_QFa0)E6S*3m<8*krLxO*fzMBIhR+*Z zc>a(U4DJ^t>Yv=fwW(%2EEOZI}4j9E752b^|IZR@fticuLyXqY~Z^6=lM0i-? zM|3lh0*~GXr*(3;vNWFx#3YGY;1qnj%7{yQ81QI`BFFZrhoMuhgXR=heq%HhMqJS0 zW>ZC$J@b`b4Vj7;FTR3_k{~)>G_5}Bz8uofP+WC0f=!P1;qy-y^V^F4xOQnZOcNaF z{tpYRH8U0uN$tdOcY0vJ;WgOXG7gUzs&HA87f<-tziPL~(Rr^4G)pU-EB-n8i7m}| z^qCC3nH&$eU>U1T)*-W(HDKQPTZ}J$;^MW$7lShrSaZN9^4vC()jBKT%HZC(M|Ou; zo8XKv^sIPHJ_hBDB6#0tGmdE7%s8YN){M@D6?r3FJ&ldf*S0_Y&=?AC)kiq%&U>mp zb(6LgjK|kk`tpG8zrv)+hFCt$7o%5K)4=C8ytDN*o=U2KY8ryyMwxJq;XNUAa-RF` zpoOfgJdZM@C!+h$3dootix-BNwNptj+XpteAbeg&I~U;lb>az`HC_ihyjB^qLG4_$WIJxECMaU)aBP73hT z!jFfv;#4Zll<^5|C)5MSxc?)DeyetU|r&UqSM z`<8%j%LbsloE(pGwxW+3M*QFLI-02XuhwRrfD)Ch>^ScpFV>tUZad|NX;Mq^di7fp zH#`&`wHcyN70o_NJHh(O03{u@*sZl*1&;vOCjaZO)!;OkFJ$lG11bM2botv>gXU=n(ZEJ!_*QtSO z8%!xjDGOrSM|1G~^McoAC4A{6hvA;_JU!qANO{DIKYe>46;EfKeoslMKog_q%;dz@ zI(qZxhOk3X7IxxQ7^BvUpDhW*8?YQa&<5V`osWFIMWUUxA0`g_OMb2EX>8FcIvqTm zlXDGW&N*pev+-tDFOBsX#;5O5od=WUQC~y!7iQDptxw`-j>1W?UK$ zJvm?4r?7)RL@V>Rdx1Rf-8A^V%9=intHNRXX7eh&|M*KsEdSimEC>k^=-g<|Up4;2 ze#;ZwUiGN~_0lbvX|30A(Z?J%%upxIx+HAT7{tm&qu6?P0J`f&;)C`ETqDWg2M2(4 zgEi;*{^T(a;OE)zCRw5GFQ>Q>~#dQ2`9PiplTS)zTGY4I`9X5)H)A?u7&gU z{Gn+2AsMbWO~ruk>ipRA3M($~gEyMt2=8BmtHC%{Ht?V=fkUu&RSw$Zmx`N4uV;tI zuM{A)hzf66qV-~P{#-I2oQEv{^AFwBems&ZZH!r0<{Gr}XDA=1i9(YaRGz2>`M+jgns&~356`{(DOP7F(vn&1QTneMM_=qcYFHz$yGf1*dq$=mj6f!&p zuU%*n_4{ezMQfsiVMi$WNQ+n;kNlqY3vylAWrMlCPpLgUM@dh~i&UNIP-^fwc; zhK=Sm^PhlX!*y&l(WctJEE-3;Q)c`Y@joS7{F0i$E#vCM(}5A>(5F*$Jv@w!-z>vF z(I(KGJWvK-Lj(Ae7l?!I*TC;?c}{V&qgy|v zNV}#NO=>KoF>jh^l-g$Qd8m`pulfnkJ}*GCeUZ>xE(>m^{1z2z&VtYDov40f4arW< zrGB3dQ?B7)Jev{;lhcRsgUkiuua#qA{N5dK>h&j9RH~)F)jdIeXewTIPp6V=o9MQ| zO#JG<2hysNv8Ry_?;kl7%5&wp)b*>ts~*vfsV&sm(;cmDjE8fJd|5_u12&e-=Gz)u z1jpG;V%)?7pl$mCj{ly_`8Pj9+q^KeT=9!Mt{MtU%>8-8AYbwD1r_qEKP${MRKOpZ ziS%ULbPOmO4+$B`{9kecE0na**Xj+zfdvo6h@SmWrcS`^#UbK%CtnWqNacB7CXin6 zS{PJ*2D;k{V7_u+937yAAs-TuY!vWS`iuJP)Fou~=Q&-~J0>}!Gmv#JI0^&QZi?C) zC(-Wm&8WHKka)L49uB=z+kH+C9KbH9lPuaClwJIclFLLSf5 zt`bdKx026hUydJV!Fewk3wD;`ihBW6)$GLcVx;)k@<#eE*^Oz51y4Dohsl4N#hd5a z8J?PB&(vr1VCP5-bsWiNyG+pLflf74~;*YAwG<$qcTpVtV_I>pE%iTVFeefc_JbV#9 zdR!@KGoFtv8;tOReF!>De<~cCb`U}>i{W`R2Yz1U$BkDXO15p)XWx)*6zQYQany_E z4voday3LS(M;CJj`qKQu85A?ljC7BAu)J=K;IQoiDQ@o7Fz;ifxZw7E%vt9QA>Z85 zJ6@f}kIO|<$GhUeGh_LMKJcfqFf5n%>t60?H(rMQ%XUJrLIN)} zdW>0vEpbw@Aa)9U_>T8;TB5KSy6=|ohc!A>F-4>|S2u7=UN5|OKAb+xNrBS%o{&~_ z8v;k`W8sbaw0UACm$t-_MUFAcYmRHswcfMOx8zz3E8>xIMDmcWhuuSlcUSRAn@ z8@@yiz~wVMd4TaZ;ZL3_Qq?^AzQ2%`&U=n3!d205$_Ln>eSm{C#|oDv+7SAuQtW&7 zpu3r6J$36uz~AhFnDeVb?7sStexzj4>wufE!tSE@w<4ATUUZAAco;ezIfK7Cj=`V7 zlej*?lnMvx(V^gr!YJP)wze#y)?r_%_V`6kHonE`VZCwIv7^Glwhfr!;V6bDEW)^4 z6}0);4n3Od@pzLiw=}x(M&&IM^~p6*u;+b!Q+Wn&QO|?I?i`-^_!P$;N#l;_2$KDn zhE|_c@WJ-IXkROj-2-1iuX75V_2n{jYYDisSFYGU{uK3nI@NuyZTMvO z133EfDgZh_#lM&KJApgYehCJlsrWs5ocJ#I2CY-=fi+Kx7|-5j>ACi-tau0l_8tbe z3p22v+D3PyxGX%csSf6~U+K5LCp-7`V7(U?vHf>Agl(IK4{uh`i7ne| z(L>ofEPZQ7DQH;y>ZiTpiq-Ey`aDo_-I(&Z&oF?$Kz7*G&R%KQmG3@e?w7sD@TM zYBA792L_+GLQ>jJyw>+MS-Gjv;&?qa+i(ZY95{vF-(2T`_9x)g;(7Ef_$e3;>Bqe~ z;`mxb5?+$8hf5Dn;vClkvX40e;~&|uL?5Bz#xw};XU0wihlJfL^|)8z3vk+!f*-Oz zf$2aib~z!(t3P>>sq7SC<`fy;n5V$)%M)3t{S>~FbrB7st#R(vY*x3;g2XSgVQj1_ zC#osXQN^>E1q$p@RwqgERpHUAJYa0Fkk%vITePp(d=V9*z6Ig z*hyolQ3TG~-&fdsDjSwYeTH?FO&lB)MgBERb1!d3ZVM7-NL0iy%!J!ve}t4h-uN~D zGD#wedDPMotX*n_1J2su>X|9x_p&~;Thu_wz9l#lRJc>QC+?XWTVK(V3~t$P$Y3&) z>+=GL!Gmoi*;=k&^09z{@$B~pS}&_btUn1 z8TX=Aq$8PZn?iLr$|(G`9BAK80(0GTZnc|+t$77h*)#*UDyP%j|^_Rco({PG-X)LuhU=Fi>cFX;Zqq6T#Nxoktx{zN#~ zbsQ3UtjFX_8WelQnhwjq683uy6gNp;3zB&kvA0S1=|y*g%HeIkQNsmS4XXY;4?5c}V({2fNw%>MuMC`tA^sm|+TFRdAV|RDchBVM!j=-zpHL&WCKWpnfmq6u4ZnD$BpIiYSV^`zZzQ@JcpSr{$*CRppU(OZ2 zv7>p{hI5b3>G;F>1HIV(SvY5Uh~#HCLe1IHxc{*XkNA=Ut45pS9Va`qfA2;s66L7R z?vwPTBU56y+MTD|aHo>622i`JLp3#fc(8*Ozj&QQ?Z)Hq{oMdK^Jh3(SDB)D>{LGf zXqsg1ts3quIu5_enZ_L)27l++;^T5>I2W`YH|bT0KsFST?TDtAjqu&`^McawM|4Wv zmcn(*g=6jp^zhg>ifum315X6vm&!hvIXMZxe{rBoxw-YLH%luP@?zok#B4n<8M!yf~ga%#u2`D+;kOrmTJQ3QT_d3ZkvNC}`LqJltAH zzVHB!w+#Kq@zONS{Ih$$Ml*dYPGO66hp^v(eemgx1)3x}P+ss2u-W$nvcQGat1pv| z^FwZ3Y$ZeQC1JW%FT8$O3luH2F+zVM8AmI^k6%MkG0B2A{~K9~1saX^G#mhw%>OLFnrm#J(=b$IeucVdf0*G*Cj5mOHfQX$v%;5`~vrPviQD zKPlVxA-hF|vTo=+DBU*{KXsfD>b=H5?oYtoTh?;$$OdtjR5q6BjRVIq2I%o#mG4VF zz^%7mDaksYv|{~u@hK>db)oig4%+)40L&Fr|DmpLk#sLxY;mJ~S+r$W9cKYSRcpX!etDiJcp+l2#X!07dTiBEcokiTLtuMv)jD=K@y9FIPDe86^`NYh#FiX@%-Oo)QygOjE4w;Ikr4+K^pCRrh_x~ z?Sm)rIdrLi9m#GE0h#4p!jB75ynb-0;QMPo9yEPOZ#z_Zfy#3V4v#1M$Zlb+<0O6_ zB!j2sN`xC>ayTODI>%UA3C{M@Y2htfRG1RYy zT=Bkz0j6g)i-k45T#O&d%xN$`P8mrMzY#RmtGH#QCZCJ^EVx=3py}(`bU5HV#Z5HC zo)Sw;)rk=6k3J&(mIb)>Yaq%9F7D@Ag6Q3N5T8!XfzPv$f9PoP$@f$E(QZTh{a`mv z{`?7EIM4xcEF>sd=uh?mibva(-;7|f3*L`^A(L=)VW$IYk zFOT#lR&bN+9lrMOt+X0x;g6rQ&}+^~vc4>W%($}GeVn3V)si8f{KC^S-vA(IJj)1km%K$XGCrgRhD1E**U253%3tV|+Di6r5{L;*`YRnA=|gOvhez_jgjjyxhIiFK-PV%kPcpPn}637t6J? zwuoNYwNM7%z=#+$q}JS1t!bIt-{Se<}1ik;rum>c!*J)$m|sqnP^M0M9>aBMn6lY=H-& z){BAYd!(COp9b^x=I;JmZI`4(i zA8*mB3Jdg(0GcIZ$$vV>;X;!K!ra&~a5ee>^$GD5%U?8$^|==)HX)r%2E;fUBSE*wUa5ihuRvZS#$I(Z&!|y>ge57sRsRFjuzGy$ouvcDu!1 zc_}_UcSBOWc@Z9{nZ`f14q}xAEgYTG1DbZ;hfy!b@F{Iw{P5%CkB7R)j(IIPemM$%qzaI1qs6id-lEltAUsuSO2$`Z+2L#lO<+6h zphR9Z@Sd3eJD6|V{h-P5H~Crp4d^Pi#FE*Akq4)NTjFz4Rho=Zts=;sF9x@B+1&G^ zC7UY8)24T!AeW#3t;^5Q_a2K;t=d@JZL7dKl{WajcfI(@;sd-LcuT03mxJR5F79Jf z2Xni^7@@{SlZQPlr9D4}qP5rr<(q1RAHl6;ZW9PrWrfhMXqRtgPk6RC8yBm0kk1~;@SA@650T(DQ= ziLLjAV_V9EiPdBA?aq7P8>%JrTe}w|DY>MqG8#_xeTBpCZUZgLqml&9;Jr;pNn@BO z*cIKNmJoJpNgPk_L$_nWy9BP-^#t~`o3W7n9xjeD2LEsUIbHr1+^^Y7VN>)ttfcoC zxxu&VQ{FGadl#g6dEdR{=+apqQM8GZw~mL7YuCkFvvncCxs0l|dC(H&eRQ{UH@K~q z#sQ1YP=dQNE-1;yE2Ee?zaNJ2b05*7KWz|U5G<_p*~s1p3hS+p)>5MENPhgt3U{?O zVPDY$R;=!V7g_7+((v;DFq%zj&DnEnvoIlYJERTTj7^JkD8BDJII-A;0_$ePcTPT+g&?>1o;(oPrBJm{N_T39PHMxcjIEq#0Jbjk<83QjMIz zqNfZ8U;5{P39mqE<$htt(MhZ~zJTUb1iekbS3zlS497;jE#r~4~~n`)fd)J6{$=uhGFUq)y;E)FN} zzldhv136>7K#d2llflwBJR?!!-wvxe+w?50-9C_h*Z1N>xiO-?w+@(8ya5-FwN$6v zAJ1rx$0HtRCEH)^V~4NL;hmKY)v4>^z`1WoQN0ji5|waixE3sYyj~1XZ=ye;)o`U_ zHon{timub5#9-qewBt(*J)3`kUwDP_rcP?*X`wa)|Vtqgcz1<3Wx;c#o(Rd3P&AmlS zmi2*rGffUku z#Xm*VbtnMYwH9dl=szK|bpyJrEWrEzYXE25tbcpjiN%L1Y@}$xq+_V>x=Y{;H^})xSaKXQ6oM z@$lu=CR%z+6AP*}Y4Gf&=-e+6)jZa)-eO~R_g&5_-lf6*=R>h2!d@~? z%^vqm$f9>^ZPBsBjgm9cVMH$vel9x(61sW{Sh<~4wtW%nZfVfX8IK@h?En~HGXn=* z3*o8^mHHvwjZ{%M9Qp(wreiH0Y;wbk=UAk&iJ?8OydRB@<3EGrAV-LEXr_!iO1RxO z71Ex@;IaDag7V>FDu1|-PQN}&<>_Yx)%M9eLi@Y8Xioqn^a|wWFJ{8%dG4ICK?@(g zyC&`$)GQ454Tp=5&B$;5S~Nf4i`KzvLes}}oHXf%c<$)|$r+XL*nBILm#t|O$ELp% z;GGM6d@0}(`+LHysq5*W%xda&W*XQ|P!|-NCQ|OMiKH8C&NIJT(5#blxW(HV+xNc^ zf@m@tYWBr#7GuT8fpcN#qZG+L8N$CKa=GJf6J+@0(y|l*-=-PU?A8oUTQvnb%J<>> zr4za4q7kkeyqMok(!deF_6fe3HsbZ+fiQH$VxH5Xj?Z0g;EL@ETzU2))UyUF+1JC= zJA27;dkTkZ$Ai@8eRXfwg$N2EIXt3f5B<#w7K$!R#x<>}f=xy!MangRis1pF;X^tH zr7z^l;CJ*QekqR4lEL8K2OzLzC*;Od!v(8q{yg)exZzk|#KB*o1G1>8%A4bZH{#qU zx1jqHLvh_h5Ld0j+F@S&r9O`ocm1W*@(6fxb*6Ap`w;0!UV_Ph$5DDy0uYFD(7L*WEGuzv}kd^-$Bo;T!&r#vxkZWHwkj3mGA?SkK>+5GdY z2j=Wd!W#9F{ITt>=n&@5w?eN%N`(v`-knA->)Jr#v6koL_T-Z%o9I}VB`QYSLY#I3 z^pCp+4!5>I){bZ5^s`>*nwQ4A7B}%T2R}HlcMCMk{toy4G2f=QT1XE((cgQMxa6%3 zZ~mIj_nuyXayw--l0;%_ObID$n+*SrTLoV%TX62LG}<~!i`HF>;A-3cbl^WAVZ|(7 zAkziSm0uvrgL#AUE_9nZj7Llwf&<2f@PXVAlK#>kRkCy4FQYxKxjmKd+*pQQpKHJ^ z$qyIa-%Szi^+K5ME~x(E!Ba~&kyL#q-?VP0Eq?lxr{#_12R6dU%)cP*ncF~3j^UzyyENV6mf=f<=`1qjB zq}{#)Y}Mb;y|oj#wKhknn|6V893SI8hf%OAstEedn#~C(YN;!tkj}&y@osG;bSWN2 zCys35cP)SD&z)HD`;;r0OQ;5j5Vx0}ze7tV~toWCq^}}CqMA2}Xeog|{ zE920;=>+&#Nod3}z_$4(gt)(oct-v%u8SH)no{h3_@*O0_xeirUA4sZtCz4z+W#mz z^RFJiE(|xTBq^n6AW1YD8j(KF-ZT!M(-{O~(^_Y32FCV|CFSyw@k%3arfBrlgX3b0DMX&Z?$ba@2UiSbV zEf~Y+_K#xksl&ueOO5$sLzTF*+=cR8yz$S<&kz(^gY!&{S;y`!Ww)*2#ry5WjiI9O zb7)WYP|N3;+k%Nsgu#JQUA!oxEXd_Li7GZ~C~im>UIy0E+uI{BrO+O_DQDrN>d#V@ z;UDO}ncb0~ePKg=8qGdsEe;)d3qsoRpuR3eSo-s-_&xh2{pXiVFC;|-LH~(C zn;(hMD@*wBCLKI1Uq#0rYhqoiKAarT0U7GuvA^43)*i3Hm&8!k3fw>~qNjUxnPEDf5H4|H>RJ zTTsLPeKhc%-Z<{~Oz=%9RrFY-$~O8dQKs64d;ICcU7PQNs_zvD`;ia%pC1u+`$-MX zPatHBmlz#>TC!x{P0Dz>gEwa7@glYF;9H-D8MFJN&J$13J#4mU^nN2gO)bIEy;*Y0 zatG@D{UUVLl?i$U19)&t3_H0jmBeZ-q#o%?^nS@Q?0auH_FJaLr=z3Tb>T+Zb#5A@ z-FsDQqdI~s2dN7Nrg}84ZyZnEeh<_`*23t^y->qpG;Nz*PHAU8fOAtG`B^{aJ2PbY zLgZkoa-W0Y$EzVgcL1h66tHjDO<`!@1g<|bfz1>}@;VU=g)3aq^t+pY58evuG8K>@ zX@|z66R~t_DnCvz;C{OMsE5){Sn{?PNjr2{F2xzgs=R{s>k8veELFvK=O^>Hm_%;* zWJhKnCSzf_z&ByL7#UYaKK=d^U2nSLr*++Uo}Y?1;qyZ>R*x0tSrmX*SWmv*F&_7` zB{zItgnFkou}fJISfyC-_Q!P+qpl_x)pG?ESI@wdUiHG{ph0kR_WFOE`G+1x?2|}7 z$+79iZqV^QgQ9*CJzv=aarq{;v792=|K%)wdN33h^}GoAfd({j#sr-C`V~cXEa%Uv zTHNm0AWa$Jj3+1V7Mk?-!`EgrRMj-X&L8(gAL}HNDbL2`DP>!{Iur7<2;Ae#}zqbMA9)1ZIK^C&t)(dtYE8)vB7g9fUn?5(4B)55e@%PqL z@Q9m8mU%7oGrNI4H9dmNlG`-o=p8ybB$JLhZRV+VzEZ=S?^6H3f9q}agxv??VE*G9 zaKddardmo+L1rwz%VerqwM&>bZ!9^RtYoh*3cSKYmHm#75pJ!&D(qXa7Xu{6p|_!w ztcvDx;FmOULqT_pDmG=U8dLU7PzJhCfxAiqVMD7xVa>5@wlM%sy!8gpj5+jokS>f| zBH*k&-63Jh0jf?=qeOF{;Ee{*W|c!*(-MW~pATS{TQ+BO|Ha1rM)0JqxiCZD2*bs9 z;JfT1q`h8)GFo~tI3k-~Y3#w5TCtFL{spv!*VDuKvM@pRkIog9EK&J{^cz8pd$!e@}%yTPP^rf^{YEpqC9n4IdTbJy<^_~BNj z5ZgWmj9+N+ZZ~^zt9C%EE7^oY;sP} zY*+(DCw~i_9!f&=^iwZNjW<)ZDoZ`5XcOE6cl#N{t8(4+7k^z6`kHovl+rs}Cd$?LgLBd3PV zEfXlMC>@p3FN>FEAt|oB&iz}z&@A;5Sl%rLZJ+gq;S2lFrk=Y%({cs$-?E!R*7Ty# z$P`XK_XMu{hd_;86b$=e4{Ne73Sn06xF*X~+-g`yDg#Tf{gV}R9#+AR^RH0IRgv5s zO6f`7FG{x<&b5}GVZsD;)&X;2wxpI|#2FYkOdCh{wHN&@r@)yUS=2vZ#qIHrIklfZ z4I23yhG&#wYvUXGBsTyy4*LPmhGhsj+GjY}_5rNR11i%Wk9QA05h7Olk=?j~_-jTt zp8GGS2E9Aa@5^dAdBe>zNl+8gJk;7y3o6SZ@#Ve7s3~JXU&a^#8U4{%Ae2(-lyN{z7J;W`_rQB6m4srK!Te3z92WOG$XBzMpy%FC@ZXkip!cCC578dY zO-pBBZP*iX%B_U)C*DBMjdM_Q-Ws9XD=!*!?;mPB#T=fZ{z)EhjNH?0zQjc1($*Xp=N|0#1FE; z`iswDZcPxY+Iv&OlS;g<{EqUj4?~&dF?__N308cx;965RqDx01>c(+loFUB9P7D>hs~MCTMZXsbdVC3OgjJ}+da7_+=c-I-ovWj!@;Jf zI{O=I@Y2HlLSn>x@Of|v!rJ78ea5dq?qe^IdGuAh{9eMR`_99>|H?>z-a;_zxk83UhGMABO_pLnI?XN*_$*SBBgH=>iLKJ*A5%qPYf^RHn>)bl|s zY)w_-I|F-(PPcnu?eis^H^>3Q(!Y^H@lQ!Wkr&4gOBHN)^v8`pjxZ!Lgth)LPltR6 zs`(8@m2n;vQLe^^s(oSOq0z$ci7MQjSi@XxB*}3f8&k#2s_24&c6F~Ci9Yq!uf|g1SMh_TATLW6?Mur^kaFjtKr9+^c>CNxD z=i`^buf?W^xny(2kyoFLfuPzhao!20h+jXY{f^&(_VRwBxBOuqVH<^03N-obK?n3& zt;Lhs27CMN6(vnxG`w98A6y$vGbgO(J=Ud^^T~uA%tzsT-zQX=rHEt0oUrWyQmHqS z+olF|d!RTrSh*X13RdLE1;b#m<1f+XSrUKv@EFn>_p-?!XMVJE3iqva$C;nwVPts% zl<0;)H|tBV#^@DvEsnt8%~vQlh$!12f}Mw~1%;8?;`;lY;`sw!^tM_Vy!?lWKTKYt zv|tIBC!KP;_R zvGNsx-%ol~ohLksE|Pw^whc0+QNmNLbU61p2&ZIKqu=~cOiX+TV*}?4S1)U@yq!MZ zbKSu=Tes1si~10{w>MsC9>RS;Hlly*7pkl`LW`fFlKxrEF3;U=i=euL@AuzEho(x& zZCfj@9X6ZfmA8ReeLhcA4W*j<=6tbg8;xu_$K8UhSkGnv`}mB)fyXCOVMjmgkkQA~ zP6J$etsmWo6S!k)45#Rc;IwxsFHrVG{jtsDsPvGI8tH&hY!+B)Y!Fpn1HU}qK?@&t z!v?QhczdiGJiMmRS)0=!94v(VEan@AR=g(74c|=tBt(=iN43w7#8;_F*w!tbKF+*L zH?}?&Y#S5Um-X<{Q)Or=#NepGnAb0fZ$%dK1hrk%^Pn;6 zq;3bYo+aMx%7Z?=y)o9z0Cm48;Ns7-@cSG~p8hV1?#5@4-T}9Nnz~xJ=F^+Q*A2nC z4f#CpK_b5VJB{u}--9IeNU(n=!~4e@;r@Rde_;4s9HhOGbM`k#vuFB~{rBPcYfm+# z`R(LCrRRj@>(w|wJC-+QZ{it0svx;=Hr{vE#BqD#;8mY+i0Rq`ExE`s(=Vgtg`wk? z-06ls^Cg11$u#cXcpdt!TEM3^Ch?UIy1a9=9bTGuL)82-n!I)!aoR>r%FR@uubICo z`H33#ez_NZ-$}yd|5;JW=fk|!S%#(h7P#8l3(t7;U@y6Jx+nF4HnAO5w@#zx$=Ouh z>dKZgby*>{L5ymPW&05}Xg2-4K_-NwrBz5%8lpDf_>60;fv97 zq9cv2c7%dAi7eYX0MGdhq;CBOVOjK1vHzJ!NWUHhCUx5UTqYHJcPyUHlBE^%qt3g89Jpf ztmGitjtrA(w<)slY(6XcE`?hgzX=0>+@ZOf(`oDU)u1r&1YeNs<~Q~_l<^@J&-R<{ zvaPgJjQTbMyDpBy=k$vEs6GrYkCD_eT#l=!v?7Hetz0xm;uap$g=Athrs(pkp z=5HxpdnbHa;UZo=;z@_pl~AVl33`~Lg8lav(=d%rT;8#he0s&f)m>#gNE!h3mo@O8 z?9*@QTY&mw6!I_;|LfCC!NwAy*YUg5XVPkM*gbtHo@2%iOKlNSdyuKtT=WZhPepIP zit{AB_>JOOTKIUqK=<=0ZF>)lNIXw%^5HmZQ!z}|y#iyJo>6w{af;(9;`#d3JZZrJ z8obRM`yNZgl>=VEmf4eG>xcbh7p(x9#s=KJX#)2@Yz#KXr|=P@)j0Oc7FylxfKSj| z9N{ts)NNt}h3-T7biEHh`n8h_!ZLAUZJ0D{x+~oIR82ar?T~Fc1pg^BtCy8RMCnWJ z7UKjfKW~Ee-8v{)q0Ui%wvp_;1^9i#HK@A%OKcA)!s{t<{A^$+99TA$(R?_N-huj?t%WU}hIIHvFdrTOY_NPA_3WF-jblH7n_oL_ZnEL}Jt{Oy zK9)xo55o(Jb?`V>i?^)YPwVyWkgtUz=B8zejdEwO;{X31#oVP0_V(@^}I+EYsc|_`xSYg|1r$_$LA(2 zVCV~fJ`peo2i4CZV>w06Ka@M=FgxV1C9AypeV?cf20w?h1BL4g3U`z#W6iUqKotk{k(Qal)vY}`5I2> zcEn3M=uJF#X?AA^vvSz{rVoCy6NToypQO9tmKgqDgBW-1moV`5cG9p4AcdK>!r{Y@ zcvw{pUHi~LWw!_7&G%FB*6#xNesTxC9J`eE&$h+Gsc8_{+m>ETu_W)B?G%Ry3l>fz z^L7idqH(ksfglj zHgr#5jisL{NB1GjQ5qnQj?AWm>u2K5kII;1r-e%sQ?cO8Oejw%XB&?u3h5IH$sNI1 zX{N|^HA=khqAe;`<-w_cWc8tL6x|DzWw+=O2y@Q?2Or-HbB4I1@mD2UIQ}V5HW8>Q z>bzLlz6u`(T%>y@(cmjT7XzJSQLkG(g*U3>&qP;n>k@>6ldI{~kpU1CDMS5#chbCZ z)9Lx!!H^NThsOG(;ujxRthlKJpVSlS+&F*MsyHZyPnyCH^3mgmVlu8yGJ&NI^X@CVZ)LT0Zu6q?iyyJY5x1D*~Pzj|!|mx=4>`94{c>-`ym-^AdBIlXaB{a!lU z`G~A#nvZ}f2Apo<98LTcC9C=()T?X*g{QeN3%!|J>Rr4-987$IuEZ zjK5zFH||Jiz0-bZEIy5a2Qr}TZYY%Y_Tb`ux_Iuj1a77q^3w)W)=8VoZhfxtimClM z`Gx~6C|1VgW&NT3YCjxrG7KP2}vl*u<-hi4eZ~AZd5T54f zNfl!}$vponZFS7X1uG9?U0ONaSUr^Y)oZeWg9>@?z5eeE99iX#2lm-rfH~gE>~+2a zVljylUy0!GAPIi0R%7xi0Egkb>GXt?sN;ARFaF#{RbKi$zpo`fOy~!#N|8c+%nZtT z_fhzr=fm>~14-HD(Z3$;`ghA>B%NMFJ~Li{MsDE+J-Q?`o0j9m*;4SEVuTK>)5Km@ zd33SsBB7NJ+xS_)w(|?cvqs48lSXr{!+5E}UIiSK9D=$BRPo06tFX?h4i0t=H~_nw!<8? z-)ZB74jZ)iwFC-$d(tGIS~z~AlEgjQ6zRR1zPCsB@=FP{2Wn%s%V_Rh?*vH+U*{OYVfwJDaF_>|sj0 zu!y?%jAd2lokC1q5sbB-iGdLf(8ZU98oSFb*A1gtGO`I~Z92+)MpN*ZZUt|SEJls$^I|z!j)=2$KI;d*HWQec!yJIcD7hIVL9lm4}pCP z^I^baOTxT-b~L^U8z(E^v!^YPr28LfrfnxbaMeq zW%RnVZZ_4|`9m4MT;NGkP45GoP(*{1(o1bc#DIUg7${ zy%2b`MJ)U04>KOErVUHWAlXiq9~2*^EQ^Drc~b*jUN;DFiaOZVoIyUr4wBNH5K;Hg zOX=Hz|8ixaD>peOqvZK}>5JC8{JF57aE3L+9pX$pHE2BFo6=Ws-0h2-YU9v1T^2Rx znc=V$K?&)N^t;z(;mfd7SYdri zP%F3&Dyf%=2i6N&x8KsO{^MCeqktlA%i#Qli+PgrR5FTRLiZ~BW7(N`IQL~49XHlQ zWJ}ysC&QoiS@5#|w$apW0l4q_TX2gX%IPXeVw=5%;FoeqY+iDn=kBT(E5`ZJlyNS& z1)Ml|lm@80S%r#zinw&aVl1982ydjzp-h(=Z}t2}N40*Ez0pguTc|2sJth~nIA`FS z-aD}OB`tVAGgfS@ucU|64uXk<|B^DdrhKAJzrWIvJ3j2N@;ctL=}VpWa>S|A7x2Uf zjqrZ4F9xJ7V=w*7=Os!%B$a!$9elG%uG*k^$LMae(4l8+zFRNz60;| zB`~^TEG?H`K=UI8bN$x`wCOt0v2hi!rF;#|DE>)BYDL(#elC=0^pJEr;l=J3&0*0= z6FggTmDbI6#_#bqc;>$_u90b@6!~r9eKSY=Zq%Pg*BkMY%oX71_nG5kZ_{Y~E>hKv z#8$UYuu>QZD`qam(21uhsyGh*{BlCCmzC6h=^a)DY^FRFbu>Bc$rr zUWG1Wd^$=TqH+f}E-ip(rP??(5LsuWEc!mw;FvYOtQwpxJm^fpZCb5wzVg3cCuje zc_}!m)rS=mydlDA6ra#pAPU28z^|B8+Pgjgn?5!1rRf(1yI*(2a$7CjSCBb&qoomc zY|6w#Q``m5%PrLBM?1ZiDT8s&YU5t%S!sMA{9Or4i?^CO@Kw8c8L3?y@8^LVR-lTYMyh=o10I#a($;Gb~Oya8?nto z?EKY2f$}tbarQSEx&rtP9L|#ZNB{VGE_J>b491xcCH7}*`Fxr)+FoCZ%k4JfagJhq`uP|X8Y?3`;I5zBPrAMDt$4&TQl`& z$cN7bTgBBA?$NQPD`Lx{1fJ^KMZT8|pmACtF18HU2zV0JJ?@MT;<*tQ*h6ipAfBHu?87^i(ZP zls&_WDYK#6r&0(UI~Qw`O5jCfp0GNw7rHz3;7Z>~_~h|W%00D%FxZ%{6}}W^Tr-1R zEB)!p?A;RcK~)e$Bd}_DUmD)$I=!%$=anOu)9r_z5U4qX<(8a=s-gR8?HVevpJ^<{ z{4qx--97v%{63{W=oCvvc7s{XCDbs+mH#_ti^8rugpwekNT!)I^yh$|Pc+1oX436% z|JDg~qHoPtIHPS7Jg{-*9>y!tcd;7Gc=;FpT-L!ePh05N5HnKMZxs}3GI{J2mf)+>s99^KO0u?blnx)k}u=;RH3A$fMV=w*Bg!!`E1)b^brm>Fzj$ArOTEiDIq<$*4bL$x5>J(cb_ zw~*g@CsqP?y8c-Sj;D{oJB2l3;-WV2Dw|$w6*?4N{9FjlEBxr{{b^#(33F_R1iUhpXFq@+iF_IJtATFze}hDEh7-eEt*5 zhMKOluyHR;uC0QYunst%bf0#eal(X0Qz%Az8(eDj#0T@ol75()klMq5dEr+W<@i}_ zT{?_nJ7!a6{&R}nk&7dt3Q`Q^@qRZIHrLVQ<?@9MYJi4cX5@Y9CYc2N5XO(lMrV0B4D4Ra@*_NW*Ugi#F8Kp=`>DdcPWyAd zixv7MWYV|gQ5;wq3wvkohVDO-Ayh7k8mGoW!j=FuF_{g4*{K-6rvYu}mr=0qc*c(JgWzxCb=3Z?e^aPo8>bFmCU8d@P%GhSFx_JDND-bq__+=pjU6Ur^P zg1@4+iC?p)kxlYIRv2+x8m{miG7?sB*`jnBcvOideLn>~<&RM74j0b*enqV6`4R5+ zW>B0KNkhLB(W#~HVC1=bToqG*Rt-sFkySR>N!IcUYiqoz5sAA)q*9G>Dm=XFBdu@@ zMq}NV!ga@CxOiA1-G8xNxRQNb5aZ@?h~I8W!p9h>jaCzXeSO5uEKh45Yx4HQ?)Yk$ z4b_~rLhn^G@Y7c?IA;eo5L}vtiAEBCss+rd-Pl zWPZ*|xb)Kw&%NBr;ZLQ)hZWL;_WHITZH&2K* z=6(B)N&Fj|;MQXuT6*1-Po>WWkCka`uYQs8nmqV?hY8MT)5R~d>|xS6D||b%O?=(! z9+<2z!|nGjk#}ei8}-=5CYdTkV>Uv<$DLF+u@&C-7>{p<>9C38LR>no0jl?1hbbku zD1UAa6;vIT{MQS4YH%TavVKkz)b;U`oHIHutraFMa^yh~>Ga1n3TCN{q_fqhXytSX z23hat(h+}QeXcRtHj3c4zK7VurXTCQvP1hF+v&*J1io-Z1&{pqK{Srpf?-bwk&>|u zeBIrf5^fCTXM;YG8lqazh>y*kPYzuv-$a3B8jc@L=MeS)E;$H?KO7oOkx5qzZ2 zgu-8&QRjmlr9XQn47G12xw?De$coA2quW3^@9)FNgf^F@?!N@02mc&jepqAEL)5 zxxArd3yB%)z*@!>zYNyp>F*bcBLc@_)yaeWO(BbyHMz4#iZ?!RH^h63rwF?7cZ7y( zIiTn=8g0KAV94c3{Nqsyzfm&=!}0y`Xhpts-N!6)SQQMna zzc)|yUx-}>tu!T3pUcB)==+PCz3MW}vivT-KAOw>y9Lm^?4=k7J395qv&&KX5;&fy}#AZ{4izMl@(p9bT+pj(tQd;!QAYw~8r z1rTtlzgV>7k*N9P6FA@`eyM1OA70pFS8XQvu6rjgJAaZA?)`<<`@gB+>mI5+ypW?R z7xUL&8nCJNN4P524J~rIgioY|FIUw;;=M94_qH5Q(iwo`r|ibe08MJx{GE&@-=Wko zBe6{`hx)mV<^C1E__N)O-2)zzuV0Dq>-S~QRbBymbV7J*W)#Q`RfopxW$2fB`X66P z$#s)E_jOVyg;ERQ!ZJfT`Scj2j=Bp`vwL%NaT&Esp-UqoP-byYaeGTYoS~cvsxB|#ZSV@t**cdq;SjjIQ^hN* zenQ&1uW&ga5WbK34njNdpch3r_f#=8$t8<1k~VT&`XLtZA6ALh#4n3%VAcmG zO!JSyVOJ*#_1aa$PNgKHJAfM|UnSZ7I(+B#U$~@S53P-hIQh>wTwB{qFukxCo0K=x zxUn`I^(R>@j{8hbwaJ(___u^kRPwy9N~}2JDR`R9N0qOxWOj7`|8@8-6e?cej=u|e zzW+ArzHdMF(3%FSQ}>hcH4VINXN!e(jgV=a#@QpwX#I&;+@jJOZ*{7JOw@Fie?pMg zsR=I8J}xyDK3wvpU)|^#G3dY9f@2ix!KHmV`H!)~$0>nmZ##lh@^j&dcP5A4zm9!E z=hLI4CvYe~n(3n&d-(ce@t(yrCd-zi`SxoW+Xrz) zvp$zzuz;$$DP-8QTvDq$T<|Yl&tE1k#qr4+6d77el%ztM2VKCMPKrk*^Ep1DS==Ml zz)clx^uXVQ-_@SrEh=ANazL?2Z=QkrB{@1GuYk{|`(xYa<$Td)3@y3Y#j$zeIBC#X z34{gW??+l>WL^Tj7er&(dJ%iitrz-sOTo;8=V{<7PqHeCf$9l`e8%>=;62OwU#~0C z?v<$&Tz7{J6G!r_V+nAfa1Pj7e}qvj-ASu50~Oqiu`up61m38^^CNc9G*xvzY>>@* zH=h%3nhySDJBf8<@vwOT*Q~eTV-u{0KX`8DI^UZME(+$5>o4R7|l%hcEO2X)>GVokLR z)IZr5YKF;h=Ve6Yfz~(_uE9nvEiOBx3Qs!kz}BSgG%0W->*ai9g~|WswbFvSy$VF{ zEDL@vQGs#ZVK}%W8w?w-gZG&MP_VUzzeGQysY{f2`k^qKOgV5Qst^ob=wYC|v#?fv z3$}gu=Q*rRvDu}xb;emx6t;r(A}6l-r6KIw;viPtab{Bp#;5YytUWag2llC?w`Y?D zzw{E}yXhC|ciIY{x~>ztFWi93()#1&rQ7IZ;YsQ<+Lv#Q3MN%+1wMT=4ou|x@U3mt zaAM{J?(`iAQI$t&zq65G>SGQM4(h{p`xtN&E4c`%pHwiz?uJjs=1Bwbsjfm0qlhE69-+<3T4cvc&L$AcDPV57kMw=Two z=G|E_ToG6G8^(Pn?k3A^i(#(&ebM1+cgf_vBk;iixp6jC7of+p*hxC%}$#e@Hq#6M}}sbMUrx7-42a(S;8s zp(cg2&~G*UXXl1p`!ABU`vWku`39a&tQ+z#)_uxj8R6J z^HW)?X#oCKnoT=elcW)S$MMMgbiOz|6Yj4!#H9B7;BVbiJpWuDHEsdg@4rN&UWHR9 zDU7RlmL|@&8Gz?P{CU~6L$LexXL_}69#?cmC~Pjh05-9qpg;7C7?Pd`76&^}T}2Zo>!@MJ z`{T5vMUS8T2;#_=V!ra^r+C!*x@7w^ZJabT5H2e`0zGddeypHFk=s?+uE`D8->n2>L~H}1L4p~nYw-vdEBt@7o6<237bka(fXD$r)Bj9 z4_QsDJnarcvjqI&E9Fxq7h(4}OOBdqib|)AL9_X?I6*@dt>;;DP@)CDd$5_+A9d07 zje2lT)*4f~9hEw}siL^&J$ybk5T_rVhbzwig|IOPd0UAxXcr!#mP>~CXVwC4u_+NB z?dpero}LGptG4{eMFuDJc|sHV=fj%jzBI3`N!)srKLR};to@EX`yR=2O z?T<**%o83iOsDd`QFQXRG0psZhaa@WVa4PZSk_q}Nx8P1$9N9Uz5Km!&C6a&*FK z5{~$&iZiJYwv9344KdqjMbiuV;P{z%=V`chI|5pl1#oJA8~)f-LH^-ZSTZ>jRy`go znO9#U$W`2g3yFte;lM|1dh3|9I%A+vXk3ale}0QlG>q@$r3+gV+JwKycJj{6Z=sNg84tscc5B!h=1Pb!CM|~7G(nxF)ZlRg+awVIez|E=wICrSD#ei zec6Rl%h?-ot*RDEKdcq{>qS$Cg|g(*E;X@l(0um&egWs)bVb8TGn{BQMsy!%BzUbn zLHnNv^9pFDWp~d~fI=~Oj4z}nhgQ&)t^tFxEfkiKLx=7hg2VYUp*h=#k80=Q-0!1! z=oEcy>ZQtUH;zm1wI@h3jt}C~n+5d$xrx1s~Tj11TUwrp4nqOZwLKUsGm>iG_SrNKe-mZbK2R2jP zKt-P3ag!#_8IIRvPg9^@v#4aRCf@SyLmtE;bib!#JD^U>@MCW*D=djXgwvq-*f_mlVe%GbTI4tPnCW@mBlU7=Rlk0E-_b2 z4~?pJ(1D{rgr*8jgfTTjf&5B1V|YLqo_(3%nbDK$z2Csz*3Uxt{9GE*BU~uE zThF6v7vh(Ht`+1jz^e!=uHI5WyOUSpQL`h|Bc?abRfuCJYM~1?yC6$t5XR2Xr$bhw zc+bwE=wtT;3VvmXekG|Km3jc54t`5fMk6p^@jA6_Q^WmFZoo&a8NAbY0v;zFOfO93 zr^~hI=9+s@@OUB4?5oUIR<7W-+HknC=^?2YMPuG>d5Ocfiy+t7NQ=I$q%V!3bbZnh zivHmuic22hth1{y<;7SuaFpR)5OR3-QryC0Ms+KhwKXZV&iH z)eY%F?!&jxK54#i^~y4Qv?&{^lwwdYUc|~04;Fe=(5SO|sFRZqDyczy%{Wykk7|am z4=v%8{!Uzzu!_^mRiOG%I4}K?2@$WgY1{ptyyv?k-b+44a$~Hxd6*i@Yzwc=aBGI! zr)ohkn*j~)s^O2d8GN4A6W9F9$D)ipJmEf$R0muU3k{d@=&E^i0}Rn4<{D-9^5BP$ z=kWaRc5wRSR#<#A7>^`7ihoadVdHpRSQGkADml=F`6Fd9V#+{*5;gAk)J(_@t%BjW zmq(w!Mww^as1izXJ`V#!CpVsGbCmjK?t<_iPbEG5r}4E{88jxU3l_Q;(TISaJlX9m zKRKt36&g}_vBC+TU4KT)Lxuv}_ytje|GBtx6|7&@4L_7Fg2LjF(xUQ3RF~ffX1{#t zvQ8d3H@so#MlH(t?8C{~;drN~4tU6^RiHRZq=O!TXnpD)-TajT*X@`J?B@{n$8meVmam%41`l{iHyIaF>>4@X7eoKR(cgCDY%7sY} z&ATM*%2DSllkU+Pn_tqicM&gMP7uyn$8*WrXH5kiDBAXjk@AMcZj zN1u-p#?LZm{XrK&5_wfJY=kF|eYAkgr&&Pskp`F(E{6#wmgv(d&!;Poix#1usO91= zX?(&jI$)sA^dM4l|Fx< zbvZJSre(ox*L-nL+YJccahw{I>d8cL4VNwRp#>G2_|1ZuC`?mggQdz?7j*+BHjYLc z&vTIXw-mfiWlENJg|fs$k)Muk5+(hn;@2Z-(hr-jgT)&~T#{4(E4ydm-{1&NJ19#p zm2#-U%LQZ4@1h}z@f=tYMb9HI(G7*w>?yY$zelT)e_Ap0kNQiqI^V&x!`~rK-JPG- z2a>t$QI6X$(vm6G^!AT8Dl{E}`a&c8alsuIw#16M@k;o*wTk;y@1V=p2WWWGZYVkW zo~rvi5EDnQ!^~)Xl$&41=LRa{eD@PPa*P_7=-i>&yBXr-zr(S&c{TMvJpz?fw(yEk z23S;mjy9CeMgK-w>6`H^=+qtt5BtaTAn_(N9hl8B<`b!3`XPMmG6h?FLdk4n201$x zgTIOvj{3Wp$B)zIGTT7>^yRrQ{_9Z+H+n=nZB|IrE)2l`RQJ-ZwyVN~*Rpjxiv3A< zfqb3*$XrYr69p@>Hsk3FJyGFo4~}pO1^*8&e1D2RD;tal3s)y>xnqQfBo^>mZW=uQ zJPJJqsq-}TsrY45G2>)Q7}5|+nu;4R`J=1L#{E6H@YD%-wsH^I<1VcDwjbR-6LIgu1;)S2WV4%9CUk4 zq1gIDDB9ajWh<|6LWvB`$acpbU)=Fi%U*g`w2NLoP{&D&Yh50xpQ8Q|i}1*}rBaK; z1~_ZyLq-N$g%NHh^xo8#Lotb4x~k~m=@a7P1Y2-Fz7h;iSmA#YMxnONL8xlbLs$S?8|)A(fLKrXm4oTvVpf%4BD!?~hqc*Dm9 zy|1c5Td9E<=U~mN%x_8+vg*)ox;>s$Ru?oUcjtrgLA2)KAMiaL&v&y#9`JG*glrFo zAM-xJf}dyU+pjHfEhq&?rX)hb4ihSPf0tC&4CIc;i(E3b8x-C81|Pi^qxJ1)u+TmP zw1({hlX2Vd&Q}M~VZ$swd2SXP-r}_$a`bjVbjC{(1?x4 zm|F-HUGd@>$xK*&crp)Ol0c@qrg$xV1e!glq7w0fxc7)WJ4W4t={q{;M9VW$d!7tK zS17YaM=Cn)@y4OUw!oDDJGMGLh#H(ffaiG?E?7B^_w;u{-P)e(y)~XDKbim zvJ!=Ozs}K+mWBrHA!*Rw_8u*f&@f6$MH(u4zs{)-g_1<1l+sR%DCOJt54azX`*H5; zT-Wvd>88sC3()OEFB}z$tZKhf7Ga0vmx>F6OG$ z4(#?ih4lq>*3ebPO&{7|n`tT?*8az4aUBrgv=}2E>_NZrw;^bBKXKo@Fp^1$aGW|b z2_}bn^7PJT>Zr7#=8&u87HB}@t;e#-q=#_(*=8tEKMe!gA4t|TOc4@h#KV|26MmYv z7JCkyi$gbhK!VLs{#~3Q+KYJ9CFgG}fVKzmbf-s^xPMtc3{u$1OY;(Ni=QLieyM_sZcgIJ@UNotPH$n= zi)6~3upA~0jDbPhC-6YkD11D^fG!rLiA~PE7-xMF=jzVFrPsDn#HZz)Re2NcQ7GC5 zE`ZL?DO5OT374Pu#!CZN(2eSk(u-A@JWVMN9<2(%C(E9In!Pbk4Tuowgav;8oe8gB z8uP|q$4RE`CuqG6#|K{`VPxOkg4T~FdVC_D+#i(Cjr^Y6H@OtY*7fBXFUzQ5?nsVW zWQJ`~7bI=%Aru-~DCCV_2hka~V1wQ%?7OHG|DHC3RSvT`_IimJxgehk3XFO3(r{i9 zsCrxegfY543Z!qVg78D$RWZKb6?&1f7eC(KLK0Ei*ye@MhX@w?7TkDE_C#b@=eeZ2G&$hOb;V;u|Zog=x=rOXl}pOX0WN0j8CR z8wR-Irl+y2DqAErPB=hvLL7e8ok=Hk92wrn358>HSvx|+3ruk;pPz0>3^XEwv%*{Aq+ z@HC$P`3RL8iVziOCG;t^5|Z@y;*FxQ*s@jNJ*E*} zYOLX902d93fe`A&(jlt;1XB-XbPTV?i&UI}zaZ|oMA)wLuBpHe~uH@n4fy4O7 znWlgHVhD<*C-GqVAbwr4jApz|qMI?QSQHs6dPdJQfs96-hOn5m5VTress= zVh-2*4|+Q+V7E0g7&6j=-lcBC2AA*PFr+Ule)uKU{1=7`ithaUTiY6`Tj z=!vg-*)nt#(W&wu)FWpft8EBo&6^Xrbb%8l*k(#bHMhd|qlKU(zZfF}_QAY2J9yBX z&G>#;G5T*e5pP}b>u2F>)LiC3$s&)c&ws%SanW~=c^`BYL&dnWCBI2x9HOTh0l zuE4$F>eSE>#yu`K(zlWfN>WiEnbVp@s%kp?=y4!BPuhY#E**yT+7r=vEr?I;1n{1s zgPmiRu+87&d~jPBHe^o%uX$2{~Rc=w6?wDy%CAJJ#MSvrtc)0h3+_G927cX6(|o|yXX4k)XNA4zKp=k$aPqeK9wW0TqUzr&*0&2ySZ1s5}$ndh~bbPZgtgw zXX4ngTLa~!x6Keg936q0%}Y^UX(GP3^a^e# z8?$n^6X2+Ol$3|$(6*3SeC@Q7kkuT3s}n=T+OpwjQDQ_d6)niu`I@-;+A^-nJ_Ygj zw^E$b5iHe-L8CS1=r-gog$~T1VZ};3u1t>~KN`uuS05xV!)UhZ&GdfMLYU-G1dlFU z5YEae!YRFQh&EURGH2^W#o9Rj8Ib|vfqqO5Rq)Q!U3g`kE6s4zNBqZ-CJKf){#6in zGi@M`8&goTa2(F@k;gAxt)kt(_u3nkDu#}k!l&GCaDtsXZG@+^VfiT7wdWT|%}#*4 ze*%u)TSBtahC-i~D9-(A#pgaMg6sY>(A6^^u6FA#&iE!^?A&b-9J5$DZP60cIA`Ee za3X|_^K2yEq1n7#qZdZ?-oXR4w3vf}!6)zpewbDv7^^*yG#i!E#%DLhWS>e%{Is4e z^zYGz8w03u!~h758j2rc&V&D(rGlKJCQq8WT>7OlosNC^Olw-k(4cuQ;K#E*oH|>= zu8VBw;4(AVcXzVjv^j#FkN67@+_&TJVefeN!k5(0&y9jFrJzU4DNq{n7&I@~q2aK5 zf`R*R-eWQX<&G}rFok1SQSePV>b45jvpFZI*|Ae#672h8!R=)a;aR^@xZXRME}qon z^WsSGo3Bfst#3)SBdTcl&k(qgXO6Ryy5W{RGBEOoCLIz!lhsy5C>^2A>B*nO+SO-i z`NveWU3G~KuK9AlBC&odS~;HR*-j5$tg6i7xl{@P@$mkT7GdaOSWR_Eecl zf&TX7Ej5R(XK_>|b5>Yd+YR3a_r-U^;?U!s2AB8-QlAI6MJu-ss<%)k&qv|hB22)* z8N)M?B$^p5jHfbn2)d#%iOMgKw)L>37?NX0w~&RU^Sd>!m!)IvU>1TPT!& zT}t0}RZ6CPR^uH{1NeN{W=W-K)Rr5!%A@zRy`;E#G7y(SjioIFr3Hb&H1ZiG_lDVnwMISt$I%^`oRgj*}S zVCI3Nv?qTuADDg%md&(akHX=Y7kB{FROZ1+|34s{zDqG%4Kc^Z7uEMXrw=w-_&2_c z=FHknSp~BEW``4>eSH)hf4&zN$OPbJHxw`QT0<#IB&<6}2Ct0qCh3e!vgpbX%l4z)F)d;x^S9Saf9uc4$XI-<<>b z<;W_rwzU=>FSr2SP1<7c6%8J9qY089oQ3dWfr`8$$Y|~rT+r^%0TZgk34Klf2zJu&nLJR|m@Ax))YhmNXmB zP9B7+8dK?z?O4wA`$-elB+;X~-hBAfa?vbfF1Ib~!<)X@;fCBN!V%FJYviub*pM;! zXWV`;%PXbi^bASOxjp#qNC;KfCqs*(1Gj6*g64Az($+ajdOAKZU+RjTt_OuB&rYG{ zWh?r*q5%?PzEbfpRnD0|kw%-?v!8M-ezdpaIWaZ-S4E#kTzf|bmv4agoFg=Boh6#i zOTY*P57ZgCjr-`Nlg-zB>T@j-9(1J%h3o2R-j_fWo9u+P>Au#+|tf>z=)U71_@@=;i@3vnq$53DfbC!VMv4dl8IW7mLG{7{;%9PKp{v zoRDysH(UXRJ`uD& zjN)xOwW(r>44Cc{;Yg4R-0`WTm_xF7`BM~l29K8RJM|wc=qm_4lY$`1GZq~WM$im{ z&%(EkQ1Csq5EVAh3U%+)6_o4Nv%e1!I zn>IC>@*<%Z)?ZHL!*PW)W5a1M`0Rj-zFF~u!jn8W#F|SKmIzZi4?)lU!-Vg<&C%qd zKB_tm=WF#c_$$f)OG5fXV`HQEGC7URH1%-XQ$xNT8$e61R!Pif&FAlPK2XS(rBwf^ zFCKjJ2;Tk;5LUM-V&bAG$Qe6|pU4F8iiv~K%UccGhTR4O=gShajCW2i7Rq4yshK?b zO&@-(s>I7CTw?E@!-f6F$6~{3Lp)Tm4m(;7!2Z70s6q*_&Mt~(`A?uX^FNU1y8~j_ zgG_icm!xgxt6`{R6j=-@gbM>UqgUP{EPE%*o+kbH{?xU6!Fn1j{_%s-j)aIcDxZYc zdrf%5T_rq|RU#QvCxr=1y=d-@zoPaobMSroo;p+#aq{D>JaR`cU(`D&P6}LxmmA!r z_bXQM%{_5qb@WQ?laWbB8&=`mQJ?Xa;vQI)W6bT3m-82AbX(1h*NdvSus}_Cq@hHU)egdT_v6lFQ*K+m8pVQ6$;CaB zxp)3%+J7XBHZ@w}S*_WurYOSfRY$<{yQQdHKzz<}IPUD>fIB_co^|&TRaXwf zjrV)O_HRLW?oS!K)GXryzxA{`Dw4o570Y!)x$d|LEwreBenF!s^x6o#bbmVEyc9tD z#>#X300Z0+^bGErY?VIp8xDaT${ctll451v;_z8cSWtUPWZ@9oHak$A-euuaW-KT6 zJi~r3i|M=UAzWFs5hwp%2>+GjiwVz7@qyteI62gd!)|t`F*Blh^8yv-FM(j`dkX5E zZi^!n&r@}GB`hwJMH!m|xMrjeTHlW0T!|iMkIbXvWJle~y*NgD6y;08@Q`O3e04a76QzxXu<3p*nS}&s%XEsUuG!kESJ)C&99iICxyf7vZ2qK zk$id8D872FQfwR;!e3;M!jDPar9V!a@|4~lXilbhbUfhXUfn42;d-*kaT8WuH{kJ4 z-RbZjBbcOr6!)$fg;)Oh^26+4a&I-{_00;0%c^S2-g?t!I0A9@K;Tb(rkZ151oBbIo1ijY8`>Hvjw=36Tsw&Gsnx!<`eCw zDfj4cD6${UPfm_TlMTt-KHm<{#K>~$y-4ggZ=Y;NR#&Y|?m6vhQ0T z){OrNArtr0*rFn#&RG$4B(nH!{eEbsTO1RU2iF=#(X8Z9y#M(#eN9Ueg9gsWK_-K+ zXB$zm`3W}BvcdfD3b<|`0L!m7QJwZl@$j70_~YJlaf)9vv}>If@+L&%pwy?Nu~&=7 zDjINhrV@!y{)0P7d312PKF)j7oqzaFgZC11&R)MjIDW-mGG6YD_{mxq|BgPL1LR!9o8JBS z?E2HFwDu0o9rzOb4Gj3FelZNvOB1i9_2=o^UeVdlcI-Gd4gLRn2C7YW#iFXsJmH}t zEUO)d&+?RM!AvEzYrhU%qmQve&}E3KN)?A%SmImXO>8$Wrnvo}I)2?L3adth;oE;_ zUT;_CoXI-eH0Ld?JDUrQ)yF7Tqc>eTYK#r7#{Bkt0)9yv#^UgI($*AJ&WIWdcV>*k z4dt(?BtIR&@;q0qn1!z_tjV*R365#YqE);5pyb*x6egSk+jl*AxM?BH zrxctgGl6$BwhD>;c5t~ve|XucD}3;cqV4OIFngsx#!JKa_nEO+`}DhHbpA)Mo-%Jnj>!;0X z-t51ad`^?7^>-Ey`@M@Q8mgt=Zq$P$LlMok=3%#gJ#K$-1kH5tt}YZIJwkQ8Gil2AC*;;Jg6}Qu zA*`Bf!@p0Ia;NS`lzObergt`IIy#)sl=tV^n{+YFX$sx6$j9>L?c93rJ2>duv5E0J z=*YVTZvF##qtPjtb~BdMS43iD+G@78ZvnIHD$#1;8XWDkjw}Wr;1x$3ghpR$a{ZJo zXiisyJKOBoAtR9r`lZs@-xnaXSqDxJHHIe+*I>>^fz_4&Y5zkm&)Av_ckETLy=5eB zAJ+&YVv0zie-v1)%Hx-fJ-Dy$Q(?Q+LAaK;5#L$nOXn-7wef=mwR0-?D|!d+T4zFkcl-gD zw~F99-9~(LFb?IW>GPSPF9bz+OwrFa3xn)E=yBCpzSl{ybB|hfL~urD+uJUy%gID*EBF8NKk`qTN{aXaerv@*1`86jAY4 zTb?^9fxW$wVe(;9{L!?LLJP7e+2kxu*%ZeQ998Lk+*>**?#8f?=j58627h!0VszgH z7;2?28a8y}Q|V`g9((5U(LiGywly3KM{2-^F`vc5Egn>#TMu5tTIfvTP?p`ctz5~`7Z<3gS;7Xf3(cgLpITOc19ER9(FMpW%t4(Mf0%8fwV zrq@xzr-kUcqL9}PNvEdQ&TMyY04}!E#Kj%gsjPMjR_u?4FS|n-TXu1YBpB{F8epc2 zJO)0yNo9w+U`EJks8aHS@u>R>74juDP_jmqEK4z$bPth^RZj9yQ+pWc*6-{J(DFnw~ zL(y#QPN7Zj0*o+qrzOGR_@pu$+b!+5OyvPBIB&+%iR!pr={zZ(e@@HtgJ9*aIP78B z16n-ncJ zA{GQarXEYoS@xAF)IS?Rd+Mjt1-D;fugLkhvE?>b1Xl^k4Gxl(&e13yS}m@s9M8TL zjj*b08dcv{!O9imaC1XCtn67!BJZSXt4V^a)Q2P*1G&ln6_}VRaQv7{STm!5p8s;D zjq@jQ&j&r|)3okrx8XJ=UU*A~K5gesW3G^%k_=wya}t(U?1K-!iqL(+SnRRHPB`{_ z8ho-~-e3{Vd3NLZoxKSjPj|)ocV%$?xeLm>R5~ve6wxs(jkR`Vqr_65TYCE8(4$YN zG_wh)>@OtVpUQ@#%=wkaL&?V62>#$Z2)@~#6uf)w!bV3OT;BfhmKg|;bt#^s3#>6Y zRvlYbhYMwUYejwErL=6;EHqe`O=~@EDZ46-be|P+`K1anX!}UsAHC6AUma%GnB&HR zXK>hG8C~uKbM4|No+Wo3CqA?l-sq^}db4mo9kvryg8JZv>os(6@d36AEE1c_ayd#1 z@%`a}SSdK5T=+4VH&L4{4d%n8;q!QOraNyH7x4F;47CFW<-Ppu~IgRR;H&UzrA!+-4A9AuZV(#jG~smD`hft*bIM7?i+b zNf*f<{{eTpSxW~_sblBhiTE?wh<*1S#pKYJLZW{djEwjXX3Ndxp}UIU{WKMny1j#@ zL2J4B649KX(^UTTQ7e_F-a^Ue#g za#GlH^$N}JoK7nr5pc|LEK;!}r_?amy(fat4}S(4it60=_6C|!e;ECXR`L&dA58qT zgG6ZV*KZ+JpF}#2>R3T*2YDEJ44U8LeNd!H=V^Q?)Mgn%LFc)PDe|47h-m zXJ>Njmw4R0XD4_1m&2yaNNU<51DEnk;FfMLzA)q(Pg6O9fm7yV^WhX!j0zy*;odOo zS~56akKr!{yU8Ia0B`J6qPIgU#K*GMET?#z2H)IHehY6>MV-HRtF;K+#+%|8S!3)` zG>rQe-KOzMPidjTa8$6#q}=7V=&H<8spjc= z!YR_VO`y(A2ibP4AIG_y3tt!7!u7#f}=9+S>=O>V`Nka2f%rW6sc7Ql(lp-p(3}y3? zTiE!W0{re6ioRp|qkiu=n)p1>$$aod$lT%tMH!#Lz{rK<=i6i3gBv8c55(o~d$M|} zfw*l$3T?^QP12ibFmTf_uEk>*5hcq{rs`q-H4iSk8Z10$GZO0Owa~_ZG%UM%iv-Ta zHvA~|n6-;so~QAtU<IFL2O-LAijMv_txyzg_QT)%!l>=$`^1BT` zhTSUb@J*ZzEjTgTUtPlh|sjvCAD&RQsK><1c-V>zXK8|PI_ULwimO4x`n0>qT=Ot#t+Mm+j=+fBkTaZ47^tK83*adqjJ! zVed*Cbg}Et@kdhNMYuVB=X98TJCu}n-=_$e*o{gs>Irx zRd}np7B01oqs>P)gZ&#N9A>tW25!pX?)(C>ycO_Qc^SAk?uYWRBdGfQN}RY&hK*i1 z;^xOHc&zOdPQ5mo#ryqfkft5SCKbZUK?YuZIwsk%!m6dm;}Bk-nW(DK0d36Y^u^`S|69eD_KxjX2#49|uok zjme3S()3fBmp&OPeP)8r%Wsr4;{<3{Z)8o!)1=_kDcPJQL7&l9|9ad*I`(%wbfwRS z$<0SWp(F%ln%XiWAkmAZ^ zFVl);>)kLx%LIRye<7nS(eVD$98~D+BU(RSj@V!*^ib1+rzOYe zG?@5=aLT8BwDX4n?@4?rgx^U5pWaIRdU-gGSKL6G{$;xTD;=zk8VZ8K0x|WV6+is) z4F1kHz*Xt{Y28dy*7w)BbxNrTKl&PCQLQOHT=|$%It~d}{k3_)r{zqa5!WcXbIv0> zK3ASknH9_6kd7V37hR-9QQu(22T+YlcHPFP4f9;$K~0RIjvU&u3vi*t+M)p;ucMIRtw}E*5mMk$4~O|`}fvy zQc-DPH*~0JME?Po!6j)d&r|s#_S@E-u6=fZRdt@?=Ee{5&%l5JRXi4} zg~Olpcp_G)6>k zJ7T|>YAyz;*>8sC0k*SgDDXCMw9uAnpA7t3Q{^ekJ=6Y z`Kn?YpZybotwRk^9;%_xd7WV8u0!>4hw;&*xqNj;BUv`>!_zL0sHFLWVApU_T(Igq zbUZ!h{5oYJXYB3^@ns>jdzy;N&KI`e`L+~>KM3L?IWIwNr~&mjJ&|Jdk5a0_S+cn% zpiN7Z=;oqNWmYj1ve%R%Z#))G$5hafY70o|769Q({5f6D9!HdXC&d}6IBW1X8h`Dv z^T3NWaPQ_h^7wE8baSG(_rzj;+T~1ETl?eb7a@3~y9SicKM7^u3gFkm?_y`k7Ve%B z$;k#A|&yE;13GZ!8WFqK$#Po<7ML->bE9@b2li&mztPy6*gbVgPFmV;v9V_%kGKa*2rR@Zl%z&(vqJKko%`6U*7E%CVjH{3@Ey) z;PIszSiK|$yo^tRfA|@8ERKO2`nSm0u?6~N9TSFs4HCob2jSKs$&}c=1``{Ko?Y%g-yqoubPb(Mi1D)n!l-PSJ zf7oq`agF6*UU30J??iLRr4X1Q@#gjtL)>W)BJNL?ftlk*ri|c$9ka09VIKwFaD}$VpM;lZ-_z6?-LXq092*?Ru#Ji<_Wka_I-8cl z+v)jmUZIgrTpECllg;?jogPeD*C{Rb2*ivp1z)@G&Ra{zk(FW~oEERcx~}KcUSz^= zO%l0V;u@Um^XeCxcZnM$8=BRsmpVvKl;sp-L`Mw z*AG{*Oxhpyc6NedXFOlV~`DNx{e%zjxQfpkN>V>@W#t zJ#of0?tQVgAx6wSNt3dV7JZk<`MK{_txWQVRr)mX}ztVW{dzc0hOPWC?xDosu z8{o0#LYiQiL30nB5Sl>JiTeM8}$@pim#T?v~a&eNNYeBAr!-<@`R zgg()xyryUX_V|}m4yT=1?zjmSZLWm!e|@_D^dd4$Z>5^)$~f#oHe^3}MM&+gVxXV8D7ns%H|AKyY6XHH3{ zF6;{tIc3-qq)Z1lhC!+45%%cqP0vDy^1G>nc;J9$NpbvN@K4wzZqsptGsmS=^FBu$ zt5{B{!6j7ZqA%_pdIuAQO5y%zV?M6w!OOQ?qk4BgFi+2;HLd-@`yb2L@Ac)YSE^{M zjS2_G*MZrCI*H$z&3Nv16b#>R1DgJ-)476F)HxR|wCh?y?}|p!v}~ZP@*>g6K!ep1 z^P$;bj%XJh!-uw~lh+4JoH+R*>@IYJ`Z^VeTQv|f^BzfOWv$}Cs$5V_T*V*yxuWiE zBkHe`29<%;WU?_;JY;qkc4bec@3M0Ir%r~CYP$YoZhJgzHW8X@(?RA?Fj&l2#)yXn zv}*lKE}iumOqYy71MZGL!jgpT=4Z%d<69xMuPNi`4`gBUNtoqV!B@P%j%lWz7 zw_*UCIGD&IOu8Ywabnr4wNTij1Pe?OIjM3rfkn&hxp_1#ymRxM;Fk?o^7vP zr1URJ$RU~VxL-I`g-Q8EsRuW04HRyeE8;`z>Dcd`D%g+r!*gFUh2i2Ue(Wgl5Cf4a zt6#uc0kG^qDJ<qJ zIxH+bpU#plS)P+D%dY;#ux95QIAeKRe9$}>$7@%LW9P_XL8~0t)OP0$$NTb^IRV1h z>&qa=NSS(doT2Qe{c*;^emG6x9$en|j#k+faFN$F@!RAsh)WF<9$ot?INZzzo2UEH zZQ=n35cuyl_~gA0_LT}a{Q5j$OuwU)eX4>2dLN*Iw~Z3(^D_K+a154$ALQ+Efy72D zerMh&PG7te&fb&Z`oWknoqF+-}6W zYxMENr7Wa|+NCsz10n_{E(y^!g=;d0M^J>oBK zPML*g4y@+P_a~u!vM#3IoP*z%EyblD=1bFM_hV|;18**uAupallg2%1)N>w%A?{g(!NgtxbBy&@KNzNm)$KR zqY6WAj#0tL!cX-5Z6_RArinM7jKi2OQT(AP3XaWl6MDRkX z6{yMkgnD}QKp(69ds6ww&Cs>8lJXQ*;9$cOU}#=Vce`ywg)0%5;P?T4RsIpzrpMFN zwfa0Wdk&AV+P--dVE-BuQQC{yb$3TSy$LSLB%x+%MV>Bj78fdU@Qx0YcB<{QnfGX?3zS1hg*aIs|NVsTp`|S3BbaRItU*Y zPj3=!Si^1yrwz>k+5AP2VkwU)qm;#dM$NFW-w1fQu^DEYXHr0~7CO{aNay{WU`D`w z*k!j}R6dsvDHEH7-Q#MpIrjn7ezqi~jv#t-_qgDBu9x({sbs$AR7?REP?EoIJ!kn{ zz_HKN#Xis7Ktsl#I}e_NKPRfemJK1cdM0gpeH!L@jORbCk$BSR1f0*CgOkfbc(g%Z zShYomogQiO(ayoVDfJ!L_?^PlT9YxOW*6+V>w{FfOk&-kL=fBWh0DFYn5Qkj>$oeGxw z%&BloDNX;}#eI8r$2DV3P-%7)KHL^8TzFpwv^5;%>a)o6WN*%|FUQKv1bR77nLCqa z^7dh$z;==%dey7&qhHJE_ysqi)2-)iXx#_LYs1K=M+~+v`VR4n(!lB3Ivjq-lwWMI zgKD$M_y8mT%MLmL>az6D9L;((S9#Y*}AyzL-m;MK1;Yak~8VCU;Hz46Dh1>A45l1uLyM&Pn41Sgf{(>MRaqQ+Px-%XNKXl1vkN@ML>N+Ti$v5sF1PY6$QRnM`2Ba`MPp0z5U1HJEtGu^Xsj!PG641 z-}7kknKByt{*0Iwv;xC+1&Qg}eQ|X2eKzkqk@v}JvVPCmcz1de#p$Zh&D@jlr`a2O zD$K{T|H^yTJxeNI`<)sdJ`+wX`X#>k?*#?MYvSDcDWFwZ!1jJYTsdro*u72{Q<{g9 z@1_!>0684(jrjZhWtgZonJ>mi@PyzmLc5*;c-^}NvxJaagH}1=&rv3WXnu%sbH7QFOYFM7CBk&}#zZtb=^$%i6jFx$}@n%#AA<^&ZkYx=ie zyX|n3;eEkHJ{pc@g`oBQG0>p!k2UIYNOFBQq?o@a+jGXezA1$?Qm#1HTgu?IC{>p( zr+uuRF_7dUa=4fCDTx28z*8&ZXkmT`jsF8)K?`XnPc+k#~O0y0_g z1y0}S&vWjNVBe8Rs8i=J)@JJ9(}?%va>12kW(838T3N0#-U^9rmmy2O3qC5!a*F;z zitkJocP|leL-a7p_*zOfzeF*?e3y8>Y8&^tVa2t*I-u1;7ORW(#O6wQmQ&~hg9m;F zlj20Dhl?WlVM8-Y)3w?8mMp|yi{WD{??K^bFSHIC%}e|W>8+JAYu-dmYO=-HuO}oo zhbVDV=r|fDJpmS*4Ee#!(`XcbfFBQ#$B#>AaF@qw;k0|JQ2Q_6G}iCN+SgK2&b^LP zRM+$P^TSZcX*NkWA8a39^8wM#_xr&gVV@! zrlENJXBVv%7g;CA|}NPP-2Q&cm?q zZ3x|)sdT$6NDsZYcG6qb#kgd#7j?NR&Z!ER5^K%R97NI7>?MqL z7O`mDPMkRDG{?<&No}?zG;!g6LG$D=b~Lnv-e4ogv+Nunq}kB^jE z!LQbxIL%-%R)76XEgQ!0vQ^#S^V4qd>HBgH?e`9HeK+7$sXT0vn*vc5I(%u76ygfz z^Hf_qD$E_khIb~T+okE0(a;;yXWynHrmljY=O~t4HHNk3Mha1xz2U@)ZS2t!2=iuN zuDzPfH*6+KuQ;l6l4&j+Jk?0y ztM0;4;G)@+rScoO$~_UDTvo;Qx6{z8xJEMP z_E^ZPOMqXSf0OLV2GTw~gzFt|;7$K4LT(bEjFvlJxYG--=UCEY&k^K*vk5-iX<~87 z5zNRDICAVws_kf_N!~voN&O&^cYh9u?V!+8Gx$W$aL#&cBI>3l3Ng`>ao4+XF!T9F zG_2Bxm3Q7!?e&K|ApNm$H|93*H{`Eyrn(d8Kp8iKE!fgBG|sF|>UwR~ z!zq%-MyL7xz$5xD{gM=sLJ_`-jLQqYok@Tr_7_=OcPXQ#bN5L232--0Eg8ku(tLPx}K|n z5#K=Z==puL5T!)z@dylV_29lQcSzdj@RjY`$9WK&ZxxM72~jH^AiZ( zQ%kd(ieTfSgBUWS=M$oy{X(xmic1#^*Oh?ZnrvuX=Ys_nCmaY_pp2+K!8Gm(X`(I1 z|EmC@b4Zw%JOcZtZhX;sMle^YQ4#kSLUeL)bb82=1p{R~PN(wIiC9_jwMSv6hL1ZQ z!f$mQDeX$2uHM4cM*y0}cK7I?Wut6RBbEl~=tGk$y63;;gS{^3<>SiRoTE`WSV5OF zy)f}x8YYGHQ(p4{Dz+H;r++U@UCM`q_CnO_j?wb!FhMcBRnVMWqUNYfj+UB1opYUi zWmDptQ_*6RlNq-7Z|&Y+Z_6W}5DQH*n6`F7_-AkYGmyz8ZMP}0KuP6`GFZOmELK%^ zQPB8y)LE~gzr}#hJMP10?|ja7cucl|LGbHKuV@ Date: Thu, 17 Oct 2019 15:11:09 -0400 Subject: [PATCH 62/77] Enable TNG test --- test/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Makefile b/test/Makefile index 482d20b925..916fd699b9 100644 --- a/test/Makefile +++ b/test/Makefile @@ -345,6 +345,7 @@ test.topinfo: test.gromacs: @-cd Test_GromacsTrr && ./RunTest.sh $(OPT) @-cd Test_GromacsXtc && ./RunTest.sh $(OPT) + @-cd Test_GromacsTNG && ./RunTest.sh $(OPT) test.ewald: @-cd Test_Ewald && ./RunTest.sh $(OPT) From 5dbc0172446b7faa0034c7ddfdeeb4b695e93a0a Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 17 Oct 2019 15:14:11 -0400 Subject: [PATCH 63/77] Protect TNG test --- src/Cpptraj.cpp | 3 +++ test/MasterTest.sh | 5 +++++ test/Test_GromacsTNG/RunTest.sh | 6 +++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Cpptraj.cpp b/src/Cpptraj.cpp index b7839bc2bb..627e6b4b60 100644 --- a/src/Cpptraj.cpp +++ b/src/Cpptraj.cpp @@ -223,6 +223,9 @@ std::string Cpptraj::Defines() { #ifdef NO_XDRFILE defined_str.append(" -DNO_XDRFILE"); #endif +#ifdef NO_TNGFILE + defined_str.append(" -DNO_TNGFILE"); +#endif #if defined(USE_SANDERLIB) && !defined(LIBCPPTRAJ) defined_str.append(" -DUSE_SANDERLIB"); #endif diff --git a/test/MasterTest.sh b/test/MasterTest.sh index a102554dc1..bfe62afd13 100644 --- a/test/MasterTest.sh +++ b/test/MasterTest.sh @@ -45,6 +45,7 @@ # CPPTRAJ_FFTW_FFT : If set CPPTRAJ was compiled with fftw # CPPTRAJ_CUDA : If set CPPTRAJ has CUDA support. # CPPTRAJ_XDRFILE : If set CPPTRAJ has XDR file support. +# CPPTRAJ_TNGFILE : If set CPPTRAJ has TNG file support. # CPPTRAJ_SINGLE_ENS : If set CPPTRAJ has single ensemble support. # ----- Variables that can be set by individual scripts ---- # TOP : Topology file for cpptraj @@ -726,6 +727,7 @@ Required() { # Check how CPPTRAJ was compiled. CheckDefines() { CPPTRAJ_XDRFILE='yes' + CPPTRAJ_TNGFILE='yes' CPPTRAJ_MATHLIB='yes' CPPTRAJDEFINES=`$CPPTRAJ --defines` if [ $? -ne 0 ] ; then @@ -746,10 +748,12 @@ CheckDefines() { '-DFFTW_FFT' ) export CPPTRAJ_FFTW_FFT=$DEFINE ;; '-DCUDA' ) export CPPTRAJ_CUDA=$DEFINE ;; '-DNO_XDRFILE' ) CPPTRAJ_XDRFILE='' ;; + '-DNO_TNGFILE' ) CPPTRAJ_TNGFILE='' ;; '-DENABLE_SINGLE_ENSEMBLE' ) export CPPTRAJ_SINGLE_ENS=$DEFINE ;; esac done export CPPTRAJ_XDRFILE + export CPPTRAJ_TNGFILE export CPPTRAJ_MATHLIB #echo "DEBUG: $ZLIB $BZLIB $NETCDFLIB $MPILIB $NOMATHLIB $OPENMP $PNETCDFLIB $SANDERLIB $CUDA $XDRFILE" } @@ -953,6 +957,7 @@ CheckEnv() { 'zlib' ) TestLibrary "Zlib" "$CPPTRAJ_ZLIB" ;; 'bzlib' ) TestLibrary "Bzlib" "$CPPTRAJ_BZLIB" ;; 'xdr' ) TestLibrary "XDR file" "$CPPTRAJ_XDRFILE" ;; + 'tng' ) TestLibrary "TNG file" "$CPPTRAJ_TNGFILE" ;; 'mathlib' ) TestLibrary "BLAS/LAPACK/ARPACK" "$CPPTRAJ_MATHLIB" ;; 'sanderlib' ) TestLibrary "SANDER API from AmberTools" "$CPPTRAJ_SANDERLIB" ;; 'fftw' ) TestLibrary "FFTW" "$CPPTRAJ_FFTW_FFT" ;; diff --git a/test/Test_GromacsTNG/RunTest.sh b/test/Test_GromacsTNG/RunTest.sh index 96a76a8ceb..dfe3f36420 100755 --- a/test/Test_GromacsTNG/RunTest.sh +++ b/test/Test_GromacsTNG/RunTest.sh @@ -4,6 +4,10 @@ CleanFiles cpptraj.in temperature.dat rmsd.dat ene.dat +TESTNAME='TNG read test' + +Requires tng notparallel + INPUT='-i cpptraj.in' cat > cpptraj.in < Date: Thu, 17 Oct 2019 15:17:36 -0400 Subject: [PATCH 64/77] DRR - Add tng entry to configure library help --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index dc2895dd99..4b6c2c76b5 100755 --- a/configure +++ b/configure @@ -45,7 +45,7 @@ UsageFull() { echo " --with-= : Use library in specified directory." echo " -l= : Use specified library file." echo " -no : Disable library." - echo " Libraries: netcdf pnetcdf zlib bzlib blas lapack arpack fftw3 readline sanderlib xdrfile" + echo " Libraries: netcdf pnetcdf zlib bzlib blas lapack arpack fftw3 readline sanderlib xdrfile tng" echo " Note: pnetcdf is needed for writing NetCDF trajectories with MPI." echo " LINKING OPTIONS" echo " -static : Use static linking." From 3ea17a6297d2c5a6bfe12b2f11c89aec09d13696 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Thu, 17 Oct 2019 15:28:09 -0400 Subject: [PATCH 65/77] DRR - Add configure test for when TNG is specified. If static library not present whne -libstatic specified, warn and continue --- configure | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 4b6c2c76b5..aef59b5e09 100755 --- a/configure +++ b/configure @@ -589,6 +589,21 @@ EOF TestProgram " Checking Xdrfile" "$CXX" "$CXXFLAGS ${LIB_INCL[$LXDRFILE]}" testp.cpp "${LIB_FLAG[$LXDRFILE]}" } +TestTngfile() { + cat > testp.cpp < +tng_trajectory_t traj_; +bool Unused(const char* fname) { + tng_function_status stat = tng_util_trajectory_open(fname, 'r', &traj_); + if (stat != TNG_SUCCESS) + return false; + return true; +} +int main() { return 0; } +EOF + TestProgram " Checking TNG" "$CXX" "$CXXFLAGS ${LIB_INCL[$LTNGFILE]}" testp.cpp "${LIB_FLAG[$LTNGFILE]}" +} + TestSanderlib() { cat > testp.cpp < Date: Thu, 17 Oct 2019 15:44:53 -0400 Subject: [PATCH 66/77] DRR - Add input key for TNG --- src/TrajectoryFile.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/TrajectoryFile.cpp b/src/TrajectoryFile.cpp index 331da7a5ed..62407ae488 100644 --- a/src/TrajectoryFile.cpp +++ b/src/TrajectoryFile.cpp @@ -90,6 +90,7 @@ const FileTypes::KeyToken TrajectoryFile::TF_KeyArray[] = { { CHARMMDCD, "charmm", ".dcd" }, { GMXTRX, "trr", ".trr" }, { GMXXTC, "xtc", ".xtc" }, + { GMXTNG, "tng", ".tng" }, { BINPOS, "binpos", ".binpos" }, { AMBERRESTART, "restart", ".rst7" }, { AMBERRESTART, "restrt", ".rst7" }, From f76825e035bfe0a62365966d2be30ee385a69903 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 18 Oct 2019 08:00:09 -0400 Subject: [PATCH 67/77] DRR - Print tng precision --- src/Traj_TNG.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 661fcb52fd..0a6f1df144 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -251,6 +251,13 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) // Print the scaling factor mprintf("\tTNG distance scaling factor (to convert to Ang): x%g\n", tngfac_); + // Get precision + double precision; + if (tng_compression_precision_get(traj_, &precision) != TNG_SUCCESS) + mprintf("Warning: Could not get precision from TNG file.\n"); + else + mprintf("\tTNG precision is %g\n", precision); + // This will be used as temp space for reading in values from TNG if (values_ != 0) free( values_ ); values_ = 0; From 735fb0b513ac275f84a9f83af2c5910f8c4f6fcc Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 18 Oct 2019 08:45:20 -0400 Subject: [PATCH 68/77] DRR - Try to add a seek for TNG --- src/Traj_TNG.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- src/Traj_TNG.h | 3 ++- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 0a6f1df144..3d29567be8 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -16,6 +16,7 @@ Traj_TNG::Traj_TNG() : tngframes_(-1), tngsets_(-1), current_frame_(-1), + current_set_(0), next_nblocks_(-1), next_blockIDs_(0), tngfac_(0), @@ -78,6 +79,7 @@ int Traj_TNG::openTrajin() { //mprintf("DEBUG: Successfully opened TNG file.\n"); isOpen_ = true; current_frame_ = -1; + current_set_ = 0; return 0; } @@ -333,8 +335,40 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) int Traj_TNG::readFrame(int set, Frame& frameIn) { //int64_t numberOfAtoms = -1; //tng_num_particles_get(traj_, &numberOfAtoms); TODO could this change per frame? + // next_frame will get set to the next frame (MD) with data + int64_t next_frame; + double frameTime; + char datatype; + // Seek if needed. + if (set != current_set_) { + // TODO: Figure out if there is a way to point the TNG file without + // sequential seeking like this. + if (set < current_set_) { + closeTraj(); + openTrajin(); + } + while (current_set_ < set) { + int stat = getNextBlocks( next_frame ); + mprintf("DEBUG: Called getNextBlocks(%i) set=%i current_set_=%i next_frame=%li current_frame_=%li\n", stat, set, current_set_, next_frame, current_frame_); + if (stat == -1) { + mprinterr("Error: could not get data blocks for frame (set %i) during seek.\n", set+1); + return 1; + } else if (stat != 0) { + mprintf("Warning: TNG set %i, no more blocks during seek.\n", set+1); + return 1; + } + // Blank reads + for (int64_t idx = 0; idx < next_nblocks_; idx++) + { + int64_t blockId = next_blockIDs_[idx]; + readValues( blockId, next_frame, frameTime, datatype ); + } + current_set_++; + current_frame_ = next_frame; + } + } + // Determine next frame with data - int64_t next_frame; // Will get set to the next frame (MD) with data int err = getNextBlocks( next_frame ); if (err == -1) { mprinterr("Error: could not get data blocks in next frame (set %i)\n", set+1); @@ -352,8 +386,6 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { } // Process data blocks - double frameTime; - char datatype; for (int64_t idx = 0; idx < next_nblocks_; idx++) { int64_t blockId = next_blockIDs_[idx]; @@ -398,6 +430,9 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { // Update current frame number current_frame_ = next_frame; + // Update set number + current_set_++; + return 0; } diff --git a/src/Traj_TNG.h b/src/Traj_TNG.h index b3357e0869..5920866e11 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_TNG.h @@ -49,8 +49,9 @@ class Traj_TNG : public TrajectoryIO { void* values_; ///< Temporary array for reading in values from TNG int64_t tngatoms_; ///< Number of atoms in the TNG trajectory file. int64_t tngframes_; ///< Number of *MD sim( frames in the TNG trajectory file. - int64_t tngsets_; ///< Number of actual frames in the TNG traectory file. + int64_t tngsets_; ///< Number of actual frames in the TNG trajectory file. int64_t current_frame_; ///< The current frame (relative to MD sim, not the trajectory!) + int current_set_; ///< The current set in tng file. Determines if we need to seek. int64_t next_nblocks_; ///< The number of data blocks in the next frame int64_t* next_blockIDs_; ///< Array containing block IDs in next frame double tngfac_; ///< Coordinates scaling factor From ced4edc347d0a41a3dab118c12eab4a34ecbd6c1 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 18 Oct 2019 08:51:00 -0400 Subject: [PATCH 69/77] DRR - Add tng test with offset --- test/Test_GromacsTNG/RunTest.sh | 55 +++++++++++++++---- test/Test_GromacsTNG/offset.ene.dat.save | 5 ++ test/Test_GromacsTNG/offset.rmsd.dat.save | 5 ++ .../offset.temperature.dat.save | 5 ++ 4 files changed, 59 insertions(+), 11 deletions(-) create mode 100644 test/Test_GromacsTNG/offset.ene.dat.save create mode 100644 test/Test_GromacsTNG/offset.rmsd.dat.save create mode 100644 test/Test_GromacsTNG/offset.temperature.dat.save diff --git a/test/Test_GromacsTNG/RunTest.sh b/test/Test_GromacsTNG/RunTest.sh index dfe3f36420..247270e273 100755 --- a/test/Test_GromacsTNG/RunTest.sh +++ b/test/Test_GromacsTNG/RunTest.sh @@ -2,7 +2,7 @@ . ../MasterTest.sh -CleanFiles cpptraj.in temperature.dat rmsd.dat ene.dat +CleanFiles cpptraj.in temperature.dat rmsd.dat ene.dat offset.*.dat TESTNAME='TNG read test' @@ -10,27 +10,60 @@ Requires tng notparallel INPUT='-i cpptraj.in' -cat > cpptraj.in < cpptraj.in < Date: Fri, 18 Oct 2019 08:51:34 -0400 Subject: [PATCH 70/77] Fix test name --- test/Test_GromacsTNG/RunTest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Test_GromacsTNG/RunTest.sh b/test/Test_GromacsTNG/RunTest.sh index 247270e273..e6e1168cf3 100755 --- a/test/Test_GromacsTNG/RunTest.sh +++ b/test/Test_GromacsTNG/RunTest.sh @@ -49,7 +49,7 @@ run MyRmsNm = MyRms / 10.0 writedata $rout xmin $xmin xstep $xstep MyRmsNm prec 12.7 EOF - RunCpptraj "$TESTNAME" + RunCpptraj "$UNITNAME" if [ -z "$trajin_args" ] ; then DoTest temperature.dat.save temperature.dat DoTest rmsd.dat.save rmsd.dat From ab593bd3ad11fb91fd43c3d94bec67bd8be458a6 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 18 Oct 2019 09:10:07 -0400 Subject: [PATCH 71/77] DRR - Add TNG stuff to README. Separate out libraries that are bundled with CPPTRAJ from those that are not. --- README.md | 46 ++++++++++++++++++++++++++++------------------ src/Traj_TNG.cpp | 2 +- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index ee25ac7ae6..ad0f4647fc 100644 --- a/README.md +++ b/README.md @@ -72,13 +72,18 @@ the following libraries: * NetCDF * BLAS * LAPACK -* ARPACK (now bundled with CPPTRAJ) -* Bzip2 * Gzip +* Bzip2 * Parallel NetCDF (-mpi build only, for NetCDF trajectory output in parallel) * CUDA (-cuda build only) -* FFTW (mostly optional; required for PME functionality) -* [helPME](https://github.com/andysim/helpme) (optional; required for PME functionality) +* FFTW (mostly optional; required for PME functionality and very large FFTs) + +CPPTRAJ also makes use of the following libraries that are bundled with CPPTRAJ. External ones can be used in place of these if desired. + +* ARPACK; without this diagonalization of sparse matrices in `diagmatrix` will be slow +* [helPME](https://github.com/andysim/helpme), required for PME functionality +* XDR for reading GROMACS XTC trajectories +* TNG for reading GROMACS TNG trajectories `./configure gnu` should be adequate to set up compilation for most systems. For systems without BLAS/LAPACK/ARPACK and/or NetCDF libraries installed, @@ -92,21 +97,24 @@ be specified to enable OpenMP parallelization, e.g. `./configure -openmp gnu`. An MPI-parallelized version of CPPTRAJ can also be built using the `-mpi` flag. CPPTRAJ can be built with both MPI and OpenMP; when running this build users should take care to properly set OMP_NUM_THREADS if using more than 1 MPI -thread per node. A CUDA build is now also available via the `-cuda` flag. -By default CPPTRAJ will be configured for multiple shader models; to restrict -the CUDA build to a single shader model use the SHADER_MODEL environment variable. -Any combination of `-cuda`, `-mpi`, and `-openmp` may be used. - -The configure script by default sets everything up to link dynamically. The -`-static` flag can be used to force static linking. If linking errors are -encountered you may need to specify library locations using the `--with-LIB=` -options. For example, to use NetCDF compiled in `/opt/netcdf` use the option -`--with-netcdf=/opt/netcdf`. Alternatively, individual libraries can be -disabled with the `-no` options. The `-libstatic` flag -can be used to static link only libraries that have been specified. +process per node (the number of processes * threads should not be greater than +the number of physical cores on the machine). + +A CUDA build is now also available via the `-cuda` configure flag. However, currently +only a few commands benefit from this (see the manual for details). By default CPPTRAJ +will be configured for multiple shader models; to restrict the CUDA build to a single +shader model set the SHADER_MODEL environment variable before running `configure`. + +Any combination of `-cuda`, `-mpi`, and `-openmp` may be used. The configure script by +default sets everything up to link dynamically. The `-static` flag can be used to force +static linking. If linking errors are encountered you may need to specify library locations +using the `--with-LIB=` options. For example, to use NetCDF compiled in `/opt/netcdf` +use the option `--with-netcdf=/opt/netcdf`. Alternatively, individual libraries can be +disabled with the `-no` options. The `-libstatic` flag can be used to static link +only libraries that have been specified. After `configure` has been successfully run, `make install` will -compile and place the cpptraj binary in the `bin/` subdirectory. Note that +compile and place the cpptraj binary in the `$CPPTRAJHOME/bin` subdirectory. Note that on multithreaded systems `make -j X install` (where X is an integer > 1 and less than the max # cores on your system) will run much faster. After installation, It is highly recommended that `make check` be run as @@ -203,6 +211,8 @@ External libraries bundled with CPPTRAJ * CPPTRAJ uses the [ARPACK](https://www.caam.rice.edu//software/ARPACK/) library to calculate eigenvalues/eigenvectors from large sparse matrices. -* CPPTRAJ uses the [xdrfile](http://www.gromacs.org/Developer\_Zone/Programming\_Guide/XTC\_Library) library for reading XTC file; specifically a somewhat updated version from [MDTRAJ](https://github.com/mdtraj/mdtraj) that includes some bugfixes and enhancements. See `src/xdrfile/README` for details. +* CPPTRAJ uses the [xdrfile](http://www.gromacs.org/Developer\_Zone/Programming\_Guide/XTC\_Library) library for reading XTC files; specifically a somewhat updated version from [MDTRAJ](https://github.com/mdtraj/mdtraj) that includes some bugfixes and enhancements. See `src/xdrfile/README` for details. + +* CPPTRAJ uses the [GROMACS TNG](https://github.com/gromacs/tng) library for reading TNG files. See `sec/tng/README` for details. * The reciprocal part of the PME calculation is handled by the [helPME](https://github.com/andysim/helpme) library by Andy Simmonett. diff --git a/src/Traj_TNG.cpp b/src/Traj_TNG.cpp index 3d29567be8..56549453b5 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_TNG.cpp @@ -342,7 +342,7 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { // Seek if needed. if (set != current_set_) { // TODO: Figure out if there is a way to point the TNG file without - // sequential seeking like this. + // having to do blank reads. if (set < current_set_) { closeTraj(); openTrajin(); From 5cf71a87110af09015ce746ee501ddc1bfdb7f75 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 18 Oct 2019 09:14:19 -0400 Subject: [PATCH 72/77] DRR - The TNG test can actually run in parallel... --- test/Test_GromacsTNG/RunTest.sh | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/test/Test_GromacsTNG/RunTest.sh b/test/Test_GromacsTNG/RunTest.sh index e6e1168cf3..631d828dc7 100755 --- a/test/Test_GromacsTNG/RunTest.sh +++ b/test/Test_GromacsTNG/RunTest.sh @@ -6,7 +6,7 @@ CleanFiles cpptraj.in temperature.dat rmsd.dat ene.dat offset.*.dat TESTNAME='TNG read test' -Requires tng notparallel +Requires tng maxthreads 10 INPUT='-i cpptraj.in' @@ -20,6 +20,7 @@ TestTng() { tout='temperature.dat' rout='rmsd.dat' eout='ene.dat' + skiptest=0 if [ ! -z "$trajin_args" ] ; then UNITNAME="$TESTNAME (with offset)" refcmd='reference md_1_1.tng 1' @@ -29,8 +30,11 @@ TestTng() { tout='offset.temperature.dat' rout='offset.rmsd.dat' eout='offset.ene.dat' + CheckFor maxthreads 4 + skiptest=$? fi - cat > cpptraj.in < cpptraj.in < Date: Fri, 18 Oct 2019 09:20:11 -0400 Subject: [PATCH 73/77] Rename class to be more consistent with existing gromacs traj parsers --- src/{Traj_TNG.cpp => Traj_GmxTng.cpp} | 52 +++++++++++++-------------- src/{Traj_TNG.h => Traj_GmxTng.h} | 8 ++--- src/TrajectoryFile.cpp | 4 +-- src/cpptrajdepend | 4 +-- src/cpptrajfiles | 2 +- 5 files changed, 35 insertions(+), 35 deletions(-) rename src/{Traj_TNG.cpp => Traj_GmxTng.cpp} (91%) rename src/{Traj_TNG.h => Traj_GmxTng.h} (94%) diff --git a/src/Traj_TNG.cpp b/src/Traj_GmxTng.cpp similarity index 91% rename from src/Traj_TNG.cpp rename to src/Traj_GmxTng.cpp index 56549453b5..d3dbdde5bb 100644 --- a/src/Traj_TNG.cpp +++ b/src/Traj_GmxTng.cpp @@ -2,7 +2,7 @@ #include // pow #include // strncmp #include // free -#include "Traj_TNG.h" +#include "Traj_GmxTng.h" #include "CpptrajStdio.h" #include "FileName.h" #include "Topology.h" @@ -10,7 +10,7 @@ #include "Constants.h" /// CONSTRUCTOR -Traj_TNG::Traj_TNG() : +Traj_GmxTng::Traj_GmxTng() : values_(0), tngatoms_(0), tngframes_(-1), @@ -24,7 +24,7 @@ Traj_TNG::Traj_TNG() : {} /// DESTRUCTOR -Traj_TNG::~Traj_TNG() { +Traj_GmxTng::~Traj_GmxTng() { closeTraj(); if (values_ != 0) free( values_ ); if (next_blockIDs_ != 0) free( next_blockIDs_ ); @@ -38,7 +38,7 @@ Traj_TNG::~Traj_TNG() { * 'GENERAL INFO' block should be present in all TNG files, and that * that string seems to always be in bytes 40-51. */ -bool Traj_TNG::ID_TrajFormat(CpptrajFile& fileIn) { +bool Traj_GmxTng::ID_TrajFormat(CpptrajFile& fileIn) { char tngheader[52]; if (fileIn.OpenFile()) return false; if (fileIn.Read(&tngheader, 52) != 52) return false; @@ -52,12 +52,12 @@ bool Traj_TNG::ID_TrajFormat(CpptrajFile& fileIn) { } /** Print trajectory info to stdout. */ -void Traj_TNG::Info() { +void Traj_GmxTng::Info() { mprintf("is a GROMACS TNG file"); } /** Close file. */ -void Traj_TNG::closeTraj() { +void Traj_GmxTng::closeTraj() { //mprintf("DEBUG: Calling closeTrajin() isOpen_=%1i\n", (int)isOpen_); if (isOpen_) { tng_util_trajectory_close(&traj_); @@ -67,7 +67,7 @@ void Traj_TNG::closeTraj() { // ----------------------------------------------------------------------------- /** Open trajectory for reading. */ -int Traj_TNG::openTrajin() { +int Traj_GmxTng::openTrajin() { //mprintf("DEBUG: Calling openTrajin() isOpen_=%1i\n", (int)isOpen_); if (isOpen_) closeTraj(); @@ -85,25 +85,25 @@ int Traj_TNG::openTrajin() { } /** Read help */ -void Traj_TNG::ReadHelp() { +void Traj_GmxTng::ReadHelp() { } /** Process read arguments. */ -int Traj_TNG::processReadArgs(ArgList& argIn) { +int Traj_GmxTng::processReadArgs(ArgList& argIn) { return 0; } /* Utility function for properly scaling input array according to given factor. */ -void Traj_TNG::convertArray(double* out, float* in, unsigned int nvals, double scale) const { +void Traj_GmxTng::convertArray(double* out, float* in, unsigned int nvals, double scale) const { for (unsigned int i = 0; i != nvals; i++) out[i] = ((double)in[i]) * scale; } /** \return 1 if no more blocks, -1 on error, 0 if ok. */ -int Traj_TNG::getNextBlocks(int64_t &next_frame) +int Traj_GmxTng::getNextBlocks(int64_t &next_frame) { tng_function_status stat = tng_util_trajectory_next_frame_present_data_blocks_find( traj_, @@ -153,7 +153,7 @@ static inline const char* BtypeStr(int64_t typeIn) { } /* Read next set of values from specified block. */ -int Traj_TNG::readValues(int64_t blockId, int64_t& next_frame, double& frameTime, char& datatype) { +int Traj_GmxTng::readValues(int64_t blockId, int64_t& next_frame, double& frameTime, char& datatype) { tng_function_status stat; int blockDependency; tng_data_block_dependency_get(traj_, blockId, &blockDependency); @@ -185,7 +185,7 @@ int Traj_TNG::readValues(int64_t blockId, int64_t& next_frame, double& frameTime /** Set up trajectory for reading. * \return Number of frames in trajectory. */ -int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) +int Traj_GmxTng::setupTrajin(FileName const& fname, Topology* trajParm) { filename_ = fname; // Open the trajectory @@ -332,7 +332,7 @@ int Traj_TNG::setupTrajin(FileName const& fname, Topology* trajParm) } /** Read specified trajectory frame. */ -int Traj_TNG::readFrame(int set, Frame& frameIn) { +int Traj_GmxTng::readFrame(int set, Frame& frameIn) { //int64_t numberOfAtoms = -1; //tng_num_particles_get(traj_, &numberOfAtoms); TODO could this change per frame? // next_frame will get set to the next frame (MD) with data @@ -437,31 +437,31 @@ int Traj_TNG::readFrame(int set, Frame& frameIn) { } /** Read velocities from specified frame. */ -int Traj_TNG::readVelocity(int set, Frame& frameIn) { +int Traj_GmxTng::readVelocity(int set, Frame& frameIn) { return 0; } /** Read forces from specified frame. */ -int Traj_TNG::readForce(int set, Frame& frameIn) { +int Traj_GmxTng::readForce(int set, Frame& frameIn) { return 0; } // ----------------------------------------------------------------------------- /** Write help. */ -void Traj_TNG::WriteHelp() { +void Traj_GmxTng::WriteHelp() { } /** Process write arguments. */ -int Traj_TNG::processWriteArgs(ArgList& argIn, DataSetList const& DSLin) { +int Traj_GmxTng::processWriteArgs(ArgList& argIn, DataSetList const& DSLin) { return 0; } /** Set up trajectory for write. */ -int Traj_TNG::setupTrajout(FileName const& fname, Topology* trajParm, +int Traj_GmxTng::setupTrajout(FileName const& fname, Topology* trajParm, CoordinateInfo const& cInfoIn, int NframesToWrite, bool append) { @@ -470,7 +470,7 @@ int Traj_TNG::setupTrajout(FileName const& fname, Topology* trajParm, } /** Write specified trajectory frame. */ -int Traj_TNG::writeFrame(int set, Frame const& frameOut) { +int Traj_GmxTng::writeFrame(int set, Frame const& frameOut) { return 0; } @@ -478,17 +478,17 @@ int Traj_TNG::writeFrame(int set, Frame const& frameOut) { // ============================================================================= #ifdef MPI /** Open trajectory for reading in parallel. */ -int Traj_TNG::parallelOpenTrajin(Parallel::Comm const& commIn) { +int Traj_GmxTng::parallelOpenTrajin(Parallel::Comm const& commIn) { return 1; } /** Open trajectory for writing in parallel. */ -int Traj_TNG::parallelOpenTrajout(Parallel::Comm const& commIn) { +int Traj_GmxTng::parallelOpenTrajout(Parallel::Comm const& commIn) { return 1; } /** Set up trajectory for write in parallel. */ -int Traj_TNG::parallelSetupTrajout(FileName const& fname, Topology* trajParm, +int Traj_GmxTng::parallelSetupTrajout(FileName const& fname, Topology* trajParm, CoordinateInfo const& cInfoIn, int NframesToWrite, bool append, Parallel::Comm const& commIn) @@ -498,19 +498,19 @@ int Traj_TNG::parallelSetupTrajout(FileName const& fname, Topology* trajParm, } /** Read frame in parallel. */ -int Traj_TNG::parallelReadFrame(int set, Frame& frameIn) { +int Traj_GmxTng::parallelReadFrame(int set, Frame& frameIn) { return 1; } /** Write frame in parallel. */ -int Traj_TNG::parallelWriteFrame(int set, Frame const& frameOut) { +int Traj_GmxTng::parallelWriteFrame(int set, Frame const& frameOut) { return 1; } /** Close trajectory in parallel. */ -void Traj_TNG::parallelCloseTraj() { +void Traj_GmxTng::parallelCloseTraj() { } #endif diff --git a/src/Traj_TNG.h b/src/Traj_GmxTng.h similarity index 94% rename from src/Traj_TNG.h rename to src/Traj_GmxTng.h index 5920866e11..12cb8ba848 100644 --- a/src/Traj_TNG.h +++ b/src/Traj_GmxTng.h @@ -5,11 +5,11 @@ #include "TrajectoryIO.h" #include "FileName.h" /// Read Gromacs TNG trajectories -class Traj_TNG : public TrajectoryIO { +class Traj_GmxTng : public TrajectoryIO { public: - Traj_TNG(); - ~Traj_TNG(); - static BaseIOtype* Alloc() { return (BaseIOtype*)new Traj_TNG(); } + Traj_GmxTng(); + ~Traj_GmxTng(); + static BaseIOtype* Alloc() { return (BaseIOtype*)new Traj_GmxTng(); } static void WriteHelp(); static void ReadHelp(); private: diff --git a/src/TrajectoryFile.cpp b/src/TrajectoryFile.cpp index 62407ae488..7a0d60723c 100644 --- a/src/TrajectoryFile.cpp +++ b/src/TrajectoryFile.cpp @@ -23,7 +23,7 @@ #include "Traj_GmxXtc.h" #include "Traj_CharmmRestart.h" #include "Traj_XYZ.h" -#include "Traj_TNG.h" +#include "Traj_GmxTng.h" #include "Traj_GmxDump.h" // ----- STATIC VARS / ROUTINES ------------------------------------------------ @@ -57,7 +57,7 @@ const FileTypes::AllocToken TrajectoryFile::TF_AllocArray[] = { # ifdef NO_TNGFILE { "Gromacs TNG", 0, 0, 0 }, # else - { "Gromacs TNG", 0, 0, Traj_TNG::Alloc }, + { "Gromacs TNG", 0, 0, Traj_GmxTng::Alloc }, # endif { "BINPOS", 0, 0, Traj_Binpos::Alloc }, { "Amber Restart", Traj_AmberRestart::ReadHelp, Traj_AmberRestart::WriteHelp, Traj_AmberRestart::Alloc }, diff --git a/src/cpptrajdepend b/src/cpptrajdepend index 91a2ec1989..f56d57bc79 100644 --- a/src/cpptrajdepend +++ b/src/cpptrajdepend @@ -356,6 +356,7 @@ Traj_CharmmDcd.o : Traj_CharmmDcd.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h Ba Traj_CharmmRestart.o : Traj_CharmmRestart.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedFrame.h BufferedLine.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h StringRoutines.h SymbolExporting.h TextFormat.h Topology.h Traj_CharmmRestart.h TrajectoryIO.h Vec3.h Traj_Conflib.o : Traj_Conflib.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_Conflib.h TrajectoryIO.h Vec3.h Traj_GmxDump.o : Traj_GmxDump.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_GmxDump.h TrajectoryIO.h Vec3.h +Traj_GmxTng.o : Traj_GmxTng.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_GmxTng.h TrajectoryIO.h Vec3.h Traj_GmxTrX.o : Traj_GmxTrX.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h ByteRoutines.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_GmxTrX.h TrajectoryIO.h Vec3.h Traj_GmxXtc.o : Traj_GmxXtc.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_GmxXtc.h TrajectoryIO.h Vec3.h Traj_Gro.o : Traj_Gro.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedLine.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h StringRoutines.h SymbolExporting.h Topology.h Traj_Gro.h TrajectoryIO.h Vec3.h @@ -364,10 +365,9 @@ Traj_NcEnsemble.o : Traj_NcEnsemble.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h Traj_PDBfile.o : Traj_PDBfile.cpp ArgList.h AssociatedData.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataSet.h DataSetList.h DataSet_1D.h DataSet_Coords.h DataSet_Coords_REF.h DataSet_Tensor.h Dimension.h DistRoutines.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h PDBfile.h Parallel.h ParameterTypes.h Range.h ReferenceFrame.h ReplicaDimArray.h Residue.h SymbolExporting.h SymmetricTensor.h TextFormat.h Timer.h Topology.h Traj_PDBfile.h TrajectoryIO.h Vec3.h Traj_SDF.o : Traj_SDF.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SDFfile.h SymbolExporting.h Topology.h Traj_SDF.h TrajectoryIO.h Vec3.h Traj_SQM.o : Traj_SQM.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h StringRoutines.h SymbolExporting.h Topology.h Traj_SQM.h TrajectoryIO.h Vec3.h -Traj_TNG.o : Traj_TNG.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h Constants.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h Topology.h Traj_TNG.h TrajectoryIO.h Vec3.h Traj_Tinker.o : Traj_Tinker.cpp Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedLine.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h SymbolExporting.h TinkerFile.h Topology.h Traj_Tinker.h TrajectoryIO.h Vec3.h Traj_XYZ.o : Traj_XYZ.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h BufferedLine.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h Residue.h StringRoutines.h SymbolExporting.h TextFormat.h Topology.h Traj_XYZ.h TrajectoryIO.h Vec3.h -TrajectoryFile.o : TrajectoryFile.cpp ArgList.h Atom.h AtomMask.h BaseIOtype.h Box.h BufferedFrame.h BufferedLine.h CIFfile.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h FileTypes.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Mol2File.h Molecule.h NameType.h NetcdfFile.h PDBfile.h Parallel.h ReplicaDimArray.h Residue.h SDFfile.h SymbolExporting.h TextFormat.h TinkerFile.h Traj_AmberCoord.h Traj_AmberNetcdf.h Traj_AmberRestart.h Traj_AmberRestartNC.h Traj_Binpos.h Traj_CIF.h Traj_CharmmCor.h Traj_CharmmDcd.h Traj_CharmmRestart.h Traj_Conflib.h Traj_GmxDump.h Traj_GmxTrX.h Traj_GmxXtc.h Traj_Gro.h Traj_Mol2File.h Traj_NcEnsemble.h Traj_PDBfile.h Traj_SDF.h Traj_SQM.h Traj_TNG.h Traj_Tinker.h Traj_XYZ.h TrajectoryFile.h TrajectoryIO.h Vec3.h +TrajectoryFile.o : TrajectoryFile.cpp ArgList.h Atom.h AtomMask.h BaseIOtype.h Box.h BufferedFrame.h BufferedLine.h CIFfile.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h FileIO.h FileName.h FileTypes.h Frame.h FramePtrArray.h MaskToken.h Matrix_3x3.h Mol2File.h Molecule.h NameType.h NetcdfFile.h PDBfile.h Parallel.h ReplicaDimArray.h Residue.h SDFfile.h SymbolExporting.h TextFormat.h TinkerFile.h Traj_AmberCoord.h Traj_AmberNetcdf.h Traj_AmberRestart.h Traj_AmberRestartNC.h Traj_Binpos.h Traj_CIF.h Traj_CharmmCor.h Traj_CharmmDcd.h Traj_CharmmRestart.h Traj_Conflib.h Traj_GmxDump.h Traj_GmxTng.h Traj_GmxTrX.h Traj_GmxXtc.h Traj_Gro.h Traj_Mol2File.h Traj_NcEnsemble.h Traj_PDBfile.h Traj_SDF.h Traj_SQM.h Traj_Tinker.h Traj_XYZ.h TrajectoryFile.h TrajectoryIO.h Vec3.h TrajectoryIO.o : TrajectoryIO.cpp BaseIOtype.h Box.h CoordinateInfo.h FramePtrArray.h Matrix_3x3.h Parallel.h ReplicaDimArray.h TrajectoryIO.h Vec3.h TrajinList.o : TrajinList.cpp ArgList.h AssociatedData.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajFile.h CpptrajStdio.h DataSet.h DataSet_RemLog.h Dimension.h EnsembleIn.h EnsembleIn_Multi.h EnsembleIn_Single.h FileIO.h FileName.h FileTypes.h Frame.h FramePtrArray.h InputTrajCommon.h MaskToken.h Matrix_3x3.h MetaData.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h ReplicaInfo.h Residue.h StringRoutines.h SymbolExporting.h TextFormat.h Timer.h Topology.h TrajFrameCounter.h TrajIOarray.h TrajectoryFile.h TrajectoryIO.h Trajin.h TrajinList.h Trajin_Multi.h Trajin_Single.h Vec3.h Trajin_Multi.o : Trajin_Multi.cpp ArgList.h Atom.h AtomExtra.h AtomMask.h BaseIOtype.h Box.h CharMask.h CoordinateInfo.h CpptrajStdio.h FileName.h Frame.h FramePtrArray.h InputTrajCommon.h MaskToken.h Matrix_3x3.h Molecule.h NameType.h Parallel.h ParameterTypes.h Range.h ReplicaDimArray.h ReplicaInfo.h Residue.h StringRoutines.h SymbolExporting.h Topology.h TrajFrameCounter.h TrajIOarray.h TrajectoryIO.h Trajin.h Trajin_Multi.h Vec3.h diff --git a/src/cpptrajfiles b/src/cpptrajfiles index 600ba735f3..40b39bdf02 100644 --- a/src/cpptrajfiles +++ b/src/cpptrajfiles @@ -352,6 +352,7 @@ COMMON_SOURCES= \ Traj_CIF.cpp \ Traj_Conflib.cpp \ Traj_GmxDump.cpp \ + Traj_GmxTng.cpp \ Traj_GmxTrX.cpp \ Traj_GmxXtc.cpp \ Traj_Gro.cpp \ @@ -361,7 +362,6 @@ COMMON_SOURCES= \ Traj_SDF.cpp \ Traj_SQM.cpp \ Traj_Tinker.cpp \ - Traj_TNG.cpp \ Traj_XYZ.cpp \ TrajectoryFile.cpp \ TrajectoryIO.cpp \ From 570af0e21e53a2b2212b196a97ba703584fcacd8 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 18 Oct 2019 09:21:49 -0400 Subject: [PATCH 74/77] DRR - Add tng to trajectory table --- doc/cpptraj.lyx | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/doc/cpptraj.lyx b/doc/cpptraj.lyx index 39bf9e9a82..352f8ac0c4 100644 --- a/doc/cpptraj.lyx +++ b/doc/cpptraj.lyx @@ -12013,7 +12013,7 @@ Cpptraj currently understands the following trajectory file formats: \begin_layout Standard \align center \begin_inset Tabular - + @@ -12571,6 +12571,44 @@ xtc \begin_inset Text +\begin_layout Plain Layout +Gromacs TNG +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +tng +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +.tng +\end_layout + +\end_inset + + +\begin_inset Text + +\begin_layout Plain Layout +Read Only +\end_layout + +\end_inset + + + + +\begin_inset Text + \begin_layout Plain Layout CIF \end_layout From ca7b5d729e46c032f3329b3b6d00a59a2b7a3f09 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 18 Oct 2019 09:29:55 -0400 Subject: [PATCH 75/77] DRR - Revision bump for adding TNG read support. --- src/Version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Version.h b/src/Version.h index 70aabf9ce3..7dd9606cf4 100644 --- a/src/Version.h +++ b/src/Version.h @@ -12,7 +12,7 @@ * Whenever a number that precedes is incremented, all subsequent * numbers should be reset to 0. */ -#define CPPTRAJ_INTERNAL_VERSION "V4.20.0" +#define CPPTRAJ_INTERNAL_VERSION "V4.20.1" /// PYTRAJ relies on this #define CPPTRAJ_VERSION_STRING CPPTRAJ_INTERNAL_VERSION #endif From 574c92f6da2ad21f9791deb56dc21fe40a79b265 Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 18 Oct 2019 10:51:23 -0400 Subject: [PATCH 76/77] DRR - Since TNG depends on zlib, make sure its disabled if no zlib present. Also make sure the link ordering is correct. Change define from NO_TNGFILE to HAS_TNGFILE --- configure | 34 +++++++++++++++++++++------------- src/Cpptraj.cpp | 4 ++-- src/Traj_GmxTng.cpp | 4 ++-- src/Traj_GmxTng.h | 4 ++-- src/TrajectoryFile.cpp | 6 +++--- test/MasterTest.sh | 4 ++-- 6 files changed, 32 insertions(+), 24 deletions(-) diff --git a/configure b/configure index aef59b5e09..63cee136b0 100755 --- a/configure +++ b/configure @@ -145,20 +145,22 @@ CPPTRAJLIB='' NLIB=14 # Library indices # Original: FFT ARPACK LAPACK BLAS NETCDF PARANC BZIP ZIP READLINE XDRFILE +# Libraries containing definition of a function should appear *after* +# any source files or object files which use it. LNETCDF=0 LPARANC=1 # Parallel NetCDF LBZIP=2 -LZIP=3 -LARPACK=4 -LLAPACK=5 -LBLAS=6 -LFFTW3=7 -LREADLINE=8 -LXDRFILE=9 -LSANDER=10 -LTIMER=11 -LCUDA=12 -LTNGFILE=13 +LTNGFILE=3 # This has to come before ZLIB since it depends on ZLIB +LZIP=4 +LARPACK=5 +LLAPACK=6 +LBLAS=7 +LFFTW3=8 +LREADLINE=9 +LXDRFILE=10 +LSANDER=11 +LTIMER=12 +LCUDA=13 # LIB_STAT = Library status: # off : Do not use library. @@ -287,8 +289,8 @@ LIB_CKEY[$LTNGFILE]='tng' LIB_HOME[$LTNGFILE]='tng' LIB_FLAG[$LTNGFILE]='-ltng_io' LIB_STTC[$LTNGFILE]='libtng_io.a' -LIB_D_ON[$LTNGFILE]='' -LIB_DOFF[$LTNGFILE]='-DNO_TNGFILE' +LIB_D_ON[$LTNGFILE]='-DHAS_TNGFILE' +LIB_DOFF[$LTNGFILE]='' LIB_TYPE[$LTNGFILE]='ld' for ((i=0; i < $NLIB; i++)) ; do @@ -943,6 +945,12 @@ SetupLibraries() { LIB_INCL[$i]="$linc" fi done + # Take care of any library dependencies. + if [ "${LIB_STAT[$LZIP]}" = 'off' -a "${LIB_STAT[$LTNGFILE]}" != 'off' ] ; then + # TNG depends on libz + echo "Warning: TNG depends on libz; disabling TNG." + LIB_STAT[$LTNGFILE]='off' + fi } #------------------------------------------------------------------------------- diff --git a/src/Cpptraj.cpp b/src/Cpptraj.cpp index 627e6b4b60..8104450502 100644 --- a/src/Cpptraj.cpp +++ b/src/Cpptraj.cpp @@ -223,8 +223,8 @@ std::string Cpptraj::Defines() { #ifdef NO_XDRFILE defined_str.append(" -DNO_XDRFILE"); #endif -#ifdef NO_TNGFILE - defined_str.append(" -DNO_TNGFILE"); +#ifdef HAS_TNGFILE + defined_str.append(" -DHAS_TNGFILE"); #endif #if defined(USE_SANDERLIB) && !defined(LIBCPPTRAJ) defined_str.append(" -DUSE_SANDERLIB"); diff --git a/src/Traj_GmxTng.cpp b/src/Traj_GmxTng.cpp index d3dbdde5bb..40b8e7e74b 100644 --- a/src/Traj_GmxTng.cpp +++ b/src/Traj_GmxTng.cpp @@ -1,4 +1,4 @@ -#ifndef NO_TNGFILE +#ifdef HAS_TNGFILE #include // pow #include // strncmp #include // free @@ -514,4 +514,4 @@ void Traj_GmxTng::parallelCloseTraj() { } #endif -#endif /* NO_TNGFILE */ +#endif /* HAS_TNGFILE */ diff --git a/src/Traj_GmxTng.h b/src/Traj_GmxTng.h index 12cb8ba848..4e0313a253 100644 --- a/src/Traj_GmxTng.h +++ b/src/Traj_GmxTng.h @@ -1,6 +1,6 @@ #ifndef INC_TRAJ_TNG_H #define INC_TRAJ_TNG_H -#ifndef NO_TNGFILE +#ifdef HAS_TNGFILE #include #include "TrajectoryIO.h" #include "FileName.h" @@ -59,5 +59,5 @@ class Traj_GmxTng : public TrajectoryIO { FileName filename_; ///< File name, for openTrajin Iarray blockIds_; ///< Currently active block IDs }; -#endif /* NO_TNGFILE */ +#endif /* HAS_TNGFILE */ #endif diff --git a/src/TrajectoryFile.cpp b/src/TrajectoryFile.cpp index 7a0d60723c..bdeace067e 100644 --- a/src/TrajectoryFile.cpp +++ b/src/TrajectoryFile.cpp @@ -54,10 +54,10 @@ const FileTypes::AllocToken TrajectoryFile::TF_AllocArray[] = { # else { "Gromacs XTC", 0, Traj_GmxXtc::WriteHelp, Traj_GmxXtc::Alloc }, # endif -# ifdef NO_TNGFILE - { "Gromacs TNG", 0, 0, 0 }, -# else +# ifdef HAS_TNGFILE { "Gromacs TNG", 0, 0, Traj_GmxTng::Alloc }, +# else + { "Gromacs TNG", 0, 0, 0 }, # endif { "BINPOS", 0, 0, Traj_Binpos::Alloc }, { "Amber Restart", Traj_AmberRestart::ReadHelp, Traj_AmberRestart::WriteHelp, Traj_AmberRestart::Alloc }, diff --git a/test/MasterTest.sh b/test/MasterTest.sh index bfe62afd13..34bf4da1bf 100644 --- a/test/MasterTest.sh +++ b/test/MasterTest.sh @@ -727,7 +727,7 @@ Required() { # Check how CPPTRAJ was compiled. CheckDefines() { CPPTRAJ_XDRFILE='yes' - CPPTRAJ_TNGFILE='yes' + CPPTRAJ_TNGFILE='' CPPTRAJ_MATHLIB='yes' CPPTRAJDEFINES=`$CPPTRAJ --defines` if [ $? -ne 0 ] ; then @@ -748,7 +748,7 @@ CheckDefines() { '-DFFTW_FFT' ) export CPPTRAJ_FFTW_FFT=$DEFINE ;; '-DCUDA' ) export CPPTRAJ_CUDA=$DEFINE ;; '-DNO_XDRFILE' ) CPPTRAJ_XDRFILE='' ;; - '-DNO_TNGFILE' ) CPPTRAJ_TNGFILE='' ;; + '-DHAS_TNGFILE' ) CPPTRAJ_TNGFILE='$DEFINE' ;; '-DENABLE_SINGLE_ENSEMBLE' ) export CPPTRAJ_SINGLE_ENS=$DEFINE ;; esac done From b75bf5365d45172363e6cca74553f8688af583ef Mon Sep 17 00:00:00 2001 From: "Daniel R. Roe" Date: Fri, 18 Oct 2019 11:09:00 -0400 Subject: [PATCH 77/77] DRR - Have LGTM ignore tng for now. --- lgtm.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/lgtm.yml b/lgtm.yml index 3975300fed..54f3baab15 100644 --- a/lgtm.yml +++ b/lgtm.yml @@ -1,6 +1,7 @@ path_classifiers: test: - "src/readline/*" + - "src/tng/*" extraction: cpp: prepare:
  • HBlBOo2rXo;?#h$!h)NW4 znz0QHN&yhFFXl6~N<$Xz5DE)QE4nsWdt-X* zScZ`03=a@nIMZ-6p%7!!u*Q=#6vZwzU+4}4Ou`5vH7^PtTW+k&Ua%7{Dc~`Jnsd3c zuxOtD(F-kDM={bMOx`Y4Za6y?}69BPLv2fL_2L*kJKdN-UFUM9} zyAZ9NfZ~-Gd3i{cHmj83AK*AW5sKF7?pOR1zudq=ArCIxp9yoMov|=QFHWdE?;LQE z0o097<}PJ zV}KRE6Oy#Qh&#S-XnOypZd<9qM`TtOK{T!-(9d)sK%l!NAZ;$*+IRk5HA zm!*|*2(W;+I=A?XPAg`e1Rl;3TIk|%N)L!FN#>Lhp%g9R0^<@v*s2d@1k;$MaCCs9 zDVxVQhLZYLI<0R}M1^9GOWDS#9vI zaL!WmO4ur&1&=M$9q<;aA<}3yebsSgs8xs&pLEqC_sZ5$ER=|SHi4ce`*%{Xgy~xm zW$CYF(OrLdob^N_mZzPwf>61-a%QZeH!DP&yBF3w46v(!zP_H86EqO+wMJyZFg`Jq zb)0+Wcm4SoB#ek>WC%8pJq?moHi$>8y8>gxcEeJ3r_FQiMs3FYOX)K}5m?OMZ1lYV2)g{Ov z*sz469A&pLq;NTO{|S&bf^x}Eo4j8&bR-Gvg+KXM)3DYNjt;wRG-0cBq%Z$#XCHOMj6xn)Z^l4OJ*zre58tCim0T0NX=G-TYg%z((%D`=W-aKPj>WM<*17o%b z&a@ZVl}-atlAT)h^!c}2MLziw+aAYuuMtFN?Bm%R?YNAJ{Rux}1DIsM*`VM|FNLjG z!Sa9snPk|@#4xFvY)8b1^+!OsB#s0$k@MY`8X5Q{1QJie)SG*!9aTmEBLlbSjkXGl z5g&NZv5it0Iv(Z|~LM&{8$% zf+JHa9;q#aoI*Kwd9C8JS4Wydct#CD!n%$W(+wgK`KpR{xq=RSRQYZ7#`Bd9R?LU+ zaU@=vKx;NiU2!)>@s_&C12diRL>_$>(e6q3hC9==7(N_>l;-xJ2yt zj?gR)Qy)xJc@4zcLnsU+#Ct)bQi=V)C)#YaGHoM;7)nJ4qt5wj75|eb2)>Yw=z{~< zSEll%`6&wJP-0mNKfh%a&mYY4s9?X@0scCmetF*_TPP^{QfO;|GLD>f&ZKqKJ@I;o z0NQ!#^8@#jr)7jw;&aY51Sn0hy5a|w;o32q*VtIC4U-H10y<}ruwHnhSS>094i&YJ zu4UxoEXVTe^Jd9STc;F18fxo&^$Us#-g(Zr>R+6*%0kyJYA-d@^ko1Q-;x8VKW0Vs zG#*T%UYS`~*vcYtg+8+B{LhY2$7t|C{{8qS?{5TIWEl8kkSI10Lz5sD8mT{zy53pK zzX>zEP}t|)e{0U~-Iav1(|$K1&wBQswpU@wXO7lpwC_5%Pi`QdY5u>$Gi3_-bdYu{ z)n56vqxIY<<9(B6nGPYJ;aj7Pdk4VUSmvUuUQc$|o>-I)*80b)3yy@of#$NjToTu3 zY)L6yq;l6Set_b-H=+l4SNJaFW*&EmtJ<`tmCH_wJVFhoBS5;M-7n?1WAxhQL@v3;6*Tpqb z#timSpYn@k#{JYAR7` zVQb8VJ%sQA3UJ}B(K%zeakS=ucG<5+;k;+UV-zp6rmZEy`^JvP@(N+j0bodI=s&{NHY)cgmSxuW)zTrexR42O2H+Zx%p521T6z}JcDMz5+b~{@9f+02*d(iFcg0DjBoTW#Z4t)4=l2{#&IiG23`VC?SOYhV@R<-x!x7VO(GErzvsn zF4al3-F#2j$OE)xu|CFRl7&@BkfE8iB==MY<}UPDY1^)xWnRcefbApffl9iF4j zY_@)?Zt_bvrUg9iwNWFAg_PXT%5!-%uv4kIf98T|G<@I!LW88Hmu2hna+IL zVM7zI%fllqxs^VeimxCo+i!}JT5M{9z`6MhkVO|Xc9+Ktu_@urN~O_xEjyn3$`7!) z67vvT^~&pE?OC8`ID`^2MgQ^V6Miolz|x;83JpXb5VoM>k?QJs4&MlKVO)ff9t*I_ z5v?~azApL6$o}e_5!Nsq+qtkuv=F~##9j20BnLPZ(m#E8I?bJ+Q3&A99^@_tuCh(p z-GLtm<6s$`*s~d3^IORkx7mEUI+F0YOF!F%xW9nxC#%L&@kpUf`m?~aT{$j4Uy9Tg znp`O4kW6CRa$*A!2bk$E4&~WX-y2`x5x5LZ>jnGOo~KQsXiMe4|96;TM=JHP!|H-| za?jGw1~Db1h_6aj4ON9qsi}ytrn`8C@J^SPVOt^Wy!WTTc@+)*^?5#w@6I@godlW5 zvA_d&!fjR;-&wpuc=CZSEzY%#=KGr1TqUwM`qxP3_7g&3PnN|aUBr;}I_&az1oFK_ zI!Vr?QBmD=SS?zlavEO~KUNU`98mTl?wjo&c0m~jw&oE8`EF9^gt_SJ^Uka5zfk17 z@wSq#()~5x71@+^T1KitcjK9#zlOV9gBo*ov2&D&{>^UYJ#AaIfe9;dp#o;hel9Yt zdKeb>3T_SD4mo%TflO;JQq+mElyrIQjB$5sDJMbf%Y9nXNniSQKz;A2#bIWBf{no+ zPq?66TG|Ft*Qma-g%tad&J`5)pZ2(VUpmA(m0WuICFcyf4cnD_U%2TNUpM ziqN!=)pARi`L0@y{Y!YsWz4g9k_iK_j5jH`jL!>|+34JWg&IoAl4p2P3+W4qvQ|0+ zu+*Z)xDQRsok@qe2HIw>R;sErmiRF6{-mXxRIP*>f{WGomBC=L>Oeg@|Er(AV@)DF z0x;_WU3e|xav|kz9e$l(mIv_57sy6G@F7gxcUcZp%G!UmNM7s0ffV|{Ws-Im*Y_D4 z;_X~P6waKI)oqUxMI|9(8~q7er0PF%ZDtDnTIkdsx&ZnZdp5~nw2^k*#$#o_KuuJ``?K+3w43!Q zTf($UJEfz79dj`xDa|ENUl%?N=gjJM#0E;;0kfd|>h-VOfGf#nqfrl>EI3>KQ6a)s z?GA>UU(m!T_!MfzKl)ZTM4@A*{5w>fLTjl0bRcyfnU*oskDOL8vo+FCV?F8^GcynP z^G5L)Ff9^3>Qbt94b5Ej3NLJI*R)h0?7!iJGSGo|hyxf2e!jk~s0 zgxi6D@%-}6fBZq5`d~0CLLGRzS1}YfX~ZiXy?_hUajQ+#ThBYjxreP!Ow7*_I4}7$ z>ke*G8%0JFg@jt|BE<3&OF7=tYQa998xk4?vv*t9>gM{dB_Lfpn@){gerc37MJLfy zL}_u|+KS?u@m>fxPcz#4CG}UBEM=QhSypaY-)OD)THnkV>z6QR;;B=c)yVCf``C+n zzyQr>vPSPB^a2TuFs(5&{;KH>jCcl%@?pH#p82ncBO7 z^c-Z{0AO1$XZ`qK9WcAInWSQMuA2D+t|SczxKi-mBnq#Ib1!NTS6yvmU9J0-Aw@bQ zRo-S|+84(_a4%ohkPDzPZB*TC9G+1}8IDm~nf^i2nM_N)15~h?H~Chp6t}Y-J1+^% z24ol2p_JVDFC7dSLmDcy)DX9FnQS9Y+}n;mAfhlT8YKW2<3t&R6rDYW=aPfX1&jIW zlmXj7Ns-R);7pxY@!a4To0%ScwIDL(Q&oGv;V-w_I%1lovCKScu8?y;5nGHcn87b+ zfeHw#^?ia}y3TLVvsW7muyl-f0YAVRxQa;mm zS?PS49si=Nt%EvmXz(*dIg+$}M4Hqwvf4H>4|zIufi?U+A#;9mL(x;oZoEn({(pnx3VD!kv~tNbem zba>K|mY`$|_l(P67sDo)agL)b-2s?yrJk)ib(}=bsp5i^mkE*^IQIW_9ES+9Xtdl3yYOo& zqC$lmY4Y#1-1~~+AI;^oSDwwFWjfKs5Y7pZM~WH*SGQc3hz?%W%H)mowgDQfSj-t# z>S0GzSAW)L@a}PldKHK6G?OIL?9KNH6SEms#MPuR-zB0j?n?|66WriT(|_D#(vjeH zN_BBzHqX($-Za3^@T$6kn3$D4RE{40Xtdr=S6JHFy1G`;ucVe`wDjvI%{~VF=*GTV zMRlD(PUW@R=nqTU+?j!njWl1F2iZno({^!7ZtZS{nCDe!XUTW`lGx2^qS?jWs2*=l zjuM}`Gk)E#%KN2_qL3#Q+$OYgOj9()65ZQ7x&c!t{XXFVOejaYhwaY2kQd-GPCo=l z<*Z@({gc}*rOiWhm^^H%db@B%j!n-b<80{GPkE_G~ z!RBSK^1g|?KIxUewmf!6q|Jp#7YgSowR$)$Kf8hpe2G*ed!`?z&%2AZ4at*MJCgJK zd01^TXiLgbYY3wY1*cqpHQv}4ahL)`>{WI=ecPz36evvoup9ltylBC zxLrqaVsO-jV~H_+%t<`nzW}BE?22V-l2`gVOqOvx%Q2`zxb3+Sn(s-^49b77wWZP3o|`X;X#)=kV3baLse%190J=c(q)M6eB8a)qeW{e5L5O zu-W99LOWGWKVu}F*S2Bk+Uaf@S`L>ryRjovx)#UA>TmyIWk?%MXSZ8O8Fq& zW>4gt&=)PHc3o(#S#7>@Zgm?dPl>B<}ZATpvs$ef$uc2kDJ*nf{3c8#c+`QLBF zEaT9}b4J6t-F&zi6%f5Qd@3bWstD4$e`4+4Q8 zg(ZLe@c8U=F1@|CZ_tQ+Me(GeiO(|v@8H{*^|ql#@vAQk$Sve*5_lw+klmDI;xkN> z8K0t&>>lD44ybv@0;tsSP1K2PIZR>(A*+Ln7z`?_2eww-2yNA?o*v|9)L(RSY4yIk z`|`*s?yx^_Xk!Z^q#s?6rPc^-3S>zxs)&g86}{!zs5PVgiT)--Wq|!ZhXB{dPK`l} zkAo!5A2zMxC)#v$grdz(+l(KPCOZwr=?b`syM$*bqjWtd{mr(JLNlGvKNCDWm3A3x zJBl#2H9SFPG$vr@RJDy~?(3T>g%d<~BZ_(xJsg!F7ei%go>j6d;_+^N+VpBdr7~IK z!vT=5yl+_Kaf0S5epSp&$iH!6zBJ^I?RJh@$sQ_CK(SA2j<5@$88kpe>+m}@QMpRK zQf=voCIje6?;9 z>O+;?Z>jUJ%d#*+-PN-O-(so^(pANeb# z{Gn!};inWmIAj6ig%4w7M3=NozDpC0Fpg|0s7pleTypVnGeSeWq6A)a?XIUZzJrR* zICF_O{jCvNP-ms1h{VC9?6;t9`2-%g^CvQ2TP6Aplhtzc`e|UMQ=3!YGLr#1WB!xO zd%zz$1fM-!Cr0ae_SQCH+}w;WUM?>fm(N;wt~&X!y;|C(RMGl zXD63@XO<%W>nN|#lI5%e@t}xA{)|hYt2L1U)}iOWlyfcsmnE$dy~H5JS?49s=M-sH z&(tN;17i(6u?)#q9ock*@Wpes6Mmx2@p2f-6{eH(TE4%Pwi+lK9aR65O}@bz`A z;H7i8=+M0Tyza=DnUCXt1Gr5!LVy!HcW0fv{A-yWQMuFF_$_kmsAFQMYrHa;jdk+| zH^PxPK8BGH{}=LCldFj`yubHMpM)k6qWNZC-Y`JQDCCsU5YWIl8dEs^9 z$8i&j&+)@=e{~r40IT6XYx!_V^DrR{diXooEd7yx;`lt%Lh1%0DRHTKbK|Kj+=q(g z(xc*_geM3{BL}qbi&^J_iDz1FPXpxfJBr?pboEC-;M%YphwUWerF$I!^k;={$AC)) zms=Bo2NpbOm^(2b4c2KBu>T@y_-=HkDNOL~Od&3F*CnGTo42rt>H;#@3I_MulEiGN zTOuJgBy?#ZK*=kH(gG-_rGTMc!b)cuO{m7SM-@`>YgT$|+Yhr1O88b6TIK9`fW2j6M4`JGOU^S`ihAyF#vByZM@%Xm0B&3q`>H#?kl9%P% zc)Ode{U1v)oxi@aj0#1d8n<$qs$85^AMwX)`MV}J)W?%R2#g1^fqZq$L=KaQZrrjU zmgG_30ee7|jQ#caA2Fw3O{SP&j}PDjdpSs~oDfH-qpa(vfJ*x(;*Z0%7)Ze>oJ*6x zVM-DH=UV{d;f{Bcm=E#0m&dY8lV)w~G!rXCqMyQT_nin~Fp%~i=}?0ePh+~yd5mHF zBa-Yn33(xu+MvesbSCQw@K#Xqeqhz&yge)Qz{`;mAb1O{SPdHrj|0dx4atGDUAFY&#M^e^VB(9 z5xI7_!SdO|1OC#Vzxa&Z111TxD009@jQe0q}L4InGFzG_Kfr3lKFGKx!CES6=BXD|th z#c-P?JOlWCzTi_TGD(~fxOlmueok!3VDvjhTxv%!CK7!ggS^?qg>CNQ$F>@qOod6y zyiXCsBmjR?u&Z{w(EkNRK)S#9fIw@$o?)vGTaT)X2?$VWh%{*-a5{C>QbM4Eh+v@D zdx}I&5`i!*GpxeW6Vr8wP9Yl@L~}K749Gju(XfV6!?A4@4uIb?_8|#-jp?=g-UURh zK60lx*K&!KJW$~-4v~=XxcxEKZjkKlZ&4P1&H*#VBJ34H!B-k!$PWv02&v$V!7)&z zf~^QyfwxQLK`i57M#x!tpyXtpDZ~;W|_#x1Tz;v`{=+y{^<7U4#iDyitVUYkySD^Hb{q^uO6g8*XzVu+^^u10CI!7Zp>P6dY*X!T6b z9CE_w;dsNF6N=kvrPm}t){{ioSG(4SijLJL=e}^NB6Ob8km@1EAh?oXO$xCZLP{z( zym~A#Ziv#52pJAlvAgTfCiwTx3CXxui;(oW}*%}}W%O+Zt z-l!s3J0wdce3_Xp1>aHT>>u*pvKXmz@4|gucy6j)wb)94skAwf=#Q}PWP4L8)l-L;J6UYq z{Q3lLXoM~ADm@25rrOB?w5{230T!VI#G?*nFZ%Tl*jHcr)O0zTCC8C+UXQtcnhQox4BpK{xf-wzfbCKlpfrcbg80VU zqKGnbk_Lcda7noYclEh95k}^SGV$!~igNAbrF)cO#H54`mwH7SZ!&pMe9?2Pm>@ag z*~#}6tAE|*p#UdkT%vKWNT6K<&k3qSFe5gw$q74eJ5^80zcZvTMFtx{hLV$lID|cn zi5O2ijn@hcNE%~eM2iw~8jgf=5t&{qn|YvW*7`OY$%eX$Nw0&;b6Wgfqe~sueTp&# z3CaO!ktF03TLY&6WyS<`U8T{h9$&zSEvHGynJmPvp>`}%BkExzfc8_I69J4;hfue(wM0u6Z<-c`u8IS?9;MiU3Km(G%PPzorL?w8 zKngEaxrDfR(baC?hkJm7U5gA}DaO0PM(NJY3P&df#0Gf3Ljbr2o8}a7HXaMQLdee+ zF$JtxQHYRkHgyuLc)XPf?2QK|(HD})S|tYGmPcc^rV>j7DgR0my1F%jYQHz&_7&-| zpoO%*y@lbKNfM9=NgGPLrnl3GQqU~{a5xb1fj~S z34C(t`y&5_W;TLS!~mZ3RJ=JzO~p^mvudRx2SYG(01{doK&VQflgDY^$DLqmFA%iS z8lZe46|C=Gj@?AVu-4jyDn1#wFU zsvHr`ggcEP+dYi(R4S_9;&3uEL`7(G{JD>MiUKejXi0;eS$e+mGFtl|6t@-RJy%f> zV}s({;4U8o{kVQ30WIw4~q1-Z1g8z~*p5W^4;I*w=|NMPj9Ll|=77+tt_nQv+U_wH!4 zJhqL83G8aBHu9HCzC@Yk#t}uOkGj)IUQ9>)iK<@0W-fxv^tg2wr+5mixy7| z7^f8aKABP?*|%$D3{g5y;+BvAn*iuC1pl{TCb{%_Nlg`x*lCH&$k1q6Rv7x1Mm5k; zd4q@<;COc7wr_)4Rd`iEjw@c>jdFa!R|e2iCnCJmM0X>l3BPiX)ZmzeA>^a2P(Vu; z)(v7G+?8KvYWpo#S;VL*NGk_o!)7S5-3*amX9#^6GT6AewkY)4%QI7UfK z)lE#~uI3dowaI^HE8lU786>qf1LV(tz>%E-ezh@~KlW>lIX@!NohRBYgsYTki?M#lzM58^PH zXD>L_w<+Z}1>g zCjd!=sppTc%_H=XI+RW1(nT|oMj($Xa)@083t>1=pp$y?y3$9^1TkPJGsN$T?sL`5tx^8FO(%xq*WctyF=k;krn(5X~CFBne5(F;DzVv~!ENeTFL2iA*)70vwo? zl-gj2u_Vq@b>%kzmbq%lFL(6Y%As#&fKVG#W#L6=lgQ+aCg^)wQ#v{X!+DoC*)&mXxW zyxQl%zK|CR1BGE}U2E&(8o-%8K(VN0#4iZRJ<@W7YRn`>X1qJtMIr)Y8wE+|iiTt% zYc^>Gvx*J#@_Dhr5Pd-!!V;x>V4HeZnq$cXMP~22qSX?^&myCZ^tB3^L{cXg8M7eC z(UKhkf;hN}>m%3&D9lZ+Gz1_B)YJWJbDN2x4j*{3DjwLf4l%4UjHr622-sNH3**A_ zu*?g!z+BtLaGia1gg+aK7Ske&;o?UCxFsuc9OKaw8WiX&s2at(Nr3eeky~#$_}(Er zT2562n{MfUl`u071mA%4;-eyr^g;IA2Y@t?E7n?IzQ8h`PRlH}VNQ35QVHzX@ND@O zh%uR9)>;`+)NcgfI($$gRxln8LtqN&g(;=QHRSi1DLs{D0bX`}8iC)WEe>J(SP9a} za^AZHIZQ-D1x)gq`hAABV`=DoKzg^NKoENY&cN{P4I#W`w8)9G^0rqg2qG^f2kF}r zm><3 z(G;1}=0Ng11T3|tsKNuNA^}*BB~5B3WHjL0tSqZPE}ISs6vBdGxOJ&g3wXtiXQIk8xbh7uM*@!)pxJO zA+rT_HjI<4v-6Xx{bK=9jkHJe8AxYkTzG*a8fm9$bI{QfN2d+B6rpD=T^p-;YO)eP zwEEoRhv-HRLOfX?xn5MNgpG1)L`vVKlz=#r1t4Ib6GAc@qT5cZyH+Si>~T4iYcY^Q zN1pR9P(iO%fkCQAxgN%YNG+M$dJ22@-qI~xEy6s25> zjGTX?jsS@sAFl7 zt-yAJ2X8&GNWsKNZC?d5SPMexiBLnm<%_UzGx=vMr#lHxQQ$o=>e8GDshGr{|30Kh zZ3BMN9z-98%ZFbYw5gC76+c)QMe$F7)aXX>1dMw}ZoBPjjlkYS9-0;ijpZavny6z> z>KLA?>nqw<0AT=-!qmwprDVZ4fU4RSfMt%l9KmX1rxsc*r0*hVc1iAK+(*c#vua5UsbAy0Y1(bMZOKk>E4%Jc$Au*iE_XoOTg&^eUQ3 z7!k1fmLPEw4-QTu5nAa7J{90Loj1V7d|F5g(gJwren=jkLgBlE_o!s41<`**CsBQ)rs7FJA~a!IC?sLdc0latI_Yv1u2dNygyNEt0Tr>I z@Qk?xu#Ia6XsH7fQ>Y#nuR{j(K=Qzm1L+_{NFnN?Cy;9C4++@c*cMznIz4{aQpma` zQCG|X<`s)RT&IMKaLvpKJY)9`2AS!~FIJSf2EpnvFW4CZFyK!kholDV?*W3AI4wRC!Uz_nz@Uvlzjn6el2mEsXymvv8+fa zO6e%NtRUzhdWpGj<=n&%XrNXyYKXFPU-C0cB!JFkV;snH=#YRoE6YA_09Kz)qA!H- zJjgMsUOGWW8ZsD^-CV?U4%@Se)^Uw0FhIC|u5el{$d?ON1TnBEPwlAL2sQPwE)c7; zrm3qQh;^X%MktGVaWz>~i$=#nsI!LFgNX zJpdK{AF$QSXPEvjG9l_x$i=x60a7Ha?DmSl;}i@O#zC<(F!R;l#ugM-5;rfcSWel^ zr8?iqcfj=_rQ5>%S#W_1%bRDy1;-AFU)g4HqC z_*Zh6*`g9;*z=O2nwCpEQ{orV8cz^5hon!n^z_4$>Fw$f1acinlW*CoWW0dbdcI8a zCs95*jd4|ys+MK=b;L1Lg*i%~$c;9eApIaExUDD|MQz@V$O9RfHeg#<@hxTuSfrv~ zfN4QtE$!4li9ny@eW7L&`ck%xHKzFtL8Yj^eN7g?ph7}Djf$12ZWTybr|N4q%W`74 z<~K@8#v`VZj%?iIGX&l;g%DOEXsb!H$cF$46j5ce2$%<7U$9&3b0%3s!jkf210q8Q zjtQwd8XCBZ3=08UR^5`|gAqdn=qIhR^}0^wEg2r=x1jtP5`1wA1#)vqmH)_&ReqTaq0r zk!-y$gL`zC7&O3NEpbI5-7O1XonWaF76qvpW?2$|Rc z7Wx-M`({t%O#f=v<&?g+6lM$~n%>q)$5a>L5?mrlF_^%y9evjf{b*R!7|0yv$O9u_ z+tq+FYFHQ`q3!qZ*D|}c0$h+@ykWdg2tjTt&#Ss6LSagh(Up63?h>_;G zu%q0#S87BPL0|_`12mNZT_p((I6cu?pP3-WsjRFaSa|OUQ+O%z4`u)cn}JyCzv#`o zE}Cm4ROJ;n#1Vy#jI1ix)b;#Azy`(C-bHd-JQCy2I0FKlrl{LAwOjtr+Sq1&50bBK zXN{!f=sd;=aZfD*0mbRD$}%BCrR|C)EO@vQgiwbVARW&8PaT3}Yn-4t@;3r`hY*?r z5QHixPR%xcR*syYGUKuf2Z?p0yo*{$=aVH}8_k5&keZrh4|y%5Qgm4b84ZYB zQ-X`h9ul!I!^vttU%>gogkD%WX30c{SaDED5mWOF#y!Y_Zbn-U32$yv-ZGVnh@rqY zSsh~-BJ`T5c*W9Pbdl<+0>vdNf^ijtUXpEg39mL#!ALVx)atQeDzCKSsH3CIs2q*!F_hf-o`$*2wGBb~^ZM4=HUk)>QQ5VnWzvI5o#i;E4! zN$Cspd}&aPpCnD{T=5{43qFm(N|Z$YF12Q%P%k&oItGX^@I({sCc!g4++XX}SnLZYp-cB!s?g`2=brh<7}+KH9_b*uB8SCL;)nuTtRKr07kU>qY=^ zhM~~m9_^#$P~9+TH94kzicmQa&syg`PihWGEU1D3ET~AlfZH(7gjGQ>RuEJ&f=J^9 z7G2yt7&1*V4$R^VSg5cF1i)pw(}*>4pWYU{n|bWK1`l z#~u@mZ>hqeL^@^KdN>_6>}D{*{}08K1Q*H!6$i#6{i^Pl!FoE0CLFMb5vLtEip#H) z38d;InZ;ic?HDA50B$fck3_Oc?bJ;iO^=|TF{A{Hvf!P@C>KQwMpNs&(3^ zELTP_g5W;v=2Kvv9njRKnWPzUih@lQ8SyFUW`+x0V(Vpi^p&7^M!RKFm){1@iDEUe z6czEvP^^8|zQ$=$KT`fUBW)pTP#bl8r%-Z%eEsA`3`Y6Ig6M+DW&_o3sXIU-9;LxY z+V2HYMq$VNqDE(0Q7|Jb-2`*mN9FMslz^TWif=(O2>Gzb52h!m$R-py9Gd7Fie#RH zFcD!3SkR!p7b$okM^U06jB_Drk>@0z!&S-Gl}LP4V!$44Dj2-YOAhUV*b~xJ>3^l> z=}|IFH)(r`CXnK;NknUn3vqz4zcAF>ijj&qwp{%L>F6u`WR8z8XH&N}3wn=AU&0^e zu9w6J1jRO&*au^N4YB%*9;k=UD8T{+3h&az&QM_T^OS?O!!@Tk(nM4Tm@V?d!;K$A zATxtm-UX*H*T)K2@Y^%+^x=Y9-W}aSMFm`L7KN5U=Dh&cNs)IYK(OkSUL>m7)B3Nv zpa~TApJarP6bPvST@sk9cftXOI%I4&V31G<;hKsedSypxKc6ZABsHHOkon|%@Ocyo zD8vI8LRiw0B99><13@_jLj>^A+YReH{h%`#i$^(7cAjg$6qcG@02pXjEtenEOH3SM zC-5rnG)v0lApr$E1L*0ekP+`mXT5e$7~UC_8Luw6y4$Y=A2z>FvOCE6?sdi64LS7 z!)^yJ#A2j&7!6FPh(%tKECwc!I8nxsrs5zx6K1mrS<=`Y)EQZej0X8S1QtVr#FQFgLoM zmD9BoVf3WJ?+C3|0?-7cBX`ZEf+AfRM^q-b4W;5&Ob{RsT!mHS!utj;E(e>SiNO5r z6440B)0e)i&j^#)R4NxR8nsMQlo!hlJ(c0hwIp~9nV^UPtf#DHOjy%0y?wBHk|Hyp z$j;X~d6CncAyIEdF{AE7ZGQnBPb$$nD}Yuf>kVS#HIO09iQEJ}vqyE<=Ass6HD4QL zfADMDvMUhH7;0RHO^X1mghv=I`Qv#w+$LBqYv5`f0F{bIZ_$A^hf0a#aBJY#fh1^^ z$CqUDn61;xEwzFSqX*!HM1kZS@n#W%6;b9!QGScWXJA@ObvTOo1}IQAj1{9??Q_R) z&~%+K=&V`-C+2zmZ4tN*`dT8nhb*<^!)6x5j%xK&Y;lV1Hb|!46!!1sshcK@1sGG; zQrsS~*D?`gQk`c5!Kff&a14f(wqJr4LDY^b?O*5H15DW_SrTi;frDDI8Jg30_@jo1&w9AA}zfr{#ZHfsY9cY*Xa2}kV%u%Jm)NfWYs+OMjsxEx!z!s{i zJ1ZYh0cVpqJz`I3`G6URsbirO4y2GeBxoR+&(-v*mEib)a z$JIs2B{N8*=@nj?3NFBpfY^)&s24WTn6<3!vC@YK7a`O)mdoJ7W)JWbB*&8hZX%>XzGU_KP8K4zmf}#$a&`nFR268RrFFh0H z_6WOHyxI?lsmZ|A0pIx?49G%X;M1e1FQkuZ$IydUjgnUcj;+kcYHD+mdcgv*kjjsF zZMx<|7=%*g!(w*se}lHHy7&OV1RNjpQA+WAYyka!nh7)?f$AWF6s`=k5trl<|)BJ7+fr2!qHC(9M!SXz;#i1H%+en?11pg%#scHbGS7EN4@GOEPdy!u+fy zC+&i1ShbkSg#an#Fy7J0(kdZUCcxt`VF=LzqZEPCFb-Q9iv&oTbSDdFIe_h?kfoDq z(PV{HuQ0hw4fGpJX~Sd&Q4nZR3kLjx(+i^%&%}Trn?_YrFOUI!%4I{{7aANHAQVkG zysX-3LL7zcY%Aajd?Wf@ z6~TvUAZ%jHW%@&vq*oa5XF~(|yy8eUDU*t+qdhqZGwA{=q>9x>egPtdD2EepIr&*G zJIC8$zqHEbV$y8(0~B|T+IvHwd_>uPN9xJzeFHQziWW?~PzTs5h$RR+LCH)d!DPrr zU}wMAW2F0_G6baYaa^ zh{F{d4NaYNj-l;nCw!L0#V*+Mdf2V|NpN@gBo9bK(%9(I0`5Ea}}N8?F({pmLY)CVcX=nW>LDXT2LVlEB9`uW0O)Fm#=_=~pMhc8V0h$%yhD^zIq~eLM%L>1B4b^TN9z0@>X1$tw3su z*rO~dO10^@3C15DLx1sn^2k93K+0L(u>Vjks$=#*0o&#vpy|NEmDHF*WaOsYPM$A- zdy{m$zEiH+E=6?@kUYEj@}U#uZn&i-LbQO++XwW!01Pl+2#{99C_@~YlbcT6ibIck zz_kH2)HVU>IXYHt5iP3>+-G9Q>r;N|fuWFH#zcRUqvOy6RMzzXcK8S1l0vxF<|9%1E#zK5OO3|w7;#d6dPR-h_kt`h&)B-X-=(}%i< z)6IEai^v*8SNqa8A!D%2Z6{_!F9wJ2R_^M)b9%CnL}Y{!ZDi2_*=u>7M*+j7JV&dE;#f+bm-s9imo14sNL361y=_SzUGL#M(6f(l%Xfr?Oc%@%!p zH4t|@273olh*I8g8H(s4uxyqt@WzO**ohHz9H6do80O`Y5KGbaA@~WfzLBj zorc8*$Icej$d~z=an=|#Y4dEv7MD~@Zof1+hv`*QSb4w<$S{W+We}9NSJkN|lw9#m zG8XFZ$W}?^akcCONbH6@D;B5oZx(HnLtICAoMLF4T*JK6F9mS-)Y8NQ6tPMa8VmO# zhY>L0eLjN$E+oI?Fbc|#YYIx?oY1`?Ff4j_(!hO02o(mV{jV4lp#-ZnksM^ME;T}j zUW%#!=$Hg_0nx5WAy-(4iv0Qf>DSXGi!IffL!YE$hJuh~iZmdG-B5c0IeHV^h|WF; z+)fajbaOH^9w~~lCyzWhER+j&S^+V3Es(hZ(>yP59p>Eqs^E7<(H6|?)Xm$ynpVI| zWd}A+n&3wU-yL@IiyQF z&OP4O;E3xjtyL5qS?5}!V-}KH*d9QFD!1@)`1|%3y57|Px$2^qT?MA4d1yirdLBcd z6H2<{S$Z!|y!XI}gWZb}9eA{4OB%^EXvYNFAQT3cBn4h32norkS@2Nf0OQVCvKW_Y z>`LDR$k-R0&>QCKoi2f>7bj_E&r;tZO!cDK9Qc4Q=8N~t#eoCDla6j>C{NC>DtuRWzZk*@g>9Tj zDSt@Iw8Vv#b$vJ>fqqe`r#Px6qXIq1-IrPL?iDS#tjId>T)5ad%buCg^h-1X}}qEk@l)f&9GUU7;*+ zQ^Hq3IHI$>bdQO-3cy?jyap^53#Zyy3Z;U>v@w0Dr#P+{WL)5)27=KEuw`EQf@q+P z-Z-hI$1DXbSvYAiX&PkSq`2l&SVyn{i6WrT>1-{gMC=+bKd58KzMJh<8psvAfDI3-jxJE8scU5>*yP6AztDG7s1 zu({wC#AMDb%%|JfNqRTKX4N`8S51}FPPH z2P3T1k%d{d878j$SHXg{7JMs1AY)Csg^FeAOLA#&!rVIeG+F+WPbLQ#d5!dewd|S;j6i39sdK1Nr3+o@TD_DSs z@uCaR2XCW7w~jTeau=8#TmaSyKqWA8xgSAp<5+Q|vVeUm3bPr`4v}NXE+P301>h_X z6Fvh#3h@2Xn671}M4r+)y&l$&Iz?pfBL(&bB*Ojz<(WId%(!Fa=e8lTOw|@Y$|vM% zKJ27Ezj_YG{Ut^7Fd(#al@KJzLxpf&FUDu9IWYtBCj+gxH6beIU}vg9GEOy;W&vVQ zg1fe&u~1nho!=P7eHzG;Iac8dAv7ZpY0%6Rvy0NCf_`ZDNDOX~Nu!WEG-)3SkN_~~ zYW7^9Uh4QZB@=sakU2s4>NkdPR^2AXWC7$6t)VX7ePP-vJW+_^nY9=CbZV6iu;~GR zKzs~kQB}06R~(-dK$Q<&+Xo7@n0`w>NKZ!SwUOONT+U`BdPO3#gsaZ7(E@gX2ueUy z%PQrGC-pRyOGc!9k%nwDBG9))^hH5pP91FX@O_3oP7hJEC-AbzfurY^!bs~KdPY)3 z&GrM~Ac#iJ*9CbAlSIg@K*koAYmo(qqVgfiH&;-x-{aAT-X?~)@~|NL0h9!#Xe3Hn zxzA`MFm&;h$6f;iRq|aANu63TLpL}27eLG!+R6}vEbc^MfSPL{zXM`Epx7fZPDKaA z3}i=kLCGoz*?QwDC%H}&C{DwHu4{!r>v4cC3N)&Wh~H>uJE9LHJ5L*$9Va zDMcN($nhaX@{R)ZSIo=~p<)sA&J9ft01*fMkgzo+#Y!T7cQiYA1iNEz>?RU-yRp(Q z`epKdQjbxDx>ZoLI>h(0AmTfb6m|!hrpXB2($=`-zN=*C45+l2m}-hx8XZmZ>wun0 zY>9@Hv>L@96)4W&8NJ1jA{4{{f@(^&Z-Q!(YU#V21(5 z{%=7Yzirx4#N~9tBbtb|Uw9F`o$Dy6!`kB?L5^AcNK1S*8HhG5-3w9+F^ryW6{-_Y zZ)h~){3{{Jk~p5Ay35i{aDa;LoudI2Wv7i)rQk|eB{YBk_U87=?EYs83_$L{6_2$u zG*MpKvaNaA;KRdHJVbX&srR%sR`js5g8yoTKd31{BZW9)=t+7jiF$*{DKEjoW<$)$ zn$aIb&Xhu8D5GD61Ku6!p?Q4(rUM>}aHw#g#Cq5?1k#6)0EK$W8>u=q!!7{yIvfo> zM`fTBF9rp%^yxlJ85bqtMb5n!6Cq2$H`6f-?3Mb?5E1?e8c%2$?1wRqpYm&lOqj{3 zI>d-~Qi_2Q%Rs6uH-ap=JUNVV`B*ugT?;XH;~5ErXfM zv%1Fwf_zF|aFmmsKQ`BCeii@>L5M@*9oc6^_r=5-dh`>ptOE%Uuq#6>RFgQZFsQr} zb6qXV9!;emsbKGz++Bi>S!6X0H8%-UbylPf)2o8Ly$`+73X*yOKtv_S(kvMS!B$6B zFGctIT^bykL26CJk{>^wXdE20pIHc)Pi(i1bTgHFu=EHI92|3v58oGXDw`JYWjRz_ zVxJ)9F=}Dw9sH5c`+$|B`l-h!yb;qn8B2xp?Upw{&S9+JE7^YOHw14evbl2No~Cl& z+5r-{A}Aq`vJcYNJ}HeLDGE|k5Z9VGC(}6))PnWt?GK?}PzSjN&iOqn46KBn0NjY<23n57Oj`|p`aP28PKf$*T54`NYaF3V&L+%c9{?kfsN z5vJW@EKc@Jyb*sU<(bx5gOaFvlC2Dvc=#g z;@6GJyhP*A)tqaUlkLLx#d_2xjQ_tmIB5No@Q;qjNL*&0sGL`D(;drRG@_ksF~-wN zl7he!Jt>+{dm!p3B|g}?L-A_9cbYE!^U;TmKw{3wfJW%LHKUG@5KN@_jhv10ngA(Q z=uQeM*A6@;1To}ChD(CHJ(|dJA}D`nuTx~jNz_vf)Jsszmy&{F8gCcQ1QCJaRJAYiUXildShYf2(am(=^Y{xT_}q!s35Ga8B%uLKN) zg~v~IRhb?Qt}+lK$asbZW|QYxo(_>FF1aCUkE8DM5og$J2-$D$o(gdUheW<+SbFF# zLmu{UD2;vENpw66&5lTw|QBJV_G%7Vt4t0(S>1lW<*{Y24}lJqWi1pYb{*Ka zu%Bt#BNM1Fx_Gc6NT`~k${JW~90m(QrX8`xD2e2*Z~sozb;7Ng9CqW)8XYzo*tW*% zAs{LA>BR+=;9&la(Pf4w`}rz<&X&g8MHdi9Je_nz&^x?0wOQs zu6Q4(!dD$}pHOfcNW6i5*B|RLPodl8XEitGHPx8SfOf66a4aYbrr>npPq`wiFPFl2 zhvi3o@jezz^)zkD3`W9_YH;F;u`DVi0E?V!q8&4|rC$pjyA^ad9=2|jx#=#dp;A>U^|492F1_>$zMx%a<5_C=N=y-!N`kd70G+K3Oigo78v zuU$5^V{$C~61a$U7LYuYaY26Am9vQY&Ojcv?ulpzlmIJp0GL`QuV4=Z?@5&P0w#qV zl)R(8Hkk;@%rw-W+Kqgnf|>EnKooA`iz&{tL`Ylp zFm8mXrzV57I3lcE!hq5tVgl3~xCcXgC?BLqknsKkI~WK%J>-lQ!BP1tm%*ACh|w1X z1>(8Olgto;izUfhI&we+mOu=R#*_JHDfWV8gJDhJ(NDK^(G7xJyqz$+k2 z)&O!Z>dK$FS?Etvj*Ao}D8rru|B{#vDiE!5q+-#-zI|+xG%5x!9=fP{!b<@ORoqIY z(NXzPxgO%t0!mZtV2Z#ve84)9Ce@fxXhF1{2|I6Ashl=G-1#1=a5*a8Ez;44~o znaOPfCdiq=YAkA9D{N;&B4S94Aw)!UM+!CI7V=@-uoGnCkw}MUIkcMM_syh#R5)mt zL%OkEOJ_7cSz&dNAwRCy?ivYED1ZTcFj=w~R%STsWZ)uDsMXU|0jz~G&@j07>V6Ea zDugE(sw#csOtk?1J=(Q`U1-sMRCee~w~W&%PgiPR z6hukrW41vs4>KdV4AQ_80hJ}1&}y*&+|l4yyNocuPqH)<=MIX9hpd6&o0W;VwD?-T z=ua6VP7tckv{UY96dOyy-GK`3V#H4(ev;(ou!|GUz=?|h%?bP@B-R{ijT9M}h(99Y z_2-QYX$V5elyVSms5J3n=tHOR1JNK=D3%=fQ%IIajys=dl(xAE89wijG;awZCrqz! zWIq1;D+?JDg>u(d2VA)2NpXvtziw5&1;A304TIS+bD8LL&TF9e_r;CfQB#)|xgt27=l($99H~61f-Qkwwb|jLbdc zfq)OKBO>|(tcO4t5@O-%=yVp%jEwpv`_^Mb@J)pkB~o<+!|U%wWEm%Di-^1x`fGO! ze);|{7SIN$o?-J`l~*b*kOB}X+bi9+gN=9ELNuDoytBBqQdV(5xskfx*byP!#FPu80D{F!?`7$?9} zf7s>%8X5y1NC7>gat({vE{1=qbfL3L3^Qp_S6!7}8rmsVQek5-l^M`MW9OYBMo&dV z1gEY*gq0eg${#ifxQT`av~oXTpL~>yW73djWHAQ@(C|~B8o{sJEm$>YpFa+=ro(dpoDfUl