From f6ea25b4d171045c263536d228ec4ab205841704 Mon Sep 17 00:00:00 2001 From: Karthik Gururaj Date: Mon, 17 Mar 2014 11:42:19 -0700 Subject: [PATCH] Parallel version of the JNI for the PairHMM The JNI treats shared memory as critical memory and doesn't allow any parallel reads or writes to it until the native code finishes. This is not a problem *per se* it is the right thing to do, but we need to enable **-nct** when running the haplotype caller and with it have multiple native PairHMM running for each map call. Move to a copy based memory sharing where the JNI simply copies the memory over to C++ and then has no blocked critical memory when running, allowing -nct to work. This version is slightly (almost unnoticeably) slower with -nct 1, but scales better with -nct 2-4 (we haven't tested anything beyond that because we know the GATK falls apart with higher levels of parallelism * Make VECTOR_LOGLESS_CACHING the default implementation for PairHMM. * Changed version number in pom.xml under public/VectorPairHMM * VectorPairHMM can now be compiled using gcc 4.8.x * Modified define-* to get rid of gcc warnings for extra tokens after #undefs * Added a Linux kernel version check for AVX - gcc's __builtin_cpu_supports function does not check whether the kernel supports AVX or not. * Updated PairHMM profiling code to update and print numbers only in single-thread mode * Edited README.md, pom.xml and Makefile for users to pass path to gcc 4.8.x if necessary * Moved all cpuid inline assembly to single function Changed info message to clog from cinfo * Modified version in pom.xml in VectorPairHMM from 3.1 to 3.2 * Deleted some unnecessary code * Modified C++ sandbox to print per interval timing --- .../haplotypecaller/HaplotypeCaller.java | 4 +- .../utils/pairhmm/JNILoglessPairHMM.java | 3 +- .../utils/pairhmm/VectorLoglessPairHMM.java | 14 +- .../VariantAnnotatorIntegrationTest.java | 2 +- ...lexAndSymbolicVariantsIntegrationTest.java | 2 +- .../HaplotypeCallerIntegrationTest.java | 2 +- public/VectorPairHMM/README.md | 7 +- public/VectorPairHMM/pom.xml | 5 +- .../src/main/c++/LoadTimeInitializer.cc | 11 +- .../src/main/c++/LoadTimeInitializer.h | 10 +- public/VectorPairHMM/src/main/c++/Makefile | 44 ++-- .../main/c++/avx_function_instantiations.cc | 3 +- public/VectorPairHMM/src/main/c++/baseline.cc | 12 +- .../src/main/c++/common_data_structure.h | 215 ++++++++++++++++++ .../src/main/c++/define-double.h | 50 ++-- .../VectorPairHMM/src/main/c++/define-float.h | 50 ++-- .../src/main/c++/define-sse-double.h | 54 ++--- .../src/main/c++/define-sse-float.h | 54 ++--- .../VectorPairHMM/src/main/c++/jni_common.h | 2 +- ...ng_utils_pairhmm_DebugJNILoglessPairHMM.cc | 1 - ...ting_utils_pairhmm_VectorLoglessPairHMM.cc | 2 +- .../src/main/c++/pairhmm-1-base.cc | 1 - .../src/main/c++/pairhmm-template-main.cc | 3 +- .../main/c++/sse_function_instantiations.cc | 3 +- public/VectorPairHMM/src/main/c++/template.h | 211 +---------------- public/VectorPairHMM/src/main/c++/utils.cc | 173 +++++++++----- public/VectorPairHMM/src/main/c++/utils.h | 12 +- .../VectorPairHMM/src/main/c++/vector_defs.h | 55 ----- .../src/main/c++/vector_function_prototypes.h | 44 ---- .../sting/utils/pairhmm/PairHMM.java | 26 ++- .../utils/pairhmm/libVectorLoglessPairHMM.so | Bin 444737 -> 446004 bytes 31 files changed, 548 insertions(+), 527 deletions(-) create mode 100644 public/VectorPairHMM/src/main/c++/common_data_structure.h delete mode 100644 public/VectorPairHMM/src/main/c++/vector_defs.h delete mode 100644 public/VectorPairHMM/src/main/c++/vector_function_prototypes.h diff --git a/protected/gatk-protected/src/main/java/org/broadinstitute/sting/gatk/walkers/haplotypecaller/HaplotypeCaller.java b/protected/gatk-protected/src/main/java/org/broadinstitute/sting/gatk/walkers/haplotypecaller/HaplotypeCaller.java index 7a25e8bc8..8d86da273 100644 --- a/protected/gatk-protected/src/main/java/org/broadinstitute/sting/gatk/walkers/haplotypecaller/HaplotypeCaller.java +++ b/protected/gatk-protected/src/main/java/org/broadinstitute/sting/gatk/walkers/haplotypecaller/HaplotypeCaller.java @@ -417,7 +417,7 @@ public class HaplotypeCaller extends ActiveRegionWalker, In */ @Hidden @Argument(fullName = "pair_hmm_implementation", shortName = "pairHMM", doc = "The PairHMM implementation to use for genotype likelihood calculations", required = false) - public PairHMM.HMM_IMPLEMENTATION pairHMM = PairHMM.HMM_IMPLEMENTATION.LOGLESS_CACHING; + public PairHMM.HMM_IMPLEMENTATION pairHMM = PairHMM.HMM_IMPLEMENTATION.VECTOR_LOGLESS_CACHING; @Hidden @Argument(fullName="keepRG", shortName="keepRG", doc="Only use read from this read group when making calls (but use all reads to build the assembly)", required = false) @@ -639,6 +639,8 @@ public class HaplotypeCaller extends ActiveRegionWalker, In logger.info("Using global mismapping rate of " + phredScaledGlobalReadMismappingRate + " => " + log10GlobalReadMismappingRate + " in log10 likelihood units"); } + //static member function - set number of threads + PairHMM.setNumberOfThreads(getToolkit().getTotalNumberOfThreads()); // create our likelihood calculation engine likelihoodCalculationEngine = createLikelihoodCalculationEngine(); diff --git a/protected/gatk-protected/src/main/java/org/broadinstitute/sting/utils/pairhmm/JNILoglessPairHMM.java b/protected/gatk-protected/src/main/java/org/broadinstitute/sting/utils/pairhmm/JNILoglessPairHMM.java index f039cc295..e6b9f0469 100644 --- a/protected/gatk-protected/src/main/java/org/broadinstitute/sting/utils/pairhmm/JNILoglessPairHMM.java +++ b/protected/gatk-protected/src/main/java/org/broadinstitute/sting/utils/pairhmm/JNILoglessPairHMM.java @@ -58,6 +58,7 @@ import java.util.HashMap; */ public abstract class JNILoglessPairHMM extends LoglessPairHMM { public abstract HashMap getHaplotypeToHaplotypeListIdxMap(); - protected long setupTime = 0; + protected long threadLocalSetupTimeDiff = 0; + protected static long pairHMMSetupTime = 0; } diff --git a/protected/gatk-protected/src/main/java/org/broadinstitute/sting/utils/pairhmm/VectorLoglessPairHMM.java b/protected/gatk-protected/src/main/java/org/broadinstitute/sting/utils/pairhmm/VectorLoglessPairHMM.java index e69d9ea50..9d46dac80 100644 --- a/protected/gatk-protected/src/main/java/org/broadinstitute/sting/utils/pairhmm/VectorLoglessPairHMM.java +++ b/protected/gatk-protected/src/main/java/org/broadinstitute/sting/utils/pairhmm/VectorLoglessPairHMM.java @@ -228,7 +228,7 @@ public class VectorLoglessPairHMM extends JNILoglessPairHMM { mLikelihoodArray = new double[readListSize*numHaplotypes]; //to store results if(doProfiling) - setupTime += (System.nanoTime() - startTime); + threadLocalSetupTimeDiff = (System.nanoTime() - startTime); //for(reads) // for(haplotypes) // compute_full_prob() @@ -251,7 +251,14 @@ public class VectorLoglessPairHMM extends JNILoglessPairHMM { readIdx += numHaplotypes; } if(doProfiling) - computeTime += (System.nanoTime() - startTime); + { + threadLocalPairHMMComputeTimeDiff = (System.nanoTime() - startTime); + //synchronized(doProfiling) + { + pairHMMComputeTime += threadLocalPairHMMComputeTimeDiff; + pairHMMSetupTime += threadLocalSetupTimeDiff; + } + } return likelihoodMap; } @@ -262,7 +269,8 @@ public class VectorLoglessPairHMM extends JNILoglessPairHMM { @Override public void close() { - System.out.println("Time spent in setup for JNI call : "+(setupTime*1e-9)); + if(doProfiling) + System.out.println("Time spent in setup for JNI call : "+(pairHMMSetupTime*1e-9)); super.close(); jniClose(); } diff --git a/protected/gatk-protected/src/test/java/org/broadinstitute/sting/gatk/walkers/annotator/VariantAnnotatorIntegrationTest.java b/protected/gatk-protected/src/test/java/org/broadinstitute/sting/gatk/walkers/annotator/VariantAnnotatorIntegrationTest.java index 287cd45d0..7776e979a 100644 --- a/protected/gatk-protected/src/test/java/org/broadinstitute/sting/gatk/walkers/annotator/VariantAnnotatorIntegrationTest.java +++ b/protected/gatk-protected/src/test/java/org/broadinstitute/sting/gatk/walkers/annotator/VariantAnnotatorIntegrationTest.java @@ -358,7 +358,7 @@ public class VariantAnnotatorIntegrationTest extends WalkerTest { final File outputVCFNoQD = executeTest("testQualByDepth calling without QD", specNoQD).getFirst().get(0); final String baseAnn = String.format("-T VariantAnnotator -R %s -V %s", REF, outputVCFNoQD.getAbsolutePath()) + " --no_cmdline_in_header -o %s -L 20:10130000-10134800 -A QualByDepth"; - final WalkerTestSpec specAnn = new WalkerTestSpec(baseAnn, 1, Arrays.asList("4ccdbebcfd02be87ae5b4ad94666f011")); + final WalkerTestSpec specAnn = new WalkerTestSpec(baseAnn, 1, Arrays.asList("214799b5d1c0809f042c557155ea6e13")); specAnn.disableShadowBCF(); final File outputVCFAnn = executeTest("testQualByDepth re-annotation of QD", specAnn).getFirst().get(0); diff --git a/protected/gatk-protected/src/test/java/org/broadinstitute/sting/gatk/walkers/haplotypecaller/HaplotypeCallerComplexAndSymbolicVariantsIntegrationTest.java b/protected/gatk-protected/src/test/java/org/broadinstitute/sting/gatk/walkers/haplotypecaller/HaplotypeCallerComplexAndSymbolicVariantsIntegrationTest.java index ec4291e1d..7598a0c96 100644 --- a/protected/gatk-protected/src/test/java/org/broadinstitute/sting/gatk/walkers/haplotypecaller/HaplotypeCallerComplexAndSymbolicVariantsIntegrationTest.java +++ b/protected/gatk-protected/src/test/java/org/broadinstitute/sting/gatk/walkers/haplotypecaller/HaplotypeCallerComplexAndSymbolicVariantsIntegrationTest.java @@ -64,7 +64,7 @@ public class HaplotypeCallerComplexAndSymbolicVariantsIntegrationTest extends Wa @Test public void testHaplotypeCallerMultiSampleComplex1() { - HCTestComplexVariants(privateTestDir + "AFR.complex.variants.bam", "", "65c316f1f3987d7bc94e887999920d45"); + HCTestComplexVariants(privateTestDir + "AFR.complex.variants.bam", "", "d1626d5fff419b8a782de954224e881f"); } private void HCTestSymbolicVariants(String bam, String args, String md5) { diff --git a/protected/gatk-protected/src/test/java/org/broadinstitute/sting/gatk/walkers/haplotypecaller/HaplotypeCallerIntegrationTest.java b/protected/gatk-protected/src/test/java/org/broadinstitute/sting/gatk/walkers/haplotypecaller/HaplotypeCallerIntegrationTest.java index 55aaaab5b..b16aa38b7 100644 --- a/protected/gatk-protected/src/test/java/org/broadinstitute/sting/gatk/walkers/haplotypecaller/HaplotypeCallerIntegrationTest.java +++ b/protected/gatk-protected/src/test/java/org/broadinstitute/sting/gatk/walkers/haplotypecaller/HaplotypeCallerIntegrationTest.java @@ -284,7 +284,7 @@ public class HaplotypeCallerIntegrationTest extends WalkerTest { public void HCTestConservativePcrIndelModelWGS() { WalkerTest.WalkerTestSpec spec = new WalkerTest.WalkerTestSpec( "-T HaplotypeCaller --disableDithering --pcr_indel_model CONSERVATIVE -R " + b37KGReference + " --no_cmdline_in_header -I " + NA12878_BAM + " -o %s -L 20:10,000,000-10,300,000", 1, - Arrays.asList("7592274ecd2b5ef4624dd2ed659536ef")); + Arrays.asList("1b41bf83b9c249a9a5fffb1e308668c1")); executeTest("HC calling with conservative indel error modeling on WGS intervals", spec); } diff --git a/public/VectorPairHMM/README.md b/public/VectorPairHMM/README.md index 85cc0a04a..ad4005526 100644 --- a/public/VectorPairHMM/README.md +++ b/public/VectorPairHMM/README.md @@ -44,9 +44,10 @@ end of every region (line 351 in PairHMMLikelihoodCalculationEngine). Note: Debug code has been moved to a separate class DebugJNILoglessPairHMM.java. Compiling: -Make sure you have icc (Intel C compiler) available. Currently, gcc does not seem to support all AVX -intrinsics. -This native library is called libVectorLoglessPairHMM.so +The native library (called libVectorLoglessPairHMM.so) can be compiled with icc (Intel C compiler) +or gcc versions >= 4.8.1 that support AVX intrinsics. By default, the make process tries to invoke +icc. To use gcc, edit the file 'pom.xml' (in this directory) and enable the environment variables +USE_GCC,C_COMPILER and CPP_COMPILER (edit and uncomment lines 60-62). Using Maven: Type 'mvn install' in this directory - this will build the library (by invoking 'make') and copy the native library to the directory diff --git a/public/VectorPairHMM/pom.xml b/public/VectorPairHMM/pom.xml index 41bb73211..2b69e5173 100644 --- a/public/VectorPairHMM/pom.xml +++ b/public/VectorPairHMM/pom.xml @@ -5,7 +5,7 @@ org.broadinstitute.sting sting-root - 2.8-SNAPSHOT + 3.2-SNAPSHOT ../../public/sting-root @@ -57,6 +57,9 @@ src/main/c++ ${java.home} + + + ${project.build.directory} diff --git a/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.cc b/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.cc index 0e3026f65..52accef3d 100644 --- a/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.cc +++ b/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.cc @@ -23,8 +23,8 @@ */ -#include "LoadTimeInitializer.h" #include "utils.h" +#include "LoadTimeInitializer.h" using namespace std; char* LoadTimeInitializerStatsNames[] = { @@ -43,6 +43,10 @@ LoadTimeInitializer g_load_time_initializer; LoadTimeInitializer::LoadTimeInitializer() //will be called when library is loaded { +#if (defined(__GNUC__) || defined(__GNUG__)) && !defined(__INTEL_COMPILER) + //compiles only with gcc >= 4.8 + __builtin_cpu_init(); +#endif ConvertChar::init(); #ifndef DISABLE_FTZ //Very important to get good performance on Intel processors @@ -71,11 +75,6 @@ LoadTimeInitializer::LoadTimeInitializer() //will be called when library is loa m_filename_to_fptr.clear(); m_written_files_set.clear(); - //Common buffer - 8MB - unsigned size = 1024*1024; - m_buffer = new uint64_t[size]; - m_buffer_size = size*sizeof(uint64_t); - initialize_function_pointers(); //Initialize static members of class diff --git a/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.h b/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.h index 8e45a4d94..d8e9aeeb4 100644 --- a/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.h +++ b/public/VectorPairHMM/src/main/c++/LoadTimeInitializer.h @@ -27,7 +27,7 @@ #define LOAD_TIME_INITIALIZER_H #include "headers.h" #include -#include "template.h" +/*#include "template.h"*/ enum LoadTimeInitializerStatsEnum { @@ -47,10 +47,6 @@ class LoadTimeInitializer { public: LoadTimeInitializer(); //will be called when library is loaded - ~LoadTimeInitializer() - { - delete[] m_buffer; - } void print_profiling(); void debug_dump(std::string filename, std::string s, bool to_append, bool add_newline=true); void debug_close(); @@ -72,8 +68,6 @@ class LoadTimeInitializer uint64_t m_data_transfer_time; //bytes copied uint64_t m_bytes_copied; - unsigned get_buffer_size() { return m_buffer_size; } - char* get_buffer() { return (char*)m_buffer; } private: std::map m_filename_to_fptr; std::set m_written_files_set; @@ -83,8 +77,6 @@ class LoadTimeInitializer double m_sum_square_stats[TOTAL_NUMBER_STATS]; uint64_t m_min_stats[TOTAL_NUMBER_STATS]; uint64_t m_max_stats[TOTAL_NUMBER_STATS]; - unsigned m_buffer_size; - uint64_t* m_buffer; }; extern LoadTimeInitializer g_load_time_initializer; diff --git a/public/VectorPairHMM/src/main/c++/Makefile b/public/VectorPairHMM/src/main/c++/Makefile index 354bca0bb..57fcc4e6d 100644 --- a/public/VectorPairHMM/src/main/c++/Makefile +++ b/public/VectorPairHMM/src/main/c++/Makefile @@ -32,14 +32,30 @@ JRE_HOME?=/opt/jdk1.7.0_25/jre JNI_COMPILATION_FLAGS=-D_REENTRANT -fPIC -I${JRE_HOME}/../include -I${JRE_HOME}/../include/linux -COMMON_COMPILATION_FLAGS=$(JNI_COMPILATION_FLAGS) -O3 -W -Wall -pedantic $(OMPCFLAGS) -Wno-unknown-pragmas -CC=icc -CXX=icc +#COMMON_COMPILATION_FLAGS=$(JNI_COMPILATION_FLAGS) -O3 -W -Wall -pedantic $(OMPCFLAGS) -Wno-unknown-pragmas +COMMON_COMPILATION_FLAGS=$(JNI_COMPILATION_FLAGS) -O3 -Wall $(OMPCFLAGS) -Wno-unknown-pragmas -Wno-write-strings -Wno-unused-variable -Wno-unused-but-set-variable +ifdef DISABLE_FTZ + COMMON_COMPILATION_FLAGS+=-DDISABLE_FTZ +endif + +ifdef USE_GCC + C_COMPILER?=gcc + CPP_COMPILER?=g++ + AVX_FLAGS=-mavx + SSE41_FLAGS=-msse4.1 + COMMON_COMPILATION_FLAGS+=-Wno-char-subscripts +else + C_COMPILER?=icc + CPP_COMPILER?=icc + AVX_FLAGS=-xAVX + SSE41_FLAGS=-xSSE4.1 + LIBFLAGS=-static-intel + ifdef DISABLE_FTZ + COMMON_COMPILATION_FLAGS+=-no-ftz + endif +endif LDFLAGS=-lm -lrt $(OMPLDFLAGS) -ifdef DISABLE_FTZ - COMMON_COMPILATION_FLAGS+=-DDISABLE_FTZ -no-ftz -endif PAPI_DIR=/home/karthikg/softwares/papi-5.3.0 ifdef USE_PAPI @@ -49,10 +65,6 @@ ifdef USE_PAPI endif endif -ifdef DISABLE_FTZ - COMMON_COMPILATION_FLAGS+=-DDISABLE_FTZ -no-ftz -endif - BIN=libVectorLoglessPairHMM.so pairhmm-template-main checker #BIN=checker @@ -79,8 +91,8 @@ NO_VECTOR_OBJECTS=$(NO_VECTOR_SOURCES:.cc=.o) AVX_OBJECTS=$(AVX_SOURCES:.cc=.o) SSE_OBJECTS=$(SSE_SOURCES:.cc=.o) $(NO_VECTOR_OBJECTS): CXXFLAGS=$(COMMON_COMPILATION_FLAGS) -$(AVX_OBJECTS): CXXFLAGS=$(COMMON_COMPILATION_FLAGS) -xAVX -$(SSE_OBJECTS): CXXFLAGS=$(COMMON_COMPILATION_FLAGS) -xSSE4.2 +$(AVX_OBJECTS): CXXFLAGS=$(COMMON_COMPILATION_FLAGS) $(AVX_FLAGS) +$(SSE_OBJECTS): CXXFLAGS=$(COMMON_COMPILATION_FLAGS) $(SSE41_FLAGS) OBJECTS=$(NO_VECTOR_OBJECTS) $(AVX_OBJECTS) $(SSE_OBJECTS) all: $(BIN) Sandbox.class copied_lib @@ -88,18 +100,18 @@ all: $(BIN) Sandbox.class copied_lib -include $(addprefix $(DEPDIR)/,$(SOURCES:.cc=.d)) checker: pairhmm-1-base.o $(COMMON_OBJECTS) - $(CXX) $(OMPLFLAGS) -o $@ $^ $(LDFLAGS) + $(CPP_COMPILER) $(OMPLFLAGS) -o $@ $^ $(LDFLAGS) pairhmm-template-main: pairhmm-template-main.o $(COMMON_OBJECTS) - $(CXX) $(OMPLFLAGS) -o $@ $^ $(LDFLAGS) + $(CPP_COMPILER) $(OMPLFLAGS) -o $@ $^ $(LDFLAGS) libVectorLoglessPairHMM.so: $(LIBOBJECTS) - $(CXX) $(OMPLFLAGS) -shared -static-intel -o $@ $(LIBOBJECTS) ${LDFLAGS} + $(CPP_COMPILER) $(OMPLFLAGS) -shared $(LIBFLAGS) -o $@ $(LIBOBJECTS) ${LDFLAGS} $(OBJECTS): %.o: %.cc @mkdir -p $(DEPDIR) - $(CXX) -c -MMD -MF $(DF) $(CXXFLAGS) $(OUTPUT_OPTION) $< + $(CPP_COMPILER) -c -MMD -MF $(DF) $(CXXFLAGS) $(OUTPUT_OPTION) $< Sandbox.class: Sandbox.java javac Sandbox.java diff --git a/public/VectorPairHMM/src/main/c++/avx_function_instantiations.cc b/public/VectorPairHMM/src/main/c++/avx_function_instantiations.cc index 6d90d5070..1a6b593c2 100644 --- a/public/VectorPairHMM/src/main/c++/avx_function_instantiations.cc +++ b/public/VectorPairHMM/src/main/c++/avx_function_instantiations.cc @@ -23,7 +23,6 @@ */ -#include "template.h" #undef SIMD_ENGINE #undef SIMD_ENGINE_SSE @@ -31,6 +30,8 @@ #define SIMD_ENGINE avx #define SIMD_ENGINE_AVX +#include "template.h" + #include "define-float.h" #include "shift_template.c" #include "pairhmm-template-kernel.cc" diff --git a/public/VectorPairHMM/src/main/c++/baseline.cc b/public/VectorPairHMM/src/main/c++/baseline.cc index a2dd8d329..17d2c279e 100644 --- a/public/VectorPairHMM/src/main/c++/baseline.cc +++ b/public/VectorPairHMM/src/main/c++/baseline.cc @@ -24,7 +24,7 @@ #include "headers.h" -#include "template.h" +#include "common_data_structure.h" #include "utils.h" #include "LoadTimeInitializer.h" using namespace std; @@ -48,17 +48,8 @@ NUMBER compute_full_prob(testcase *tc, NUMBER *before_last_log) //a straightforward array of pointers ensures that all data lies 'close' in memory, increasing //the chance of being stored together in the cache. Also, prefetchers can learn memory access //patterns for 2D arrays, not possible for array of pointers - //bool locally_allocated = false; //NUMBER* common_buffer = 0; NUMBER* common_buffer = new NUMBER[3*ROWS*COLS + ROWS*6]; - //unsigned curr_size = sizeof(NUMBER)*(3*ROWS*COLS + ROWS*6); - //if(true) - //{ - //common_buffer = new NUMBER[3*ROWS*COLS + ROWS*6]; - //locally_allocated = true; - //} - //else - //common_buffer = (NUMBER*)(g_load_time_initializer.get_buffer()); //pointers to within the allocated buffer NUMBER** common_pointer_buffer = new NUMBER*[4*ROWS]; NUMBER* ptr = common_buffer; @@ -154,7 +145,6 @@ NUMBER compute_full_prob(testcase *tc, NUMBER *before_last_log) #ifndef USE_STACK_ALLOCATION delete[] common_pointer_buffer; - //if(locally_allocated) delete[] common_buffer; #endif diff --git a/public/VectorPairHMM/src/main/c++/common_data_structure.h b/public/VectorPairHMM/src/main/c++/common_data_structure.h new file mode 100644 index 000000000..4b5f0341c --- /dev/null +++ b/public/VectorPairHMM/src/main/c++/common_data_structure.h @@ -0,0 +1,215 @@ +#ifndef COMMON_DATA_STRUCTURE_H +#define COMMON_DATA_STRUCTURE_H + +#include "headers.h" + +#define CAT(X,Y) X####Y +#define CONCAT(X,Y) CAT(X,Y) + +#define MM 0 +#define GapM 1 +#define MX 2 +#define XX 3 +#define MY 4 +#define YY 5 + +//#define MROWS 500 +//#define MCOLS 1000 + + +#define MAX_QUAL 254 +#define MAX_JACOBIAN_TOLERANCE 8.0 +#define JACOBIAN_LOG_TABLE_STEP 0.0001 +#define JACOBIAN_LOG_TABLE_INV_STEP (1.0 / JACOBIAN_LOG_TABLE_STEP) +#define MAXN 70000 +#define LOG10_CACHE_SIZE (4*MAXN) // we need to be able to go up to 2*(2N) when calculating some of the coefficients +#define JACOBIAN_LOG_TABLE_SIZE ((int) (MAX_JACOBIAN_TOLERANCE / JACOBIAN_LOG_TABLE_STEP) + 1) + +template +struct ContextBase +{ + public: + NUMBER ph2pr[128]; + NUMBER INITIAL_CONSTANT; + NUMBER LOG10_INITIAL_CONSTANT; + NUMBER RESULT_THRESHOLD; + + static bool staticMembersInitializedFlag; + static NUMBER jacobianLogTable[JACOBIAN_LOG_TABLE_SIZE]; + static NUMBER matchToMatchProb[((MAX_QUAL + 1) * (MAX_QUAL + 2)) >> 1]; + + static void initializeStaticMembers() + { + if(!staticMembersInitializedFlag) + { + //Order of calls important - Jacobian first, then MatchToMatch + initializeJacobianLogTable(); + initializeMatchToMatchProb(); + staticMembersInitializedFlag = true; + } + } + + static void deleteStaticMembers() + { + if(staticMembersInitializedFlag) + { + staticMembersInitializedFlag = false; + } + } + + //Called only once during library load - don't bother to optimize with single precision fp + static void initializeJacobianLogTable() + { + for (int k = 0; k < JACOBIAN_LOG_TABLE_SIZE; k++) { + jacobianLogTable[k] = (NUMBER)(log10(1.0 + pow(10.0, -((double) k) * JACOBIAN_LOG_TABLE_STEP))); + } + } + + //Called only once per library load - don't bother optimizing with single fp + static void initializeMatchToMatchProb() + { + double LN10 = log(10); + double INV_LN10 = 1.0/LN10; + for (int i = 0, offset = 0; i <= MAX_QUAL; offset += ++i) + for (int j = 0; j <= i; j++) { + double log10Sum = approximateLog10SumLog10(-0.1*i, -0.1*j); + double matchToMatchLog10 = + log1p(-std::min(1.0,pow(10,log10Sum))) * INV_LN10; + matchToMatchProb[offset + j] = (NUMBER)(pow(10,matchToMatchLog10)); + } + } + //Called during computation - use single precision where possible + static int fastRound(NUMBER d) { + return (d > ((NUMBER)0.0)) ? (int) (d + ((NUMBER)0.5)) : (int) (d - ((NUMBER)0.5)); + } + //Called during computation - use single precision where possible + static NUMBER approximateLog10SumLog10(NUMBER small, NUMBER big) { + // make sure small is really the smaller value + if (small > big) { + NUMBER t = big; + big = small; + small = t; + } + + if (isinf(small) == -1 || isinf(big) == -1) + return big; + + NUMBER diff = big - small; + if (diff >= ((NUMBER)MAX_JACOBIAN_TOLERANCE)) + return big; + + // OK, so |y-x| < tol: we use the following identity then: + // we need to compute log10(10^x + 10^y) + // By Jacobian logarithm identity, this is equal to + // max(x,y) + log10(1+10^-abs(x-y)) + // we compute the second term as a table lookup with integer quantization + // we have pre-stored correction for 0,0.1,0.2,... 10.0 + int ind = fastRound((NUMBER)(diff * ((NUMBER)JACOBIAN_LOG_TABLE_INV_STEP))); // hard rounding + return big + jacobianLogTable[ind]; + } +}; + +template +struct Context : public ContextBase +{}; + +template<> +struct Context : public ContextBase +{ + Context():ContextBase() + { + for (int x = 0; x < 128; x++) + ph2pr[x] = pow(10.0, -((double)x) / 10.0); + + INITIAL_CONSTANT = ldexp(1.0, 1020.0); + LOG10_INITIAL_CONSTANT = log10(INITIAL_CONSTANT); + RESULT_THRESHOLD = 0.0; + } + + double LOG10(double v){ return log10(v); } + inline double POW(double b, double e) { return pow(b,e); } + + static double _(double n){ return n; } + static double _(float n){ return ((double) n); } +}; + +template<> +struct Context : public ContextBase +{ + Context() : ContextBase() + { + for (int x = 0; x < 128; x++) + { + ph2pr[x] = powf(10.f, -((float)x) / 10.f); + } + + INITIAL_CONSTANT = ldexpf(1.f, 120.f); + LOG10_INITIAL_CONSTANT = log10f(INITIAL_CONSTANT); + RESULT_THRESHOLD = ldexpf(1.f, -110.f); + } + + float LOG10(float v){ return log10f(v); } + inline float POW(float b, float e) { return powf(b,e); } + + static float _(double n){ return ((float) n); } + static float _(float n){ return n; } +}; + +#define SET_MATCH_TO_MATCH_PROB(output, insQual, delQual) \ +{ \ + int minQual = delQual; \ + int maxQual = insQual; \ + if (insQual <= delQual) \ + { \ + minQual = insQual; \ + maxQual = delQual; \ + } \ + (output) = (MAX_QUAL < maxQual) ? \ + ((NUMBER)1.0) - ctx.POW(((NUMBER)10), ctx.approximateLog10SumLog10(((NUMBER)-0.1)*minQual, ((NUMBER)-0.1)*maxQual)) \ + : ctx.matchToMatchProb[((maxQual * (maxQual + 1)) >> 1) + minQual]; \ +} + + + +typedef struct +{ + int rslen, haplen; + /*int *q, *i, *d, *c;*/ + /*int q[MROWS], i[MROWS], d[MROWS], c[MROWS];*/ + char *q, *i, *d, *c; + char *hap, *rs; + int *ihap; + int *irs; +} testcase; + +#define MIN_ACCEPTED 1e-28f +#define NUM_DISTINCT_CHARS 5 +#define AMBIG_CHAR 4 + +class ConvertChar { + + static uint8_t conversionTable[255] ; + +public: + + static void init() { + assert (NUM_DISTINCT_CHARS == 5) ; + assert (AMBIG_CHAR == 4) ; + + conversionTable['A'] = 0 ; + conversionTable['C'] = 1 ; + conversionTable['T'] = 2 ; + conversionTable['G'] = 3 ; + conversionTable['N'] = 4 ; + } + + static inline uint8_t get(uint8_t input) { + return conversionTable[input] ; + } + +}; + +int normalize(char c); +int read_testcase(testcase *tc, FILE* ifp=0); + +#endif diff --git a/public/VectorPairHMM/src/main/c++/define-double.h b/public/VectorPairHMM/src/main/c++/define-double.h index 2067d369c..96fc274c4 100644 --- a/public/VectorPairHMM/src/main/c++/define-double.h +++ b/public/VectorPairHMM/src/main/c++/define-double.h @@ -42,33 +42,33 @@ #undef MASK_TYPE #undef MASK_ALL_ONES -#undef SET_VEC_ZERO(__vec) -#undef VEC_OR(__v1, __v2) -#undef VEC_ADD(__v1, __v2) -#undef VEC_SUB(__v1, __v2) -#undef VEC_MUL(__v1, __v2) -#undef VEC_DIV(__v1, __v2) -#undef VEC_BLEND(__v1, __v2, __mask) -#undef VEC_BLENDV(__v1, __v2, __maskV) -#undef VEC_CAST_256_128(__v1) -#undef VEC_EXTRACT_128(__v1, __im) -#undef VEC_EXTRACT_UNIT(__v1, __im) -#undef VEC_SET1_VAL128(__val) -#undef VEC_MOVE(__v1, __val) -#undef VEC_CAST_128_256(__v1) -#undef VEC_INSERT_VAL(__v1, __val, __pos) -#undef VEC_CVT_128_256(__v1) -#undef VEC_SET1_VAL(__val) -#undef VEC_POPCVT_CHAR(__ch) -#undef VEC_LDPOPCVT_CHAR(__addr) -#undef VEC_CMP_EQ(__v1, __v2) -#undef VEC_SET_LSE(__val) -#undef SHIFT_HAP(__v1, __val) +#undef SET_VEC_ZERO +#undef VEC_OR +#undef VEC_ADD +#undef VEC_SUB +#undef VEC_MUL +#undef VEC_DIV +#undef VEC_BLEND +#undef VEC_BLENDV +#undef VEC_CAST_256_128 +#undef VEC_EXTRACT_128 +#undef VEC_EXTRACT_UNIT +#undef VEC_SET1_VAL128 +#undef VEC_MOVE +#undef VEC_CAST_128_256 +#undef VEC_INSERT_VAL +#undef VEC_CVT_128_256 +#undef VEC_SET1_VAL +#undef VEC_POPCVT_CHAR +#undef VEC_LDPOPCVT_CHAR +#undef VEC_CMP_EQ +#undef VEC_SET_LSE +#undef SHIFT_HAP #undef MASK_VEC -#undef VEC_SSE_TO_AVX(__vsLow, __vsHigh, __vdst) -#undef VEC_SHIFT_LEFT_1BIT(__vs) +#undef VEC_SSE_TO_AVX +#undef VEC_SHIFT_LEFT_1BIT #undef MASK_ALL_ONES -#undef COMPARE_VECS(__v1, __v2) +#undef COMPARE_VECS #undef _256_INT_TYPE #undef BITMASK_VEC #endif diff --git a/public/VectorPairHMM/src/main/c++/define-float.h b/public/VectorPairHMM/src/main/c++/define-float.h index 318f78280..056bd53f5 100644 --- a/public/VectorPairHMM/src/main/c++/define-float.h +++ b/public/VectorPairHMM/src/main/c++/define-float.h @@ -42,33 +42,33 @@ #undef MASK_TYPE #undef MASK_ALL_ONES -#undef SET_VEC_ZERO(__vec) -#undef VEC_OR(__v1, __v2) -#undef VEC_ADD(__v1, __v2) -#undef VEC_SUB(__v1, __v2) -#undef VEC_MUL(__v1, __v2) -#undef VEC_DIV(__v1, __v2) -#undef VEC_BLEND(__v1, __v2, __mask) -#undef VEC_BLENDV(__v1, __v2, __maskV) -#undef VEC_CAST_256_128(__v1) -#undef VEC_EXTRACT_128(__v1, __im) -#undef VEC_EXTRACT_UNIT(__v1, __im) -#undef VEC_SET1_VAL128(__val) -#undef VEC_MOVE(__v1, __val) -#undef VEC_CAST_128_256(__v1) -#undef VEC_INSERT_VAL(__v1, __val, __pos) -#undef VEC_CVT_128_256(__v1) -#undef VEC_SET1_VAL(__val) -#undef VEC_POPCVT_CHAR(__ch) -#undef VEC_LDPOPCVT_CHAR(__addr) -#undef VEC_CMP_EQ(__v1, __v2) -#undef VEC_SET_LSE(__val) -#undef SHIFT_HAP(__v1, __val) +#undef SET_VEC_ZERO +#undef VEC_OR +#undef VEC_ADD +#undef VEC_SUB +#undef VEC_MUL +#undef VEC_DIV +#undef VEC_BLEND +#undef VEC_BLENDV +#undef VEC_CAST_256_128 +#undef VEC_EXTRACT_128 +#undef VEC_EXTRACT_UNIT +#undef VEC_SET1_VAL128 +#undef VEC_MOVE +#undef VEC_CAST_128_256 +#undef VEC_INSERT_VAL +#undef VEC_CVT_128_256 +#undef VEC_SET1_VAL +#undef VEC_POPCVT_CHAR +#undef VEC_LDPOPCVT_CHAR +#undef VEC_CMP_EQ +#undef VEC_SET_LSE +#undef SHIFT_HAP #undef MASK_VEC -#undef VEC_SSE_TO_AVX(__vsLow, __vsHigh, __vdst) -#undef VEC_SHIFT_LEFT_1BIT(__vs) +#undef VEC_SSE_TO_AVX +#undef VEC_SHIFT_LEFT_1BIT #undef MASK_ALL_ONES -#undef COMPARE_VECS(__v1, __v2) +#undef COMPARE_VECS #undef _256_INT_TYPE #undef BITMASK_VEC #endif diff --git a/public/VectorPairHMM/src/main/c++/define-sse-double.h b/public/VectorPairHMM/src/main/c++/define-sse-double.h index 2d271a854..9456e1453 100644 --- a/public/VectorPairHMM/src/main/c++/define-sse-double.h +++ b/public/VectorPairHMM/src/main/c++/define-sse-double.h @@ -40,35 +40,35 @@ #undef MASK_TYPE #undef MASK_ALL_ONES -#undef VEC_EXTRACT_UNIT(__v1, __im) -#undef VEC_INSERT_UNIT(__v1,__ins,__im) -#undef SET_VEC_ZERO(__vec) -#undef VEC_OR(__v1, __v2) -#undef VEC_ADD(__v1, __v2) -#undef VEC_SUB(__v1, __v2) -#undef VEC_MUL(__v1, __v2) -#undef VEC_DIV(__v1, __v2) -#undef VEC_BLEND(__v1, __v2, __mask) -#undef VEC_BLENDV(__v1, __v2, __maskV) -#undef VEC_CAST_256_128(__v1) -#undef VEC_EXTRACT_128(__v1, __im) -#undef VEC_EXTRACT_UNIT(__v1, __im) -#undef VEC_SET1_VAL128(__val) -#undef VEC_MOVE(__v1, __val) -#undef VEC_CAST_128_256(__v1) -#undef VEC_INSERT_VAL(__v1, __val, __pos) -#undef VEC_CVT_128_256(__v1) -#undef VEC_SET1_VAL(__val) -#undef VEC_POPCVT_CHAR(__ch) -#undef VEC_LDPOPCVT_CHAR(__addr) -#undef VEC_CMP_EQ(__v1, __v2) -#undef VEC_SET_LSE(__val) -#undef SHIFT_HAP(__v1, __val) +#undef VEC_EXTRACT_UNIT +#undef VEC_INSERT_UNIT +#undef SET_VEC_ZERO +#undef VEC_OR +#undef VEC_ADD +#undef VEC_SUB +#undef VEC_MUL +#undef VEC_DIV +#undef VEC_BLEND +#undef VEC_BLENDV +#undef VEC_CAST_256_128 +#undef VEC_EXTRACT_128 +#undef VEC_EXTRACT_UNIT +#undef VEC_SET1_VAL128 +#undef VEC_MOVE +#undef VEC_CAST_128_256 +#undef VEC_INSERT_VAL +#undef VEC_CVT_128_256 +#undef VEC_SET1_VAL +#undef VEC_POPCVT_CHAR +#undef VEC_LDPOPCVT_CHAR +#undef VEC_CMP_EQ +#undef VEC_SET_LSE +#undef SHIFT_HAP #undef MASK_VEC -#undef VEC_SSE_TO_AVX(__vsLow, __vsHigh, __vdst) -#undef VEC_SHIFT_LEFT_1BIT(__vs) +#undef VEC_SSE_TO_AVX +#undef VEC_SHIFT_LEFT_1BIT #undef MASK_ALL_ONES -#undef COMPARE_VECS(__v1, __v2) +#undef COMPARE_VECS #undef _256_INT_TYPE #undef BITMASK_VEC #endif diff --git a/public/VectorPairHMM/src/main/c++/define-sse-float.h b/public/VectorPairHMM/src/main/c++/define-sse-float.h index 20af947dd..e9371c000 100644 --- a/public/VectorPairHMM/src/main/c++/define-sse-float.h +++ b/public/VectorPairHMM/src/main/c++/define-sse-float.h @@ -40,35 +40,35 @@ #undef MASK_TYPE #undef MASK_ALL_ONES -#undef VEC_EXTRACT_UNIT(__v1, __im) -#undef VEC_INSERT_UNIT(__v1,__ins,__im) -#undef SET_VEC_ZERO(__vec) -#undef VEC_OR(__v1, __v2) -#undef VEC_ADD(__v1, __v2) -#undef VEC_SUB(__v1, __v2) -#undef VEC_MUL(__v1, __v2) -#undef VEC_DIV(__v1, __v2) -#undef VEC_BLEND(__v1, __v2, __mask) -#undef VEC_BLENDV(__v1, __v2, __maskV) -#undef VEC_CAST_256_128(__v1) -#undef VEC_EXTRACT_128(__v1, __im) -#undef VEC_EXTRACT_UNIT(__v1, __im) -#undef VEC_SET1_VAL128(__val) -#undef VEC_MOVE(__v1, __val) -#undef VEC_CAST_128_256(__v1) -#undef VEC_INSERT_VAL(__v1, __val, __pos) -#undef VEC_CVT_128_256(__v1) -#undef VEC_SET1_VAL(__val) -#undef VEC_POPCVT_CHAR(__ch) -#undef VEC_LDPOPCVT_CHAR(__addr) -#undef VEC_CMP_EQ(__v1, __v2) -#undef VEC_SET_LSE(__val) -#undef SHIFT_HAP(__v1, __val) +#undef VEC_EXTRACT_UNIT +#undef VEC_INSERT_UNIT +#undef SET_VEC_ZERO +#undef VEC_OR +#undef VEC_ADD +#undef VEC_SUB +#undef VEC_MUL +#undef VEC_DIV +#undef VEC_BLEND +#undef VEC_BLENDV +#undef VEC_CAST_256_128 +#undef VEC_EXTRACT_128 +#undef VEC_EXTRACT_UNIT +#undef VEC_SET1_VAL128 +#undef VEC_MOVE +#undef VEC_CAST_128_256 +#undef VEC_INSERT_VAL +#undef VEC_CVT_128_256 +#undef VEC_SET1_VAL +#undef VEC_POPCVT_CHAR +#undef VEC_LDPOPCVT_CHAR +#undef VEC_CMP_EQ +#undef VEC_SET_LSE +#undef SHIFT_HAP #undef MASK_VEC -#undef VEC_SSE_TO_AVX(__vsLow, __vsHigh, __vdst) -#undef VEC_SHIFT_LEFT_1BIT(__vs) +#undef VEC_SSE_TO_AVX +#undef VEC_SHIFT_LEFT_1BIT #undef MASK_ALL_ONES -#undef COMPARE_VECS(__v1, __v2) +#undef COMPARE_VECS #undef _256_INT_TYPE #undef BITMASK_VEC #endif diff --git a/public/VectorPairHMM/src/main/c++/jni_common.h b/public/VectorPairHMM/src/main/c++/jni_common.h index ee43da2ec..b3139d4ac 100644 --- a/public/VectorPairHMM/src/main/c++/jni_common.h +++ b/public/VectorPairHMM/src/main/c++/jni_common.h @@ -37,7 +37,7 @@ /*#define DUMP_TO_SANDBOX 1*/ -#define DIRECT_ACCESS_TO_JAVA_HEAP_MEMORY 1 +/*#define DIRECT_ACCESS_TO_JAVA_HEAP_MEMORY 1*/ #ifdef DIRECT_ACCESS_TO_JAVA_HEAP_MEMORY //Gets direct access to Java arrays diff --git a/public/VectorPairHMM/src/main/c++/org_broadinstitute_sting_utils_pairhmm_DebugJNILoglessPairHMM.cc b/public/VectorPairHMM/src/main/c++/org_broadinstitute_sting_utils_pairhmm_DebugJNILoglessPairHMM.cc index 8a3f8b5bc..641e2016d 100644 --- a/public/VectorPairHMM/src/main/c++/org_broadinstitute_sting_utils_pairhmm_DebugJNILoglessPairHMM.cc +++ b/public/VectorPairHMM/src/main/c++/org_broadinstitute_sting_utils_pairhmm_DebugJNILoglessPairHMM.cc @@ -26,7 +26,6 @@ #include "headers.h" #include "jni_common.h" #include "org_broadinstitute_sting_utils_pairhmm_DebugJNILoglessPairHMM.h" -#include "template.h" #include "utils.h" #include "LoadTimeInitializer.h" #include "jnidebug.h" diff --git a/public/VectorPairHMM/src/main/c++/org_broadinstitute_sting_utils_pairhmm_VectorLoglessPairHMM.cc b/public/VectorPairHMM/src/main/c++/org_broadinstitute_sting_utils_pairhmm_VectorLoglessPairHMM.cc index 220b1aa60..9c00c45af 100644 --- a/public/VectorPairHMM/src/main/c++/org_broadinstitute_sting_utils_pairhmm_VectorLoglessPairHMM.cc +++ b/public/VectorPairHMM/src/main/c++/org_broadinstitute_sting_utils_pairhmm_VectorLoglessPairHMM.cc @@ -26,7 +26,7 @@ #include "headers.h" #include "jni_common.h" #include "org_broadinstitute_sting_utils_pairhmm_VectorLoglessPairHMM.h" -#include "template.h" +//#include "template.h" #include "utils.h" #include "LoadTimeInitializer.h" diff --git a/public/VectorPairHMM/src/main/c++/pairhmm-1-base.cc b/public/VectorPairHMM/src/main/c++/pairhmm-1-base.cc index d2cc7d903..20e9910a6 100644 --- a/public/VectorPairHMM/src/main/c++/pairhmm-1-base.cc +++ b/public/VectorPairHMM/src/main/c++/pairhmm-1-base.cc @@ -29,7 +29,6 @@ using namespace std; int main(int argc, char** argv) { -#define BATCH_SIZE 10000 if(argc < 2) { cerr << "Needs path to input file as argument\n"; diff --git a/public/VectorPairHMM/src/main/c++/pairhmm-template-main.cc b/public/VectorPairHMM/src/main/c++/pairhmm-template-main.cc index 00946d086..4f8304689 100644 --- a/public/VectorPairHMM/src/main/c++/pairhmm-template-main.cc +++ b/public/VectorPairHMM/src/main/c++/pairhmm-template-main.cc @@ -24,12 +24,11 @@ #include "headers.h" -#include "template.h" -#include "vector_defs.h" #define SIMD_ENGINE avx #define SIMD_ENGINE_AVX +#include "utils.h" #define BATCH_SIZE 10000 #define RUN_HYBRID diff --git a/public/VectorPairHMM/src/main/c++/sse_function_instantiations.cc b/public/VectorPairHMM/src/main/c++/sse_function_instantiations.cc index 550272494..a8b88f6c7 100644 --- a/public/VectorPairHMM/src/main/c++/sse_function_instantiations.cc +++ b/public/VectorPairHMM/src/main/c++/sse_function_instantiations.cc @@ -23,7 +23,6 @@ */ -#include "template.h" #undef SIMD_ENGINE #undef SIMD_ENGINE_AVX @@ -31,6 +30,8 @@ #define SIMD_ENGINE sse #define SIMD_ENGINE_SSE +#include "template.h" + #include "define-sse-float.h" #include "shift_template.c" #include "pairhmm-template-kernel.cc" diff --git a/public/VectorPairHMM/src/main/c++/template.h b/public/VectorPairHMM/src/main/c++/template.h index ce4dbfc86..550e76396 100644 --- a/public/VectorPairHMM/src/main/c++/template.h +++ b/public/VectorPairHMM/src/main/c++/template.h @@ -28,27 +28,17 @@ #include "headers.h" -#define MM 0 -#define GapM 1 -#define MX 2 -#define XX 3 -#define MY 4 -#define YY 5 - -//#define MROWS 500 -//#define MCOLS 1000 - -#define CAT(X,Y) X####Y -#define CONCAT(X,Y) CAT(X,Y) #define ALIGNED __attribute__((aligned(32))) +#ifdef SIMD_ENGINE_AVX typedef union __attribute__((aligned(32))) { ALIGNED __m256 ALIGNED d; ALIGNED __m128i ALIGNED s[2]; ALIGNED float ALIGNED f[8]; ALIGNED __m256i ALIGNED i; } ALIGNED mix_F ALIGNED; +#endif typedef union __attribute__((aligned(32))) { ALIGNED __m128 ALIGNED d; @@ -81,12 +71,14 @@ typedef union ALIGNED ALIGNED float ALIGNED f; } ALIGNED IF_32 ALIGNED; +#ifdef SIMD_ENGINE_AVX typedef union __attribute__((aligned(32))) { ALIGNED __m256d ALIGNED d; ALIGNED __m128i ALIGNED s[2]; ALIGNED double ALIGNED f[4]; ALIGNED __m256i ALIGNED i; } ALIGNED mix_D ALIGNED; +#endif typedef union __attribute__((aligned(32))) { ALIGNED __m128d ALIGNED d; @@ -120,200 +112,7 @@ typedef union ALIGNED } ALIGNED IF_64 ALIGNED; -#define MAX_QUAL 254 -#define MAX_JACOBIAN_TOLERANCE 8.0 -#define JACOBIAN_LOG_TABLE_STEP 0.0001 -#define JACOBIAN_LOG_TABLE_INV_STEP (1.0 / JACOBIAN_LOG_TABLE_STEP) -#define MAXN 70000 -#define LOG10_CACHE_SIZE (4*MAXN) // we need to be able to go up to 2*(2N) when calculating some of the coefficients -#define JACOBIAN_LOG_TABLE_SIZE ((int) (MAX_JACOBIAN_TOLERANCE / JACOBIAN_LOG_TABLE_STEP) + 1) - -template -struct ContextBase -{ - public: - NUMBER ph2pr[128]; - NUMBER INITIAL_CONSTANT; - NUMBER LOG10_INITIAL_CONSTANT; - NUMBER RESULT_THRESHOLD; - - static bool staticMembersInitializedFlag; - static NUMBER jacobianLogTable[JACOBIAN_LOG_TABLE_SIZE]; - static NUMBER matchToMatchProb[((MAX_QUAL + 1) * (MAX_QUAL + 2)) >> 1]; - - static void initializeStaticMembers() - { - if(!staticMembersInitializedFlag) - { - //Order of calls important - Jacobian first, then MatchToMatch - initializeJacobianLogTable(); - initializeMatchToMatchProb(); - staticMembersInitializedFlag = true; - } - } - - static void deleteStaticMembers() - { - if(staticMembersInitializedFlag) - { - staticMembersInitializedFlag = false; - } - } - - //Called only once during library load - don't bother to optimize with single precision fp - static void initializeJacobianLogTable() - { - for (int k = 0; k < JACOBIAN_LOG_TABLE_SIZE; k++) { - jacobianLogTable[k] = (NUMBER)(log10(1.0 + pow(10.0, -((double) k) * JACOBIAN_LOG_TABLE_STEP))); - } - } - - //Called only once per library load - don't bother optimizing with single fp - static void initializeMatchToMatchProb() - { - double LN10 = log(10); - double INV_LN10 = 1.0/LN10; - for (int i = 0, offset = 0; i <= MAX_QUAL; offset += ++i) - for (int j = 0; j <= i; j++) { - double log10Sum = approximateLog10SumLog10(-0.1*i, -0.1*j); - double matchToMatchLog10 = - log1p(-std::min(1.0,pow(10,log10Sum))) * INV_LN10; - matchToMatchProb[offset + j] = (NUMBER)(pow(10,matchToMatchLog10)); - } - } - //Called during computation - use single precision where possible - static int fastRound(NUMBER d) { - return (d > ((NUMBER)0.0)) ? (int) (d + ((NUMBER)0.5)) : (int) (d - ((NUMBER)0.5)); - } - //Called during computation - use single precision where possible - static NUMBER approximateLog10SumLog10(NUMBER small, NUMBER big) { - // make sure small is really the smaller value - if (small > big) { - NUMBER t = big; - big = small; - small = t; - } - - if (isinf(small) == -1 || isinf(big) == -1) - return big; - - NUMBER diff = big - small; - if (diff >= ((NUMBER)MAX_JACOBIAN_TOLERANCE)) - return big; - - // OK, so |y-x| < tol: we use the following identity then: - // we need to compute log10(10^x + 10^y) - // By Jacobian logarithm identity, this is equal to - // max(x,y) + log10(1+10^-abs(x-y)) - // we compute the second term as a table lookup with integer quantization - // we have pre-stored correction for 0,0.1,0.2,... 10.0 - int ind = fastRound((NUMBER)(diff * ((NUMBER)JACOBIAN_LOG_TABLE_INV_STEP))); // hard rounding - return big + jacobianLogTable[ind]; - } -}; - -template -struct Context : public ContextBase -{}; - -template<> -struct Context : public ContextBase -{ - Context():ContextBase() - { - for (int x = 0; x < 128; x++) - ph2pr[x] = pow(10.0, -((double)x) / 10.0); - - INITIAL_CONSTANT = ldexp(1.0, 1020.0); - LOG10_INITIAL_CONSTANT = log10(INITIAL_CONSTANT); - RESULT_THRESHOLD = 0.0; - } - - double LOG10(double v){ return log10(v); } - inline double POW(double b, double e) { return pow(b,e); } - - static double _(double n){ return n; } - static double _(float n){ return ((double) n); } -}; - -template<> -struct Context : public ContextBase -{ - Context() : ContextBase() - { - for (int x = 0; x < 128; x++) - { - ph2pr[x] = powf(10.f, -((float)x) / 10.f); - } - - INITIAL_CONSTANT = ldexpf(1.f, 120.f); - LOG10_INITIAL_CONSTANT = log10f(INITIAL_CONSTANT); - RESULT_THRESHOLD = ldexpf(1.f, -110.f); - } - - float LOG10(float v){ return log10f(v); } - inline float POW(float b, float e) { return powf(b,e); } - - static float _(double n){ return ((float) n); } - static float _(float n){ return n; } -}; - -#define SET_MATCH_TO_MATCH_PROB(output, insQual, delQual) \ -{ \ - int minQual = delQual; \ - int maxQual = insQual; \ - if (insQual <= delQual) \ - { \ - minQual = insQual; \ - maxQual = delQual; \ - } \ - (output) = (MAX_QUAL < maxQual) ? \ - ((NUMBER)1.0) - ctx.POW(((NUMBER)10), ctx.approximateLog10SumLog10(((NUMBER)-0.1)*minQual, ((NUMBER)-0.1)*maxQual)) \ - : ctx.matchToMatchProb[((maxQual * (maxQual + 1)) >> 1) + minQual]; \ -} - -typedef struct -{ - int rslen, haplen; - /*int *q, *i, *d, *c;*/ - /*int q[MROWS], i[MROWS], d[MROWS], c[MROWS];*/ - char *q, *i, *d, *c; - char *hap, *rs; - int *ihap; - int *irs; -} testcase; - -int normalize(char c); -int read_testcase(testcase *tc, FILE* ifp=0); - - -#define MIN_ACCEPTED 1e-28f -#define NUM_DISTINCT_CHARS 5 -#define AMBIG_CHAR 4 - -class ConvertChar { - - static uint8_t conversionTable[255] ; - -public: - - static void init() { - assert (NUM_DISTINCT_CHARS == 5) ; - assert (AMBIG_CHAR == 4) ; - - conversionTable['A'] = 0 ; - conversionTable['C'] = 1 ; - conversionTable['T'] = 2 ; - conversionTable['G'] = 3 ; - conversionTable['N'] = 4 ; - } - - static inline uint8_t get(uint8_t input) { - return conversionTable[input] ; - } - -}; - +#include "common_data_structure.h" #endif diff --git a/public/VectorPairHMM/src/main/c++/utils.cc b/public/VectorPairHMM/src/main/c++/utils.cc index 6c623e9e5..3b0ce35ee 100644 --- a/public/VectorPairHMM/src/main/c++/utils.cc +++ b/public/VectorPairHMM/src/main/c++/utils.cc @@ -22,11 +22,8 @@ *THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ - #include "headers.h" -#include "template.h" #include "utils.h" -#include "vector_defs.h" #include "LoadTimeInitializer.h" using namespace std; @@ -36,51 +33,107 @@ uint8_t ConvertChar::conversionTable[255]; float (*g_compute_full_prob_float)(testcase *tc, float* before_last_log) = 0; double (*g_compute_full_prob_double)(testcase *tc, double* before_last_log) = 0; //Static members in ContextBase +template<> bool ContextBase::staticMembersInitializedFlag = false; -double ContextBase::jacobianLogTable[JACOBIAN_LOG_TABLE_SIZE]; -double ContextBase::matchToMatchProb[((MAX_QUAL + 1) * (MAX_QUAL + 2)) >> 1]; +template<> +double ContextBase::jacobianLogTable[JACOBIAN_LOG_TABLE_SIZE] = { }; +template<> +double ContextBase::matchToMatchProb[((MAX_QUAL + 1) * (MAX_QUAL + 2)) >> 1] = { }; +template<> bool ContextBase::staticMembersInitializedFlag = false; -float ContextBase::jacobianLogTable[JACOBIAN_LOG_TABLE_SIZE]; -float ContextBase::matchToMatchProb[((MAX_QUAL + 1) * (MAX_QUAL + 2)) >> 1]; +template<> +float ContextBase::jacobianLogTable[JACOBIAN_LOG_TABLE_SIZE] = { }; +template<> +float ContextBase::matchToMatchProb[((MAX_QUAL + 1) * (MAX_QUAL + 2)) >> 1] = { }; +bool search_file_for_string(string filename, string search_string) +{ + ifstream fptr; + fptr.open(filename.c_str(),ios::in); + if(fptr.is_open()) + { + string buffer; + buffer.clear(); + buffer.resize(4096); + bool retvalue = false; + while(!fptr.eof()) + { + fptr.getline(&(buffer[0]), 4096); + if(buffer.find(search_string) != string::npos) //found string + { + retvalue = true; + break; + } + } + buffer.clear(); + fptr.close(); + return retvalue; + } + else + return false; +} + +bool is_cpuid_ecx_bit_set(int eax, int bitidx) +{ + int ecx = 0, edx = 0, ebx = 0; + __asm__ ("cpuid" + :"=b" (ebx), + "=c" (ecx), + "=d" (edx) + :"a" (eax) + ); + return (((ecx >> bitidx)&1) == 1); +} + bool is_avx_supported() { - return (_may_i_use_cpu_feature(_FEATURE_AVX) > 0); - //int ecx = 0, edx = 0, ebx = 0; - //__asm__("cpuid" - //: "=b" (ebx), - //"=c" (ecx), - //"=d" (edx) - //: "a" (1) - //); - //return ((ecx >> 28)&1) == 1; +#ifdef __INTEL_COMPILER + bool use_avx = _may_i_use_cpu_feature(_FEATURE_AVX); + if(use_avx) + return true; + else + { + //check if core supports AVX, but kernel does not and print info message + if(!is_cpuid_ecx_bit_set(1, 28)) //core does not support AVX + return false; + //else fall through to end of function + } +#else + if(!__builtin_cpu_supports("avx")) //core does not support AVX + return false; + else + { + //core supports AVX, check if kernel supports + if(search_file_for_string("/proc/cpuinfo","avx")) + return true; + //else fall through to end of function + + } +#endif //__INTEL_COMPILER + clog << "INFO: Your CPU supports AVX vector instructions, but your kernel does not. Try upgrading to a kernel that supports AVX.\n"; + clog << "INFO: Your program will run correctly, but slower than the AVX version\n"; + return false; } bool is_sse41_supported() { +#ifdef __INTEL_COMPILER return (_may_i_use_cpu_feature(_FEATURE_SSE4_1) > 0); - //int ecx = 0, edx = 0, ebx = 0; - //__asm__("cpuid" - //: "=b" (ebx), - //"=c" (ecx), - //"=d" (edx) - //: "a" (1) - //); - //return ((ecx >> 19)&1) == 1; +#else + return __builtin_cpu_supports("sse4.1"); +#endif + //return is_cpuid_ecx_bit_set(1, 19); } bool is_sse42_supported() { +#ifdef __INTEL_COMPILER return (_may_i_use_cpu_feature(_FEATURE_SSE4_2) > 0); - //int ecx = 0, edx = 0, ebx = 0; - //__asm__("cpuid" - //: "=b" (ebx), - //"=c" (ecx), - //"=d" (edx) - //: "a" (1) - //); - //return ((ecx >> 20)&1) == 1; +#else + return __builtin_cpu_supports("sse4.2"); +#endif + //return is_cpuid_ecx_bit_set(1, 20); } uint64_t get_machine_capabilities() @@ -154,10 +207,14 @@ int read_testcase(testcase *tc, FILE* ifp) tc->haplen = strlen(tc->hap); tc->rslen = strlen(tc->rs); - assert(strlen(q) == tc->rslen); - assert(strlen(i) == tc->rslen); - assert(strlen(d) == tc->rslen); - assert(strlen(c) == tc->rslen); + assert(strlen(q) == (size_t)tc->rslen); + assert(strlen(i) == (size_t)tc->rslen); + assert(strlen(d) == (size_t)tc->rslen); + assert(strlen(c) == (size_t)tc->rslen); + + g_load_time_initializer.update_stat(READ_LENGTH_IDX, tc->rslen); + g_load_time_initializer.update_stat(HAPLOTYPE_LENGTH_IDX, tc->haplen); + g_load_time_initializer.update_stat(PRODUCT_READ_LENGTH_HAPLOTYPE_LENGTH_IDX, tc->haplen*tc->rslen); //assert(tc->rslen < MROWS); //tc->ihap = (int *) malloc(tc->haplen*sizeof(int)); //tc->irs = (int *) malloc(tc->rslen*sizeof(int)); @@ -279,15 +336,15 @@ int read_mod_testcase(ifstream& fptr, testcase* tc, bool reformat) tc->c = new char[tc->rslen]; //cout << "Lengths "<haplen <<" "<rslen<<"\n"; memcpy(tc->rs, tokens[1].c_str(),tokens[1].size()); - assert(tokens.size() == 2 + 4*(tc->rslen)); + assert(tokens.size() == (size_t)(2 + 4*(tc->rslen))); //assert(tc->rslen < MROWS); - for(unsigned j=0;jrslen;++j) + for(int j=0;jrslen;++j) tc->q[j] = (char)convToInt(tokens[2+0*tc->rslen+j]); - for(unsigned j=0;jrslen;++j) + for(int j=0;jrslen;++j) tc->i[j] = (char)convToInt(tokens[2+1*tc->rslen+j]); - for(unsigned j=0;jrslen;++j) + for(int j=0;jrslen;++j) tc->d[j] = (char)convToInt(tokens[2+2*tc->rslen+j]); - for(unsigned j=0;jrslen;++j) + for(int j=0;jrslen;++j) tc->c[j] = (char)convToInt(tokens[2+3*tc->rslen+j]); if(reformat) @@ -297,16 +354,16 @@ int read_mod_testcase(ifstream& fptr, testcase* tc, bool reformat) assert(ofptr.is_open()); ofptr << tokens[0] << " "; ofptr << tokens[1] << " "; - for(unsigned j=0;jrslen;++j) + for(int j=0;jrslen;++j) ofptr << ((char)(tc->q[j]+33)); ofptr << " "; - for(unsigned j=0;jrslen;++j) + for(int j=0;jrslen;++j) ofptr << ((char)(tc->i[j]+33)); ofptr << " "; - for(unsigned j=0;jrslen;++j) + for(int j=0;jrslen;++j) ofptr << ((char)(tc->d[j]+33)); ofptr << " "; - for(unsigned j=0;jrslen;++j) + for(int j=0;jrslen;++j) ofptr << ((char)(tc->c[j]+33)); ofptr << " 0 false\n"; @@ -363,6 +420,10 @@ void do_compute(char* filename, bool use_old_read_testcase, unsigned chunk_size, ifptr.open(filename); assert(ifptr.is_open()); } +#ifdef PRINT_PER_INTERVAL_TIMINGS + ofstream times_fptr; + times_fptr.open("native_timed_intervals.csv",ios::out); +#endif vector tc_vector; tc_vector.clear(); testcase tc; @@ -377,11 +438,11 @@ void do_compute(char* filename, bool use_old_read_testcase, unsigned chunk_size, uint32_t no_kernel_mask = (1 << 17); //bit 16 user mode, bit 17 kernel mode PAPI_num_counters(); int events[NUM_PAPI_COUNTERS] = { 0, 0, 0, 0 }; - char* eventnames[NUM_PAPI_COUNTERS]= { "cycles", "itlb_walk_cycles", "dtlb_load_walk_cycles", "dtlb_store_walk_cycles" }; + char* eventnames[NUM_PAPI_COUNTERS]= { "cycles", "l1_pending_miss", "lfb_hit", "l2_hit" }; assert(PAPI_event_name_to_code("UNHALTED_REFERENCE_CYCLES:u=1:k=1",&(events[0])) == PAPI_OK); - assert(PAPI_event_name_to_code("ITLB_MISSES:WALK_DURATION", &(events[1])) == PAPI_OK); - assert(PAPI_event_name_to_code("DTLB_LOAD_MISSES:WALK_DURATION", &(events[2])) == PAPI_OK); - assert(PAPI_event_name_to_code("DTLB_STORE_MISSES:WALK_DURATION", &(events[3])) == PAPI_OK); + assert(PAPI_event_name_to_code("L1D_PEND_MISS:OCCURRENCES", &(events[1])) == PAPI_OK); + assert(PAPI_event_name_to_code("MEM_LOAD_UOPS_RETIRED:HIT_LFB", &(events[2])) == PAPI_OK); + assert(PAPI_event_name_to_code("MEM_LOAD_UOPS_RETIRED:L2_HIT", &(events[3])) == PAPI_OK); long long values[NUM_PAPI_COUNTERS] = { 0, 0, 0, 0 }; long long accum_values[NUM_PAPI_COUNTERS] = { 0, 0, 0, 0 }; #endif @@ -398,6 +459,9 @@ void do_compute(char* filename, bool use_old_read_testcase, unsigned chunk_size, baseline_results_vec.clear(); results_vec.resize(tc_vector.size()); baseline_results_vec.resize(tc_vector.size()); + g_load_time_initializer.update_stat(NUM_TESTCASES_IDX, tc_vector.size()); + g_load_time_initializer.update_stat(NUM_READS_IDX, tc_vector.size()); + g_load_time_initializer.update_stat(NUM_HAPLOTYPES_IDX, tc_vector.size()); struct timespec start_time; #ifdef USE_PAPI assert(PAPI_start_counters(events, NUM_PAPI_COUNTERS) == PAPI_OK); @@ -429,7 +493,11 @@ void do_compute(char* filename, bool use_old_read_testcase, unsigned chunk_size, #ifdef USE_PAPI assert(PAPI_stop_counters(values, NUM_PAPI_COUNTERS) == PAPI_OK); #endif - vector_compute_time += diff_time(start_time); + uint64_t curr_interval = diff_time(start_time); +#ifdef PRINT_PER_INTERVAL_TIMINGS + times_fptr << curr_interval << "\n"; +#endif + vector_compute_time += curr_interval; #ifdef USE_PAPI for(unsigned k=0;k std::string to_string(T obj) @@ -50,6 +50,15 @@ extern double (*g_compute_full_prob_double)(testcase *tc, double* before_last_lo void debug_dump(std::string filename, std::string s, bool to_append, bool add_newline); template NUMBER compute_full_prob(testcase *tc, NUMBER *before_last_log=0); +template +NUMBER compute_full_prob_avxd(testcase *tc, NUMBER *before_last_log=0); +template +NUMBER compute_full_prob_avxs(testcase *tc, NUMBER *before_last_log=0); +template +NUMBER compute_full_prob_ssed(testcase *tc, NUMBER *before_last_log=0); +template +NUMBER compute_full_prob_sses(testcase *tc, NUMBER *before_last_log=0); + double getCurrClk(); void get_time(struct timespec* x); uint64_t diff_time(struct timespec& prev_time); @@ -71,5 +80,6 @@ void do_compute(char* filename, bool use_old_read_testcase=true, unsigned chunk_ /*#define DUMP_COMPUTE_VALUES 1*/ #define BATCH_SIZE 10000 #define RUN_HYBRID +/*#define PRINT_PER_INTERVAL_TIMINGS 1*/ #endif diff --git a/public/VectorPairHMM/src/main/c++/vector_defs.h b/public/VectorPairHMM/src/main/c++/vector_defs.h deleted file mode 100644 index 2aca9565f..000000000 --- a/public/VectorPairHMM/src/main/c++/vector_defs.h +++ /dev/null @@ -1,55 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -#undef SIMD_ENGINE -#undef SIMD_ENGINE_AVX -#undef SIMD_ENGINE_SSE - -#define SIMD_ENGINE avx -#define SIMD_ENGINE_AVX - -#include "define-float.h" -#include "vector_function_prototypes.h" - -#include "define-double.h" -#include "vector_function_prototypes.h" - -#undef SIMD_ENGINE -#undef SIMD_ENGINE_AVX - -#define SIMD_ENGINE sse -#define SIMD_ENGINE_SSE - - -#include "define-sse-float.h" -#include "vector_function_prototypes.h" - -#include "define-sse-double.h" -#include "vector_function_prototypes.h" - -#undef SIMD_ENGINE -#undef SIMD_ENGINE_AVX -#undef SIMD_ENGINE_SSE - diff --git a/public/VectorPairHMM/src/main/c++/vector_function_prototypes.h b/public/VectorPairHMM/src/main/c++/vector_function_prototypes.h deleted file mode 100644 index c0fddc394..000000000 --- a/public/VectorPairHMM/src/main/c++/vector_function_prototypes.h +++ /dev/null @@ -1,44 +0,0 @@ -/*Copyright (c) 2012 The Broad Institute - -*Permission is hereby granted, free of charge, to any person -*obtaining a copy of this software and associated documentation -*files (the "Software"), to deal in the Software without -*restriction, including without limitation the rights to use, -*copy, modify, merge, publish, distribute, sublicense, and/or sell -*copies of the Software, and to permit persons to whom the -*Software is furnished to do so, subject to the following -*conditions: - -*The above copyright notice and this permission notice shall be -*included in all copies or substantial portions of the Software. - -*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -*OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -*NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -*HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -*WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -*FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -*THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - - -inline void CONCAT(CONCAT(_vector_shift,SIMD_ENGINE), PRECISION) (UNION_TYPE &x, MAIN_TYPE shiftIn, MAIN_TYPE &shiftOut); -inline void CONCAT(CONCAT(_vector_shift_last,SIMD_ENGINE), PRECISION) (UNION_TYPE &x, MAIN_TYPE shiftIn); -inline void CONCAT(CONCAT(precompute_masks_,SIMD_ENGINE), PRECISION)(const testcase& tc, int COLS, int numMaskVecs, MASK_TYPE (*maskArr)[NUM_DISTINCT_CHARS]); -inline void CONCAT(CONCAT(init_masks_for_row_,SIMD_ENGINE), PRECISION)(const testcase& tc, char* rsArr, MASK_TYPE* lastMaskShiftOut, int beginRowIndex, int numRowsToProcess); -inline void CONCAT(CONCAT(update_masks_for_cols_,SIMD_ENGINE), PRECISION)(int maskIndex, MASK_VEC& currMaskVecLow, MASK_VEC& currMaskVecHigh, MASK_TYPE (*maskArr) [NUM_DISTINCT_CHARS], char* rsArr, MASK_TYPE* lastMaskShiftOut, MASK_TYPE maskBitCnt); -inline void CONCAT(CONCAT(computeDistVec,SIMD_ENGINE), PRECISION) (MASK_VEC& currMaskVecLow, MASK_VEC& currMaskVecHigh, SIMD_TYPE& distm, SIMD_TYPE& _1_distm, SIMD_TYPE& distmChosen); -template inline void CONCAT(CONCAT(initializeVectors,SIMD_ENGINE), PRECISION)(int ROWS, int COLS, NUMBER* shiftOutM, NUMBER *shiftOutX, NUMBER *shiftOutY, Context ctx, testcase *tc, SIMD_TYPE *p_MM, SIMD_TYPE *p_GAPM, SIMD_TYPE *p_MX, SIMD_TYPE *p_XX, SIMD_TYPE *p_MY, SIMD_TYPE *p_YY, SIMD_TYPE *distm1D); -template inline void CONCAT(CONCAT(stripINITIALIZATION,SIMD_ENGINE), PRECISION)( - int stripIdx, Context ctx, testcase *tc, SIMD_TYPE &pGAPM, SIMD_TYPE &pMM, SIMD_TYPE &pMX, SIMD_TYPE &pXX, SIMD_TYPE &pMY, SIMD_TYPE &pYY, - SIMD_TYPE &rs, UNION_TYPE &rsN, SIMD_TYPE &distm, SIMD_TYPE &_1_distm, SIMD_TYPE *distm1D, SIMD_TYPE N_packed256, SIMD_TYPE *p_MM , SIMD_TYPE *p_GAPM , - SIMD_TYPE *p_MX, SIMD_TYPE *p_XX , SIMD_TYPE *p_MY, SIMD_TYPE *p_YY, UNION_TYPE &M_t_2, UNION_TYPE &X_t_2, UNION_TYPE &M_t_1, UNION_TYPE &X_t_1, - UNION_TYPE &Y_t_2, UNION_TYPE &Y_t_1, UNION_TYPE &M_t_1_y, NUMBER* shiftOutX, NUMBER* shiftOutM); -inline SIMD_TYPE CONCAT(CONCAT(computeDISTM,SIMD_ENGINE), PRECISION)(int d, int COLS, testcase * tc, HAP_TYPE &hap, SIMD_TYPE rs, UNION_TYPE rsN, SIMD_TYPE N_packed256, - SIMD_TYPE distm, SIMD_TYPE _1_distm); -inline void CONCAT(CONCAT(computeMXY,SIMD_ENGINE), PRECISION)(UNION_TYPE &M_t, UNION_TYPE &X_t, UNION_TYPE &Y_t, UNION_TYPE &M_t_y, - UNION_TYPE M_t_2, UNION_TYPE X_t_2, UNION_TYPE Y_t_2, UNION_TYPE M_t_1, UNION_TYPE X_t_1, UNION_TYPE M_t_1_y, UNION_TYPE Y_t_1, - SIMD_TYPE pMM, SIMD_TYPE pGAPM, SIMD_TYPE pMX, SIMD_TYPE pXX, SIMD_TYPE pMY, SIMD_TYPE pYY, SIMD_TYPE distmSel); -template NUMBER CONCAT(CONCAT(compute_full_prob_,SIMD_ENGINE), PRECISION) (testcase *tc, NUMBER *before_last_log = NULL); - diff --git a/public/gatk-framework/src/main/java/org/broadinstitute/sting/utils/pairhmm/PairHMM.java b/public/gatk-framework/src/main/java/org/broadinstitute/sting/utils/pairhmm/PairHMM.java index 4203677a1..e45cf0941 100644 --- a/public/gatk-framework/src/main/java/org/broadinstitute/sting/utils/pairhmm/PairHMM.java +++ b/public/gatk-framework/src/main/java/org/broadinstitute/sting/utils/pairhmm/PairHMM.java @@ -78,8 +78,9 @@ public abstract class PairHMM { protected double[] mLikelihoodArray; //profiling information - protected static final boolean doProfiling = true; - protected long computeTime = 0; + protected static Boolean doProfiling = true; + protected static long pairHMMComputeTime = 0; + protected long threadLocalPairHMMComputeTimeDiff = 0; protected long startTime = 0; /** @@ -207,7 +208,13 @@ public abstract class PairHMM { } } if(doProfiling) - computeTime += (System.nanoTime() - startTime); + { + threadLocalPairHMMComputeTimeDiff = (System.nanoTime() - startTime); + //synchronized(doProfiling) + { + pairHMMComputeTime += threadLocalPairHMMComputeTimeDiff; + } + } return likelihoodMap; } @@ -314,6 +321,17 @@ public abstract class PairHMM { return Math.min(haplotype1.length, haplotype2.length); } + /** + * Use number of threads to set doProfiling flag - doProfiling iff numThreads == 1 + * This function should be called only during initialization phase - single thread phase of HC + */ + public static void setNumberOfThreads(final int numThreads) + { + doProfiling = (numThreads == 1); + if(numThreads > 1) + logger.info("Performance profiling for PairHMM is disabled because HaplotypeCaller is being run with multiple threads (-nct>1) option\nProfiling is enabled only when running in single thread mode\n"); + } + /** * Return the results of the computeLikelihoods function */ @@ -324,6 +342,6 @@ public abstract class PairHMM { public void close() { if(doProfiling) - System.out.println("Total compute time in PairHMM computeLikelihoods() : "+(computeTime*1e-9)); + System.out.println("Total compute time in PairHMM computeLikelihoods() : "+(pairHMMComputeTime*1e-9)); } } diff --git a/public/sting-utils/src/main/resources/org/broadinstitute/sting/utils/pairhmm/libVectorLoglessPairHMM.so b/public/sting-utils/src/main/resources/org/broadinstitute/sting/utils/pairhmm/libVectorLoglessPairHMM.so index 7cd8b1f73c4bd47edd14594f70fb97476db73916..ca0f6eef78eda420d2cc6ce7d80ca20142d6fa5d 100644 GIT binary patch delta 90585 zcmaHU3tSXc`~U26kyPBpAn?8#B#9b|7>Xts=BzGCX=Ubxyp)zDuY#GGOM>ONZjocH z-RW*+Z=}9zrnaaESs79mX&17rLA;Qa;FbUPIp+)<_Lu+pIGp)@pYuHD_MFR{nORHM zblLn;m!g=CC94#6r13zpk9nrg;Pi>zLm4(hMR71}!CxkEaJk~Rj`3!g--W}pXI_i$ z=!oNy9C197Bkq~~(|S7ghOjt+;TOW<7rN7Or~Ay`c~#SnPkVp-o=fA`{gbfa+e=HH zCbc%m!2rqyj)OR}*cJct9D=Pl&*D6Rb1lw(h}#3v7t_#p8Te@HSk3it99- z!Gbe`7|4DDXuw$`$a;hhaZN!O;+V%$aq+97%wU(N@i!O|df~hu*W+-yaPG(XJP~Zy)&Evn~;!lJJ za9$5N9XoJ##d(SVjyN7DpCEh{=T4lpI3p1M9)xtv;epZ-;W^VyZUo53c^A$yoOHa1 za{Bn^u&O2~Yzx@j#9m{b3gVO@;O@yE0 zd-n}|eOPGwt2zmB7ox}N>p~qN-9h!y zcZQCz+@N0yP4K1N5*n<}ve+ZqK@cnAI}wIczv_0kVB!%D7T0DlnPQAe5OA1DBkYEA zsD$bAT7lamyj5H;65$}pj6|AAA(IYjUq5k7$Pe*&AqW?an2 zxk3<42%izxs}bIeb0N-tIR9e~iHb#0UIXzR&NDd8W4E}t2H{U8iST2b?V(dBxV8w} z0&hon4Z^nte+$BIsWN=|YG`njU|G-w(f-EO8@`^`ggD%2lM?Dz((w(NxtG#T$vV$T zyO1@(0f{f7A(M{YJa{yW^Vxom&G;Wc-VyPYAE@RrsqjD<5XX7P&lV+u1X)7RBNzh8 zwIx}9CNjEHuQnnheu{Ex8KdxO{rUd%^vL>(~;}upXExXG#ovg z3X!&h7ot+wJR~wzk}fhsK8)j2U(fqPqeD_Ke6Xx_O6vw6 zGmj4gWNj_STj@v}r6a}=+MN}?jsQv{W&#e7FP}|fh4$)`Lgm)lARItil zC|$UcneY&DfuSDZk(C#@Ia7_+PNb&%#Iw6zG-d)ua7w=DD}88(>nwNc_jHK1oYeral&MN_w{IiL0i=d*=) z7L}hhcaGlE7MFC%jqkcgMr))#%kv`_Iu-d|T82OYxpObOEY^;(*Hj3O+}bUCr94 zW!?BmFpqDi5gUh@(s02i2DJ5l-qRw@BD!BirBfv&{=yBU@j%&eEhQME)DPs|Zu&$4 z8inGQ2&YRF@iQ>r5^rD3i&T&)}n|M;yaN zifJElXV}t*(MlTCBXXYe3&)iqJRE8^=l~;>H&FH`Tml7l+>MSy4PC#4=gGV`yOBmH z=UR~-Tje2siO_maxJOoidps?Mf|{v3eFUXbH#{T^A*pqS=S!X2KIn9_+GT0|2dvk zz9{EaB9+8|RNfGNnqSW2oAxJS1wrNP-9ExHgJvkpdDhJayom~+M$SIZEmw+)@pt8w zk@F;PuCnX7d>|F_xiO)^ZmO!RgPcv{fwEjo9QLZ#d^NJmoKQ4=qKN-rEOUvkJirMv zyHARy$a3=3v(YMaTxV9_-BvzT6^ZP+^v9#3JB<;UE~5Kf99cs81GQl0JE#CktXK@j zC1UV?0BI1P{}NMD93rt-gzpvQ@l4c+cK#TJiJ-yPeV>R?9N;k*;44(A`F?KEES4Af zAwEkCd4Aq?m9Sns2Z`odf~zTO(Ks~1Rrg1I;1JQ3(Xfx9wxd!MFwr|{z2uxFX5*|{ zUjAa9e`S>Dn%Tl>(wI@)B8vgGtKl@>h zOGJJa1@Vfg52y%-na^K%d~=l>DtuWHLqV~yQ-fibHE#Ye-s)j{xuZJS%5b>wxx@gU zt0EsCunYa1TBAlZu|pV5GZzy7aH2-=t7!D?^reGqIX>Z8%oftO*=qBTUfetF0dv+M zQN{MpMMa3}ix*>1;%A&UTXKT%lpHa})d+Wv5+w?p8AdR-RCHftMCMPzW>LWW`<*Cn z{w1E}v``*C*oNoX|02g`4?I9#Mt!%_yP~-gMROJNh{~N*BeSbS<5vkUf0KU}vu+J-iqRqJa6Zyu3)a3U79AKN==cF$o>{kyXIAc{zwSCHlb1A4+G51p zAzHdv%xq?@y(((sU_fm&2-o)i%5!6`mM8b*_VWY$=}Xp%ioUgdMDkM6>Vc!{A@FwP z&!&7awDEE%$`r~Q)!2Zcq79UHL|GT}I6Z|gREmMZ%>4|Sc`YI2%bf;@2`6zs*C`V9 zcZk+j_dF-clmBPy+MR6HZoEiQXgw{g`2(h}PN+{dt?lNin4W$&rQ&WQYO|Q_V<5&w zZk2{zrnQTwZu(FkbbsP=UgFlwa_tkjEy;i)j$)CkX{?qp&xy%4jY+XV03HKNALWaH z75X7_=zWAITp|=AX{^kAOf+UqKx6h0vxegr9^K5=i!7NKr6yqD--s^4rp<2S#mHAF zMm|&XX0ubc$D)a;$c|86v>f4}n&=`qGkH$^$O9cu@JT}P2Q+;M^k}kC#88^XVq-^9 zbfc_qxgCe#w{rV^l#Ve5?+5X=V!OIfT28l%&hLBi>}Gw(wafy&AV!6( zfaTD7Q33U$0D9E5R0knbNsCp+6lMKI>Z$mLg6fp;Fb^ddvH77mufU5 z2uZTBBYBIcs-g()ST&+Kqp>!mOy!(yoyOIsW~a>}d&L1O>qPyvUeV5ZqNR%ta{U~U zmkA=hdKz+Zm`gDm9Gs2Ub3_IPbA?rOi|*bl(kco_>mF09SZHCEqoYw&wIjeWUN+-j z6T;%9i52h1VrNegvt~Y%D#|DP=KmI@Xe-aIU8Hm13WM@sL}UF_cxom08|81aCp(8Y zc*T}%7ZycQd4l%~K3nkf5i;)x@cm_M5ckm_o@^B>utc#`%o4h*#IRdZ&WU{9#!4qt z4{v@0F?wP_T^X>TK7l1Yl_N_mk4&FzYibVY70YAzzvSgG?~_KF4Q%eUh%}#PyDTrE z-l;SW;p=H4r^AG`nuFY0iO@qww6cUlB?@aEI2xsLQH<3nE;}?RQof5scPJ5lP>g)D#e2XEG6wCAr1f{~ z5w{hK>8ki0Zp&53HpbFLfTKCJZ|iSg~>BXrcWE( z&v*Kh(9ZhhK`F80CM>*pz^FwqiL2z9^I*$FgBQ$RICshHQ4i{l)B)EooV$3`gDl$I z8}FN)J8$kovqxpkoJR~y54v~mL$gNRhN}mWXtI9q;5gqyTSCJCLP8d1AO+nrNDZ4j zA$QQsdGqhnM-RF-W?eMs0d?@GOfSoicFKgp|9j z`nI9-HqA)gAF98b7OtPl4AZ|(yT*5NM`+BZ$s^ZTe4XD4P0-_SY47vD8G2WbfkUQe zPDhER&wXg&>;<{g=gfU5cY5AKbN`b!dwS0Ng}(Vuh4u=XFkreb>z&X@Jvt*<|7TQ` z@7uRSui4b|mJU`uPrXH-ee*TGn~FlO_O1RnbmXQq=WD^6&Sr*MLad4fcWF)Ip4RKf zW5Zd0dVDAReP?{K{?qvQc1)_!U#tF~tgH22S(Eewoc;b)E}%4OM=}07nPOOEGGi@~rC~!H^N6oRQ=o zBXI3R7p2S$Eix(h3vZLlj9@+!= zqTQU23E+#r;=Ch(&lV$Dd^69=k7ot+oF7MGvw#~&6HBU;06t4B3ey7k9I+#%2JmS= zq2JV0xz~>z1{NeyUtG{TPf8)vjR{om+ ze9;y7bywhv1NgKqJmK|M;7hU}1%Cjac!ZbOFQ#MDj)~1_+T>j{0R9WXFAm_p5q!Sj-Dca=2*Jt# z1w-&f0erpS*9Gv6f-er>m2<)wTl47uLQv9Lpx6b!Er5>^ygz_<2)-hKj~9Gp0H4Ts z_+NE^AVnzD1n?PxHv;%9!Pf`y#TR&q8w2#pZyyX986HF0?!bl+T*@CwR@N)zo z6Ts&P-Vwkr7JR(Kv;LPa1c{P>GO$wcDFJ+u;L`&5b%Iv|_+r6l1@P<7Sw;U35Nr?% z*#Z1!!OscccL+WwfZr?l#R2>mg3nKMx321MgkWWW!ViKk3gCYe{JH@Cgy4$<_`e0e z-sE}tvD+mCC8mJtA4jm5*S7`m?FH`-;3EZJ5x{p9d}RRdjunFH06|~D*97o`1aAcJ zDT1#L;D-smF@R6wJjy?ybrWO=g|Gl#6}&xwcL_cwfS)LMM*u%X@bQdC`eyf=B?O59 z3iAY?62RvQJ}rP>DtI-3FBE*1%v1Xp3Be>;0Di6Dvjg~-1V1N$e^c-|0sIERFAm^0 zgJ=GiA0XHv6jlcCdj($e-Qlo0oSqgo15S_At(t@I3f6L0sP;B z_XqG71z!=shl!!LvYF@UE0ID_-7KKahxNMPYXbPbf;R&AM8Vew@F{|C4B#`|LZAff z3ug&FEP$URczXb!E%=xKevaTB0ep_&-SGi}r9zMxz!wTWC4gTo__P3it>D!F{w2X@ zalU2!zg`F?1t@G5e0Bi8L-2C~_`QP93E;mF{Nh$T+W#9N$ZsXUQzF5y4B&qgd{F>z z2!34ve?suZ0en62K3{%?+e*+Nhq zppYT%*_5Q#L$!I!78bypw`}%6Ufi<9wD7$DnfGjt76I>m;?^uafH!a15(9Yi)+{A} zH*d|-0{FxuZhi+-E$&hY-N=&We`>D48&}}#ufR86fmhfY1W1b#&Xf`k6L+|=0`@cMIf4?MfNC{M2 zfv>y*Uws9>M&c_a`^L3m{ZF+i3+k_+(0BztP3(-2oi$Pds>EBQCd)E;*8Y-Uk|}@@ zSwRtBdr{PCDS>xY4Qn~&zIsakm9eD z_(ufK(l3$(a)#DPe4%8hSmIYm{CbIhO5#f-{%MKd)?2LqsR^Eu1b#{3If<{3_~#|Q zQsTv<0w%4Nc=1jW<7=9E6nB$k$Y>TQ%4Uggl=zP&UXdoDJrW-#@#3W#Cbdia=fs%R z9U}?E({iTZkoZH4;eX;K{;dLm^W9e2JI8uv{te^c9eK)Jyi;TFm-~v`A9uA}Oqs zc=H7_GFB|{;)4{H#(IfQknB{5O>CmBF?s#1CALm{pO7gll|s7>U>p6*CDEPC)j7#) zBxzgy(vs-Tco5fo)JxL#ir)XxYv>bncjN zB<`i?%OJ)x`sO1?62~d}e<6-<7Ai`ai6W01gVljjl>U=cthfcOMJb= zr%QaJ#E+DCrH@!MksIAC3BvlcxYsC&w@dsj5+5V+qb1%U@v6kfn>>|&j3h`j1>nX? ze2T=oBtA{z$4R^@@#7^vOX6<@-#lhak_5L&3fU4rLE`5~{2daXBk^}i{9=ip)WW-! zd`U35MWC#d_$d-!B=J)vex1ZmllWqZ&zAW0j7RyY?eCEUC6dAniQgvivn1Xx@%Kr5 zg~ZR5_)3Ytzq$Sqp;{6=C@IuP{6i9NNc?<>ub227iEotn{|KI^pU~p%3nhgxiO-dI zyTs>7e2m0DEb$JBUo7$Q31ZDeO<=C#NS-JuERhsaB>qu}Pm}ni60b`9V-la$%%lAI zl3-G^pydZ2NSrP4Pe}3SNc>8P&yjdd;ulN&D&o!d&zA%qNnxeLua@{Ci7%4)brP>j ze6hr@m3a4hN${*BD3SPe62DF2Uyyje#LLUp3Wr`Y zHzfWIiLaOVHzmGN;@@hne~Qqzr5C&{DTGPKey9-i2GY=8uJ&3NERmX^jl8m zVV8LG_nk-i5}zpXoh3d+;=4+Gn#9u&35#YV~)gMEAcrJAJ@XWmBo_ax)y~}MwiijX0N*LZxIGAuT!@CKG z5H4bPJK<2m`3!F)Oy#J}Vfa15VT7|8ex2}DgtHiafpA;G?leZMAp%8HY7-e=MYug- z2gAz=qtr^Ro#7>fI}lbFUO?DJxc)MTxcdp)3D+<@gKz}lN`@yB?g;Fz^)uo&B4`Jv zwuIp^gd+(TGdz-T6yYLk>bp$Lf#wQ+?}w(@EO8A2-jbt8aPhaLAZwDql9}Bu4MQy z;a=4LYW<9;BH~(#P{Qzj!m)&l8Qx7ej&Kpf+X>TLU7OGFM#8-b=P>*p;dsK?48KnJ zdcs)@zd*PT_5a#5Myw$sfp8+js|fcc>|l5~;eLee3@;(vpRmI40>U>CuD{59fN&z= z8ir>O9zeK~;mL&Ew9i!QXT)tpBoQuQcnsk|go_y-NjRBs5yL|X4{lCOnF85yRUF z-$FQ_;f;hx6V74yJ;EyCY=&Pa>?EAU@C)y_L5v|HjS*`o!dSwI46h>WBJ5yzIpIvg zc7~S_9!FSVcmd(@gzL{UA0V7XxQ5{wgl{EW$?#-15wzb_>u1DmgeMR#VR#JTiG+(8 z9!dCi!bJ=ZC42|re1-=SzLRhc!+i)(BAm@|FT!^b&SKcznTW|mq%oo+;kyYZGTfH% z6v7UMt%Ro%wljPlzfv$~8exUuGlZuTu0O|ofN(b98itP&zK3unVRzhNB4!ZbXA!Ch z&m>&J@P5Lx2p2QFoA7MHMGS8zd@tdAhBp$vk8lpd?-8cis5YD7*9p%hoCWM|ihF^G z`-w|l5~;RgxZ8D2v8A;Jp73kc6AT;IrifN&1s8ir>O{tw~G zMx@^qH<^e9MEF^R+XyctT*B}e!nuTt86HVEk8lygLkTY;oX_w;!VeS9VYmO87Ctc81Tt1-y)~!tfcwY-Fu( zAp6G&=aamK;iH5fCtT@f#9<E!XCnj46h=*ny`c6<%GS2?F=s={1jn@ z;RS@BCR~4(YT$mtMTBb@oxP;*`gx3--W_TpwX9*WE zJe2Trg!365NZ3a>hv7bi*AdQUxEJB)+5Dfyh|Wa3KoQay?nwAW!ifyGCHxX$2g6pv zFB7&ieEv<~R|qQ%pCSAz;rf4=4-hUUT*L5D!mqLUzmgG$iFlnN_!+Ju{089?hW8VG zlW;M^y9vKVxQOBHgx@Bd&+taV?-0&m_&vhw31>6>I^lPjmu4~I1tQ*~2x$zjA^bk! zM21%p-ay#F@N&W*5VkYCgz$d}D-16n{2}4`znKpZE+JgQ@C?H4kBF#b#AG5i681BE z8{tiaOBfzQcr)Q*hDQ?qAK@Z~hZ5dGIG^ExgtrpTVYmb-hYx|ClDFV?wP5&Q$Q2}*K5;^Bd(|_1`WtbIF%ZL)>h1Q| z+PHAV<&FDoEwbkc2`|w#t-Jf=hjB`JQ{-MSM{%hRsa|l*pxc1E)2B?`7g7e!vWMlf zV0bY!mE7wPb^43E_?>S@L06GM?O0Rg)Y@n$+Ir+uP1Ux;wOK0&VT8ss1$RyP6x1eR z?6B$AtmhLAO|{_Lu6} z!D6ZjKdak@JoRe|{&i3r>eSNnR<-oP2vs|%CVZ}@)-LL%CLCA2B6d)n>UG6BRPDI& z4tj9i)e9q3Z^lWqMr65)M9I27%hT&Bl_j$yc9Qr_jRp>6Bb6(@6JWvS{(RaZ3S zh8Wrz=ojpX$vercsM-c*7fB99nk>qFh~m&AU3b2oQPn=ElZQ zhDb^!oul8r+TkXqn6l_XpB!H(D(1d8p6)4}-R;G~mIPa7no zdN#)zpfj}NO+|A;sNUg>A>-G@L9@x}v8mcms>j~+484Wx)X0~TTFbJS5W|nEl|gz< zfHa1yQueBm4r2W6Yh^pj(GsJQ$EXU35oX5N!!zyDes3z8gv`Qd7zzp2O;x7-u6oz9 zVmB4}Sy>8WY41f86(#vU;zp!sickGtF>Rm-F)E4`;QyG2r#SBB+GJ(;KauQ+l;lSv zP-CJIXs5-cy&1a>D5)v~eo%}nYAhPrUD}S=5(?2JNYmwcGnSHZ!5b(`F3(G`lymAK zRKN_6o7aR3x%5Mj;aSby1`)_@ns%#T$YatygPv4NYl2;7=kmD1!p3@o&yLc9%S|%9 zXziV{;N9Pb^pXpATL%or`>3ld` z*hCAaU)7Ti!2oi!6v}VHKDD$lSVfI01PdBNYy|`83S)1>VHyZllKq0+A#`1YYg=Iw z$&n%qA{=8^6IOF$rRRdxRP;cKwR{M<7MhX}lxSX2^%GC`v!v*qi*9wZ)PwdlXQZIf zp4*YEk^ucz8(ELDQS}sxbh5%I2TTndS)~S2gG514AmVEKq2DfYv}CVP6wIFmb1ik^ z_5?SiHU1??O&lyLh_RXKG^;GqnjRR3epLUP43FQ$to#`dUsJT{AbyO!EB~_D!?)aKRctr7_dh%xDC7g6PZvY;FI&V~=3~Y+m<}M~2y`KH0bBfTV;+-$ zpqfS$E-`NB3cTU}vQ4S@%QpG5x+!K}kiI9%iHz`UoUuh@#D=-gAn`a#oPI3I*o5I6 zg5X%tkQ$pXJloAW` z&eW56wKT7wJr_e)_0Vi3CNEWciBF@QD7M+4Vu*qr>N0bn1ba`i7(2RiBP@wLMy+NR zl1`E{t9t0#LCO7zZz^*Z?2S=V>lXaZB(RdX;hsrjb<@ab z%=r`QnCdCF#)Xp{P_c~;r#T?EGX~TGc!tFq)ii}`!Lh0r%K&3P6zaZ|J0*N>!T}8>XgK>K&h**zY{$Ps@l! z*IdhcJVvh|FZ$_vs>8umuY^GM~JXo8#;$RxD;5q=OMk%}M0pE3NDh}vxs1fJBys?jP&N#mOZBe4&WUOerZ_QjixE@xEI}=r z#rYMPR}(l&`fR)YpXcH_+}B+9R8IXF-(rm6ZP)dk*{uUF)tJ>T! zr#8oKe97_}vTv27^B=CWk#WsYRnJw!8=*b5_Jw15*B9bvs@j+7+P6-vDRbrlr)Lxf z<56KwPy1L^JK)q@vACX!G>$kuw=1rM!_LwR!TT~|Cn=e!pWB{jivcE6t5CISr*=3q zVUMkle!a`-$;4Fpxr$j7ZE9Qo;igYtIA#g1>$EUh&wn9$1}(M|zNKZoD|Nr^i38M9 z+5uIoa3$=w749dm^GrciCwz}(ztx%gy={3f3|y-AIUFu`u(RM?jP0o)w&43}j5m_D zGiYu=Cv_piX~v~rbodlZc%sek1T zQxmXYyg3NBXlki(lj@xq1FwgTg7ao_Fr;b?NoS4azhD?>xA3Yl-r%R4=&WH$M@FqU zYkPw3vNNJQORy}Z-vH8y?l$`MODN2Yg*-HwG+tXZ6654|?8_a;yy%Yz@M(mI>`nW?1< z>T6#CIV#Ct_akx{y!27rMd?q!+1-u7Wa;g=U!q%_&((rog4BlZ)u8?AiX)3`<-t#o z3AM?urtVqr=e@Sm{(Eii;8$>;f<@2w3(lx$l!EtRxICD4h7hw9)Pg^2ec+NltHa$H zAKaQos0q7WXyGRh;!%n-^`J}p97Eb+)g5$LO+CDzs}wP{`r&XSpVv_>{nd&L4^uyB zHUdV~enuBZqo7JyBVzrD*|Y9f>I%4W;ZK^%yuyQM-eE=L3b$}qpk-dtS<@3Rc)DX9 z%o2^G7-~qBnae!V+8m_JrcoyI$FnnYNRb*n!4s#`x3hQIM!&c^|!sVM&fDaS|z+d;AJ#4oRGFCTbytuNalnX>U7&%1Kl@{ zz#~>~cwYoq;9*3-{)(-Tep|=o3F(hV7p%E){}t7V$Fw4FY8U~7r1&d%{L9Ov`2XC* zELS0LYH6qpSs|G#eCd`ozTq0LaSe>uvc@qK16g`WR``%B%YBo-6%Enxb4aLY>pb8wkwU2 zMt4YadNOXr?q0^AMl6(XtVh2ZRPXe-ZZt4%3^Fhq-B^PjHmF7|IOWKz(*5s8x>e63 z=&2WI(rBo2YTr0ZFS1=KSHiELU8%>g^8)iu?VQUy>mmjQ`hfmYQ3#61HFa@iL_7CkU3SmBMoR6 zYGdL}jYxVJYQuF?J;uplsEsK%8LDUAuo~5^&ASQJaT?WuHJl1dd7spthXH582~{(4 zCo+@iA9I^`rj7ATY~MIWn`mns<8igGAEUW!^>I16f- z$#PX~s>s{ky6jG^+N?QuN(T(rs&^i$me(I9h0|so_Fz?DR-%TU*4hx}`?22O-%v5w zBD^&$cNC46W(C}W3do=e$e;?CNEI-VD!@e*;1U(kQ4Oqszw{aJU3&+418awm`3B}w zSVLUKJh@*DI)JT9+moB9y0QAf4P5FW%$5-Br|I=Nbz8GWYQ@9R>Wa@?o_VoZd0j^( z{iYv&FD^L*0|oAsGtt(~+oMj=>YCv!y#)6;1YcLZ?W>&L$S)Q-U0ST3{QfQ6U$q98 z$Kp(AR2xn^wL^#wcWoNsN;sW+9qyXOdMDyO8!qS4_NnE;v1m!f*iB(o_wK=or;3Jli2t;Eq!YGlsy<9cixB*qvk6bF$xuZ%7$*%2M+3w zZkT3mcThjFp}+M=rQYs??!7*#Y(0d$AAn!1+%)!s*R9q+s`S$z_O*UorFSdoZ2jO% zeMm_ctN);WN6EF;N59n{E$Mzk0!ABlQ@HUEUC_djZcq#zyfN)da43l}8^Suxc<7K` zQPOCQJgD#fsIN8jkY4{$_kml!5f+BCi)IVmp<~p3E-ci4-PBYYfmzi!`?a37G2XiR z8~y%`-3Jacwf7(brEjP7!;Ck<8}m)=MWpS+s~yJDul4O4ldU1&=znhPY`y;LP2roq zv|8I%=s*0ghqbm`zx2QH*7cS8xGiz+TTv^lXw|6D=At=_kHH&-!%e*uyRIL5{(YvsKK?Li~?x6v{Nqa3>QuK3|4M3t&B3Q^ks>XuC?lb{`Zz^uj&V; zZoP5MSGr?symiA@`k1ZVdrdLp|9XI@zzV$&tnth~{Mm3oUxnBsztT5vy)O1RBC(SE zhh5Ohip9T;;&-F?DF^h+Tf1AU59r;ub#C)b0^F!!k3M2sAM2xK`UBf~TW>4V*KUim zCX{XZWZSF3)>VFe%Fcw?2T=(0Kd0xWy627J3hsC0(dvq`xtI$YYE%9C`#bwv+xhh) zJBM`RThh2!a(Y5tS_9=m#a%`09NMkc2kh!hw*{HIIuGR$%gkteOSd^Djmg*u=O#9@ zO`>L*{@Sklt$)te!#~9va(e2gU52n7p61AGt4%x3_JNv;TFXk1bL=dcGX3dKW4g*Q zFh?*M4dj!ctnc}>XZ-p{aD)25F4V9$`6XOq2^TdFfoJ%ZS&-cNDb;<*s@Zyb|7+Gi zX6YaLCs<$K>GQiRQI-O|b7_+G;a&Rp((bW$#)%y>y7dV&@HU>gZH8SrJGMTJkbRq; zDSgsnc~kGSXR#$|)0#b3S*=%n%x#_5H(1 zO^Z{suk%x|a_*mIA;kXeh{)S1idNMczpESD`z_#FxLTR)GU`19Q`*;K}? zrW#A%!frX9x|JK>ZDPs$NsM(jOMVjpDfu^mrR3jaDpB6M^{e)GX_vz^DIo_-XdK~x zN$3`y&JK)q<+0nd1V*N)T4llF z_R6xUNuMQECHad~Pq#ns(%<@gV%Up!;mz2Peh=!FFC4x8+S0s>MZ;a~gzc^I*CqPR zU)*C&+^oO-#f{d{CHl`_M7g(NSTOGX2nF&cZ=fN<8x?{Mh>_y$I}zY+r*=4UW9yLt ziwn25wy3vG0n7TwPsGrDBo^G-KeQDaW{et1i3v7`7@3oziu8W6^06N z?@2ees&_}M9Y&1b|4X?N;I0pwnszC6N!Kg8Acf`6WrKBq30@Xl4W0P$Ky;aj{owJvRL-e) zV}T=*`IzOFN<3Z8x0RZbRm3`IVqx5(Ny{lW6D?zIi23?iY}wG_q}l3TYh(Ao+`V#;*Ze{WkS6MC;92Ehlk6`E_GKjpgn=cOX4QWB`TenRhja z`iVRPxi<3eIy?JGdt9_JrahsTd>Pr-PZ5x1)HzcqxuQb%C-lSvU7|Z7zh_iiAM8m{ zKo51Mh0p7x&p2?M+kh21s9EB*&$WMy$*8|H+m@4f-kXK3f4nCUkF_?6GbA3x=}Ya2 z&1=%52aHVLR`^gmJcGej(C^F+cj<%FkYv{AjaDL$em5Ksi?$rO-!ci!wc-dKE@RgV zY1lIMB%Q?betO!R2uvaU=O`3rBOyGKp&c1|^nw7XQpOb8YR8)alo9w{4npIr4e*d? zR%0w>)w`Js1|!?p?f2|pc2^v+t&TumT&d%Bumo*|2inrpn5Ntb^vtIOw%DDeQyZNI zVi+ZhJ*W}5w^}=la)e!}5xBitJ!}#Kt`WG!+&nBx?^V^S9X(2Xh`(j)yu=otM` zja0Whzx8TEHJ($$3Q9mGvDb(P3>?sNG`wR%YAhq($TA9zPvG{hAef+EDn+fuva*$) zhn2OlDq`ba77xY?W7C+$s@&dWkp%R_atEhHesCAYjowFH3(=SkY*KWJ%<_q6bKc-e zGD(@q4L9C>kHxk#ObHfW+i-;Ovpf~ta9O*lwJ zcLnhZB$_o|Y9*Dr68dy38cC1L;DpSIcQq3j-?D*BB-?!VOV8^aK~yOXwPtE+!oj)@ z3)>_A-%xc#47B_k+f<_o)W{O{ot# zsH8;&F||ra3x%l$X-p{5fBJslRrI@%7@La5>owoRxZjSXr`X~l_R9b*53%RKuJI7Y zdG-*S5POI{2^aJbdoPnqbqxUe#UlJNc*c1@2j^+tsGV^bq6ehT3s7hcQ;%Ah@vfK*2^=rQ${AWGShg6 zB-6MA)3c$IGc(CYWGjP7D1$Fh#N>CI+?e8GF;_+{=x9}b?i=eYJuw0bBYy}!`eUoC zk=#gb&e}{ecXmCi05+`V%~8EHXfL2Bp5aNESQ8CqU1Xncp+McI+#J;)CR+Foo-I*)LV>MACL;~ZN{Adbssf5U&Y({)arQK zC=J_$$FcQ;ei?M!rR&wVjII?!6#4NO&(h2Bl&x^1Du52-^d|u{t=kd%%?-Na`>0Od z04aMs5pFEnppW~0)L7Q1>A}Ak!!QKLBT=ZAy-7vGV{Y;+Jhj99^mj%HNSa^1zK9)- zXB&9oSXX-PeRQSt^lK5pxQv1_pS44mxiR^4wGD0YHEPcIiOJ!$ByZWlBCp$~XCJ2-(uyGuJ*l_l2PDD**0{)MrPsCwJPkoQ2> z1@p&gH$?3PTJ-3>wi`mW)75{_`pz-v2%hAj2#o)snppQDWw@3x>ot^)`Q-hS@i^u% zqB^wlGb8c-$QfeG^cXoaqgBPLjw6AhOjWczhtzgGl7^-q=*bZ&-gIVx*?Yl(z>uRvk zHYf~f-C0c4KRg4aK~L$4V0$s$7JI{A4u`n$HP&mIB+p?`%y%H8=|zEw<&qkkN#LAJY;M4>c|S|1DD59mR?~_%qxTx-lPO)n3;_ZP|PE z4ugayZCXFy0dH{PP5}*1=}B2__}&@xRqIJa^$x1a#Cvk|G;q928x+g8$Hj^U51-Pc z#Y_qdj zZm~`e8S%W(c!@bAy#RqbqZk^5XtY4rcX@|Zy0l@jxmURjc4n2#xNqBR#xlMF1~3&>L|~C83Nh;^?X7bjqG~+6bbo75MQayWDsf zMZ$77o~nuB8^6EeZfZ)`Mh7=DqY#C?dn;m;G5izWR&;vY@x~owO=znH{odEQJg?2Z_cZvgg4R zi*b`mpRk%2z4Tm=`CNP^hMC<~dR<_}jkGR5l5`R^@)W&~K`TpEQ<#k$r0(|ShS-f? zC=Edwg_KFpow&{BaaIO*HtJDsN)_3j>BkFZcr&AV>884y@TOO8C#vSJSTz%0mj}-l z?SUIBOc4tGiEgsHmfJ-y<2MInR|&NHA+vj% znLTfCn#gyG$hVjB`@Aqrq%n-!b&y>m$nJX4e!M1A-PKF~JF4)kt&qOkP`xx9j>e3) z4cit9yT{8PK5|T)5ZOjy1)lsW8qioyJ%B}@^9H~1{DK@F{S{JSXdK01vl5#rPE*$8 z2zWpk<~FWxj%6dm`w=VYNP58tW!Ykh@9YU#I8GxiTz9bhn~n=e+1iS z@FCZV|MANRdBKdngEhGkyAB%vGmSI>b2nGVvY~-adh6Vp%XU@%ZyCN~}1=J}C8vlC6h6{b;m%9IcF~KG-e= zG>u_cufSsV-`}z zo*;T!J(N?!E}pU~PMXJ_oZEzDa*q{12O=PVGlL znxk!rGxTm+nDG@_(d?v{4xJ4@=SCuiOFOUPbtl?JRg6dB*JHiI`a6R#LG#^6+SWlv zDH<)QRE-?!Wi0)u0$o7}cxGu~KoN4=8gHY*TpnDzG~RJDgYaOGngigaNSLG+xv%ET94fr#A`Af0%EBd@c53VI#&A$=Q2FX&EAP2ikfP&`qjtpBB8KrfoE=YQDeu)(Z0}mm2cb&XRwMPINz{u- zY+R&4Rm3&Mlg|J!LmSa;Rjl(6cWJD965G$74eUWRr2zQGZx&k2Zb4m5PrFkPTbmTjV5IP1XRx(R1-uAC|+y)XL}F zdb|}xf_V8*|>oa0I3@TMdh)wMNxUtNsKQTOI6Yl23?*!c>Uil&x3IA zf5_wiFpfV*9={jFF?c*$ke7wJP{Iag+NI@%;SG);M-*2@bf$)(D8$HOVz;RNzn&pEuOnJA zu!=L6j?a+?$_oV6#^%y7Or*ma>j8@T_+A?R<#$d*yR*iPK~l9nFC!jUH?PrTsMY>K z9)h(cv)*vn8ANY72W>+ooAE(6YRmH2RyBEZ@Y)-4G;1)#ETb*HQ0rriQye{-& zXJTEV6p1OaDCm9hc`lGQV`$~J!X{*wCW08`8e?My-dsS(j3Q%rYFLh2M57Z`7*a`b7L>b@Uq5Dpa*Wz} z2Pu9ERRODhCWwr6rQ(Al+{xMs=aFqnp4}?qB1_nYSxjMg5zE-c+8I~Wo5^%$YD3;P z%_b?1s==n|kZxu!bx>?>XABHR39`n<0Wf)|%vdyTpr14tJ(-tGq?&S}22ln)g%%Bl zv6}a`LHlW6f<~X(ofmj3^I>2noVhmSqM$rWk$ug5+4z8ZKK1WG>|$xGL-pjMD9LNF z1yxhTqZ@y)X&13Nuvqix1)7t2m;>Y{GybIFd)dlDsq1E5(FFGgGjvKtvWdoFY5{De zdUD;o)#D8VMKczfsVzZjwJLQrsxkHxKB|VX3)(8~n~n2kZXRbBut|ANF_y!y(T}Vk zUy0<8DYZ8US0`mVDeolX1DNq(H*DgAQ`WGTjWm@pKz z?#RDSb1rlz8k>8cgXUoTp~ia{#+_PO?M)5bQtc|3^eu2%I=Kr@VCND~JVN3J$HBuc z!2R)AE`OIz^@ORmQ3tl;(G;eI+*pVCQn&Gj7l!BwZQ%;q(U>_8Er(^t(x=Hj-e$Tv z-pFabPBdoWnl_OT-R3oAIsd~}Lf$buhgHA})ZVuK5oQe%UhNhsE+f09k7DP$C%`Jis>2dPht-Rc3~+2#ofkY zf0-VRV&oD;08Ps-aQs&BV*>H-{OIHDB9}|1@96 z7_;eGyV-$n7TRxF8GDoJc{FC^%D(Oqs^J%zzvkj4Bz}X7mvZq3B(CD(yGdL~V#-z>D!avcXiJ(hA761%wX~q zT;oZ{s3GVwp5ea_K!7>D_OaFC-Hh}*@oA7T4I@IKKR4akP>!7*B{u~ncpJV3m39NM zpWT6)7(Z%2>YikS1tC3I5Z((BR1F(r9nz=oF=E#=xlL2(Z`@QoH&qG+V=q#MsSs}J z6>e%YH|3B`AqzYHW?9fkZ#CEZGLdEBUar@~^$a4-EZFolfA)5_Tg6@rmEIe7I5q45 zVr7I6jc9w+PS3LnUuE5d7Fg$0YzjCN@LaPoh<44FKg;^sC3^W9YcXu+gT~O@#r6dK zM2m~P@y#D8CzR106P|0*Lt8xE=%%{atG4i{eMU#>N*Gl!XCqP7Gd@gh_;HLk_)llh zX<=K{ut9>AN;LiAfGgn=e(V7K(Wqv=2qnZm%UP5B3^LsZZNhU>TwCU3YJK7(FLnO+Vp*VFyl*C$|Mh+u%ED zTFv02zxGb8D?KVu@e$JB_u3-;>9*^Gzrvr4uh2p9*TMcKss*LU$9{Us@a;lU`i^~I z^6i4Z-BeCg3YC+842ByxDr8k|XL=18YYF25bE=k#86DkpXo+eYeL6GfbY|-51$|p0x>AjY zyP*+yg9NeW&BQ$23*XoVVHB$y$c7^4P8zmx^iZ)OjNu4gKrv|8@Y67h+nwfiW$xka zi#^LOed(H+I;19EOg}$L{d3!*~PiTi5Ksv zL;tC2?PHzVWo%*C3O~b&S#f%ng*iR9;6uZ5XKJ}^c`3LI+m>tDXC3$vkW0?gpYeSw z9*1b>oe2$aQ#`1A0K+CJsvi18@;LTJoOq<7fk-%r-h>|}p-&mH3Sa{=#rZ0OZo$qQ z_aJL`nNI4)OH;0d3qmxSY5>NV-9dQsy@?WwCbPx`3{;S*_&^OLixPB!C8#w(-DoG9 zr8na>yy9Q&^mI_Y6D>`y)bq9{|4VI{a1OgG&QuIFePdlV_h^hQwJub4>gk1%&hj$y zV{+VZj44>i)P<45pTfIE&Y%-)yXUlROOo;G3S`EEB_zF)JQyFp*Y+m+N&61FY36^zMzl<41s}c^y@WPfE>I0a_dn$c!0}Q#mow zI#=rtHfCDe7V0}1r(54G(7TqlA!MGJE)$O2UI8Fzyy@{5gL{WOQ(tc4BN%mqFX5TZeMQs=d@*zZQ z&lzjzd=Nffe0zVVTvlQg3&0u(cpxzxkrenw+mcb8(XOh+D6_IL`V>zMguihqcc# zeafZ&?!)BxRGZW}c!4nqI#?|m;mat0C|aZ$i+VS{M4}to=FbjpL@YQieRj|nZ9^MQ z)LZBVX_yJE<-lRQ)~8)YroR zrGy;D81F;HxZ^QB`*Np|b*AM7?1Gw&m0}^q=}zf;hueOIGY`bR2mDg}Zc_7CZJ#gQ z^vUH&t2OV@XAfGUt+S3ld)(6f>R`j7l%2e@s_f*HU(0@+R$+8m?(1T)42|B3eo@x= zuu%^4Wfvk=(2rgk`wM*YES5diyv4o&R?9V3?~<)ft0mWBoqx>tX^>@`_1N#eM}jSb ztvi4BeH3gNZC(4D?|iUjQN$a+W1=ZLx9qcq@5|2hk9zrc-{T>ct`Um_{cXcfpu=;1 z_x(4-65Vke(R)iDSyqwWPz^!1TYRTOEm6J`A(plg-Gojh6NN|r?rRfjc|5{%jHhsr zrO<7~G2io{maeJO1pO0BA!-s}Ub`h%?SemHmn!M(`rzESvLm~r22(srvXUnm*Z-KW zKGf1ZB19OdX30f0{pRb@#^SR6@{8}mHkR?$)4%w3wXs}(?J>MkU@N?Z@{o5|R0Gic zO_RzVv&XeRih4Xhzgyw2zP4eOB1<3Ni(!_YmN4H=1lHd>`D(%}4(r}dKI>JMA=Zc* z-|(v}5A>e(Gqf&6cy-S1$*p)y5O?!@BFRoT+U}h)`#Urq53Q6DW50&UEi#>mLzLg&DQ7J zS_-Vz`Y2!baLaYpil4UL5^k|ttdT!%9n-<$v|7{W`JS~~imf+R`)-V|oU_Kx@eS-~ z(XHd}-&)?$qFJql_xWy%vP`g+f4%jcD9c?I>%^HpYqaG(>zvtJ{~K*_1Y4(lxwW#3 zr8BH#^P!>YV>f!fZj>QiY+~xb{T4ZwX zC10Od%N)yOpB`(u-5Pw!H#E;OZ|fa#@UFO~J*;xW+w7&#?JdFmdfB;${7HV4x>_l_ zI3Z--Zr|?S7JRs~+jpY3WrTI^L|?yn%ea*9q3ZH{pu!Kx%~wr9cs^o92|A{6Qh?0> zpW+r85_`ycC>S%R_%_8`wptJ0xpm(4mUdR_px7-YyZc%6h-7-d4>e!P+%oQlUB0G%aQrYqbH@*{?(%(Jbygw~yVPD(M^M0S8h5dWB^Slogv`ApkcHj8{mSxtzxB8Y0wA^hy zyVdvIKuc2W(XG@s2VkGI?1#Ie{st<$Xx~Y{(p&b+q9bKX?NQ1$U;iXafkpRiOtSR0 zJm5P_!OcGFAOu}}eFmX>ojd8v9At^JR-N?aBDB2kdts2}dduU!y@M<(tk?d}H#XTa zy~py+WIe*0MZ@KnnMmTIJ^TYA&(BYe+T!~x*^+JX`1%Zn;hDbMC`k1!8Em=E66t$w zFp@b_=i56N$$Vbtt3zmc(-(0gl3B7f^+wB{V9S>ON7$FZMOpm+Kl88;q5``rC?4pl zpo@W?yEdr4E$ zQdDIB@6SAgSN8kw>oxnH`ON1t^O^IRnP+Am?&^Zt99-ZC>dG{x&ROFKjbLu7n)J0J ztUDXaROgqD|5;fEQ-_9gOAoZs^IaU@_h6~2I(~(tVKf`3s<+$oxxLwU>hql(J!4oi zgL-)>e>IK`R%f;qC!bXQ2|pIcT6caW6esa9tiNi;%P}=I+E}?ecE%%Rbe4CN`{T@*x;yVa!@I__t_}AF(_;}!EWPX<*V3Fmc6g;YqVs*Q~7bPS%hA(w_}g4=iysNni_@+IBH_3_!nfZjrd>(zcrIxZEWLDIrt z-t7gpuhs_(n35W09P2e1mT2SiTX@sScv!R>#G1S?u!Ww0RiQ|LffBH%Dgo>1LZ=N7 z5qn{si$Z7%EHW9g|*SJyf+}Apdy?`bk#+KQ@F7 z30yJ-{o~L6qJPYT9sT3TJpt4|x^Dx}`pMG9JZUIPV`jd4D7)=Jcag{B%s25}FS9;1 zJ%np#T+YVwkG^&J_|i?}G4_r5<(TW-S}#tpxf<%lT{4>wO<}F7oo*y@i_cAAjq3ko zuPWQIO-0#e=Tn^?7r?iru{%cf2Oq*VBh(-}UBa7Ph%JsgjY0G2?s4NBx}-BU(}hKZdfs%?NqL7unI+|T za@{c2-fXl8F6=|Iiv;Da73s{~m`1WqsA^(H>T?X{D3%Kj8iNKN!|Zh6QJSJ2B-=5} zQwJWU$?8F}9SbEV{-O?I?z#ml3B}_!NnJ2u8;>`sA|^VM_efkk{S`Kz1#;&rY=r8U z%li#yZwAF?-uH;gT|p_NDU@+`8&67rQ%?Y&k+7(-Eu_AaMjk z8|Qf=1aaR8Hn8~_tRd&xEl5<%@U@`?x%266dD;wRkHyLbiaBZ|>)qyKKNLXje0pU_ zlTJ%m!F#k^wYC6+o<_@5UnSL;d^^=RG~$c*_zxplOPgh2m=bBUMETNx99{++Ey)oI zct>dTKiUf!_(Fj(D7zRz7=z-AjX^_7j6oywjX`e~M&=GOpxowDxfz4jmI#(66=q{0xF{YKy*78O@=IrJZ@1!wXmud@)FC9ZZE;x9piq*kq#^)Oln)}sI9y7WJyUKzD& zQ(0Aai@W9Nb1*r@`sd-j4 z;?)IE0To}gU*L*7-Muyec@vkLtso-V1)vWX8HVK9NN=Q1sGm(iU;!1<8>t+q3H`%R z1Hye}`B;Sd@VA#y5-p;1!H_hc>I7MK!c%YGa1>I5L^n-s8{DF4!<*^?`4r=xF7yHD zC6194)s1MQMYQ>?@1UjY3{d(G+P!G} zu;JR9EhgL`3r$#4PK`s0-KE5KIg%P#fzOH%rt=(cUa8 z^t@V4C635#BHvMgs~W$Z8b1=2O^sf5CDdps3;xyOvu(wcGeLS66J#$CuK9%mHs%Rf zP4Plzw9zdOWuo~nrrm@eMTkC=V{--~Cn+K0$_uZnqZ04=TvoQY3c-D<|<)4mcAGOLG zfzjvJ)ew$7EDLswK3`ZXMxVD<%h9LZgF=qtmCaczb>M0-O;`U|#s5xcQR?zl{Eq;J z#^m_l1Xcq(GtoFwjYqRHM0%%ZQx9hh%F^glB!u({5<>d)2qArOBqq~oop5p;%^R>p zjB*|8J7EGtuWs?0Ch&P}!UW!AG7GCV$e@p0Uz*Gsb?7p&YEb{Nrx?_WSe+Hpk%g!q z4C#&Fb&m7oUrlDey!MxhNOJ`@vabN|{MV7*`sgZW{yGqhmWMi1RX18@OWkK{dBQzU zreU6zA>2zuT8u$Uv^2Oyn%48mw^@Ta*@ZWaLyL`b=+g=MfVTs0J%zQd7v%Y#G01Z! z#;-GsL2>Vy@HZ2G{LLxs(`F;9}O?5;fY9oC>D z+Fo!T2=LHW0^#;85NO*-no>KNPb!jSX}%~AKK&imyBg(mn9n%A_Z`-+KKZUKq*9AA zriN{Q3jtxoVA`9?J4|IQYFfMwgJeuPv6Asurm_HA&{B~tFP=BnK4pAyYkCVjcD!mK z-W$d(d!fYi-M3Gs8bbozL86to^=Of_5_c%on6}q@r78scOAsgoPLKeW?jYdxD@ac+ z-33wLKj^$WNwMiQXvq-l+81x}TGLo#U)uv;ItHHu=}8?gR_PeLK^M460@s9&f!|7jO)^omyhu6*=IOlWg^ne8zf?;x%$C zKQ*1zk3YuQCZjpUK4;&GN<>nIiZ`Ds5NIfwvAZLUgHfQBURmHnOxAgvYRVM3#1)0=L zHeB_6gYU^?6Pn^}G+xGFF4hp|$FVp6iMg2VH9jnhVVKW%WwAE_&t$VcwW*8wcob9Y z15K{%L&iDRYw{1XS*w~s8!6-LZ)s?ZJ3z2K>@Cus>@6lg(OaaTsXf|TBnbDz-oh%} z4||JHxb@xwBZLw}OOpnRnAgcEX-{KqOIIUQ5JUgu+nD1meU*PblbMHGe2mC$LpA() z*27<;XYd!$9RtBO)iArmlrEcgN#PM_#e+po@Gz!(vmi1z+JI7>PwByvQtzKJ!Rv9; z*a}xwV}dvM0uBExJmfvrs0qe#B7p2X!M`FOKqo1(%|y2F*WP2#VtS|hil-$8*u;cq zA4&GGd#VW+U*p5WabV7Mt%AB`Ma}NTU-3? zN-<}{+Qbcg&PIvDoNbjH6JoeWGoG<4C>YGyzC`_5O5;FG*}j7Pg$(?yrmO_6Ek+C| zL6Jd0+0-(Scp9MSQ#KQ9k!~~#8}~QEfXZqk-SkNtg-^4ys)?HqP27qFF=@L#V@rbz zv6lf5*|cKJ*D&Z4(=|C;%M)ISG?x^ELU_j);xD=YvoxBl!DDlDZgLhK;~ZaZsEbBh zH9N$7%?+bKnq2X{IV{+QDnhCwc~pGpS!lY1(P5!*RXsRtB4?s+)^k$u&|VRg6u;#F(sU4z`#7ptqhAjP7tFpF^o12 z-7J;@cwsJUGQu*@9aF>k1<(qd9%YykRx3kCFhZgK(Tx7n)v|}pJ)4q+>?stmLT^B; z^My;)TXX=J7NAI=-h>Y5KGJxv+05(#3UyyWe9UY-QG@ub*{ma)y-pO(ULVF~UqGd! z^0a%>#wH9-XtH-51NjUPW$V``d(`?Lw0kkmN5p!Opd8`pT!oU)&8Do3{6+R5q5~Lw z3MI3#U>JBJ?NJ66g++kK%t~|<$3!=godI1VH=0GaBUiFyJ(0CXuK$RI6eN;rxR@R; z&4c7aHTV)ci?NZS=m9GgrJ_6 zNgGAINfNgz z^2S!HRLtX!;|(vifROJse-^T|vpy#gX8ccUOs`ZBEqI>e7Q6hYQ#8X-NAe={ez961g{@_QzV=H_*&uhdJfH*o7 zX8$=cC<@yuJR<4P0M1}NZ^nMzj`iq}=etizM`OoPM_t_(6vSCDV1HOt&MoJUlsDK; zXAkovpB=&{0A7{OCGgUP8oZ1SKXaR3)gCKcrTj@L=kr)-{iPyr-@*QHSGs#luF*9B zyF7n)_PWkX=3$JnK$OII9Ql05>`W4Y|L#0{i3iR{Co(F|J}D+PcZ?~{{%S(hEIRU( zb8}W)Kteq2d>V+Y^tf{sX|&?=HvuW>&9D1L&>t@I zgTsPLerc-s-BIzBfQTdeQXKKp6VFIMb6x_(J0SR*dy zVm$3~x}p*Ifoa02D}&+@t_AfH1L^dD7-t>i;QL5Bb^&9{7uD$cLr@Z{pgQt=)WbX% zyQc6qkSn;>KtPV=QLZkf~k6kK?A5$4ZQd|eQW-J`MpH+LlF@iv@W z!m}}}5dw=H91zo-A(Y6j3Vo1MupY}#DU8G7buLKuVtGT;Ko; zZOf4PR|rmQ+@&h6=U@K-lb(SV=db7W48$gFkqSKn!zrsN|8RZ^p*w$Z>d6d`K@RH5 z?S*pWX^qdd@wYe@!8>psCOR_bzV64pCxddPFh&$go70|RU9=E`deeV^zgH#H>LJzb&fy)qT1+v z*L*mUIreFk#c0e{C4B;^g=?5`&I{+%tP?yUX?u!t1$*7#6zw_9>`aDWWX`t8%~zZJ zVu81_H9h{GsE_D-&p3Nfj5ex(QRqi$qd4jz<&pDQ>Qh8yl!54`XO*DuL5EA5R+RO0 zWkJ?1WAtGvBkZ5=19n)Q?UCR)7S6XxxNur6p(Qw}KPznxZYn`^(y!w* z%_}%SaUuQ9$NNkx1Rv=$ZI3>5j{ZCM4`P5zxxf4OCvyJ|2v6qzaxhEft1@1kRGTL1 z6EfZ)Y6_Yuo=(ooXOQo<@93L5x6p}3QT2E990G$@fl7QOUM&gY&dEkdf42!r31ERlxN z=TMyTHUeB|W5v$(xZJ=BTxqNib{5e%=pRHJXAeF)0975gL}A5s&vX3wMa*I@Jw>t5 zfTXZA!y_FcTI6I+;^|(fpH{~5_hh9j zYSt}l<$h~MrTe6a7~`f&DEY=zB-5^ait&4#o1rq&RT7i?eIaD7m}7GJvc)V!O-SJT z7h`+o_5r+XF>Bqh{=;ad<2i%8pdv#Qp(lB#C9JV61(}5F*E{GbjcXcVL%6mw zBS6`1jfCmRwp)9?9MmE+NYbHFQEMK&~*NGoCkfvB5m)ZC~4dWU)r9252XXuoSDZ#&Z)pA z797Iefot4R|7UDPJUBN#)Gsz?46a)misMsbEY9Pnk)^rX$F=}PT%ElRS4qJArS482 zLXCMI71fMw3nBmbu#tP_vs$)AB8Uz0dyP9LJ4MmvJ|M(6*P(`qUE@aTlym+45IRn< z$7WtI;*E8Bdo2D0$6=*gJfQGWd>7ucobHRFn2U0~VNBF+!RiI>*Xy`aEqOO)%t;hve+p7XkRT*(bxuCRYkkU^ zcj<}1Z$zOjHXsXDgN~9Q_*L+u_U#5O2?6=+a;`+i!j)Jklxc8=kNuQ2ZSMdd=FDS{ zQz&7Z$rWiFyG4ZgGh7`Gku`7~1qX{Zw=duFDSJl!aT>q(Da%rozI?`KtU=4Geee=P zo8lHVtGuf#eJGlQ??I68^5!7D7%9F*Z)3c+^KZXkvDT3Iyfm-B#qa|=l4~l5)ZsYbpvC8JZwFj^KlJzmR1ex^Rfx^`K^x%WP z!qJ2qJ^0+Ou+Q>L5B~L6*l6qM!4G}KdaC1k@OodfmTGJdZvC1KQ@cg-&%b6J8~8{?Gv@)3TlN@)`}vh5y_Rc0!nJ5h_T^5 zer*+tZacy%Q#Dvx{QJNnQqQC%tPBD~iKu7gudGIuUHcYaz8Y4HLKt9OE5gF z9?4k8_5Tp0oASl!@mt5y^s>5h|23>{*UJ&Ib}ZN+6i zgq$Py@a1c88sObDetivVZp)+3P?&bn^CJu0D~>|TFC)>1k@0e_h=f)X0G5o{UsbDhow#&&trFCDjETz7U5QDgjosBLEF2tDeWbS0xWLw?1Jt{>EIEwTyC>F5+q z^B&WL5=3hSGv4I&be332h#e>k|-@IfW9tLZqaO zmL?vHAU=1R$tDgLE`k;!t&@<}`_3N_#)GtCz>BonkX9F^_1fcUjRor?**ry$9ce`Z zF^lt{v?AG<;EEfXM4msIRGU17joE_X1}*h`sj0{3 zLz@=F(e{6rWct)cO7YZ=M^Z+mX#4MCOarf&SL?<2DV(T5PcO#*E=67U&pH(TEBmqO z!Y`)tllAY(R8*b3LMtgNde}-zpWn$3JJ>Vz`=ANLW4%ibfG9(#Wqee`o3CR%>Rm_0 zp(;(QNY3w&1RBnCF5*+yVLQf2G~P#K`wH*N&coYuS)1^dvNyKtvQxJ4u0OFroA`Pe zHBqr(6EkDSO5}laA4QLeyGOiz!sPhe>1ax>^bic#Vsj_?IgKK~u}}uh;$0D-%UNR^ z4b`sG;mu=06few-ynCc{7Uo1xApqnqhSwR}E*0%PVt!7gv8r<=l5qc9n= zZwR2(*_hl==TFFSjAn}sxK)mFj6O{jAC6JlEoV29$Uz4BPi>0uGw(r*0W^5FM?3=# zXUKNGa3jVRcen7p8`%sSN&+XF3vm+(n(1}~Z;u%D43;m@ zCvu4h(#=&7#6otHP>!xYvHQArp>+_iIwS%4O_0dd?x#{B;Ex0hK(WW{&_c{Lo<%%Z zPSld$;zu{(%*lJd@V39O{N_tha+qdvg4{sY$N+5mx`pp1X2XVCR&&Gt9>H(?!Yn>L z@O+Fm{&*+jTxBFZ4|4reM(~hA7ObwY@*#z+k^0iJ{GCD^$}w!^>Sh)g_iHjK;*|rX zW86H8U1#I${!NF_?9Z$78vxuQlqXV;HKgz1 z`;aQ&#CpFr^mT6D!n&#+$$aP*mZ<*t5?=>*c-l+Evq1zz0a7zHZt^+qbZo)84PE_2+^XgK zC0TQ|lf(Gct*nvH>4!cCb)OG)A6v&^4`hPKnybAocvXBIBLjLoJY=dd_&;b6%b|m8 z5O>xgYcj8TI4$@#37VeAl|%HYMU7&5z;8f>k^CP+RPdM2QMh9p>!Wt)#@&ioi!N^6 zm@*|XeGuJueI4VHaf4{nm<4kOi@!q*ZpI(NuD3B5nGQUhYCLj~rXS?_egq#;#M*hj z2d4C^bldxc2>xjic6M|HrTM@BzsY?|X%k+mv1psyW~b*(<8u2dbhKL9i)GT>ZN1L+{R6fu{*QQjE!Mr~NpDXP%10uqqfr68|8`be9ln_l-;VP^*toZ4 zJDa68>&oMHu(p1&g<=#hJFLv|y;FywRJV5FAMIfM>Yo4QQD1atM%3n1-ggJitJU7g zeCsTIi~%*q(1my2i6fNpJ^2SaS$*|TXCA+s)#pXzxYn7M>}2h0OhNObJbSk@Z?uc~ zcNh;hCbRoM^PME@NjOZBRvLwDjOeBlPJm%MhS(R8Z($8O^U=H5?`peeDfId3xeffn zZnj2!(dwAD2Ya_vkDvLby=-9DMVMz{@gNs)6SL)y1inafKBV$ZxG;mkJB5fBb!%PJ z^xm+dOu~Efe*4&)>iu4P<383#ZP<%n*~bDKj=*#Z3-KP{8~`i2jP`>?Bk$6Sx8Bd{ z`-jtf%a~+_zW%Gk+{lDONJ(fC5x#@?u>CmKTdf!WWpJdsfF-N@;`JPSF8Yxi922eQ;9X2pCt;>lI@5ULtw;9)T|Kyj5w_n^V}jL|IAFtoAq=lQjREW#8=P1mP5 zCdaoLu^!_4oUAENKE&z|?Eek*T-vDT!7|)*ix z5W8BBX}}XPZAO3j)a(i$z}Fl>c8S16cD+ojk7U=gb61J%TA4s${wuqx|5wP96R041 zyMOWG6X6~BT7>89|J3jX5c|^#c3poSauk~Op==PEUQc==WTPIk<>?`ROze+^ED8}- zrXRm{l*M{J47qg@?|F>%Y4^-mLe+$Rx~dDXc!(l6nD}HsvhG>>@lD5|V(bGI#}ezK znQ8k{gt##Nsfn-uuaKpRqvHAW<52No$X^c@Dpvnur3kPvj<-0$BGeC7@R28Qggki# zUvvWVSGIy*Ji%IqhYrSZ+&^EqShR1@wxXgzdoexIN{1uA@Kmd+{4d1hT#U)QfNy18 z#c%^d1ns%Lj;NF9uGKkT@Wj*1-?Ir6Fj`8`)b|Z^%s7pu1ov($Xlb1%pJw$v5A>?? zwm+wPtJgl`LU9X&Z)U=;5gU(N~J`DEFN(l@B<}>Qx5=R>OQZPUUZ%Wi1=Q z8D(_D1>hqD5oPaSA!^21V+K~O@pyWN&$-IX4Xi@KlpKIPUVDs|!?bKr58Q?C@M~vT ztCkZG0v3av5c!q@$UJXDpHvUShLdpiwEMh-A<>R^c=vOxNlQ>jK8p5%c;%2Q(r9`X zkC&0UPcp98iFoZDo_&rrWAE^l=h&FYDb$&Jl?#X{1t6xA0=)JJ@ZBK5e>H&8jnppE zt<@p;-V{FgJbSH{PVvx>^$qrlpTZBGXJI(0Q0)S1t-c@W=y-t*R2z9NMm{f2#RtJ2 zl#-&CQiJY%`6V2(o#beHncZZ~#w`TrlBz!Q-~3a$@~Beqr|bN656yp+ze6EZ^>6Vu zKYoQ->rH-8Y)Q4To;xsrifqzk-u5c1$0qaMS6S;u;CWC~wsG5SY;3})j zCQ-ro@!zkqS}ostSURO7gVI6C?1z;KNtTXd60i3sYiuSeN+(W~&J=Q?bizSOHlkRD zP2w;7$tJf39obr4K*U`fazJ@p5#V)NfbTv5{+lN9@;}+gT5ut)4{|5E_-(VBj7mhJE*;cnfTkXiVpC8VUGOtd?I@m2N z%0-x#i^Vx#tiIyOG4=#ZU{~E9JWrr4F2I^*3vY`P@|SMoq7K0|?x3GB@oK8^uGib2bKi2-fyl-ei?Gw| zD7Kqf{MUZYlge4|c7i(z!^Gr>VZv^~sf48aV9`F%{V=wq2X)eA9M1`h_?#as$I_SZ zN^@NUoeb8i6N5YI{QhwQ6Ez>;P2(l(J*(nL3Jlf#g3CXnv?OXJ0(F1mi+CSR0qv2V z-%C&9i`Wx`P>|xp;AKSQTZA5HGW;!pj?eh*J4lT#g3J_(oCmA#SV0?KhJkcq@Q1>Y82G-xBx0-}rq^{r z2qgUhxBnDf=r0IaeBacWPs0NOiT=_J`xWgi-4D7a`o8cP`g0^8Y{+N))4QxofbbjZ z_3@{ayd%c#7qP}pHE1H@O#K@*An;oLf_tn9j!l~Hu?|uBqFUf;RD_JeyK)TQ$}t8d zQ(lhsulR&~Q#FI&N2l^2lVz`C(2B&=2e8No?ETFpZysjP0cSKaM z>ju-}#|rMb#Z+(&LKZ9{RrQi<02T!GSjn{zG`-|nEvAxdW~(b`7Ag^{hob1tiEw1m zX@Vg!@V+2EEV|$H$f}Ai@K0SxFS-()nL?wY3zTkAbQg3#QT{ut3&+^7;zd++4S0;I z`bFt9FJB;@K*sIARh1u#I~6B9PWiw7F}$|_Ity;<1<tnx9;96ODFqL&qj}6<_Xcz+nQ=?Q(eJ-aP!$3 z;PEZ1>v+AU8pUvz#5bPm0_Ka$aa4E4ym-8~+6FMiTWtyW%v;S?{p&h{jOt`J_4#r9 z^V;fYHLSLyRvqc)v^g=Np$Bi?P<^Q>kvCUH493SQkeY~32+t;-1gjIQS`!cc zNkg@#Kaml;8?oO>DuT9%82DF`m#Z3gHB>{HyCbxb`T=9^e2c%jo@snqV|7Mtd?Nyd zWSFs4QT+<>F!nZZQxo;KaL{qLQgVP9PuJn%LlXX@1q4qJ5H?*v#Crfda`OcE*LQOS zn$;Aw9aEJVn-!(3J08`2;mC;#@U+JT<5?Zt22RX}qX9+lnD7N}h{rJgV>7jjs;G{e z&D28H%7u~Zsl=k9dr9qL?EW>$xhJtpQO~48h&Cc;mn6)eBbvJSZvkq1R>@7cv4&Of z^MPtY+X|W#WA%4lKpAFnr8wP5i&$IlKTa;AWiq?A;lAUQ7V0g=M(`wy+7$4PMU7{7 z_%4h35+E>0?FJYTgeFqXzYM}%Im7vxAh4A4Hm%eM_6mQ!mD+>d=Brz&jRAXGse4-v zleHfm9-2KZ-kj2`+f;OVvi76*)4FftzqCf}AI2+MqxM6_4U0Ngd_RT_o$PrZ>P(i9 z18-vW+K;f#r5dUBBLM$A!B|!M@sRhQK8&ZdLG2eFr_hTfqxVTFhbe*mE8G4uD{H`2|?}G$$^IjCSeeigop)t9e9}=+oJXlby(Y~A2BwR9|=`| zVng_xcIwOQC4Q|PYR^l&X?wLS{3Vr!hS;ltI^P5i)I5uTuyz6>Is;H!dkXN16A<|8 zi;mb1s!a_|s;cu~aVE+-@7W0zb~jw8tmgrUAf2kb*QG>W9)_|{bcA(M|6+lI;D?vW zp4Oe5?AU;1_-Ngp-m!DPR+ddD*M=HBfuk5W}c${3W zSN7&FI8HsQRxq}KDtjY$#HO{`!0&cJbsoS=x~jf>NLN(!1l{iFs#-o6|HBu02INzmJ8N1f7KkwO1{Y7nd$zkZOo>bMN-FQi) z+DvVB-eKsWW*O8rogMG@QnMM`%}p_C13>E-wG;b>zY>FZck|pBJQa8IA7j){*)B(7 zEEc&vc2K?quie3$_Eo2{ReV`r)gQ2-FWTM?eyXoJAZoi{c|}0j^8zA>h%8(!z;~hm z|5pVBCIXNVwXiB5Ehu4~wmZ_|)Kx0m%KiJ}al4iG=&w!#6!urMy|++7)78x=r>$G~ z^9fLP3!j>xCII#&;DNrGR~w*C#0_xM2cSp!AI~44HUSh4P{VA8nv3$9aSj_Vm6#cK z39yAbSL;PS^nvHP&aK$_bOi@ewJnF6D?60x$WU6n)0z{D{3tYu)Oje9M@* zcvOj$9n?jj?gSFCl@LLXW=NGxvXG&xi$ydWr3_xm2$|InMOsyf1PKvZB@-g=OA*XY zg~*hLBDWEY(Cikp-CTL`RKH;z__mqo@7nXt@2RgfX#W^*Rng^or55n0 zS?U+89lttDy~aZMsT}od)|S8bzPc0;n5%xvLin*DB(mUg(>@FF{0ZTO@) zaJA;XbKz>mcg%&W6(5-gR}ioF0bCZo_5-*q{M8TPYRR>a)E`+3zTqQvA>f61@C)SC z=EE<5ub2;403W;nuIBuo1#mUvUvRjZ@#uwcHRZP#!e!?3KZeW9doO~k3BR}quEv}% zhO03TTLPCqzq|ylMvm;Is)vbr@;R&36M#``)DAvIJv(CUK6NPXkpFYN_%~}*Ywfi; zqNt3S^wAQ~H`e0p8?~wWZVnIl2IC>&^yQPkQGL`#IegAHs*QPb?*cW0)#P&v)Soe5 z==&{Z95uMdcj^`p_k0JJ2cPvlTs3&#AKwwF^u|%^4 z#69caQu(Z(;4<*O>)~SD<7c>3zUODSTzu9BxESxd5w1$^u?a30-?Is>3O?%>xGH(y zLb&d6kIm{<5ch6|f_M0=E%3X?`)-9_IrrEG*B!oR8(g>etRlF|dEf1D{loFp>7b5$ z%Mr0dO<`~^+X?r9v5vz#)gg@CaJ1X4h8ay;v~a9xbq!F`JK)K%QsWa(sL9@aKrQ9y z7cr`M<1#Nfp*~mr4?{SdzLyP-E+^IIOx^FsQ% z1CP?@-S~l1>a!yQK+je1-7CL1dsss_a1spR_`(*Q+bPQUO?$YE#8f-7%Q3;F39e(H zyVOUy?!fhs>pEPKxZB(ATdMLmPpggF*Gg`#M7iC~(M+(oZH_$XI#?c+6H)n6b0tSp z$TKHwEu>0Y>Pee%!LjkQT9?(|^Mtz2<-Cd6BzpK5N`f7jv%vrUuPi%kGM|?1sVDot#TG!Uz z=dYbrZfhO%GI30V@8fPj~F|0ym`#n^bqsFac`R^q`f+B*ofE0ylPG# zYaUj`lRj!#`eQ+d;O;x|i%}j?AZ^@ONWW>G^xEjr=5Z6on1_!YHx4?Cep`=r{OGZh zMvgNhv@!S_DRmq-9*WiAElbr@f6MsSri^?!J;>7D+}hl+l_h<6aJO;eM~@s66r?D8 zS*f~`m&CanK1yRX93_|3f0(68;sK|kAhnRNycT4Rh%i_A^FN)cU%M*TzqyA$#{Izm zqhZYK==F!%px1jDp>8k+M@Fc|azZauxbiMlxYC>zu7p1-T%lKCuECVS+^BFB!aoE4 zDe$+#-^>TB*P2I^{aN8EyAJagyuo4xiy15mSW2!y4E}}iFNA*r{7vvLyIkQaF0F7C z@DJ8&b!;UU;SEwgNEr}GfJg#F5+G7?9(4F;z&{24R`{FXZ-T!G{`v4vfxi|0X80@c zFNWsD(7YI$r@-F~|1v~d47CcORv!HG;GYM7^Z5#!s~CFagCPS9X<)E|!3qW|7)o{_ z`TOB_009(3;1GE5+3vz4P~a#cIEHi_N5m(g@F|3I8j<}5+20XC31s$w2Kh3`TMvQ; z`4Y&7{)#XmUwq7lKu;i01WXtke#85&P?*97 z_gx7vCH3#S(qI&rJiq%cGfY9f`z|X?F=SI=jzTUK<`(2;!qkQNA7nehY_~yh5X>bA zPK0rXSpeY{Fh4>#8D=kplVPqxa4L)^%n}HPRJ(0I3YI~#sg*{WV^wvfowOJ{g53Ba}9FSVZ0mMx4D)HUQ=a$VR~&f$RvFzaf_e(+Xx0WLv?khio61 zlaPBI=5GBr?z`THa08gHAlw;dH-uk=`2&JeV9YRi5H`aUK-daX4B-@*GRS4Xm|*fD z8wyhh*#wvp$fd!UJi%WFH2%Rxt+{`pH-dmE@IsID_ z*JzlEnkWyjG~=~4f#pMZ*M@l)EH~i&3d{|#ECh=m9{`rdv*7IkGZ`#ScqhU*!7>Ld z-gWqgo3v()r^CMz{$pUyz`q~N8SrF*$54kK0*`+>c>ad}2$&=AkAgV@o+;qD%WM4t zZC(eTrp!Zfc8Xrbxe&buxvu=wa**G|kb^N-ziE%a2B0$>5K5V#YVa2$NN zS11LT2+TNt*HsQwF5PvNK;8r_2bzH<%nw3=7GT*Qa95`<>RkZ=5tx8hU;%I;un<@P zEGBC`NKv2#m)JA;31Yikpr45!cSc-w6-UyHwfTlW#7#Ipv{O`H)u_w<2 zTn9`5I)P>!1YGEgh=FCm&|rj9AK31mOKFId15aRg)q=HZSt6K-ZGtOtMKabPI03}^*i~;5WQ-B4)JYXSkC9ni|9GLR# zJ(m@V<#)g5@`EA;z))ae_j@*13@jxe94Ab^=bGFI0S-Yxz_gbUfj<~=UNVJn1pI+z zz=gnqkx&qrmWl|8-;R{Qowoo9Y7E6cL6$c`%7HOJ)3@*krT`T)67szbSqe+p_sAMx z=vpuUQ-B^#A@CzK1r`JSKun zW0IN&OaZ3cL{UIK4Y&}PVY`LO5C8@sHoPkNzzm>r8wvqafaXA?9GC_)mqTG-8PG2X zIdB&W0ZV{sz`XmYY{1Y;$OF?e650zWVVSPl%W1->@OIpAbqXzdD@ zM=;z#b1>R}C=T!zfM5mg1eO6qL!hBgg)0VF04x9&0(Sz_eBs{~5ddR=*1Cuom;gKu zRO&&&P$&#c1Qr8}$?b<>56}wqXorLW&F#?si(v@|L1|dw^6P+r{GoYAq_7DB?1YG$ zK@b=kh=9Vu-x3OSh9a#ne(H*x3$AdjBy0zFHxxw}Qfh^}3vv`_>W=V$`9M=7-2W21`CHDL|zM1c@OY5d#wjAS-*K%m*Wd(V)KsH_$v1iuR(~kAQ$>uOXmVMD#ks z0fqu612e`z0bu@QC{FaZD_l-s$}|*ZJp6$;ApuQb2_?)xPV@(3HX;}RcOC))CVU75 zfEn|k7_ejk0(cG)1O0#shdj^(i~*W~DZn(~WMBp`510pB2`mH_0uw&2c+QphJQzO4 zh!a={oCQq#7Q<9v!qy7cI-nV2>|$UEMiEYOW26x}5d4ktGzTU$!Dxf9DaK;F=?<;F zx_vnBxii}yRD2WWU1*@zzn*ai`rBwY|CJqmP>C+HX8mkhcB zdLg&()OxZn`N5r9A6z(Cd|2zkJ$Gr|5mfqI(graT ze`}Xkr!g&}dYqFwf6*6AdInU0uI%Hjc56eM=gXiBU3CAB&~G5tP8Wi%)I?^q?aSxx z)VlG~-P-l`DR?|TnWftdijw#Q9Sud<0D8g|USqG;twF*Q{!`)aqhV>|3V&s;DdSFZ`7~|E6C6y?poMbaXk&Y0%4d^H%$`kW}ka!i#cOl<=p}lR*!C3OyZkk0;`% zsxlgM(#u?vZ`!BzLT3MUKnvsjk7(}Px?l5CGk)bS?$`e3zVlCHp~~m%)VlNN16ohj zdY!+2Kx?d~T<2dM&}O=?yNSVz%GVqK!-Qfm6#T>27i;}qDZBG{@~EQyT^(mwo>t2qf&Y`my%%)z z6ZCY5Z3CUcOF>YEFVOyEn3<|>@tf&pzz9+CE-)A_5&CWKBU!fU=%GV_AyWnKGdj=z z!2*T=m}Jyah1WWyHEBfY%YxJI-d$H3>{U9tW5O3k5s5F@}H?yZlixHv&EF33?Xj9YG%jdV!n5JDkwM+!72M_!}p* z4lxOts7iKqj@w)`I8k&Pz?;|f-(epCJ<;QFdK<`G1wFxoe|AJ`RlfrE6z~+IH5txF z;*UBDZ_^z9+J4Qyx+uXilpvo2XT$xvuPnJTL#AP-HbeArQ~PW5eI zTiFEa^Jz!59?Z@Qk7}{3uMX=8V)))Ynuqo`GCqdCbwsP9dDg;sL0B6Hz#9HU?4)T| z&_m7q#xbpPi>bo?xQ3LA>7ZL6YbI?M^F_zC#yst~W@xb-9)2=V!=&!;#$y9!1L&qI zfj3B?nfF!D6wopNhTeSlaqUIpz}mXJ6&;V^W;ZJSX1`iioshEIb=-9be~ymwrY2qW0tSJ3Qf*`(apqKMur?ooX8(=Mrg&f+pp*w%~ zwDw`AshHlFdtmHM-JAT8*gVh^dxDo*jQo*Ct3bE*=6!zC8o2L;J)t*${WqwnW0xo?17nap22qb<^sF#{^&cg~>slU2#UQ~?EG_~u#O{CCaD z&hinzYYE*OVS;4-02;|y2}q-kpeKS}@`$EX?c0D}ut1;L8Lo%(n+Qu?(13@PX#G1~ zg=fZx|IQUd15}ugFdKU$FiKt{(5>_M`Vy@{^{%id%!4d{^Eb^*6300^t2NhV!&=6J z&T36skYYcO&%wtl!4K#X_JUqabT@jyh18nqZlKKcwi;d~2;I&<*rNs4vCedVP~|WR zf4axu|MK`x2~oqJ7DuQ53hJHz@}Lg*sp`^W<*6R@{Ffdrd&4dYFbmbyg83o^SM{U( zn+m#F(hc8q6kc)op9i`h=qa!pKJUn{T+pIxQUHQ5yd&>&QH!n-UPWlm-@mB!surWW z$@AG~M?iEh=D#T*7E>^bJK#_6uI;LB@tfnOTg-C}dI5zRa(Tfyt$A?hgJ*`Gf`Ls? znOEsu4?+{aEc}lKy@a>Bq-7e9z#6j#H5+8ZH|_b>OInh#s~M9IB4WMAFc@Fl!e|k@ zQ4P)XF)fBfChw^br~qH#k62p}Ln6GaysSOnT4YgEbgn-=o^?wgkPf;9^kQm9U$hfl zzM+^Iz7ky*k15qc)#3wuN+}I6Q57+5RFvV~rdW(%x{^H1sDu0v{97D9jMWvml}K-s z8tLspkO)31iX$+IN6=gh^DEt(^Q1qtmbRGVSP~$9`6E5MqB*5Jg^tU9l*vz_j|M#t z^hfogaI!#O`4svR&q_w?FGHy33?-NT#ylD0F@~3P`7s& zlB)kGW2i=WoRpnSl(!jg<&Ys}>}(Mb?d`#*U(uTNSa}Nl1Jx(+xGhm1gh6qP06qK+ z3P+E_?6&>!II`gH{GFe>qIK(Bj&+fzg+pn(0KQol9xr^V*fdAUxWHe$s--sA34b$a zRlnJ=OvN0f_yRw9RhxtN-YA3y*6E}; zjBN@o@~?ZBvOI5hguOZ=I;1XY7rcJb!!{18kqu%xObT`dZCtU6kVA;Pbou@9O4>A`1mQf#l?ma*S>( z7zMhuiU>T7Qs@eL9)*LPdl-*fF!QYD_~tKd7gI|vJEq*!&M-B>>3H!USQ->Mk+aCj zsvm{(H%5RvuQ;B&O`M5W9qsSH!u%ZV?r6tYGtyul#vRB1q?TMIr`Nevpcj-mYTVZ@ zF?Ht+$Bjy|r2I4gq);e3pubWR&TTqy~m0J-3q!OJVGBK`BR8d{*r-H{S-GPL*XZx`%pEnrlYg!?yjn% zyc|6Y?q^uDL@Zt__u*x9>ts0abI97i$+5A zpdN&m-U|I`tAr-DuG*pm3qHh2_Z)}CD2=P_@h<*h0 z7%YDM*h)c5kv~f9Rd|$b<$ZkId#TPM{vn}tH$Um)-a=iuo2$O=gVcn*{6$~)mW@}b z+6I5+D>tp!SGjC(de8M$_V}Xr%BlCg`&?hgC%*2rnJu&0dgz44JWa&nS{%w+(Rxdx zPODVq#SDDeSUJn!zRQfTexPa~FIGX=M1N8yf`tXaHO_dj5gsXxOT3j$hB@vZ8I@(8 z^HjKYdBfL5e?J=+cz|xNzt9bIri`QzT#Hj#O4uRwkLt=?H|^b;%I9tx?AzQlM@?n1 zf$S>{+SM9ZDCz>c%b=a8p?suuh5eYOZLgtR(OSU%t^1U$8p_FP+V?e-MIP%J93|CB z*u{s{a}TmDXY6Cv1WM#G?c+L%-ED!o*h4APw4Z7#@40ISYAf^H$^L_T^m``d>uOql zZRKz^KiEI;(7<`j1F~m5VqiU3U0dO){9e61>^p0aeP2y&uBTF76D(hOX^=VNrM+L< zZIQROua?_C-r6ElW4G^(gL@9W-{_w#fAt#$z> zDB|Z@?8)5Ut@b6p7v|^g%R4u454F{2b?RykrgW^0QNUPC_`aj!p`UAU4Q6POq&tK= zi?JzDZ58E1Huz^%$y3pNTvi*vTHuE5YMx55re%4#t#sF5Kj5yx<4<=qoL$x0ZZRoy zJhZz;w;dkX=c;^KQ>!$&?Wx&XiBW#{B=-M#)hO^%PI%3vaF&>A{LiFpG(nL|CJnOr zwQ77->p`t@E%sxz7cy;ob3A^IyKUE$EO(86+s=I~FKp+Y^2ncgkXryRT;Nu%r>kVK zo{+pPI_4kHG36f}ODr^=K=(6T$Aq_aOj{u7XZY(4-H+Pll~X6BC@P>SQ1?Y&A?XH# zNzkgEZ3`t`^Uxc;K}e$?x~qrd;gKjPcovJFL9CG~il;;$iH&shQ7n?sQDWB$mDg$P z{w7P~Ga9?U42Wz3Na3G0aj(YwjuMnwyna*nCbbGIdgOWtcs}r0keil| z*14;S%Zm35^urKH{MPXtu(1OEB|z=d-?6)?ySIuBPkwIZz!un!?d)k#4!@5OPnKdnZz{`H%Z*DqfI#@3D+c6O7zYU@hgobhDhutv7f}D z630lKE^&^;WfIp&+$3?oKty&%60S+Cl;}M}5x>R~LnL;S*iYh6iDM*AmpDh_GKp&> zZj!j4kP>@F60S+Cl<57gR6t^g#BLJ%NgOJ1jKt{@=SW;8agD@H688f|W}lISYZ5CZ zdS^-nB!)=rCb6Hyp%TYPoGx*W#AOoKNZcfGf2N$_osooV5-TNoXGsMlhDhutv7f}D z630lKE^&^;WfIp&+$3>-maJ@NB;lIGN{QatQUQq}61z$4Cvm96F%qXsoFj3W#5EE( zN!)LfmNOEsNvxFUJyR+mF+^fFiTxxFl{iM?bcu5$E|a)M;wFi<{nBzq;x&nt620G( z3P=o**iB+Ti9;ohkvLuA9Er;$u93J&N1L)=63$4xCb3eY_bjP^#1M(yB=(ayRN@$k z(CUkhp=)v*5SkmWp8gZA;|PV!6as5`U1mLE<)vdnF!`SR&CWu}osQ zMCFbipNB+~L_ZyEidhmY5RKb2TDwqI6~rRiRnPmkxrF_EQxs%=Sf^5ak<1*5`U1mLE<)vdnF!` zcv|8GiB~25eODFnD;1L9ANZcTCo5Z~mk4QW%@q$FB#H$j^B>pY2T%x&|Y$hEg#z;(&7*!#fDGhxM zz1&b)@{j24KkZkEM|Dg&rla||jwKTFPe{I#I?C}h<~T1o3PRi~s@3YOB7tgkz2F49f{T~n)*D6L=Q+>s z1m+mj{p|T8=bi6)Zs+oz_q=D`dDB_pOmq)Ta4vL1lbxD&I?D2Ne-60G3g;pIv$Q=n z*;(lD->NJIK}}uyyt@61>CQ}#8?1C9o`dd&N@tAEtdUK=-tA;;meMBoxy3UHpLagb zQc9Wpa<`UnUUGrpqJ@k&w}YmkJm}vH>1eWVkY;x#Z@Gx__;k!ez&H|DbHVo&x`!-UHrKbpBrh* zjXwKg_#E?#xrAGM9+{z=1+g;BtvQdxx`xZ=uHhnvNnR^^Y$QoSLXT^VgtiqI>pSXH@^t zjZ*ZtX;P&Bx@+b*1$<}Y-aXeTqj!evnd=mcF=OF4LE8Jw=^hN3+;PXua|)upl^F$@ z#ktB1gG`>+eXEzr^OYG7nfwRJ42VpAlG1}hX0l^N+4TB-Gb)ZzdZ1R z4W(}6iVUyaq~(0{)JJB8p3wYM6~q}%A9dP6e?7E;YFFql#My2V+YKU3zk_v)&!@r7 z8%rL~v5_zuNXF4TZpIGf<}n;#|M(Ei~}uEKlv9LOWA@I$aAp_1exP#b=XFH>02x4$NM3elIq3 z?3_zLo~G0boPt{8KfXX#iYpctrm}iUk}b-nR0p*Jesf+%&1QPk2LACBCk53kc9kN@V@!txZ(^MT&IDT z6Yr^oX0SYsiCnqOh<0y1FGPXD{RdT4r}`5Z`pF6Sjl_AnSI^4%q933jOLuDfg=)*# z;o9y9{g?XxVHA9h0-CUN+NL>OAJAtepuL)(tO8$33w6;%!>J40pH0^ZO84o%N;wn@ z*LXYldT>AUC>5;7S0ScgoK`5Lud5}})nZRo!q6qX1OzZ4TnHYA9TVtPn)g%wVzCo} zWBy&3hrWT15ud`0mpYtI)YK>954oimIR&1rlI@c0O`S#GM^K;VNU$cTPrDQexc?2sg!jZm%F#s(5CFbQ^Z`ZWo`;_HfOeL z(lA%2r7HrKIX`jT zv)BE`}>Dm(=T!5Rsa z7ww!*6wrzIPE+ApwnM9l@2as;@M?wcmfr^le#pnaEzq)Wslg!=={=cUljYV%=o->M zx69mfeiZ9x3d!6O;yiX^Ut>8X+G-VefL>t9DX#x26$6jw2={~E4xWO%vA3=@0tAB#XS-S%^X#Ltup@(*h` zjRp^%mDwO=;2q#WtS?PNdGWZ4Ut6Isg`|GdRKO~jMTWS7K?GzP>O%04#jSb-<2~0S zF%}&~%U4dO9;wMa*CRAVc)+ShY%1)C8B-71zd?bC*VMz0fDAYF2v|I`qhOt~@5hH6 zQ@8>RrT!tIr?EfS>U!#E8T*E0?@D$=vfi$*fy(+xHbSyVI*ZQdXA|i@T`u&EAd4nvC8=xTk|6cQx)yep# z!F1qr#QDrAQp*>9V^e+sc;+TPT{AD!1$|V++R45W4(M@P9bpW2 z+SkBP#A+cIywT!G%@5P7B4nL~`l=_05028v3>^_?6uS9Ak}rJ zX!9?YIDMpxOUKX_t&Zs|6icbPgt(74*x!`%`)ly1>${Rpzc!r}{Rgx=EbYJQ;^<)% zCyT{+S~4|gpcsDueN7?iG@dvI(}4$OO#?;2Q+q`&LN_Ly+Q1dKk$+h1M^y@2f95uA zClq3zNF*_g`q#kYR?mC@-gTEaG)+IBcFMS`{0|B@j;|ult=6GuUAo~gj&Gv^Jw~dY zfNIClOw|KWRr}7-1rMM%zh+Hx72ho(n_-yiE?7z(QJ}M&QM5Ox?dQxgM-4S}=&;5-v+DFLc<_LHj!33nV$S0}XTLcr{SvZWe-zsR z$o8XebagFK02s2rXe;#22RcPJD4F_H`zlmj*t|4@rMF+?lNgPr+5^G8^nYkL1tn86!Gn+w=~8;D zuja~im(%viuOXDOdS(-N98ZXtc6!Ee-1i#(0(b|W6fyiY@Gjhm29=}_G?yUgZK=i0 zwCypXSQWG7L05Q}Wa=T!Ra^T>zM>tFQI@Ya z+cuw6;Q0st9poP>@g#pM2Ke`;oTd=>>xm$RrPItWl>SIuS2dc3L}-s_1|?HpfqQX%F?;|mDYQilg8<}5f_J3m>4;=&3k*vy}=4b1w{vLp44`ib9as#hfMPy$^}R0dZ>XY0E}P zkg>ak`{DF=;PI6bOd37^Bypb}!@D4nu*T1R;@rToRA%*jX9*8s4ovlu^5w+2nF40% zAy~P@eYE6%4XbL1tBsl$4N!4wUGN+m;?SyIhsn@;(hdo!gE~Z9_dP~Y5Ux(68H7Vf z(*Gag)CKujZt*G_IrKjeD2uv~ihr0X^$2mc+F?!lyNPoJ4q6lU+nN`toz}AB2<*pJ ziv6@?YWOH^f22xh3-Rk9m6}ckdVuwpc+G@Y?Jl5ri&{{e6~E<-+oQ{BkKaMQxl`oL z8s%wlg*hStJ8u#vzXMckGM!KJM6LqX7#w9J#!sUo4knE*_iGFE zFO;Df|3p9<{92^B&m|qu z3_Kzd3CZZa4v=V=Pe(i;_F7+=uhE>gulP5IobHkAcGe`HaZHf(QKx&sBUreFz}uN~ zEID7AqoO{gQXhG55ed?Qj#JQ`dNrM*7wN3@N|Itv>7mlXW^w8g*NfcI*`k&!*`uQU zfn-_k2C@|$Fcz+oB1HCdx|KK^PvBzcMe!!$+#GwX=6DMxlC#r__OF@yH4Hg9=?WF#qXjxb~v+@KP9eR^K)99FphsPUd*Ll5^P+L1n<}; z+>HBM-8Da@e(0oPZr6la(H|AFx#eQ6;~8-u5N&k|crz|##?4~zQeS(WK@ug_dri{*QXbI&CI zAO;eM?J^ol6>q40%U9HmLL+V#aKqrG9yUesCX!AasI&QEbtO5@!A zoHz&7{HYi*)gR^VA?-m6CW~6aT9{uU&+jA9C6(VxS+-~RcgNQ zX)4|>@p|FsD=O$|s?Pb5w2U7Emfx$%=@R$w8ah2zQ8D{TJ_&PDs(ufi0*`>_pNqJx z@!!|o{B!EXGM$x%NQ#F_0Bg$-v~LGb?hp_|V|R&Kc93p*X@2Uk*5GrA>p20dC)4>g zuJ1ahpmYU_Q@f-N<{s-B@Gi4c18+Bp+D0nYU4n5=A0_w_+|<(Aup->LG+ei2`Lc!<^-bh%zrh*e4V0>S`Zpforux+-<>Lb5+CRI&c`G|u zHohcKQd+92YnRnuzI=5_U7cFl+O(vF55hHL$F?-ouBdAaU(vLrA$$d?(|^UFf9p}* zQr$9i=-lcVQ{9jL#knqTT%dx?j4cneU$f3RoaO#~yHno&>MhPhkJ}ulS4w%~PNcmp z?wo#7-okm)!Q;v@Z)y#8@D=bdEuJs)-vjZ#qPleoe^%uGtRHv z70)_rPyeX3It4qTw+)!WJTHCf~c%_^32dA(5%68}VB5Ks~6%G7f VP%4*Zv})T|!PDAzJnvkc{lCHO{)+$r delta 89115 zcmZ@>3tSXc`<_`Y;&sy{#Vh~kJ?G4Nod4(i9L_w?d(L}q@43#Ib>-`w zDi?GrO=y$iSJ>s|j-m{Ex%c&%ojb)cY`Ti#WLU*tk~oFj*{LVvO*gL-gNpOzx8vL7 zIk}QNC-;=+e0lr*-SfgR%#YRG#62sUbdP$s?>~Xj(>}eJKjeYWjE?QS*OY#` z441Bz+=={cDI%H zA0>dxg}Wo})wo~B{W1x3J6YjmZ z@59{;@?N;<8i_j*&l}-7;l|)zhvy*fQMjXk|A0%^)42b{eF1kF?ya~V#cf{Qm*MGt z-1)fU5%32gSx6Z7tDy(piyEhw+oSbCu`Tp`H7=AhJT^M?;CoS7`s=YyFwtr+y)t%4 zs1&>&-6To9nHrGpZW7({YN1Vo+mh_9^)-SqoqJeg>n&i0aJ#_0(extR9>Q$_H%B~A z6K<+-#|f951l%)l-$FpT9+RHw@h+4uqo^)AAUW6gGVwHqas1CC;yD@a8{)YiTo3M< z0>2%iD%OpEFRuA3AjGZUo{gt}+fR-~AJnFlvlDN>(E0^L|#9)+ERgf?C)|8%nhLl>TSC_zuTnx#BX5 z;-LO^+xQM`h5DS)Jh&NcN4<61c+Vz4N^JR`6a)Hu?kL}N=6v4gJQMYTH$maxYVmUNcUz=*4cJ4%ZFKOiDcg zT`xA_p$cE&*vxxOOU~!-;Jng`y98MZ_wW=#ExTS3WfDHgqb(HqeVUj2y-KyE=(nKk zSaKJ01=T{)rzlLSjM5J{VJ4^o38ILrf4)58c2vOwCkcBCpT0bl0Z5^gpLnPWQB^m& zcyNbRsV3?#w~AMv)E{V0rCix6e&XHm&{}D!I6I3FBBLot4>N2p&!?06BV0>R zK9rsCF^|Ak_T z;1)W+y_(`mQ0lMc_H5c=HtK`?*9&tq%dr{SGUKQ5+`74=JTK~}Q25Ug`sbn)FdYi5 zo*vuU7bl8Su~g3WLTUBR%Zu=1(L}3%xSSu~i6_Eg;r|i(Q$%%{nJkbJp}s=3=4mQ= zh_cgse2+eeLd2CIqAdI`w}j7nGg{eh+NCJJvKY=s>zR)De#>J;T~~0{teNZ4Jy4BR z&kz|vM(G+(J&@;d5m!CU&~TNrzZmg^UAQfFv6}Y*igOH4TR9plT`Tps6XSii08w0J zB9xQK6eUB1%CmGFnkaOKNLyI=*U+6(4VV3Rd7*#Zo%7`jIA6~l#f6y&YFLkN+q%m| z7!ieaTjDxq+I-q)B39=cA~=H56)#esB2sUb;4ZR5YAwE-L{FOX4G&@Z7$wR+&r%_g@gg{^Y()CqB0Y0OzQPuM1xkecm*30vqzM1BS}^_=#rZX7%!Ixw z3cvIg9v}}DNmo4&pg8a0e5pt%%0cNtMcW}!w5LK^|dK!!nuoyQ}igqfZcfQK~*9-s4$Ub8Jp?YP-nwO3cgWv6%Cgd!UdN>P4>K$sOf$p4&D`c^jVYYSE=V z&8B)=UA%1TZ|Bl5*Q)$XHlgO}pC-h2m@5j*d6*0HMFH%j;`F76E;jsAI*;-q_ccRw z0d6sbl#2wpG1OB+-Ijt#6|t26!o!9Sfbyn$DL+$KJ`7|VLy ziNg5uEyni>+BqvHQOi!Du9=uQgzGs`Bls@*b6w**6gowsD|q7ag!E-9Cg0f}ybyD~ z=Tft7Zxw}`Q^ommQE(Ze56a)dd9x0?plT>>VbRCc2#ZbcM03% zF=9^$6+yGW!cM}*-sHjdP#d8tr|B>*Gi}X8m6wTuJco;w161bfGx~u}@g3q&%~U4! z!mbqz@^sxnwXBxV-+pV%2?T8w(Iv`l4$7a+N|TTsy2P|+HLW?+@l3-b^w+lz0V$Ro zVU&1e*SDf(9bz0aYxZeT0y`}w&`k6J$^o7dr--;^cdoz8Vm~#k))akpo7Vl7h+4LG zs29LHls_8_MQ_GahOMj6r_*EO`(=wlcfTv*n#Dbw7Xw#V6r7p#J~V+=d((8W!#Obt zDBQ}!l!}6z%&Pf6qI$w7E-%){%wlzk7)7XiL`!vumTJa$NHi^Hn8#w8^$8kgeFss& z)X|llqrC=P=egE3Xe?wj4yqemDeSMJ{EbQ^-YLc-GnSu3YU?w3D=QPJdV&=(mIPve zbqhURz$4zF%GZ|p_iJVkTfieO7Xj+gp^=R^KjFN&=>CKHfCo~#bEzU$zj-3m1lC3| zfB2abW^(__qEAq2Ed725(N>(_T<-q|Y7@Tug?;5k@l56mJAF{JlDzvxn#EvDi*rhI zxy1;+MU_yYE28goi_`|Xa{qasay>b*T+olVu%SxncU<5U0Tzge%SLg&R5Y>Es14Q? zr108QkZ`)Zv|Q|WOf;*~-8__8C}kq^Y)cou-4p~@Dx3Na#S^oL7a1AZc(?{pP$pAE z<2AK)GcCfhPFN%C)NQfTrb)b^x%Us`5s1GvC?~|*M#@7YMQ*=sqO7W0*_iJdQEe{^11kHID>2JzQ!_> zz8UFd6F|>2QJsatmfa#DlSE`GwIWA6PNfHogp9`hposl?9w3(@^Zh8wq1qB(ff?#` z5vmCfwLz3~{xXiuq?eoi+n~U4x%sp~@rup4dNDI7WKz7N;Qep!|JMO4NImO`ggq8w z@krOV)FF6|i4B8l%f>*GlUH+%;PWU5t{ZWaS+I8=cs7%(u?>$Zb1f{UeK`~aSFY&6 zmCYO%ilRJ(vS78Gwj4gXW0qWHnI&(Fz)wh52|`}ha#1l2(=8lDU~^E zcqnszI#b{2i1!^vqA9K%u{bmH5Eh|Ig{hpwBCB|4eLWMZ9ssj>0M$bO_=idbiFXG zkN$baRS*{0vDuN_pNA4t2l<-<2TG_hdH!&4^?%b74`Me^Vsv7tXJW3SV93{42F*&ds; zVs_RY>Q&c|%O3ae)aeta6^xrP_2DOGOdNK{h&yl4-@avd=%X)V2kQ?EyU@1Z4OUO% z^k;7A(G4EQDdXAlnY z>TT2Gb(iNBz4n%Vp#h6xlXORVM}0|p+t9SHW4o^S+cPIRWLqBFe#Oj@v8wL6-J#FF zZH~U+_BKsyN)%eMs`t%F)AMhO)onR#^rvyp&neKS=EUm1fZKap3;mItW(cS0`8m;e zU#2S2`ct>3>M6HJ`1JXLNiR1`(^Y!eBxd`P_{j$CT&vdFE%3$ReW!A*P?#iM@`Geo=_}k#vG6tPIiGIf z>%}nUw(zC(+`newtFQKP1JAJtQp8+jw3Qe0syqu{^D@^n*}@m@L(9PB?u=r2i4y)rg(eJPThgW(Hv^Z_e(zUaqH1%+m@jd>&iy`tbI| zB5;Z=+Xf5oJ}o-KZkI<;Bm9?H`0^jQ{|XCVn#`*vOg!R`7=@5`%TiQwZb{5ruqEPS=#6MFkDSM>8=Jf%)cfS*MGw}oFPnx$spHwiw+!hdbH zdz0t+$Dth|$TJ00{uEijxK43kC16@N)&9VBt#z@3ioX1)pT$ z%fK`HOR)%+iU8>rzFhEb3tu64&BBKTpJU;x1V1{tC%1pI3cePCJWGJxf}d>Re-?bc zg+DC#Sr-17;0q%>k6-y)2sSE%q|12Jf3XmxTqeMgB*CX!_=SRZTlm)n zuUYsdg3qz=<;0WyjkX9@iU4^Qex2YaTlh_a&$sYj3x1Y`-!1q;@XY?r=J&G@%(VnK zEcj9je@yU;E&ShtFSGFH1;6wX&)Z+L=o-r}30U)MA@~Xl-%jvh3*TArRTe%;@YNQ6 zz-b@vtM^z0ZV{ly!g~d8Soj>l*IW3}f^V?!4+>uKS+-E~g&@wt&l0@D!WRlY!NSiK zywk#$3O-5jk@^4YLXct!utf0b7JixF-4=eO;57@sPVhOG^FF0Y2u5EnP<9JG&%*yK z_{kRju;BA8{4v4LvhaU19`;vg5u6tR=34k@v4SbJ@Nt4)Y~fo7zRbcq1izGcvVXJr zwG)DJOMnEyS6FzrnA3$Ve6HZDEc|4_S4%u=e}zJ@M-ou`dr(BITqn&~z?)06I16ts z%^X%{W~oJzBa>&a|>@S%~CA9xdcnM@a7WCZQ;#@N^*;%cA6eG*e*VbFRRTz5-t+@yjLsOD#Mve|RXj2+S}Q zSKysjbDM~TM>zsTteUChj+;v0#{F;Jr#Sw%KuNd)Un)f`N02W07u!ZGdbh+=V$Dlq zJn~N|l?6Fh2r&8ze4fO2AZ6m3d<8yV=EeRK3o=UMB}5yXiN2P^Nm0-taN-YM~7Ymmi~ z6ycG7S&$MDT+XLofiIN!m!u5LmG}!1Uuxx9`NP9vt3U*Di!Bx^iQSSSP2%waAadng zfggPZ-j_lzu5eKc5N{3`PM3J`Ziw-2iO2Db$fZd<-uFbV9EryZ+Q>DU^F9_aUN=Op zJShNA8W&BL_@sz$e7Yg=y(E5?#P^Z-LW#eY&wsget|S;N1t^vHnf0Af0pcY7HHmjf{3jBhAo1lApCs|C7%$pi ziX>Ps1xT0pEfVjR_^lGJNxXP*%%nLIzf12tok^JXN{6UGI zCGo#We4*fdRQJD2g1J(FV-mku;@OZXWQJshZF$s+agzj#J7mBn5;@Xy;d`?B#AfA)Q~Ji;(a(c z5V_JN0Zw2=F1N(vplRgNBpz?%BUg^Z zQ~s}&1Qn(L+;tKkmiWFBUnTJ=5??Lx{Um;m#18<^%O4LllHdj@fFbee5??Rzbo|4- z8YKR*qezLDN;<>zO!3D_f`iOZ-TQ&zJZdiJv9$w@ZAX#NQ!! z7XMsHFiHwgD)Dzo{9=i}TjI+k{vL^6D)D0^zC2OP|EUVbN`eY0z#pH zDDg`rzSQKY{>vr7%ccNsg~TtA_^`w;lK3i#4@rEr#LKhlJ>Z%BQS*CU3Q!{jcthe1 ziGNe#>m~jziEohjGKp8NiL?Tr^0p+1yCjHwvrJ-##J?-~PmuT}67Q6FakPy|lO+Cq z#)$TpA_+c_6s1f2Qi*p<{D%^+N&H6=pCj?hB!09{5_~KP@+AJh5DW<(NSCGm#DZn*BdHWkJ2@XjC@+AJS#7~y^BNCr4@rK0DlK5JQFHDl=|3@XkTq%IO3NDrS zc2ot zKU!p7PDyN6^;T1_>gbTfDU!I2s^0{0J4x)8#8;{MREXmxagHQTQ1v$W;!*qAo_{Y0fP(Tl(KZf-mg zo=m}NYZ`GS4kb*QYO5I@NZ3X=%y54n5m7{xGom-)Xu@R-_aGcYxRl|JgkuR8GTeqR z89{A6!_5fC5zb@SMz|^A9EQ)n2i%OXn_=HcB9JwuHiZ#K2_u(Et&`z{gj*7JFua#= zE5ZuHy9nC}*IxvYxSgHj_*KGJ5iVqS0pWPU`3%2EIDv2;!*d9CAe_VS(}Zc8qt*@VYfPL*L?H?UL?jcD!aN)$+=sA};e&*)CG22$FX8J5D-7=mxYWemSV zcogAMhF>Lo7vVyN7ZARia6ZE?5*|%BkKs9l?;)JS@Y96vMf@lMMoc4O4B-@pA0a%J zu#@5OgzqElVEA6b_Y+nazJu^M!u4mE4G_*FT*L5C!VeIxW_TcB-*_UzjOb6q1j6ME z_a^)x;WCDM5S~c5l;MtqClM}WxDDZl2S;5w8;AW*(*yevNPn!;cVtov@SP@r2(X z>|pp_!fz5*7`}t>TZHTXVKzXxjBpLZLkYi4xcVQ&-XX92g7>_|Cg}B@Gioi5U&55^lv9zPPm5Q4TL`>TAV(*xfVaA zre&9e3v7+mY&u_RUZV;JCw-i#D4PGb%-lO?jMs_==g{x26|~TTgCExu6=MxryB6#c zwIEUP1{42&8JYqy7nbQy1-kn7FH2N18{2IHvkQ;fjeDm3wk76EJgQ?d$8Os=$=;0` zG}IRjE=NdZ6yho92=9T#@QwtvLNp;rwl&t!vSQmtp0JH(Kzp}B3SavbS{!*0I5RhM zROVfJ&w26cMg69Esom36`0_7wh2ePNjs_-|RwU%+=?msv7n2nzc7^p#^W5X|z-#`0 zw7~1ktCn1+RopoLP&)p#(oP@OD$m-q$_qm@|4uFW8*fJC^fn`c(P1svZlgxp5W23D zH+h2=T*sq|+N=e=E~nSO!RUje>XU*!nz~sW>s&ed%fa@(={IY^J|3;|w0IIaa|yYe;vGUi7Mj&npwH_+?d=~dcF||ifrYMm#ODppbIk>W!eD_bfkKm%GBKIJ zEC7Ane5cPi1v?*>dVEW<>qc-W%w;aJ@1k|C8aRsm`R}9gS}XOiClHHxw7^Q20XoZn zu(6a@a~}UzRQKD9U_JiRotHJ~jVl$Vx7k_61`2T)rm*G;G?D?O58ZN~SJuEAhxO~N~giDJ2zx@Ark|0hEqdKTsQ62On zzghkzE*b|?cTshf;mPY?>7sto8(89^5MIPbioLK0N`)5}z@ zvjX$D;lKkKPU8j*4B1R(V89DnWlgjf5^8o@z#A7gBA9ht8Rn1PYOr65X+ZC|lCdL$eJ*+eqvAY)Y*g_=R|@4M zd8ZFOLA2(d=ZYg-bT(#Y7t+H~ILG537ST}KoxJ#~wbOgZM&=@FttcEr&!u>_7t`q! zPhglsOD^W>D;uJ<3?ZGP!t^v$Bl(4A8WIqbek_!%rsxTaZ}+hjMQtH{?6Ii9QP4(1 z{SiVt_7APc-GCV4B7Trm(nr;!MTu}CJ+(1tx5ER`7c(2tf6wDqjKXlRT%cZ-F+|aa6O!E@T#^`EPS*{wEW>;HkK?GM2EO;l=zW>*%#1rjB``}Oy-JbpJtzP9oAo$+EfL_ ziuRHY54>%9{F_pbqYT54pedXu4@d^Hui)6@0PWu>O;o4@9ki#hjXkOQFT0~T&AY+*y#6D`pDZ@fT`^U^9@Ss_cW2*R_%a5aL~x9(lv-o`2@WXR#)dyQ zpo%uyGbMvu#ylFbk#=fnmvsmSVXj&Q>WVJAhUr42wLb|%FvDmW)tdd*4O-L&G+Y>j zma##`XX?qM-`{2RSdzZA3?9%$D} z^S6r~8OUvg(#(yG^Aw${FK9O$7%e|H)Yhm482G4@M_z*>v45WYbN;>+{!>`Q3-}_$eGYLV+P&I$FtDvb7cZ8}i+QpLK z@sCops9aYZRVDz+pN|o2DUAv1iz94`k@g$a4uS+RO*4LkG1Ruj1{qPc@pxc!U;Wst zQ`H82%xivM(i@meU;R6L1k*a>SqrvLD}oakdo<*)Sk!;rUU^0bSP zr(!xdIFSjHH2=d$)?|nAJ!uQX+y!|g%z-(iGi@m2B3`vX)4}-&eP8W6zw1+8Pa2fz z{~>$A4$c3~mMqt3SS`AfVa#|vfdMYf|EI@afcyvULqz*9EGpjQy`IW*(b*YaP4BGN zycwTV8;71F+h3*m_jvq!vy(U4i%+3qF??ct`%0@k6OBr@&-vGi)35)g>ZjjqnKixD z@L=?O4_SCEEnqZ1;;-^1Z?_lI3eFQ4i`q~ANvk|(^JM&FpVLSKqW`Pxl5GXody38^ z*yqo>jC!FKVWe$QK7Jw*r4d;GJ}Tu|c16J`ZwY%J)jCGXLKcSdPD&uW!NZ_C z4z2QpO$(01#9-%atd_n@-KHf&a41SUy-$nUtCgIZY2O-6lM96!SH_NMe@?Rh5uRlC zMVBKy!u9xT+DR>Auf6CaM7cGZrb6(#5!AFlYeV2t_vs_w>*A{toeu9}GB!*b5b3Li zXc_2Qrd_QCsD~*D&%ktmo+@i>+E&ybQ%OBj-OW-M-c`*ee@9Tf^x$vjLc?{rHT+31 z)*dE%#gi9*d~Pk!4yHyO9+bzSo-t&WnsxmulaAtmjw?G*o{Q zmVUGmq6`lXnoD`Zd<9+qqfA3C#7Jt2CosrGeM&I8l+ucRrEV|9!21<6CFB?Vii5QQ z%pLJq`zMyyux@4&=TOhgBsQ8Ru@6f@6lWbw;^t^?M%C<5UjKG<;mO}=MF(LLdp+nw zOZJgTyr8#!uU+4_5CAr?ciKr$#!h?DPk3#!HJY}FU;-OJ!2~vgOWjrXtG!#6qQCV) ze_xX!c*z%Rc^*GKk7*Q|HEP^mOuuI04a8iWO`XfHY#G$P7GB_U7aWft)e|N8FX8@o z$o@BT|L-vWZq&0JAdLrj!zYJW!b3d4L!jrCL;QwpAW2i?06reT%>!U%AP1nmGc9m! z1`pu%|Bg=eULL?sj(-?xxb>wF1s+V^TFusLmd5)^L@dFyWOy}Bp(eflMx*O~)F{fM zXj9yMV=~8Oj;%fR3z*>GRjd@#?ttetLn+>1%LRiF@Z&v9d_Nbbl9=A6Ks=qq^SPMU zL0UT!XOP$zY?({)$GLnN1Q_#d~}t|LaGV_9a~Y6v?mS^3O@U8)Dj&(E>x*oUe8Th>ep< zBlukl);Z?8H<@?eISTtzqdorJ)Sxtv|62{CP7Y>i_Tp#sf)9K8ycq}WFXX`@J%L-@ zU$`l1^cQYVAggZ!p88<1liRl*bB;dso`AQnfo`UcftK9225q)ajaGErIb)X>O;eM0 zcQCie@dQR=-1tdL#t^h$J6-GXfA6WhfGwXhL%hkg*%`;|&mW*SMwf!!7IYnk-{HX) zWQ7XCupuQG&Y2-(5Xn1P8)>%-gG-cAyALHtF=@#sE-8_BmXg2M9z9w?-HoP2?I#UE z9@Z1^#ElF_AISFmGUJT5nW9`*4hGMIm?_$eZ$`VJUevvw7szlo&>)nDcVL4S7&{2% zF?L|R7ML;!1@e~~0)YDNBYkpEoDe{MSR@1^{E(~f2mk^HAe@*hV2H|y%h zSC2y7*Rgv1obUb3$3y|Ue#zUlDD3(ju)pvw6?XFXUjG44#%>Il5Ny{nwogmcDk32= zs-C<`E7|4^OmXGR=#+X~fBNIZ>#t?~#O7?d`aOJO5#i0yB`L9skd2M+9@R!X@LYr)JFzD^mW<7PF&%^9C~G zE)_l*HC4dK;Df&@s0FNzy#Dbnmp9mF7slP=un)y}mubtT8i_tek z2NE{KkrDUC4g?z3y$hCITy_I`jJtPIk5Q<%_@s;NyIp$nC->W? z@6rRGTxYv^m%jFsu05{ab$Jic)`FvUtvL6|J2qRl-TGV0``G^cPXA_kM_c=E_1fi~ zY;oV|u`8~&t@u$-UeUGhbaXZvMr5NId!PvcEh~(#0F5m>AVgk_FMeojtn(XNe$Z#F zXs~&A>C;yBvEB58UbeDp|BK%X4U5=AM8jPOW8D6Y(4awB+ZuzaG4gx8er1wv)AxGE zRbBfRo1r_2&=}1ysWyHFG=BVAgx;|mp+h)ZVC>$lKe8&#Hu!t}?NuFZ&+T6E#j0;? zwrSh+c@^Dkw{O!wuDH!svs1rVk?4B`#mKUj!X8AzoW`Gk#<41)`cSp-)r|QXi)DAo zzJftCH%c)kLFk21`F}CiLhSXQ@cK`3(MQ{%<$Y7j8>W^AMO-O{t#`G)R{V*s)(5UhvOQg`Ke(o+tH0@c+qab1 z*)-*%LVA(>myrL`Z}tDK>1uOS>pRwTY_bWzX=XgWS^r~AZ`+|QdZ)G5*w$>(v(_fs z^ernMUHewF?PR6iBAo1c51GJrkSB0c-77}JHZr?nGG|O~P8GmJPuIR%sgDU?XPaKB z2f{aY;aj^{44L~X1u*Miu4^*wEa?Zr9cgKBA>45w_qf^gw$c?QrKV3j`Zr#ZRmn2_ z_R2?WJ16L0R9=fUVO?dX8`)+{WZ#_aXZeq^Eg8O(b4gJ-6k(6Yl<7k@By^TTW29j+ zYL253Sf9S3d(vq9iofyQdK7Fh&5LKuetsJZCouT^@sNBTrXr6SKS5u&;ceUc@%p%p zciNh*4^`i;wpXX?+c&1#eqFCOZtUv1HBszc(efwGaBqriU|}oFfd!Q@cpH4WsJh;E^IHA2sxCcNIwQK4xe_SsJ4hk+y|Cd-XvqeB zZuEiq~UJ^#yQl9OP=@Bx21OrS#SIz&ev5p5=#1+rKS11;M;_&7QGUVY0~J;ztCqKK~TMPB^F5@MwoU9!F!)A8cHX)CJSV;u$@~_qV|b4F2~hI9Tk|zK7J%l2NJs z$P&X>m&cHqYuvM@v2hI=Grboq4twpx4jTVPX`uttiniMXll8gDsDn9$i4o=srFX#+ zt8)?UX=qTD8Et{Xgp1OZ0z2is&cS}^7!OU1>*nh2UG4gmiU5d}1t`2?fDglV27P@FNFwXy#{~x12 z^6R#LcHF2Xl&x9}gXZs#eN27R4_IdqFd@d*AuxD+=i&|`i zg7QfIk^P7}Hp*1YxFN)L*2!r}@{GIw$qpFDXLQBxSg_qG&4*d9hF$Qvh`z3eq&_(4 z6!m19A1^H_XN{|=+$%lUYl}>cv!hOXPM_dwk&Bp>|DXj2?D7UX|Cx>1QZBvwD@4%D zHEyb3?8N5-dHl3QTG$SCsf_UF`r2ZZw6dL(p@O#cBLl_l5&&-VXSFp(2IjSMFyL*A z<F$&*|6h2uTC{U^ydKZ8^v2s9Q zmJ50di`>*r!8@yhJ88e4ik_|dJpNnVAO=zSV>hk)5Ul(b4stS-I|Pfrd4s6@J$~;H ztp8RHa_FwzJ(^SGyrj?Qx9@iO-hlS(l2e~k<|y`bDm&Vh#w#WEIL}oMEri3ut$=GU zewC&e=mpu;jm~kn;h!#VM!o%oCu8vces9&6F0SFPgSDYNg8olHOtR=%~afYg%P38qqu#73#>~fO@>o^ZEzi-3K#2 z#rU(FV#QenQi+7Ik}PTT1f%i3n(c%>{t@}0#iOX*BGr;N`84I5DyXi7TqT;nUQ4djDjTARH6W)86?Hv( zBk?CCfQ7<=o_Y;^Ak&7$P;egeZQMcwJ@{$_HT<70__=>m{`xLvYPSCDj|slwHqr~^ ze*s*2fjk+BH5Q`X;AJsRBLT73$D{FJPugJ6gn$uwOoI2xBr(3@0p__lJ+|sE`@P%h z9>F;HR5l%?X-qxUh&RKSGRMLDH8f8?)7pH!d;{u&Pp2V+hL`m zv#OoP#u!W-j>CjBe+z8wZ~e883zjqF=jiSGal8cTSaSHoJu!#zVD$aKN6NNB_o^sw1t=uJTU>wztg(rui&Q;As!EuIQaznK&II)O zT`=1ABM>vv=BYe3MDzQ$4*fa$;QvbCFiK$Q`(|`kkl1KLEpI8z_m-ZJGsffWc z1Q(-c-{bYy)2ap?J)+f$YR=Q!A8Pvpc22U#XYIt&wqU1&JtknM5AOo1rycZUY_S*J za*mR2I+?YYam&?eE&;Ovo^s+QYVYL=!Oj{Ff5I8?(_3pmroWJS1sFb0q10 zBq`D=-u^&;c5hNEKMu|vWxJ?a)KN`ewf7d^3fAfK5e~bC7n7(&S{kog=r~T7SZG>i zz&ERMF-(#YY-A99x5c-U({72@pWc_zxtxlM-u2=b3)KlaktDd#@YZ|!&V6k=zlglh zZ02qle(gj5NEypnw&3SX?ZOglL@Y%Kuy*A@Say#W^ykKQBr!FNPO?hhv46Y|_1^@3(W(x^4AwkE zLt(IG9+^byyF4>w__b|tgav-Tf&hLi$nO;HcL4cqLVhtc)DD5^iM5JwH2=la#@bUT zQ@lgRf+I5*uL45A`7Z!?2co zMll{_96!Ed+9t&B=`8(#?%-YYap+H*U;q+=|#UewwzX?j}!0V?k%le+~nP(V2{(Xk(lw8wUE^fD?V;7{+Jd1Y>X>mj1d(MK(;a~^bKx4 zJdyN5W*>$(C~4)W7-JvxD8v~DFb>grk^XNu>R71Sxa0%!!7a0Ly%Rba%O64kjlD6CdI7z1ES`bR1zg&A*k9Z zjhEE1<;Szc-bHM1@JN=ww675FnqD1wcaA-G#pq~Fga?VJy$+%9f>WvnN8k>}W2Bi=qR~h~O8$B!)L^)g|4OWIJ^=Ct9j}B9)NPyRQK+OMZ;4k2y z!J~nN#10BvoP{TWVoWCu2&Pc!{Z2&?hqQiB2&hBhYw=8W?58oAFygYwAe9qPWqK zY8m^{oDhnn*=SBJ>0Fl8yfdMh3M0bVLGmso`NI;hDXtH>QGnv7N1W7kw+jqihV%ZPy&* zU!Z+cc+ap+`|+~unYsHL>83vK0*Jn7jz^Q^t5=I9_Nz> zEN_TWu)VggZlL7V)L?o<;WCZEL3|HkFEvv?>PRRG4*HJvkY-sf>Y2xYL_z_-zkuP^ajWj_J)NCoLbBqJ5@6U zG21iDqR1whMXP^P<}Wj~bFdyV|Fc{5ypNL6%Lt0cO6P~6tT$$9X6+_?@`*pp-7CoUTgHRv@`S{3WQFL;-&777Zcv! zu(N|vco#MRuZ^{+f3&Cz#%#*9@J#b>vrs8g?q8cwjRSYHzc%|CvPUXPw&LV{And`% zI)6-Te?|r=_pG#ET1eV?X_Ils7+(mnLFvwCVqQYjWsyZ7s|6h>?}tJNYv!HGmGVO$ zmZ9waFlGontOKbCHOA1kLz4dX@vD5SHW%rrefrf0v-Vlh_@J})5R8ZFqjoLC=BPtf z3QIg?T3;iVKCN~4fmv}+bS+9gY4umxH^_T?a}y^(B@nHcqVU0(GeiswuYd1tN8 zf6*v-gA~K0nzIMqPO0dtpv5?alo^#&9#Caeu;CJZe`OELcq)+hOmEN}C65>fnfG7O z*BYx4oZ1-d!Y2}M97axz$4!-!s5#u*NNF&?g&VZd$VVG9Ro1OHn|y7P^CC}3e>E$B zi^eK5O52fC>u&>Kw2ZHtr)q zrBqdH#JUw7N^Qn@;T;B5L2*?gPj&nL=g>&q3iS=XgAE9I0)Ol!i_p2k@cnyQyG0v7kc~L{7 zy;#F`g?GY(t|T(=jSGaK+?-^rjy$IrAK@7*eDYGp9=FirBKEkM9$#dSo3sGMA56RL zoQhQ9MNhW>&(v_{C@pX&_76s2Dc+tMP|+qwQA2D&+X`fjP>SC5WdG&^$w&fsruc7; z*25=VEt&&+{b#ia4gL%w9Q&wpGPYug&IXW^L^l7xBr8;X?a5xvrki-8e&S?r-w+eF zAp>dsGBixc(EK;Y88MM(hjE6AgYgN*aeDUO?8Ik<8H#;=8H&s6e-Iyv_^06PHqK}| zJ=DKqbJxFdsQt@98Ac~`@|pBCXRZrNqd{$rW{f~-FaoeexAhF zkoczH;JIA>ImzGP@`p$sM{<^|kw{j=6fUKV)=t_#oqg%XjrewiMV8hF&)C9F>q9g1 z!KeDc!5pDB26e`p#@+au!}tOHR&lr>({p+&COJw$I+EX;G8q`$ynmu%JWo{|Xg`jE z2ht4Y#PnlM%O3Ec`LXlWDs$XMM) zt3ndoJe;4xMe}g`Q&^noL9EUv$&0_DV+lC7E4rO;=3(G5|ajLr5rPZ00_i@v9*JQsz1P<-){vELh*2=gFOCHpnm;?v7|HzSx*WrU z(MQ>F-CC5H*WUws@tCDl&-lA`4-v_A_G0=e2~W|5IQzWa%+H@%(E&R?={#MDx8RuA ze~G`JBh9Gp%s8BdHth50mkGT7qp)BcH!eEZgw6NA$JwBnEwcTtE!fc4@U_X`lkDxn znf6}MJMbrKhlBlfvcD->Q6dN|E-wn z9>lTQt;W-^PUJtAI&>WG40hh51+wVtj(eeMb3qHQ--*3LdY)MtIU{&$^m8(MYcfPDDs3urN&>tuLiB!X3 zRt*RcsRk`@gE#qJe-o*i6I=y>&CDz{ML)oGy z+;jr{*5h-juPH_Wz)blMG(=8S{^e)QH1Y|+A&w&h_Ncp9oBa!)o>4kI{)?>5E`_S> zz_W3lz%6LATUmQ81Ba^jMEz?2>@gp;)tR?={pV0Dp5*;#1(=i=zs;vi;7v3dCO$(` zr{c8u>@=+B!PAk}qijam4OzWMvPv{RXkl_A3Nnnb7;RwP16+t?--;5KmXI2qd=Nz$rHUo=KL`I_<-claL+RBr> z8|lXRAmb18hS^bnc$0slL}w=-V{0x<)NtP1f7Gak7;6|$)N#J5$U}`~`)~3_o%8so z#%24Tb;wyjz5a0w_4?}bRIiaL^*7*WI562_RjhaYqAgRcjF-2E%Wusjp+}xKy`YG@Vf#Tf6c(saJI{7oI(2P*0EN>a4m4{P3%=1 zO~DZ#&A)F(VX`Rq&Z7sK-%&4Oe1&ux|1JhcOOoKcMXK7#rCRcmToZOpHu3>?Z%iAy4GL*EmG_^#NmOjwp#njtT`v9~odQE-ScJ;haCsn=P zHljFmr>c5w7m7k}tLkXmyG5aMsyfm(p*S?crgpQPd@eM_re5cp!+HY5)`2}xwvj=n z(F|p6eE*!t;MdF+;ftEM#=h3Pbey~qzGw##O>#Gqhqv*x{zi6EjOZe0dCAoBys0Hy z#D(MJ8=nhxic&ibd>$d|%4tA%*8V6JiIZw!n;9?<4{Wm%-;uKtHM%|*%8ybz4Ao69 zz1c$~ADy7r_`MLR4h|mo8w|af?=nL-KVQ-dSAP|ywzJs=`$7j|)Og#%y3pAewQJh} zwW_lD_}#lUA0K;Y^Zxs*jPFW9$+7Cd_#<@?G(2gHLkyeGwJxEb)HBAv5SksUZnO=a z9m;H?US%8g?CN`(s0FI+t=~i6#;Fyy_D0Cx6!mlbNT{-@daG^IZ=q(*)S0cnJA%Py z^O0dy%EIShVvY8s+_F1AgRX+7>Rp#kE5OkS& zuovCFRqL%+6CuTyUewX#FkwH-qJ?5gwX<{c81&F37h9d*&0f4ckd z<}>-*Zd@8y&>p2M?zcePP%sx9l6 z)%UhlJvLj@{Lp*t)iT>dKZS0+N_1nUiI5--bX{@JF0iuPVZj5 zx}$oJYU}e*s7+_}LtDzjtH125I-_m#cdV{)svT|W9jnjvP{+imr$Topslo1Xt1$6D zG=?lU?fgnM@&Bj6MN{w3F1oP&IW`p23yExZF*LB3I$8ZN^lmS8l$skl(@UMA9$7u9 zH>@kM?`BrIEpK41FIbM{_2x5E!>M6pdylgD{GBncZw&3~qbAv=Z4907qYkn48yy;a ztvWKjDS~(dA8W7!GV>mJaL=|bDM#ZpN(5L5upZN1NE|VHHlcZ)8yDJmt-9JaZOrP~ z*Qw2IwwQ3ppQ0YM`NN?Z{nXjEPT|mB{nVMZqAx>__E+`R6W4RItYl`HIBtE&o(jWH z7c@8gnEvZSm1$~xYlon>p8l209$zf%zaG91(Wz0?A2<1!{a=P&PE{Xh{e+;o?zBh0 z49z9qS%Mb2Z~Bt!?ks4b`>HRw?mxb`On2=Up^^dW#nv_SY86q6bnjiq)4f8_Lifk( zxbA?Uh3=AdT=)Hg7U>?nj?&#W)a!b6Wb0#VC>BAVjlf^@u_0 z#%Q!2dnT;;zE4-*n5o97wl6W z7_xfft?DG3?cMiRCl6Pr*=*llA9~BHF1MY#arK?qYL94J{9BtKaH(?@%95Z53~ZVsq6hb$;mET=jli z;~T5{j#B@v+Qz*e+Ikl{mNu`i?tHh}HLBfsQdNY3Pbt8Ux4<=W`h`Z`tA5kGGNdY# zvh0tyTp9}X9HR~#)wwrM^|BPCI+{}bm6_@_^g}qu5P+RyH2U`!hZNa+ST_HosNvr=Fqs~xm#fw6Z+^23(_k^y!U%k(EaN+8C_p2|e zwmbAtLY|sqi`GNPP?yy&6xWW0J`;WK(`QPw~^n`_udNn5*NM+P}mv^DsnpcyJz$fsj|XzE0@catSfD!taBwjttkitsGN{jl`thBIH{7MTi;JxsE&G5eQikH+B+2{ApnvGz7=bZoZ zoU@;2?cdBh?>qC(%saDYX3d)QgWa7H&(0yhYC-l|QpWKws4r4Nx^!}1Y|dIr-tl*1 z#1O5w>SM~z$OJ(jz7M;QU`9D<@L}iIcHMVD0`$cL!T0DGjefJ8SV8difqq$cJMEiY zdKdSv8+x5hx<&9|y*o$bFMF-XclO3KNV|4i`T8B!ef2-+h^lR%7S! zkz?3vEn~8mQSNBgWz4&q;YEU&EQgT+JmDKvcvBy*{q!!sHHP(IzP!ULtP5bwE37LZ z?-fD(;}tff`2j5MX6J-a6^>dPPLRETj;n@>YEC~)h*9lB#HU-b>C(5P(}BBEiXEIm6om8UxPA|ny_DOAT=&g35 zBKPW+B?%-t9H)2q?bm&mBnZh2I?7u2wJfj!@%%M=0o9vs;Zt8_L3Upmyue^yLQJ|P zBL$+pa^iY27z%~JoB{x}I+e4a6g<(wn4xXDNF*l>;0PciC)1w2u@F2=e{UyDUK$Q! zH6qVRp)`CKffZnbDip|L(9inF!t8qCQLW$Xx zw%$3Rx-PfWwUBYAj1=K#`N8Rp~Gp)6Alhf?TLKEwBn>HlBhsi01 zAvshI19MCjU@nLACc3j#lolH1G8+aU_JKKGf5WpR1s)vKaS!gH>G)eqRRrs#2(rqf z-HK337VxA->u>zUz_5{Wk*X)f=c6M`szlZ)UPzaw>XH6KOF+mcj%Yop7=MYsr|OB@ zA(xRL*p`(5dh7PEyNF{ay4j@Zxq8?Ec!m~&OBA+lS(QssATWna1c9&R!IyZC{`SD& z^{}#3{f!6iF#HU`+E0I?-cA;uoxIhO3U{+hsG5yb)5v0}fVFvmxa{OjmiR2ca=zm= z7Hmhc*hR5`zS$7mg1*Z)Ck;8iNnwOw+L!=`?z<7?j3V^Spb`NtqZHz@{O-g$i*?^s zB8R?96v4Z!9AV%Q$pbf*kQ%;g3k8TW>H_itQVWLK zb>FB^(7aFi&#$vE_B}uQItz*Tp`K`|k*KbIn@;0o!5pK}M!hwMDbzboHuXiz^esnS zB;Q5(jnu}^;nCwUm$k&zDM!MkXmr$g)$*rw%Mf4sPp(J*qwAMbRJmT(r;y zB?6Wd3RspeU=?-BXso{>uXOS=GLu0kZ1zS&4v`H7t#>CHG4+I%=>Ne%N3&9a11|N9 z&CVdZgVCk|^x?{B_@BB{Z~k2>r43tcR2Te^!STKzpgp@L|QSZq&+*-*+b?*;jWBGhPM z%elh0j5@=(>H8Mf6XeT$&)vcncpccBys2hw|g$-MTor0HY zmRj6KvIlaMQlq6Dlcx}kJ+XrR?t;8F0c7A3DhUdH5Uqz@?X8DxNgb&tts?6nY6jT{ z^#K>?&w=m@5Ry%NZLXBfA@e~K7dLfu7JooA@wcj$jee)XT{L$5-R09JumJlhB{dd} z{Hg)l&}1zON`*?k3#j$M^p=zxDy|~iKwpq&co$HylIB!MXyKxGsrjWrj9U7#aB`sO zCm8Xpl1+Xs6&Ls@Iy<#fqX>LOx@h}U5-|Ki0ixJQ2_sdbaYHy=DB-&?4TwWB^m)An zyHTr%64gmfJ-&OTJ};eGfKlOc1c2%wj#Rx-A|CIZMPpHjM^^YIygZCM17H3IX5Qrw z_-}8pMtsczR;S?p8w_g$FW-Q@6_%YP;~13@4$0W84C*$@cEU37_^hD)B=#k9%gztx z51O&Jc>J5}0gs=;BHVg+-^6E4VNbHfeA5*6VXOSnG^nhN7;++(!cBw96~>_QJJ+Dn zi{gyoJ}p@*bN7G# zH|9G>OTSNfoTJef3uKEn(wnYPerwnQ zUPThBI^L6>IncXmjNc8s4wHqina+N-|7eD$=uyA`p}c$0H(SV}0`lQoPbFXswz3wi z2LUf4Rb^ZBt(JK*`|~vFWbuBKEQXJ?T;X4=8O5bXm=*g*?h->zq$D1PutlS z&3>o{ZYK@`>y4uaCk5ctJ1Yt~>Z>;xBB?a#^Rl>4I&0V&jkxW5AROAB>>wl%iNYM4+~80>3tsHTIug6^O7q zM<{5*1m0{G>&9;K1viBuCPelUfD1p-=?Y5;L(Zb%dq&V1p;0Lo7m;kxOp48WYVGLtB04-64Gas8X^OD(^*(MNt}(Pf}7kvn>7Y}Hk;KSY4IMFhVmS8E(XP=M(e{dPz<}G z54qM`A5w;{aV=F;j6UQdy1jg=6+N;(p3&B&c5G?em1L7H>y~8{rdxu#h{!JMVK?=# z3f$1^&SCBRAY(a+s_{n#kHwC{G$^7mA3BFw(dSGiIKer<^7EI$uo_F?tV?djaA4aU z_GVp+HsW>c8PUV`I8He$aUyK_O+F}t)$cqDWJGP-t0&w{)hC>0sd}ZDRZv$?7Idc= zS}NFHIZAl38Kx^=oPpt#4=>7K!K{p5B-mP@&t-QR=EUxqtUG(3$7HfmYTa@C>r6JO zDUQ&DnPVzRpFoPCx6EiNSv3=zK9={)VlQLv^;H&o4dDMS>+g#uu;>-0NF`9~CHi*gK8)Ntj+01IU z_~{rAGDxckve@TGiX8ra)}%3eTOeK-xgJ?W{N zdMmuwiD}^Qvow0dT@m_#^K`2IMAI{Pg%AH$@gJ@?shS+-ifEQmhf6P7WLPOV3vV)y zb;Bsh2z3o8i3ug20+y$8yw;MDV5CC#cudl!A&?%Us?H>QWJ{;sT= z9)cUw!(WU+C25L?jren9qPc-W^uLTJ`OSH(T|H_&z42~aP7Wm>J$su8W63l=zb|XT zhvhI|`=|FR#iY-P(>|duYKbz4N#9D0185XVeW+-l=zhhd4|Be+;dagWzJXiL`H%wY zmE>v8SB$LFa0h+fgokrJOvY?rkdwZAJM^RJot*jkRn7cp;`g{IU)Wtt_%PMOzz|cu zYSTTM*y+ZU4`Emwz-$k5JeulZp4U4&c@Ap$jR!CdIoXS*$zG5f)cda!J^uE4tgW4H z97YLbC(p77{{Q*>E+)&b;Q!bB?v6h1Wt1tF6|HgISB1f;&-;o`exHT;)Q72|f<*TK zt6lj%YhXto5;z*&E1C$ImG1(hi^xfbFE%TO+RcB&U}7zep0d^&UBpM;#%=#2Z=;J? z>}`yt7JD0A#8U4RF)Uc>ZFCVUy^X=dN^hf!SmSLI;cH^NjXt7GbP)@TSVi|rrwzwt zFQIPYW^cV!Z&Poq1G(XF0kM?VTTjLEHRqSvJ#T;T_xHRCey;VF&%I-8bcWx$&*?c`zCdQliDxc zHilz`%z|6~6HSkb&f;h*(OVo1M=KU(g6S4Ix=T3PPxKPdyMziDqP{$MKI=@gD(Wt2 z-s&1*W}KBBMvm74>MxAB=QWz?f=6~6#@y2=Z`oliNJB6bHEI@f1El0oZdE$7GpHV- z>5&a}K17EG!UkS|J31%E#9}Z}iKg>E-a9S&mkiQ7dZSf{$n`U^lz^P&Q|^5ilnBTv zH-Or;n5{0!h2%puc;p8xb_gko-Xk2ma;~b;Ty@Z2=xVCws(9Z5`qh}LA}X}b1^HA) zmK@hyRrr?i-#%asWdX`*DFSeJ7SmFyE!?sFR?%&c@=6KfpY(F8PsCa1;(G)Z*EG$F-Y6XMn9qpmInG2{r_N?J>{ zg`VS$3KLCBMMoqiq8mOmCZfhX6#xITX();SX)htG64OxO|DR1m(YgIUnuZP)wjnG+ z_gzMYhiRx)Ohbhg;)VTIZc`x!*h08wD?VNBL-$8S_N;%(Iv6yk(vY*sLWDjjPO zWC-ni9?SVPwyl*NzRX*E%)%S26=nOjIC;Pvo2@%>h$yyR&A7qSK4$IeeqFC#y6Fq3Jy-C zJu8tDn_>G)zZ|>Oar9y(p3hA4h{x`>Y`f)>3I74K_J1lzHhzAU;)uCXiCvfCT>xxG!f|kTMCd-T5$!}G9_mmXFI=xgbsGZM zLngQA$7N5#dhj(YolnGTcu;AE)zP;~r91K1U`;AbhDx_5oxC&@8}G399riad*yeZ= zrS&dyh%LW5HcylJo`9V@?jQmbaE((vp&TAITJYR>ENz-1i*tPMsC1S+3ol;6l39Jz z>ex|6B{IDe)S<0c0gmk;;Kc%ZnF|@PQjW2K4gv2YecG)lxa?F!bZiU`{J~d4kS*lN zC}!kol8BUw`L9RvgcE#a+LNq~0X5SObHuySzDj9_yV4GG_=&XfDW_?{VUDgy8aus) z1V_eaPvFwKaOv z`O}9Gs!iQW=qR6l%ls5PxRwQD7 zTq;Y!T_crVk4Xg$@1)~hQal^qHi<#+MB9v zG4HI#>{vy-nUdFGryz>3517TXx3c3X>ZZ?@R5J2oymWJ4z1Bd82_POn6trn*D!AvRFzee}~WgH*7w>imm%_ussPclESfP_gBEI9V1bxhLU)2 zuQ-|*!E`FmXyo_?p1jPt?-2IC%`q4X#AM#KRsLp6uQb0I6|4V(TV6z?bmTKf`vS!g z=SJTpDvizlu@Ewstg+d=-BQ+0Rfh7BOR*Jf@-Uvhl(lX&NE9pH%DL)T2xCB52)p0r z$UMc1m$Jro3kvB5MpWW6I#}*QyVf4c^moa?+O|1*oN{I17~NF=I9ruNI-SMw0CGkS zf2QDH9tMx0;FDFsbbyHCa|B0M@=?o}Z~HMI#F639u1Rz$c*|-Mf+@1uTW!W$C}nS; zm16U4+0$qFzn8J)eSSnIrGJN=+}YX`9F1CRi^kQ972Eo{725`wifuzw^ow!XZ9OxB z6>lXS2m8_I5ip^Th=qRocYeW+@n;I&U(V{X`rjZqyj6*v@8~wCqxkVW$q`b@|ML}# zw*P>-iYN83bsD=qn~UHJj$MC(oK-=$tpmT}bL2|w%q>U-Z`+T=dl#?cK$el{#$FF| zya+~mBQTTN+O}=9SQnc$D<6fjZPp6>ldNM8nP#@uWp=P4PHA254(4pF&+K3?B20V^ zsynjI@fTOHF#G$08E*hmjI*~*arjW3Wmgem9UDa-f@WkwvEj6+wX=eu*ol6#&+2%3 zHnF1~=KWIwR?|dJg$Hyy^f2ue5FBet$xITpIfH0X&9Bf=7rDo=K5oX7x2*HgcTRGT zubC~v0(Pts1_c0nXWhY6?0gB%+1Y`80y{BwPNFDJ3`CSI5G4qSTO2v(_>8Yv^X?@O zxq*?e_gCb=^U6ac2>$oM4^!L;S`s4i+u_)Q!h96#|jYuYgea#$B0e}rO* z7(l*gef(w-XDoc3_K`EBH$@MJ7MQ@>f5W<}&&=dwzF~9JoPqr6H>_dUTS#w`Hq|XA z^KK94#F1zp{v(A7oA)C3GfHmLLaX;P19|wjEY`L+UX;lWN5DzZmi!&KvE9(0qij

r2!f6?fAIC+vT=2nQ7q7X6AEu9F8_(~yz5HVQujarl_I2) zyxYX{@he%ldMuuQv63}w`in?=2IjMqk58&KRa;MHM61fLBlUJspU3mFE16AwE}n<3 z!kxH7JRiIYI|!rW_|8?VwIw)?DYrLcWi;uk9u^fE$F=WRY3I@X#e(YZj&E_?23A)8 zNY$T1j_GqL$y*$K{-9OX?Npao!qK{d*)i)FZ}2^{g_gr3in!L(hQs@|q(q#Pj<#F- zbNlzKqv}45|M)$&n|;<_6ncwy!SG0-k0%+uMxl@9?Z0LHY^P&onYYBZI;ejB?)R87 z-*EgNW&Sk;9k-6~ukx{9^T(;&k$36`X|^l+c&I`UC5) zufhIc(svu`Qajv-Z~Xx~rR{xr#Shp4_G(`q@FVv9#q{Mpe`LK>XCFT2N7h0;)Q7M7 zk-ebq>dh@{Sm%bzdJA*VlMW--XZ0ayf0K{HFqZV@BiFD!;f-UEvsVrXqqqd4a7d#l za+r`^X%tXW`>PiiZ3pl%>Oqt{#tz)2%Q_jtVViP>xl?w(@ch>`0i_;K#tMaKjbfFR>+ zJPf&^7__A`3b6WgLoM4sUBHYv>yKsIEmYkjLuk z^?%mYe$lZFM)!ZGEM*1t;fTw^`#<76t!g=`F-WZomBg6xn?rPG$J@}jnLC#JhH>W@ z{5|BgV?=uaJc4;fb>@E&a}UYv=;Y$L2Zu38^}?v^;XBv(fFE8D#KZwcgf}qp{uRzW zofE84trx?3t~tsP7nSgqsuISa*B;w_N`O8mhX#x#yGgSx7`nyfyaACrj$eex^l7oP z-wwc(at*9TyxN5wU~}y7h*^MPFukDHqm|%Kqri753x>hG2K%6ISHfN}=Mv^(N6}zd z)Mr02VNwNyiFG~|M(YOhrCZX+D8ALiR4stYi~?bx4u6?B`Vh2XJ`|We#frnt^f?o0 zIQSx217+`;k-giF(mj=SnooTuGBtY!R8ZaHVG^$D)}U6_mQ9zMl#L|nL%t(u{~}+P>Y)8&zJJ?s3^7G#6-RHn zDx3dXNbIqhEtF}Z`B$sWnwg!3Zc0{W&CF6>tLN?Jew4qk{C82cR8*pwOy7mf#o{k6 zJB=1Z^f~lN_iDCw0^E<)&Q&5cwR728CBCQOC>4EzuryN6Uc=OCXg6HgBuf4&Dz8ep zQ#+yDO8il0N@okt8I55Pj7qE@eF&|MLVre#xvN#AyDPfSt4C-5fZ}_O;;U9e`kZ&L zI7*g^%CR9%Svh5sL9WJFKB<-{mP@{_TCeL;z%bf1Nb9k!^1e*b{`jIYT4llSRTcS< zR#~H{+6nVUQ5B);tBiF04rFaM{*0o!TcxZhEi6I3yc6{=ip$W}{l95DP-^>Ml*Nmn z4zK@PU1tmHgsu%qSG%ik_9kVIY$s)L9ECnNPjn=9bc03*vyt*a=1E=XYy{%vY%6*K z*ub5d8N)JSE|{z3s{>Mcti4XzVW(Kd-LzVBs$sAZqW`Qi*c$dq{p&Ic|8Kp=B4O>w zYA12Da#>H}J;}48=)m+XnCRUf<}cf|ga7yw z>)PN47+pNQfN4xusmd{GakSpX-F{|I)gLZ`Cm|H~`BozEnqyxvPyQL3ZU&>9swTSy zs*&ug#fI!1^f&QXWfZbwMc_3@onjuifrZ#{c!ARD)*=)gza&4^b438wShH-T6 z%uQ^bFlFAvD8F}ABz0>DiBG74lNJi1Uk+BXm9G_gWRr0jihfNKL_K5gHh$$7HoxQT zv|wd+RQrDg)7PUr-<=qWMS+V=@Ysd!t~sJg{uKA2n5=toS=SvWxA6R5*^nVqP;`iX zP%0L?a^z_>+2Ib~VvuKUEivIBLOLjfzF^h1D<g^5-k z>x08Fc^gkG#I$hmRz9zg&9uKy{4`$9z@4!enaPQY?SiFAy4mAU(BMvmj$}$LCn^MF zBrt<~B7x40T?zDq>@VUdotz$6!1O=gjn+85Z$?0((6RVeNMvj0MpGsbjtqRg6{Kz2 z)gaGqRD#MjEpR+vxCyT>IScuLcEs5i z`45{}m|wG=SOC%2{hfZgGMWYt*+D5U@~fL!TQ#F658A>4)$WnJ`xd<46}Odd-oirS z){Y=Wyt8O1;O150JQbG{#Ga+qJ@0#C09Y)_6}g`lZ2QGexcoO#<_n+B_SzetZ948a zy#XyEN83MwciPI@dd!1mvFW$cvsVQ5?;M2r!yU!Mg4oi=%%LU%HjG z@ShJI;&S|3kt*OEgUA|>;iX$y57m*x8yDey=!HpqN)hW3nUF+08-nvl6P(&aEm;4> z?}(!b3b8DUs5x3|F!e^$$ElleA?5*5{BjX%R{P`@w3??;C)X2sgJRZMZ4$u;7PJ0! zM?S2@t$q1QhgxG_huaap%PJEq7@TzzdKOK5hb(Y!M zbp$+Y5YRz3h=2WrqM3c!-4TXy3_1b#OZ(`Hj2fj>#UBTQk^HA1D){fdr|>tovHoh^ zD86MI3+;ZU2UDgdP8>$ZN&gP_gkiLyFAVE3VL=>zJTcza84EO6RT#2ARX>0O$Y+Sa zu{}5r?dst5GMFY_#`3E+vP1`KHaWa*>NB*x-N_ua zod8;0GKmLaG>^O#Q=RP-gYCmAwo5_Pg1z51f+xygFA>X!BB?_$!Cc?L>Zspt=FNBD zt+R36`K%o*Q&qcjubr%Yzb~69E=L)OK!(`5OK`}-(HV8+-P>kh~b11indy%}&ZuY0@8_B)* zumx(XU-;5J>^t>|o&`gG!yZ62VFRD>I~&qtDi&6-IQ%NDuV4Z64S^$Q6%V6(RrabTJnJCqqk1Rsy$6}U$4T^alP)@*U(K%_ zWN`z&_?{BCJ?t)*8Ru-ZBiBejHD8bq^1uvk~)w64@rIh zgGj2=7vC94QOwnonhCbYmXdWKfBi6vvWVFIN@BD8n-FWY^6GYBl_;;=0Tkyy%4Qt z*lXB~s885T9RKbp>*w`Q=S#!5+cDO^!~5Tg2qWVRRTtvv5NdG#uty`3#%GD+Gmb&U zzEzoTPps85fA|{_WBSvN&HPa`-p8t#@HBt&I8=NX^Q%LJiXP6dMT9H*^Yh19l^JJ2o5agBTiuH@vY^2*$LJnlAgj9T^V|=XwR^%MMcAQ-Lxh>9^mNRTbF_<7`G9N8+R!E>EXl#;de|;KY(K36 z*9UjuRQ}yr)~dxs#DJ%L4v4I#2xgzLqf@Gnal++SWYLXvAC=2xcj-se~|HkFS#$6k+qOAG+-3WzELAf;mhymtxk-yk4p z6@c=M+J&?*fZ}Ix)*(<&V#oc&2bhvl?TYUa`7Qv?QZRc5QbwbaATj$vjHE_sc zl=G*lxz%b(F=|PT;-ky(?)Kz@Yh~;vYxdK};9TtLH2=x};uG9-8T@Y;{Pi00>inGw zp=wa*6u#&xv(fR(#AD0AppAg``M?laollb~__L47r$ZJ)}r%&STuA}59 z@zK}uL}yUvf@Rm)Z*JlJc3MY+u7g`iW8Wq`2lb0=dtC|#gh~gZiKbH`vv7CQ7aW_gzF=) zWs4%(B?Etyf%=Gv!Lf)1IZkZ*84-D>3f9H~mmYQ>s+Ll*{`mzTU%?u+6+&UxQGQWh z33ny5JB;U6V)PbeM4F87u#kc;ctHhnV~C(Ig(7Fb>OWr4-YCaNI z#0P#7{l^-D5Jp1>~miFfOU%bT-e35-~>dC z+PicZAEVJR8bV=?532Z#LQ^%9;7UEFw;UoEw?N0JKSkhi|KXqW;gzh#VDR7(eWZXg zq`C$9IA-wdLc}Pv<3ab}*Qxv}q1X8Hcrk`lS}M3E?5_{{0c^OvjfcL+{lEK+msGM~ z4-t4x+xvOJgGzSIWcj2<%?j_#I zRS6lQsJqi59$9yqU`PykAczm^?hhj|SKWnNF@%h|D>axYHmbW2=@)f()(8^@u-!v= z#z&NVOm)|gyK8Ddj6w7E2jUi_7ysd^K-70C-W56?GJ(O=xARgP1=fdvp0o|GIM5tpmGqK(S$+PJm%1A%bo5p?0Iqqf ztu6k7fA6MKp5XB>_b+JWqsB0tVl`e@7c##Bvqd#C=Ec2z)i!`9eAO0!7k$+X)!VP2 z%vYV_rhfYdALXx(Q$s8Td;QgywXO$VL)Tb zAJ@`eRh6P0!?EBY0xGrfuk!JY)E>;8uWY0??t?>(-F6g}UGm=nSJ9~nXZ(sz9S_xdbLW;oH6n-tHXW}h zI+}c;Xj9VNqN7QrMVpfE6_q9WPjlxlV*SKUEPsc!okDmt=|a)oq-#ZgCl(hSO$?bx zw7rRKrx`pqtHKc`_z{*~LoV!Zk`w$#lb~VR{_7x|LxfwANXQm^#G~j`;*p{q$v5e| zBrx#6AhkBD#lwQsZ+t0uZ(T|+ViO0a| z0ISxd7Jt66+AE02NZpOt|4u4`wn!LwJ;~c?=D#*p!SPv zVw|U-l1wwVC~80AnF|e#z46O zf*Pm==bEW0Y6mQu&D^9YY%h&7^Eg-;Gq zyQ@xC@MDNt$XZom=z2V{sOWxDhuEB;+T`7p*uAJ%QXxbG$=f{%Gw7(Mm3&DHwIg2j zD`}zb!@)=Y4pS4_-=}FYmW)3NF2{_ntd>|O)V5UAB$v}dS&p`$qM%tz^)_Rpc!Snz zQ$Y9DYCOBkvs$aq0?xHop9BQAK@+*dUumOuW-s#3+JNN_zuZQRVlVJkZPll6{LyP| z)y9B%ZPnc^Ql#~x!$Y&D<(uQ0ZHtOdPg*~EKdt8$Zf^(cPvINd!TKTNhGm^g{vX4I zPWFr+bta3+gKad1^&_s+sXAFdA_&SAj4tcPT|Q_=3b(e0^^1Vx=*5!J`y}1PRSNe# zx+BG<@Cof<{emT|ZLARov0XzjmN*haVgxO*ZJfb_PL0L~B0R+4Pi&h|LoN)Xn#2%; zKM5Mb`aw8{Yb#U^`S5wlQ6h>W8IjR~RT^&-4(orOM~1`tM~YzFlfn*zE$Y%pelr}_ zFQh7?T8QA|QR59Z+yoP`cO*=^HjZJaMCG!ED)#up={#|Dn&j^01vsxZGLZzW0HsitMo4^CZ3lk90K|s_K0N8pj z0p4)}LJlSscwnoH8lLDfd9XN!OOyBN0(;#FA8hpu00~Sai}yZ1oUe~W)ekTDD^k7A zLWUv?8`AEAp#c(p6Ml%~5}AhJDTwsLp}cl?wI3VGhjv$YuxEIa9%_91!C$+j< zt%lSj-!*K#`H+H7d#Du*$B4n!1IT2#8ZRG52CBnYL?-`Kfqy8vB-y9H0gPrVT*jE9RdLPzS{n36>WHL_8xP ziijx0RRa7c3kZ5yKu970Md6Eu`QCyO(WR&$e4x5gWt;gQgK)py%+3D3InUsZUdXpSqfTba_>)7>r7YtqL)0dK^dV}5y`;IQ zv6-i_u^QVu?-5M&!y-c;3c=^LC)IOo!85K)c$HcEW^Z$4o8o~2r3E~#IkCtubdyNk zha$NoassqBg^0ULr2Kb71nN#A5ql{SjAWj3$;1d5IsscGvr)=me}s@(^-!dhOT<@* z(2|)Dc~^>Hekw$!J`}lwXoO}bq3t%if(B-jwK zxkUUPip+P3Oc5f`(-67-nXhD?`|g2Z8JD^>kqPr;l- zHB4nY`Kl3WH~Y@!%BBnMZk5qlkY&|yRM9qnbW zg0mw5tczSJoG-O;?M}tTUhXj@l<= zENGQU< zIyr*JW~vhdI=SKOKEDs+*fHm6y|%G_o9#U;pC8Cnu~U@K$wH6UfzNzbeWhWC8oaKm z%k~caj+?U8uUI%=nXO)B?fIwk)Nffk-Zw{G0yvkWu4ZjHe-FO4JmP)$+VBhS!`GT; zjZK1jd z;Li~j%(robHRmrag0DHR|1o^c@Je@cQ$}A5=f}#9Th$2i4BJ`ENg{ z>CBT4{89ZG6NcJrFy-*z+t;X@LCjtYUo9TH4n7ZFy8u2j-(CP;EuOs|J`<1q4}4}` z`zQF^`1YURGx6-7;bS~@1AK10_D1*=zI`KnjA#D>UnP(I6+VU6E`;v^-(Cn`CC}aj z-+dmt8NLU+_7?c=@$FmGEg;U@3I*@-*dm18j#Hv=0U}a(_+!@BW z@h&ISWFJpZ%Q*T)j4NI}&+|^GgFU`cBjNS`N-em5LT%14>*LmwYDaY#<3moWE$cL4 zkqUhVWX@GI4%|xXGXDNawcAT)l}Pju_+nc?Tu#Jsc<`1V;yDOc?`#|b_I*eAekZ0n z(cKRVt|Gy881!FjaQ&wS*Y{OiUn{)rpK9Zddy|?gF>d#=v=TVnHbw7s?!6n674-{z zSy~|lW<^YbR9OonYctOjO#f4@#~NfMHdppKva}3fOjgK~&aMQVoL%|KQZ?3RMP*l| zY?~qDahj{A)Ulr7ph3a5m0b%apHjOr)mc&S{b{uiQ(MIIJ7?6!ejf3#$DAk=!KO1f zz(AXHpSL`#-muKSCuBbn;QjA=y!AOXyFQ-9qJJ9`33hyL2H$SV33?VDzUQ1;zxIwT zxin36cQjdEaP6GB+N~h(lKL0pORlH^d?Wq+fj`fQquM?>;f--Gy{_<=FRH1&9j&dc zom+)fkz4YM7u6L7p;y(0eR$pwH|smL&ThC&1-8x_%d(%VaOPg9aHf@2I1?^aIK!{t zx`yjIuA3FkLWHLyJO$x4gj*4ALAV9s7KG;^JO$x4gj*4=AiVr4u5w&AAd7Gt!mS8b z5MFv2aU#4B;e`kvlmG?`7|IOTto`P^2|JO#Xc~A-TD1n|O&@%-rRe@>Xa~??PAf-Vy z8$@gnu|cGCC$j%L!b%{r7vlTDa{!_Tq3vNrc?6msMV5|3ixY_F4@7?wvZc`a6l8XT z2KjQx+xCG5`BKP-A3~gvFF8_ScUq4jQbbUQ2rLjz`4f>M0_Ajt^Y!`Ne!v5#4Oa^HkeiFE9|k7*Av+k?X~<2$rQ-SkvdwV)V2AKixb{K#MO-%^I15)DTwg*s7T0__&Tmi2)>7_Gp?l&?u=_Igoofd3&DxFOt?ORY%s1hkd4800J5WT z-Gba4T&-|@0@+r$eu8X&T*n|c7T3Lo5A4o&A>0txHxPaT*G>qJz;zLVQ*l{wu0mfvY?D?m zDBlP1`2!0XQ z4X`XiZ~(4Mu()%N&06!uQ^4Xta3U@TSl&ah53U(tsjS2MZ`PVMejPj~5k3IdN$|`; zxCz%p@Z74y-vv+5Xz(0Bcnq!s;F*f>dk7zk>muKQq=H6(Wha84z_k-BX<#Wwa0;$c z?y&_d31BHia5%0)u%v*c6u}9&N_ao846uPEAHh~)LAOwf4kv{=9Q1lAe*td;?*jh@ z-Us51(UeM{6UY#qifBzh4RMt7xm&a+)D$zX+@girw_>Pz7&pzl9rv8>n9$?{t-wNH zB+z!`p0g11Da+A&&RiUSYXz#=B|2Fkmh)5op1=6otTqC-0+Y03UD>Fb$Xw%mvyS0iV5Zcb39o zOTLc|6*(CRhCnbrkAw(EAt7KMPzgdrqmdBM`VtZb-8v5?0KaVkatbV2f+BB>oPCCP zfcf7eyb1jIC?R0!YLtK#3IBkS1(y712Ll|+8srq14_pLHTMNx0kiHi=fxiTpAA%h1 zgJMA20my|y?jUReSa=jUZvpue$QhDz>7+`KCj0_m=ggh|Kt-=}5 z3i7~kURcffeFA8;CAvisBk)fHlWf0 z83P6YOMu}W(EgP`jCndCqQ=m?GjeD}gk6wua|i;%LlIFV1j3-u6Hugeg)_4U>aZOK zR)ihlf09}Ya%zLW2TBxZu^~QS9?(4+a!(-xz+9jWm!=dzoATbO;!oY;VD9T>2 z?nLCUH|WXm1Ffl0v=2%K7zQjKi-`Imp;r+RFdUc$Odk&gfO&60aiUMftpJ!Z163J^ zaG)g~iU93l2p9zad_)9H_z(&J(-%N7U@1ogz;d8vFce<|MSvEd4QK@> z0@HwLz;s|HFc+8yECj9xCVYY_dIsU2VCXppjzSR9foVTfI2QpEwqp1Rv|@C<9au_3 z3G!pO5jF(;O>ip(CRlNUCv1k>Dv*BY7Q~NDO&F}ODHijmb6>P7jl62P=Q0YY79KZP z83>MApT0yKE*3v9#o)@_e9vhi3Hc*>GOo-==!-$4w9`RP=dbP3`l@|BIs09Ef|u{o z0tO`fX~biC9z~5G#nT3=#7ep#N;>uxDz-=HXAzbRdL-z1CjQ$#t*0rMnLgps2eb&D z{<~)8P4;L$s_A#`yT2Nx0W0U5_Gon*Cu0@Jak^$^NMWpbE2XFT*ge{?j$vnNhLe)C zrf8LP(^pS}ViZ6H=u>{1RPtdxVZI zNjU-fnBDwFiPrAb#K*)JV}@xxhMo+1>|^K?K~H}q9kPybpp#yup6Gus#q!_xX-{f- z%yi4mFcbHET7bI#5O20mTdtN~vP8 zUb$cE$=B}JdZ{J1_`UtwTy^_xKI?!sAl3c;KTG142c#cE_kw13@BNcM81(W-=wv!Q zKzD$ir;t6?<8cSI9%}e~{_a7oaR=LD64(ua$VceGi0CZn;e5~`t%*k%Icbs5l$qQTKx18tyP0LaF>H84~A)K@f7~h)KK?1yu&^% z$P>e8#i!h4I>~s>J}r=kUetWN%T2RQbG01xeK%8iHG0rPx-50xhpeO_j)A=Yj43uY$@keHCq#Y^llAxRxkcR?5FPrq%U`(_u6yt9-uknD!KV zbK!BVAG3-70{qAF6UR080n?D-DUT#VMe`BpX^)|=1bxgSbjrY1&{LZ5jwiGyLQTHp zuBkYcWd(Q=LASzfI?Ruq&>Hjn6PhWs4FqDPfa%Ac2u2@_D+Y9%OW-RKXy!8!v~bYU z5pJ5zJ^#=~=qIGS4K3N!z9(;g1Rd>)KeSjMKeWzybri+DE=G#NXgau~8&iBz&_ml! zY7O|Z-CFyGDYMO0b~6JabG=OOf~(jR&cE2Lb@Hwr{yx8cQtR~6(z-MVs+mbDxW%Av zZ*I^{_oF~D?kNXAFO+mal=RD>uLs@gA_4<(nGjhD&-xQ>Ef~%;{`H^QGkP+dvEZiR zw&|HDUb|GA|70L02`hS{rmICks&oe3X2Terx+wW018M`hdp|^i5i1(du~O}Wq|2a< ziN>h48ZX6R!o(x*DezLM$sef~2zq8843~-K>H`rU^?}rL^g#F`gctINbDEW63Fl>} zwC0}k;N1Q?^6O!Ajzdpt!#&$zx)S>)+O@ku{0l^FH;9pZ&>3_lQ}Y-&g&o^w_k zn3RkO+xq$cEXs+XCwzd}L$%_eVweZ|ln);%h7bhEVpxgrOoZq2qElKE?Et(Mo^(!Y zu2sOfp3gj|HK|KIn+X%Il08TOU5e>aSGox`Za|6ogw54V!enix>%w1bVtn;(t$AJB zT+Ogr)4%^)0BRL6xFniYNq~$W4LvR+;jrIPeAITjccr$|!e}Bk3|Yn>(OTEG%|-|I zp4EqBY z0`~v2Rn7t3@)-Iw(A_27^lSu0qr~C*2y_MX6o6?U=tdP-P3U`-d8&z)NOIixPKVa6 zHpMIW^a%cWnbwW>DAT+=tuE^Cd~li8M-AW4KPl6mY)V>QZVW9~8hseN;x`BXCYsao z7cOeE8;pa~u?p>n$X|8BpK-5wpU*#_`ElP%T6g^bcx>N+2j*cK*hvgrXzZy!yz|l6 z)8ai1k$hxDe}aj1Ip4ESvvU8-+B0=WgMJHiE9TGTaGQ8Xio~A=3?7CNgqyzMBM)jp zVkFx&e6EQs4y;CTPiu-^1Cw%#pcsFP0TV$_0bN1YYwFrj+@ee+%(SQ4sMvBv3s;Yn z@Taa|Jei1@dpnXJltuU=0FjiJ^Ka5Pdi3 z>mQ*9f__#cz&)=aLzd&b)iq=={{$aPe%qh?UBdEG{teNUGyEd_4RX)bjGwBGM*5lj z`gLuTHX3zO!aH2o>T1*AJi_~3*RmUX!7#$k*SxpPgJ3Y|;pch(>)Lw_(h*)=af*01 z!l!U{OB)r`8DpKo$FRhKzTRM21E+G~F|mMtSFkkhjLyaO2+KrB#ep7qfls)pO>UU} zNH{5S0^w6GaP^j!+OY7EaFS2Pm}~t7KI@h?S;Z-I_iky8`&%9VGz~Ab*GSM4AmjQ` z4dHYYB@J|&iwHb{+UWuMB1gfCe`zNfa}+fFTRY4=DWC$Q+QhPgW`84~;r22Vtic>kYWcedgSV<#*>udL!&oi~;X2DM? z9HC=wqkEu&jll;a+}_gACd4lp|BG=q+>Vu{d^cWsMQhH>Oy;f)1Dv>h5=)GaRki!L zlcD+1EzrrI(9Deo*ccv8QMk=VR5xWm4&kw&3qm#eXwZp2h4|%<5}pQnCg^Fk`AAQ5 zbG}0}cU2d86{u#jSyj_~3OwD-l}~E6RMP&R z313EdY&cd__;a4-76m z7YkF5(C2|33Hn#Cao3Odmx5k0vch>B4bb%?`UcP!rByhKC_VWj`T@{sA!}VL1Mb;%@hf<_fw>N|UofA9PN?bWA{FPSQ7ob*m?r3DjnLKq!Sd=T zD?ARFeyppM=wGVvWz|9Ouk^R8jt2i9b&r}6O2(on&QDWWN<@kJ9}f&Lw7s6n7j7Ed zzq)C2Yh&4$+)GT_&z{O^Qzy7DcQ9!yJe72fJU?sN0#D_4tts5O=BfKVl(n_AS)R&Y zwZ3EUeD6Whzwzf9nOoXFVeEa@1Uh6g?M7WCSDmL8c`D~k+Ff7efk}I>j`FTX?r*fq zY^|#l9r-M;bAKtJfA{Rsh&0Jwkl)DXqY+K4o}c7Hf4Yqu%! zQGW312=`rY?I$1Q-#!TZOZRj((%rtc^xbPwzW4QX>TYZ6tYu&_N|BFiU~a_+2b%w| zf8j3*g^I`J z1Nk?N$k)i3Y1X!z-M%%$dC^SN%vx~%rxrPn*MeNWyLR2(?SMO|A9@gVjR$PMx!|J?RPFA8Tvxc)1;_9ik{-dl9wJ3k*<+%!&67GDq7znJF|$mIIZdeer%9Re>Jdtw}H9k29`8OqWFc6lsM7A()k9e>Bo70 ztND<9%`NIJ6$QKVm8L)=82!aXgKjce1kH6zUN8AIccb?)327{}+&1{#-4g|c7H;Sl zeAl42k=R*c4+HVSt0WAOm@Lr{N5p}lAHKkX)Y82l&R6U5v}JBjtNHt?x%XGOd0|s? z3bx8OZDxKR``>0ZGuKybcU-}pu!sZF^DLjALP)>d)`n*PCrl48`2HKF@#yB}=eae+ z>~8-I_c8jpN^!*_{-V&D;Rhb^pQ715elGb-((h%El_^Glh;wC)Ul@H&5IEe6_K`SD zVyeW+66Z=>XrNtLE(z--7E3%N@w~*_63uq0fW%OVT_pCAI80)y#K{upN?a%qf6FCd zoy1~^ha{etcw3@5T`C|kRALv2eIyQ(m@09y#JLg|5>lMYC1IV!Vu^<&o|kxAqIsqw ze)S}VO6(%BkHldTQzcH8I9K9Apvcp5NmwVbSmGgx=Ox~jXr3h%kQgeli^M(>he=G8 zI9cLci3?{L=_|`6VV%TciH9Vfmv~#EdA3wQVyMI}68lITCNWjwWQlVnE}Sjvbh#v~ zlUOYAki_#6Z%Z`KkqSr*mDojMABn>xrb?VFajwLLcIj9yah=3siH9Vfmv~#EIYTNS zF;rp~iG3svlb9-Tvc$O(?F*%2xx{r6izObCcwXXdiRQUd0g0g!yGZOKahSwZiIXMH zHPEgsl!WCH*GVjvcu3-TiMJ)1-;oMP43*eLVjqdaB&JH7EOD+t)c-hBo339Dsi&JxrFh!7D~c$iR&a5OFSg;yu{lQ%~?_biJ@7z z_co+^n;GYFSO1N>p$hL5iE|`=Byp+44H8Qvp15hqow%XWZQZ^>jwiNC+%55d#1j(F zO1v!bmPF+*BR+SD7Ks58trEi|hD(ez5SuY1Ay#67#6*dsC8kL%q<2;D+bwaLq^C>F zl$a}Vk;FWSDicuQi1M3Wqec}et>7$`AVVjDv0 ztU60V4~a1n<0KA|m?$w>Vv5Ak630j!Cvl?0X%gp1oG0-kpy(_YOTto#`4ZPi+#qqQ z#N84PNIW6&ti;O_Z%M3>Xp&XtCDHGWD$-X1B_T{=XNfk6aS{_GCQ2MFF-_tWiRltE zCFV+8EODvCm3QohF|Cn=4HCCYJRtFe#Iq7FOS~nqLZV3yp4}ySNwi4xlNcb;)=V~| zAri+(OqV$Nu4tyz1DJZd!B|T78vQ{2K8gDc%sXIU%0UCIhYT#0n19&t8>3~66DxxKGz;Ojznex1m!@v#fL@eWUeymJ6GYejM4F#a!)J*;y4Yvo@* zZSLyp8Vytzvqn;iJN(E10T5N~ehn^LHWOt^3>UmXuU!nPUY zuxYDAM_CM{R>w5~Invx9mumb5=pHQ%?!uP5Rf4&z zM;F7J-i41%F!yxtVlcnOS0hmUyBEKhV1Cj+omRc+*Uf++Kvy0$$lTgLJ;Mmv)XNAG z|9pOexjw8gfUg{6?#wdzsX^xYc9%s|V^rJ}t;!^7(#?v?HfqvqDK6uvNq1LV)=`u0 z;hNSNoslch4SNw>cH*KDx+%34m!Z_8dnqn6sY&-%TxL>}?xVQO#GuRc-4tDM8B9$9 zi{dhvnsi@mQ!{F*CcTd0vY?vux{Aw^YS06*9P2Wv8Uczw9@}Gn=^s~5aT!xhhWd)j znrhMmltO7vHR%l$*wc+?%lRl+PLSq_&4zmLty)~=74VySJf~U!^H17Nnat8@sRYnlD_5<`c6qNe1u*m z>AN4HH-k1v*RC9q0bj}lzAyrmY4wcu>q;06Kq#6i>2)N36zG&c*V0(7r1vF$r2)2j z*Q|h{GM>dE9@xHXQRO8Wuu>-ATI)V7B6`@E@?-)I&`rv9r}S2VOQF(V4U$cUxD>K= zt)|fbYVG=?qpI%wodg~~ByE9!O$V9HS=~W=-_7(;_AotUO~r($ z&0l>poswJF4&{S~y;xT>(akK_A5b9yp@-6R;XAwRSE+>?`+b|j;5X)TmigcyozVWE zMNaXYO8UW0q(071N~5%IhuKp4o~3l6A6P_fx)JK4C-T)TXPkVmv3%bSe6of2na9Sq zo%A1A=Ch=SPEy^bm=QL+;bF`7uA}+=@kcoEWjMie0GHJ?X0y{9fd5EfRY@tz__&Lu zgG|QWCU{Iu1HlYA`yp_Hh0muwTUK59WrCTzt_JQ}_&hB}-@#$&*c#&Ek=olY z37?i!pu1euT2-#P#*fj)YGL$I;Jv_U0MX@XjaSgCC(>QUi+vg|QsKXd;%+*>xf~Xp zuKCXi;hzLoCm`@1@NK{c)4n_Beits63_e2R<;oi?j&{%tz-2u6H}D)qC4>`t2Jp1j zL*X}`-mD3w%BvJb5iLf~X8=zDHwlM0qT1@uY<9}%qanKbsZV<%D=px|V7CsVq#xgJ-c-q3R zCj4)+us^cJ8M>qqydn5voL>k$Y~d}yJqvFK?pio~q_ls=cnM5dIKgioa`~0`cogL27a}! zfPW192Jn{y=NBFMl!yQ~-Pj8}2R#Na8m@heor8Q|Wr7y0>_2E}7%+Wif~NRM7b-z3 zXc>#&1TCv^%10Bmk>b&39NI=Wk3MRGoQtLf|3WyAR((4kXu>hgPxo)D^3UCV^*51F z0nO8FV6bK2Qo`AQ*;2{Dz+BB=sv_qxkaS0v##mv{Quq%>A@*jB!XHCn<~#~vx3BuG z<}X*}mi|wmpZ0txu2j+xDW%Q|&_$d(@^gfQWa>13xpFN7{0=Hd#B3%R{cX@6@6#{# zRlhMO1K)*#TFbyQFkp76jDa^`AlGL=T6RADAI4xHWEmJtYfGIp*#63h9(6h493gMi z=ZjE-<}X*%Ed94bf6VNwnHGE#22!8Xz~eCBSqApOK=iQ8VWt5`pkK)zPfSJ7vh#)L z{|i5<4Hqdl^y%?}jxX>7tuzZtRq-%g4)XXE%40KJePpkH@=i#{zbZyjj$hei91CLKk&ni%T|i=G}hInz~f^CH;t5-t@+9!a2>;Iq6oMvdUbw#(yVx z3Tdz(`rUWrG6=BxrRa|-4+dz7rppl+aA6<;{6j5JPOo{(WPJ=&_@y`%FBAIvz|$|}^G~EjbP4J4-j)b?=z^!c zGxHqqTbQ37f4FeqDsxo7k&j46#?tW|@KmMf&Pk=-HIlJP+MHo4|BQa70O>NBaMl?A zNBM0c_4mM|Z-9|5WVn0}dNSBLGZ#R6z@Pa2&A@&;;d9^BJFu{ z-z0t@fN^Lc;oN|%wU5)DtR7J|=W$47PUTCz1}XLSbWP~OQs?)CbF;Jjst^^EWgq!l z+Gx@_E!7wNXV=iLD|EGF2JL$l(**D0V$_U$Um=`5j?WWa{M8;V_Y$r<>m&J{f$g2Z zBgX}gNTr?=YcK1n{usDI2SsZLT)n_^F95*#apy>~#_3XjKOd>j-sjt-@e5S+?REvT|TM;c`l(%~9+CA93`LDqTFO)Df3$maA^;2bx6v6XDF?jeIn5J!|kbX|X4j z8e0wh;15IpH5ym`W$T>c*m^K2tFscovv?rFH1PWd$CaPK_W}=E_--)Pi>)IvcTDJYVK**44Y7z7_CYk` zYks&I7ctdHI0x3X%*4T;L2?@X4{Dr}=WeGsaLlj1n})hxUB!md!F&?3Uw zbozejBlGglD&QWP;K8MbfoCjym(fEXKj#tx|MP;+R_-A|jIaESCpMgzEdmiN7*7Cq zZx%cOM+2FGH?nWOO@aAc0d3tVX(03LcwaQ;jQm+6;_#%!C| z%+aO;mpOzNv&PtBaOA8!Sxq>HHH)#^v@Qia^8?Xj7VT%DC-sOpoe{DcL#Hl}ZCTtk z9RPfa#w$ux!kXn5_%Gc<>z-Dk>nQ#~^rfT$YCYlXR~VV&LEqEhcj>>QaOnpBziV}Y z4|P>B<_g5)Px)Lk{QEXgdT$`IPRnORt7-Ih!nqM2SOfGPjaR5wtrf;AFcXQ28MDUu zZ|KjS75%PMDmYHNb&*P!h}&5VY%UXYZg|3?x^EPYjA&Lj8;*f@(~<7esswo5_k<~m zSnM#ov3Ho47jkb;6Bo`3=Ya7N9}hE28V)uP&Vli)z;u8={jSKHwaJ6P!-qsc3VMD> zIN7CZ0o=nMd~k>+W&IuZ(uDAP$VIJe>?K@hqcx-!PY{1I-C`gIJChjKaa%=4+Vd{) zFanMZ|#P7_*}!2nqpgBwR0MYYRnkuvD!^a^TLsqb_q4J48opHvEim z)1fX6wA5fLLCkzXkZ&iPgYu>ol&#=b$HXfaPCP?6>rYvUmDT*p_wRFx>rOz}9)AOq z>4pzoTbqZd;DajitG`LJ^I{@%i@lvN)*%cl2xpragwpuFQHupqx~lqwxVVM!S41j- zIL@j^q+7Q05$idTAL%`W>qytYE+k(9e-Nj$v6}<#X2g<7`GzU56!YnbqnbKRnat&k zX#P2KkO#s2`3ZjzxQmI*SgM*T{M|FuJN>$7Sjml;42Kap5~@k`oSN0 zR@%y+b>Y%OIJM+DmB5WQSHrX_q$^T3oLVRX37mmf5YG7$$K3}-%QP-C{MFy4G+sbt zj!fb$5i>1~09P1KJT1hZlVGvfK9GZ(1UF(uUlK1uIHL_dhHy61ZC!Cp2ku!}8z!7j zJ`WpYu&x#ge~F6V9+5Gy#NWYwwL@RX(zgwGHx{jNX{|~T&QVKasbtiB1U%f8-@dt5 zqa8mN1t~aoE8(PPtjbtxu>=GXzYzf!0^j!o-=XpMjIIV=bq%TIyc*bUj_SAY5xJHf zE~irt=lc%Abw~GzD&z87MzZR!kjz;t^nw|b3T&nEB06H-apboLuf_on@spEO%!=+B zmgK>XzfZ!2h5#;M=GW)LN=Rlco8K^!+aWnfBp)K2TM@o zQz9RiN}VE{5@qaXhUv3J;3m4r(D-nXSm+;nfYz?7t`+-PYv*A%@Eq_6>=b&!udIY0 z=C6K`PNVTeW@|yLCc_Y01zi2B0C6l(UKg<(k*jI^dDU8ZUp^E4(=B2qI#d0?CbBjk zWc8YKQ&uW<6Y$Ux0Yb3WDq{B&S;rhnO~!S32V(B8Ma-^Ku-oKpFl1h)BLoy zwzf%c;ZFz-h;89XuR+FczCANKJZ5l`qyoCn*0|wJC_6} zU!|6=Xj){{ec5X{JJq5`-8ty2Y(%jhGx^hiR+uG*#m94AWTN)P3ZJOHbS3Tmi zU065OrZy+{Z0cfOc(t_t`gwmK2N_Yr4w(rXyd8QbcV59{2y z!`WEq&)VgTy|{T%)7rXe%?oaCUfb5v(!8u?Xe|v|xYp?`f66Hvl5Ds#=-;;22_@UF4Rs#b>s(XNS@)ciEiBK|*1GaD+P>gt4$*7c zv2jJ6?$4a&g3d>~oXta$f7h`5ylt-hg|p4CN;?<(dtRb%t@QlDc`&)O;p-*+M`3`D uQ^x^kQ*!I{+T@=4q5k&Qodun{4my7=?418gXKEmM|E%)PeZO+n7yd7`R?`&#