diff --git a/LICENSE.txt b/LICENSE.txt index 946a6df602a..99989f180cb 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -288,3 +288,36 @@ lz4_encoder.h,lz4hc.h,lz4hc.c,lz4hc_encoder.h}, - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html - LZ4 source repository : http://code.google.com/p/lz4/ */ + + +For hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/gtest +--------------------------------------------------------------------- +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/hadoop-assemblies/src/main/resources/assemblies/hadoop-mapreduce-dist.xml b/hadoop-assemblies/src/main/resources/assemblies/hadoop-mapreduce-dist.xml index 0cb01ea1a1f..749e16af055 100644 --- a/hadoop-assemblies/src/main/resources/assemblies/hadoop-mapreduce-dist.xml +++ b/hadoop-assemblies/src/main/resources/assemblies/hadoop-mapreduce-dist.xml @@ -135,6 +135,13 @@ *-sources.jar + + hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/target + /share/hadoop/${hadoop.component}/sources + + *-sources.jar + + hadoop-mapreduce-client/hadoop-mapreduce-client-shuffle/target /share/hadoop/${hadoop.component}/sources diff --git a/hadoop-mapreduce-project/CHANGES.MAPREDUCE-2841.txt b/hadoop-mapreduce-project/CHANGES.MAPREDUCE-2841.txt new file mode 100644 index 00000000000..cfc9412443d --- /dev/null +++ b/hadoop-mapreduce-project/CHANGES.MAPREDUCE-2841.txt @@ -0,0 +1,26 @@ +Changes for Hadoop Native Map Output Collector +------------------------------------------------ + +MAPREDUCE-5985. native-task: Fix build on macosx. Contributed by Binglin Chang +MAPREDUCE-5994. Simplify ByteUtils and fix failing test. (todd) +MAPREDUCE-5996. native-task: Rename system tests into standard directory layout (todd) +MAPREDUCE-5997. native-task: Use DirectBufferPool from Hadoop Common (todd) +MAPREDUCE-6000. native-task: Simplify ByteBufferDataReader/Writer (todd) +MAPREDUCE-5991. native-task should not run unit tests if native profile is not enabled. (Binglin Chang) +MAPREDUCE-5995. native-task: Revert changes to Text internals (todd) +MAPREDUCE-6005. native-task: Fix some valgrind errors (Binglin Chang) +MAPREDUCE-5984. native-task: Reuse lz4 sources in hadoop-common (Binglin Chang) +MAPREDUCE-5976. native-task: should not fail to build if snappy is missing (Manu Zhang) +MAPREDUCE-5978. native-task: remove test case for not supported codec Bzip2Codec and DefaultCodec (Manu Zhang) +MAPREDUCE-6006. native-task: add native tests to maven and fix bug in pom.xml (Binglin Chang via todd) +MAPREDUCE-6026. native-task: fix logging (Manu Zhang via todd) +MAPREDUCE-6035. native-task: sources/test-sources jar distribution (Manu Zhang via todd) +MAPREDUCE-5977. Fix or suppress native-task gcc warnings (Manu Zhang via todd) +MAPREDUCE-6054. native-task: Speed up tests (todd) +MAPREDUCE-6058. native-task: KVTest and LargeKVTest should check mr job is sucessful (Binglin Chang) +MAPREDUCE-6056. native-task: move system test working dir to target dir and cleanup test config xml files (Manu Zhang via bchang) +MAPREDUCE-6055. native-task: findbugs, interface annotations, and other misc cleanup (todd) +MAPREDUCE-6067. native-task: fix some counter issues (Binglin Chang) +MAPREDUCE-6069. native-task: Lint/style fixes and removal of unused code (todd) +MAPREDUCE-6074. native-task: fix release audit, javadoc, javac warnings (todd) +MAPREDUCE-6077. native-task: Remove CustomModule examples in nativetask (seanzhong) diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/pom.xml b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/pom.xml new file mode 100644 index 00000000000..c18949e3695 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/pom.xml @@ -0,0 +1,216 @@ + + + + + hadoop-mapreduce-client + org.apache.hadoop + 3.0.0-SNAPSHOT + + 4.0.0 + org.apache.hadoop + hadoop-mapreduce-client-nativetask + 3.0.0-SNAPSHOT + hadoop-mapreduce-client-nativetask + + + + ${project.parent.basedir}/../ + + + + + org.apache.hadoop + hadoop-common + + + org.apache.hadoop + hadoop-mapreduce-client-core + + + org.apache.avro + avro + test + + + junit + junit + test + + + org.mockito + mockito-all + test + + + org.apache.hadoop + hadoop-common + test-jar + test + + + org.apache.hadoop + hadoop-mapreduce-client-common + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + listener + org.apache.hadoop.test.TimedOutTestsListener + + + + **/*Test.java + **/Test*.java + + + + + org.apache.rat + apache-rat-plugin + + + src/main/native/testData/* + + src/main/native/gtest/**/* + + + + + + + + + native + + false + + + + + + false + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-os + + enforce + + + + + mac + unix + native build only supported on Mac or + Unix + + + true + + + + + + org.codehaus.mojo + native-maven-plugin + + + compile + + javah + + + ${env.JAVA_HOME}/bin/javah + + org.apache.hadoop.mapred.nativetask.NativeBatchProcessor + org.apache.hadoop.mapred.nativetask.NativeRuntime + + ${project.build.directory}/native/javah + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + make + compile + + run + + + + + + + + + + + + + + + + + + + + + + native_tests + test + run + + + + + + + + + + + + + + + + + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/CMakeLists.txt b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/CMakeLists.txt new file mode 100644 index 00000000000..7eed1769fce --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/CMakeLists.txt @@ -0,0 +1,276 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +cmake_minimum_required(VERSION 2.6 FATAL_ERROR) + +# Default to release builds +set(CMAKE_BUILD_TYPE, Release) + +include(JNIFlags.cmake NO_POLICY_SCOPE) + +# Compile a library with both shared and static variants +function(add_dual_library LIBNAME) + add_library(${LIBNAME} SHARED ${ARGN}) + add_library(${LIBNAME}_static STATIC ${ARGN}) + set_target_properties(${LIBNAME}_static PROPERTIES OUTPUT_NAME ${LIBNAME}) +endfunction(add_dual_library) + +# Link both a static and a dynamic target against some libraries +function(target_link_dual_libraries LIBNAME) + target_link_libraries(${LIBNAME} ${ARGN}) + target_link_libraries(${LIBNAME}_static ${ARGN}) +endfunction(target_link_dual_libraries) + +function(output_directory TGT DIR) + SET_TARGET_PROPERTIES(${TGT} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${DIR}") + SET_TARGET_PROPERTIES(${TGT} PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${DIR}") + SET_TARGET_PROPERTIES(${TGT} PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${DIR}") +endfunction(output_directory TGT DIR) + +function(dual_output_directory TGT DIR) + output_directory(${TGT} "${DIR}") + output_directory(${TGT}_static "${DIR}") +endfunction(dual_output_directory TGT DIR) + +# +# This macro alters the behavior of find_package and find_library. +# It does this by setting the CMAKE_FIND_LIBRARY_SUFFIXES global variable. +# You should save that variable before calling this function and restore it +# after you have accomplished your goal. +# +# The behavior is altered in two ways: +# 1. We always find shared libraries, never static; +# 2. We find shared libraries with the given version number. +# +# On Windows this function is a no-op. Windows does not encode +# version number information information into library path names. +# +macro(set_find_shared_library_version LVERS) + IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + # Mac OS uses .dylib + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".${LVERS}.dylib") + ELSEIF(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") + # FreeBSD has always .so installed. + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".so") + ELSEIF(${CMAKE_SYSTEM_NAME} MATCHES "Windows") + # Windows doesn't support finding shared libraries by version. + ELSE() + # Most UNIX variants use .so + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".so.${LVERS}") + ENDIF() +endmacro(set_find_shared_library_version LVERS) + +if (NOT GENERATED_JAVAH) + #Must identify where the generated headers have been placed + MESSAGE(FATAL_ERROR "You must set the cmake variable GENERATED_JAVAH") +endif (NOT GENERATED_JAVAH) +find_package(JNI REQUIRED) + +SET(STORED_CMAKE_FIND_LIBRARY_SUFFIXES CMAKE_FIND_LIBRARY_SUFFIXES) +set_find_shared_library_version("1") +SET(CMAKE_FIND_LIBRARY_SUFFIXES STORED_CMAKE_FIND_LIBRARY_SUFFIXES) + +# primitive configs +set(PRFLAGS "-DSIMPLE_MEMCPY") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PRFLAGS} -fno-strict-aliasing -Wall -Wno-sign-compare") +set(CMAKE_LD_FLAGS "${CMAKE_LD_FLAGS} -no-undefined -version-info 0:1:0 + -L${_JAVA_HOME}/jre/lib/amd64/server -ljvm") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} -g -O2 -DNDEBUG -fPIC") +set(D main/native/) + +SET(STORED_CMAKE_FIND_LIBRARY_SUFFIXES CMAKE_FIND_LIBRARY_SUFFIXES) +set_find_shared_library_version("1") +SET(CMAKE_FIND_LIBRARY_SUFFIXES STORED_CMAKE_FIND_LIBRARY_SUFFIXES) + +INCLUDE(CheckFunctionExists) +INCLUDE(CheckCSourceCompiles) +#INCLUDE(CheckLibraryExists) +INCLUDE(CheckIncludeFiles) +#CHECK_FUNCTION_EXISTS(sync_file_range HAVE_SYNC_FILE_RANGE) +#CHECK_FUNCTION_EXISTS(posix_fadvise HAVE_POSIX_FADVISE) +#CHECK_LIBRARY_EXISTS(dl dlopen "" NEED_LINK_DL) +CHECK_INCLUDE_FILES(fcntl.h HAVE_FCNTL_H) +CHECK_INCLUDE_FILES(malloc.h HAVE_MALLOC_H) +CHECK_INCLUDE_FILES(mach/mach.h HAVE_MACH_MACH_H) +CHECK_INCLUDE_FILES(memory.h HAVE_MEMORY_H) +CHECK_INCLUDE_FILES(stddef.h HAVE_STDDEF_H) +CHECK_INCLUDE_FILES(stdint.h HAVE_STDINT_H) +CHECK_INCLUDE_FILES(stdlib.h HAVE_STDLIB_H) +CHECK_INCLUDE_FILES(string.h HAVE_STRING_H) +CHECK_INCLUDE_FILES(unistd.h HAVE_UNITSTD_H) +CHECK_FUNCTION_EXISTS(clock_gettime HAVE_CLOCK_GETTIME) +CHECK_FUNCTION_EXISTS(localtime_r HAVE_LOCALTIME_R) +CHECK_FUNCTION_EXISTS(memset HAVE_MEMSET) +CHECK_FUNCTION_EXISTS(strchr HAVE_STRCHR) +CHECK_FUNCTION_EXISTS(strtoul HAVE_STRTOUL) + +SET(STORED_CMAKE_FIND_LIBRARY_SUFFIXES CMAKE_FIND_LIBRARY_SUFFIXES) +set_find_shared_library_version("1") +find_library(SNAPPY_LIBRARY + NAMES snappy + PATHS ${CUSTOM_SNAPPY_PREFIX} ${CUSTOM_SNAPPY_PREFIX}/lib + ${CUSTOM_SNAPPY_PREFIX}/lib64 ${CUSTOM_SNAPPY_LIB}) +SET(CMAKE_FIND_LIBRARY_SUFFIXES STORED_CMAKE_FIND_LIBRARY_SUFFIXES) +find_path(SNAPPY_INCLUDE_DIR + NAMES snappy.h + PATHS ${CUSTOM_SNAPPY_PREFIX} ${CUSTOM_SNAPPY_PREFIX}/include + ${CUSTOM_SNAPPY_INCLUDE}) +if (SNAPPY_LIBRARY AND SNAPPY_INCLUDE_DIR) + GET_FILENAME_COMPONENT(HADOOP_SNAPPY_LIBRARY ${SNAPPY_LIBRARY} NAME) + set(SNAPPY_SOURCE_FILES + "${D}/src/codec/SnappyCodec.cc") +else (SNAPPY_LIBRARY AND SNAPPY_INCLUDE_DIR) + set(SNAPPY_LIBRARY "") + set(SNAPPY_INCLUDE_DIR "") + set(SNAPPY_SOURCE_FILES "") + IF(REQUIRE_SNAPPY) + MESSAGE(FATAL_ERROR "Required snappy library could not be found. SNAPPY_LIBRARY=${SNAPPY_LIBRARY}, SNAPPY_INCLUDE_DIR=${SNAPPY_INCLUDE_DIR}, CUSTOM_SNAPPY_INCLUDE_DIR=${CUSTOM_SNAPPY_INCLUDE_DIR}, CUSTOM_SNAPPY_PREFIX=${CUSTOM_SNAPPY_PREFIX}, CUSTOM_SNAPPY_INCLUDE=${CUSTOM_SNAPPY_INCLUDE}") + ENDIF(REQUIRE_SNAPPY) +endif (SNAPPY_LIBRARY AND SNAPPY_INCLUDE_DIR) + +CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/config.h.cmake ${CMAKE_BINARY_DIR}/config.h) + +include_directories( + ${GENERATED_JAVAH} + ${D}/src + ${D}/src/util + ${D}/src/lib + ${D}/test + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_BINARY_DIR} + ${JNI_INCLUDE_DIRS} + ${SNAPPY_INCLUDE_DIR} +) +# add gtest as system library to suppress gcc warnings +include_directories(SYSTEM ${D}/gtest/include) + + +SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + +if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + # macosx does not have -lrt + set(NT_DEPEND_LIBRARY dl pthread z ${SNAPPY_LIBRARY} ${JAVA_JVM_LIBRARY}) + set(SYSTEM_MAC TRUE) +else (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + set(NT_DEPEND_LIBRARY dl rt pthread z ${SNAPPY_LIBRARY} ${JAVA_JVM_LIBRARY}) + set(SYSTEM_MAC FALSE) +endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + +configure_file(main/native/test.sh test/test.sh) + +add_dual_library(nativetask + ${CMAKE_BINARY_DIR}/lz4.c + ${D}/src/codec/BlockCodec.cc + ${D}/src/codec/GzipCodec.cc + ${D}/src/codec/Lz4Codec.cc + ${SNAPPY_SOURCE_FILES} + ${D}/src/handler/BatchHandler.cc + ${D}/src/handler/MCollectorOutputHandler.cc + ${D}/src/handler/AbstractMapHandler.cc + ${D}/src/handler/CombineHandler.cc + ${D}/src/lib/Buffers.cc + ${D}/src/lib/BufferStream.cc + ${D}/src/lib/Compressions.cc + ${D}/src/lib/PartitionBucket.cc + ${D}/src/lib/PartitionBucketIterator.cc + ${D}/src/lib/FileSystem.cc + ${D}/src/lib/IFile.cc + ${D}/src/lib/jniutils.cc + ${D}/src/lib/Log.cc + ${D}/src/lib/MapOutputCollector.cc + ${D}/src/lib/MapOutputSpec.cc + ${D}/src/lib/MemoryBlock.cc + ${D}/src/lib/Merge.cc + ${D}/src/lib/NativeLibrary.cc + ${D}/src/lib/Iterator.cc + ${D}/src/lib/NativeObjectFactory.cc + ${D}/src/lib/NativeRuntimeJniImpl.cc + ${D}/src/lib/NativeTask.cc + ${D}/src/lib/SpillInfo.cc + ${D}/src/lib/Path.cc + ${D}/src/lib/Streams.cc + ${D}/src/lib/TaskCounters.cc + ${D}/src/util/Checksum.cc + ${D}/src/util/Random.cc + ${D}/src/util/StringUtil.cc + ${D}/src/util/SyncUtils.cc + ${D}/src/util/Timer.cc + ${D}/src/util/WritableUtils.cc +) + +target_link_libraries(nativetask ${NT_DEPEND_LIBRARY}) + +add_library(gtest ${D}/gtest/gtest-all.cc) +set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-w") +add_executable(nttest + ${D}/test/lib/TestByteArray.cc + ${D}/test/lib/TestByteBuffer.cc + ${D}/test/lib/TestComparatorForDualPivotQuickSort.cc + ${D}/test/lib/TestComparatorForStdSort.cc + ${D}/test/lib/TestFixSizeContainer.cc + ${D}/test/lib/TestMemoryPool.cc + ${D}/test/lib/TestIterator.cc + ${D}/test/lib/TestKVBuffer.cc + ${D}/test/lib/TestMemBlockIterator.cc + ${D}/test/lib/TestMemoryBlock.cc + ${D}/test/lib/TestPartitionBucket.cc + ${D}/test/lib/TestReadBuffer.cc + ${D}/test/lib/TestReadWriteBuffer.cc + ${D}/test/util/TestChecksum.cc + ${D}/test/util/TestStringUtil.cc + ${D}/test/util/TestWritableUtils.cc + ${D}/test/TestCommand.cc + ${D}/test/TestConfig.cc + ${D}/test/TestCounter.cc + ${D}/test/TestCompressions.cc + ${D}/test/TestFileSystem.cc + ${D}/test/TestIFile.cc + ${D}/test/TestPrimitives.cc + ${D}/test/TestSort.cc + ${D}/test/TestMain.cc + ${D}/test/test_commons.cc) + + +IF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + # macos clang with libc++ does not have tr1/tuple, just tuple + SET_TARGET_PROPERTIES(nttest PROPERTIES COMPILE_FLAGS "-DGTEST_USE_OWN_TR1_TUPLE=1") +ENDIF() + +target_link_libraries(nttest + nativetask_static + gtest + ${NT_DEPEND_LIBRARY} +) + +IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + # + # By embedding '$ORIGIN' into the RPATH of libnativetask.so, + # dlopen will look in the directory containing libnativetask.so. + # However, $ORIGIN is not supported by all operating systems. + # + SET_TARGET_PROPERTIES(nativetask + PROPERTIES INSTALL_RPATH "\$ORIGIN/") +ENDIF() + +SET(LIBNATIVETASK_VERSION "1.0.0") +SET_TARGET_PROPERTIES(nativetask PROPERTIES SOVERSION ${LIBNATIVETASK_VERSION}) +dual_output_directory(nativetask target/usr/local/lib) +output_directory(nttest test) diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/JNIFlags.cmake b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/JNIFlags.cmake new file mode 100644 index 00000000000..0100b06312b --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/JNIFlags.cmake @@ -0,0 +1,118 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +cmake_minimum_required(VERSION 2.6 FATAL_ERROR) + +# If JVM_ARCH_DATA_MODEL is 32, compile all binaries as 32-bit. +# This variable is set by maven. +if (JVM_ARCH_DATA_MODEL EQUAL 32) + # Force 32-bit code generation on amd64/x86_64, ppc64, sparc64 + if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_SYSTEM_PROCESSOR MATCHES ".*64") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32") + set(CMAKE_LD_FLAGS "${CMAKE_LD_FLAGS} -m32") + endif () + if (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64") + # Set CMAKE_SYSTEM_PROCESSOR to ensure that find_package(JNI) will use + # the 32-bit version of libjvm.so. + set(CMAKE_SYSTEM_PROCESSOR "i686") + endif () +endif (JVM_ARCH_DATA_MODEL EQUAL 32) + +# Determine float ABI of JVM on ARM Linux +if (CMAKE_SYSTEM_PROCESSOR MATCHES "^arm" AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + find_program(READELF readelf) + if (READELF MATCHES "NOTFOUND") + message(WARNING "readelf not found; JVM float ABI detection disabled") + else (READELF MATCHES "NOTFOUND") + execute_process( + COMMAND ${READELF} -A ${JAVA_JVM_LIBRARY} + OUTPUT_VARIABLE JVM_ELF_ARCH + ERROR_QUIET) + if (NOT JVM_ELF_ARCH MATCHES "Tag_ABI_VFP_args: VFP registers") + message("Soft-float JVM detected") + + # Test compilation with -mfloat-abi=softfp using an arbitrary libc function + # (typically fails with "fatal error: bits/predefs.h: No such file or directory" + # if soft-float dev libraries are not installed) + include(CMakePushCheckState) + cmake_push_check_state() + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -mfloat-abi=softfp") + include(CheckSymbolExists) + check_symbol_exists(exit stdlib.h SOFTFP_AVAILABLE) + if (NOT SOFTFP_AVAILABLE) + message(FATAL_ERROR "Soft-float dev libraries required (e.g. 'apt-get install libc6-dev-armel' on Debian/Ubuntu)") + endif (NOT SOFTFP_AVAILABLE) + cmake_pop_check_state() + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=softfp") + endif () + endif (READELF MATCHES "NOTFOUND") +endif (CMAKE_SYSTEM_PROCESSOR MATCHES "^arm" AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + +IF("${CMAKE_SYSTEM}" MATCHES "Linux") + # + # Locate JNI_INCLUDE_DIRS and JNI_LIBRARIES. + # Since we were invoked from Maven, we know that the JAVA_HOME environment + # variable is valid. So we ignore system paths here and just use JAVA_HOME. + # + FILE(TO_CMAKE_PATH "$ENV{JAVA_HOME}" _JAVA_HOME) + IF(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$") + SET(_java_libarch "i386") + ELSEIF (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64") + SET(_java_libarch "amd64") + ELSEIF (CMAKE_SYSTEM_PROCESSOR MATCHES "^arm") + SET(_java_libarch "arm") + ELSE() + SET(_java_libarch ${CMAKE_SYSTEM_PROCESSOR}) + ENDIF() + SET(_JDK_DIRS "${_JAVA_HOME}/jre/lib/${_java_libarch}/*" + "${_JAVA_HOME}/jre/lib/${_java_libarch}" + "${_JAVA_HOME}/jre/lib/*" + "${_JAVA_HOME}/jre/lib" + "${_JAVA_HOME}/lib/*" + "${_JAVA_HOME}/lib" + "${_JAVA_HOME}/include/*" + "${_JAVA_HOME}/include" + "${_JAVA_HOME}" + ) + FIND_PATH(JAVA_INCLUDE_PATH + NAMES jni.h + PATHS ${_JDK_DIRS} + NO_DEFAULT_PATH) + #In IBM java, it's jniport.h instead of jni_md.h + FIND_PATH(JAVA_INCLUDE_PATH2 + NAMES jni_md.h jniport.h + PATHS ${_JDK_DIRS} + NO_DEFAULT_PATH) + SET(JNI_INCLUDE_DIRS ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2}) + FIND_LIBRARY(JAVA_JVM_LIBRARY + NAMES rt jvm + PATHS ${_JDK_DIRS} + NO_DEFAULT_PATH) + SET(JNI_LIBRARIES ${JAVA_JVM_LIBRARY}) + MESSAGE("JAVA_HOME=${JAVA_HOME}, JAVA_JVM_LIBRARY=${JAVA_JVM_LIBRARY}") + MESSAGE("JAVA_INCLUDE_PATH=${JAVA_INCLUDE_PATH}, JAVA_INCLUDE_PATH2=${JAVA_INCLUDE_PATH2}") + IF(JAVA_JVM_LIBRARY AND JAVA_INCLUDE_PATH AND JAVA_INCLUDE_PATH2) + MESSAGE("Located all JNI components successfully.") + ELSE() + MESSAGE(FATAL_ERROR "Failed to find a viable JVM installation under JAVA_HOME.") + ENDIF() +ELSE() + find_package(JNI REQUIRED) +ENDIF() diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/config.h.cmake b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/config.h.cmake new file mode 100644 index 00000000000..e69dc43298c --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/config.h.cmake @@ -0,0 +1,23 @@ +/** +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +#ifndef CONFIG_H +#define CONFIG_H + +#cmakedefine HADOOP_SNAPPY_LIBRARY "@HADOOP_SNAPPY_LIBRARY@" + +#endif diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/Command.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/Command.java new file mode 100644 index 00000000000..6256fd1a009 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/Command.java @@ -0,0 +1,57 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask; + +import org.apache.hadoop.classification.InterfaceAudience; + +@InterfaceAudience.Private +public class Command { + + private int id; + private String description; + + public Command(int id) { + this.id = id; + } + + public Command(int id, String description) { + this.id = id; + this.description = description; + } + + public int id() { + return this.id; + } + + public String description() { + return this.description; + } + + @Override + public boolean equals(Object other) { + if (other instanceof Command) { + return this.id == ((Command)other).id; + } + return false; + } + + @Override + public int hashCode() { + return id; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/CommandDispatcher.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/CommandDispatcher.java new file mode 100644 index 00000000000..798479435b4 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/CommandDispatcher.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.mapred.nativetask.util.ReadWriteBuffer; + +/** + * a CommandDispatcher receives {@link Command} from upstream + * and performs corresponding operations + */ +@InterfaceAudience.Private +public interface CommandDispatcher { + public ReadWriteBuffer onCall(Command command, ReadWriteBuffer parameter) throws IOException; +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/Constants.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/Constants.java new file mode 100644 index 00000000000..1f7a5d1a4cc --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/Constants.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask; + +import org.apache.hadoop.classification.InterfaceAudience; + +@InterfaceAudience.Private +public class Constants { + + public static final String MAP_SORT_CLASS = "map.sort.class"; + public static final String MAPRED_COMBINER_CLASS = "mapred.combiner.class"; + + public static final String NATIVE_LOG_DEVICE = "native.log.device"; + public static final String NATIVE_HADOOP_VERSION = "native.hadoop.version"; + + public static final String NATIVE_PROCESSOR_BUFFER_KB = "native.processor.buffer.kb"; + public static final int NATIVE_PROCESSOR_BUFFER_KB_DEFAULT = 64; + public static final int NATIVE_ASYNC_PROCESSOR_BUFFER_KB_DEFAULT = 1024; + + public static final String NATIVE_STATUS_UPDATE_INTERVAL = "native.update.interval"; + public static final int NATIVE_STATUS_UPDATE_INTERVAL_DEFVAL = 3000; + + public static final String SERIALIZATION_FRAMEWORK = "SerializationFramework"; + public static final int SIZEOF_PARTITION_LENGTH = 4; + public static final int SIZEOF_KEY_LENGTH = 4; + public static final int SIZEOF_VALUE_LENGTH = 4; + public static final int SIZEOF_KV_LENGTH = SIZEOF_KEY_LENGTH + SIZEOF_VALUE_LENGTH; + + public static final String NATIVE_CLASS_LIBRARY = "native.class.library"; + public static final String NATIVE_CLASS_LIBRARY_CUSTOM = "native.class.library.custom"; + public static final String NATIVE_CLASS_LIBRARY_BUILDIN = "native.class.library.buildin"; + public static final String NATIVE_MAPOUT_KEY_COMPARATOR = "native.map.output.key.comparator"; +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/DataChannel.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/DataChannel.java new file mode 100644 index 00000000000..03469eed457 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/DataChannel.java @@ -0,0 +1,41 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask; + +import org.apache.hadoop.classification.InterfaceAudience; + +@InterfaceAudience.Private +public enum DataChannel { + /** + * We will only read data from this channel + */ + IN, + /** + * We will only write data from this channel + */ + OUT, + /** + * We will do both read and write for this channel + */ + INOUT, + /** + * There is no data exchange + */ + NONE +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/DataReceiver.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/DataReceiver.java new file mode 100644 index 00000000000..b3bdf5348b4 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/DataReceiver.java @@ -0,0 +1,37 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; + +/** + * a DataReceiver pulls in arriving data, an example + * is {@link org.apache.hadoop.mapred.nativetask.handlers.BufferPuller} + */ +@InterfaceAudience.Private +public interface DataReceiver { + + /** + * Send a signal to the receiver that the data arrives. + * The data is transferred in another band. + */ + public boolean receiveData() throws IOException; +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/HadoopPlatform.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/HadoopPlatform.java new file mode 100644 index 00000000000..da6f252ac38 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/HadoopPlatform.java @@ -0,0 +1,84 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask; + +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.BooleanWritable; +import org.apache.hadoop.io.ByteWritable; +import org.apache.hadoop.io.BytesWritable; +import org.apache.hadoop.io.DoubleWritable; +import org.apache.hadoop.io.FloatWritable; +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.NullWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.io.VIntWritable; +import org.apache.hadoop.io.VLongWritable; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapred.JobConf; +import org.apache.hadoop.mapred.nativetask.serde.*; + +@InterfaceAudience.Private +public class HadoopPlatform extends Platform { + private static final Log LOG = LogFactory.getLog(HadoopPlatform.class); + + public HadoopPlatform() throws IOException { + } + + @Override + public void init() throws IOException { + registerKey(NullWritable.class.getName(), NullWritableSerializer.class); + registerKey(Text.class.getName(), TextSerializer.class); + registerKey(LongWritable.class.getName(), LongWritableSerializer.class); + registerKey(IntWritable.class.getName(), IntWritableSerializer.class); + registerKey(Writable.class.getName(), DefaultSerializer.class); + registerKey(BytesWritable.class.getName(), BytesWritableSerializer.class); + registerKey(BooleanWritable.class.getName(), BoolWritableSerializer.class); + registerKey(ByteWritable.class.getName(), ByteWritableSerializer.class); + registerKey(FloatWritable.class.getName(), FloatWritableSerializer.class); + registerKey(DoubleWritable.class.getName(), DoubleWritableSerializer.class); + registerKey(VIntWritable.class.getName(), VIntWritableSerializer.class); + registerKey(VLongWritable.class.getName(), VLongWritableSerializer.class); + + LOG.info("Hadoop platform inited"); + } + + @Override + public boolean support(String keyClassName, INativeSerializer serializer, JobConf job) { + if (keyClassNames.contains(keyClassName) + && serializer instanceof INativeComparable) { + return true; + } else { + return false; + } + } + + @Override + public boolean define(Class comparatorClass) { + return false; + } + + @Override + public String name() { + return "Hadoop"; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/ICombineHandler.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/ICombineHandler.java new file mode 100644 index 00000000000..d28b883c169 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/ICombineHandler.java @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; + +/** + * interacts with native side to support Java Combiner + */ +@InterfaceAudience.Private +public interface ICombineHandler { + + /** + * run combiner + */ + public void combine() throws IOException; + + /** + * @return id of this handler + */ + public long getId(); + + /** + * close handlers, buffer pullers and pushers + */ + public void close() throws IOException; +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/INativeComparable.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/INativeComparable.java new file mode 100644 index 00000000000..1ec05dbc077 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/INativeComparable.java @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; + +/** + * Any key type that is comparable at native side must implement this interface. + * + * A native comparator function should have the ComparatorPtr type: + * + * typedef int (*ComparatorPtr)(const char * src, uint32_t srcLength, + * const char * dest, uint32_t destLength); + * + * Keys are in serialized format at native side. The function has passed in + * the keys' locations and lengths such that we can compare them in the same + * logic as their Java comparator. + * + * For example, a HiveKey serialized as an int field (containing the length of + * raw bytes) + raw bytes. + * When comparing two HiveKeys, we first read the length field and then + * compare the raw bytes by invoking the BytesComparator provided by our library. + * We pass the location and length of raw bytes into BytesComparator. + * + * + * int HivePlatform::HiveKeyComparator(const char * src, uint32_t srcLength, + * const char * dest, uint32_t destLength) { + * uint32_t sl = bswap(*(uint32_t*)src); + * uint32_t dl = bswap(*(uint32_t*)dest); + * return NativeObjectFactory::BytesComparator(src + 4, sl, dest + 4, dl); + * } + * + */ +@InterfaceAudience.Public +@InterfaceStability.Evolving +public interface INativeComparable { +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/INativeHandler.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/INativeHandler.java new file mode 100644 index 00000000000..fef56d9473c --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/INativeHandler.java @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.mapred.nativetask.util.ReadWriteBuffer; + +/** + * A Handler accept input, and give output can be used to transfer command and data + */ +@InterfaceAudience.Private +public interface INativeHandler extends NativeDataTarget, NativeDataSource { + + public String name(); + + public long getNativeHandler(); + + /** + * init the native handler + */ + public void init(Configuration conf) throws IOException; + + /** + * close the native handler + */ + public void close() throws IOException; + + /** + * call command to downstream + */ + public ReadWriteBuffer call(Command command, ReadWriteBuffer parameter) throws IOException; + + void setCommandDispatcher(CommandDispatcher handler); + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeBatchProcessor.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeBatchProcessor.java new file mode 100644 index 00000000000..9458c6b9f05 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeBatchProcessor.java @@ -0,0 +1,279 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.io.IOUtils; +import org.apache.hadoop.mapred.nativetask.buffer.BufferType; +import org.apache.hadoop.mapred.nativetask.buffer.InputBuffer; +import org.apache.hadoop.mapred.nativetask.buffer.OutputBuffer; +import org.apache.hadoop.mapred.nativetask.util.ReadWriteBuffer; +import org.apache.hadoop.mapred.nativetask.util.ConfigUtil; + +/** + * used to create channel, transfer data and command between Java and native + */ +@InterfaceAudience.Private +public class NativeBatchProcessor implements INativeHandler { + private static Log LOG = LogFactory.getLog(NativeBatchProcessor.class); + + private final String nativeHandlerName; + private long nativeHandlerAddr; + + private boolean isInputFinished = false; + + // << Field used directly in Native, the name must NOT be changed + private ByteBuffer rawOutputBuffer; + private ByteBuffer rawInputBuffer; + // >> + + private InputBuffer in; + private OutputBuffer out; + + private CommandDispatcher commandDispatcher; + private DataReceiver dataReceiver; + + static { + if (NativeRuntime.isNativeLibraryLoaded()) { + InitIDs(); + } + } + + public static INativeHandler create(String nativeHandlerName, + Configuration conf, DataChannel channel) throws IOException { + + final int bufferSize = conf.getInt(Constants.NATIVE_PROCESSOR_BUFFER_KB, + 1024) * 1024; + + LOG.info("NativeHandler: direct buffer size: " + bufferSize); + + OutputBuffer out = null; + InputBuffer in = null; + + switch (channel) { + case IN: + in = new InputBuffer(BufferType.DIRECT_BUFFER, bufferSize); + break; + case OUT: + out = new OutputBuffer(BufferType.DIRECT_BUFFER, bufferSize); + break; + case INOUT: + in = new InputBuffer(BufferType.DIRECT_BUFFER, bufferSize); + out = new OutputBuffer(BufferType.DIRECT_BUFFER, bufferSize); + break; + case NONE: + } + + final INativeHandler handler = new NativeBatchProcessor(nativeHandlerName, + in, out); + handler.init(conf); + return handler; + } + + protected NativeBatchProcessor(String nativeHandlerName, InputBuffer input, + OutputBuffer output) throws IOException { + this.nativeHandlerName = nativeHandlerName; + + if (null != input) { + this.in = input; + this.rawInputBuffer = input.getByteBuffer(); + } + if (null != output) { + this.out = output; + this.rawOutputBuffer = output.getByteBuffer(); + } + } + + @Override + public void setCommandDispatcher(CommandDispatcher handler) { + this.commandDispatcher = handler; + } + + @Override + public void init(Configuration conf) throws IOException { + this.nativeHandlerAddr = NativeRuntime + .createNativeObject(nativeHandlerName); + if (this.nativeHandlerAddr == 0) { + throw new RuntimeException("Native object create failed, class: " + + nativeHandlerName); + } + setupHandler(nativeHandlerAddr, ConfigUtil.toBytes(conf)); + } + + @Override + public synchronized void close() throws IOException { + if (nativeHandlerAddr != 0) { + NativeRuntime.releaseNativeObject(nativeHandlerAddr); + nativeHandlerAddr = 0; + } + IOUtils.cleanup(LOG, in); + in = null; + } + + @Override + public long getNativeHandler() { + return nativeHandlerAddr; + } + + @Override + public ReadWriteBuffer call(Command command, ReadWriteBuffer parameter) + throws IOException { + final byte[] bytes = nativeCommand(nativeHandlerAddr, command.id(), + null == parameter ? null : parameter.getBuff()); + + final ReadWriteBuffer result = new ReadWriteBuffer(bytes); + result.setWritePoint(bytes.length); + return result; + } + + @Override + public void sendData() throws IOException { + nativeProcessInput(nativeHandlerAddr, rawOutputBuffer.position()); + rawOutputBuffer.position(0); + } + + @Override + public void finishSendData() throws IOException { + if (null == rawOutputBuffer || isInputFinished) { + return; + } + + sendData(); + nativeFinish(nativeHandlerAddr); + isInputFinished = true; + } + + private byte[] sendCommandToJava(int command, byte[] data) throws IOException { + try { + + final Command cmd = new Command(command); + ReadWriteBuffer param = null; + + if (null != data) { + param = new ReadWriteBuffer(); + param.reset(data); + param.setWritePoint(data.length); + } + + if (null != commandDispatcher) { + ReadWriteBuffer result = null; + + result = commandDispatcher.onCall(cmd, param); + if (null != result) { + return result.getBuff(); + } else { + return null; + } + } else { + return null; + } + + } catch (Exception e) { + e.printStackTrace(); + throw new IOException(e); + } + } + + /** + * Called by native side, clean output buffer so native side can continue + * processing + */ + private void flushOutput(int length) throws IOException { + + if (null != rawInputBuffer) { + rawInputBuffer.position(0); + rawInputBuffer.limit(length); + + if (null != dataReceiver) { + try { + dataReceiver.receiveData(); + } catch (IOException e) { + e.printStackTrace(); + throw e; + } + } + } + } + + /** + * Cache JNI field & method ids + */ + private static native void InitIDs(); + + /** + * Setup native side BatchHandler + */ + private native void setupHandler(long nativeHandlerAddr, byte[][] configs); + + /** + * Let native side to process data in inputBuffer + */ + private native void nativeProcessInput(long handler, int length); + + /** + * Notice native side input is finished + */ + private native void nativeFinish(long handler); + + /** + * Send control message to native side + */ + private native byte[] nativeCommand(long handler, int cmd, byte[] parameter); + + /** + * Load data from native + */ + private native void nativeLoadData(long handler); + + protected void finishOutput() { + } + + @Override + public InputBuffer getInputBuffer() { + return this.in; + } + + @Override + public OutputBuffer getOutputBuffer() { + return this.out; + } + + @Override + public void loadData() throws IOException { + nativeLoadData(nativeHandlerAddr); + // + // return call(Command.CMD_LOAD, param); + } + + @Override + public void setDataReceiver(DataReceiver handler) { + this.dataReceiver = handler; + } + + @Override + public String name() { + return nativeHandlerName; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeDataSource.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeDataSource.java new file mode 100644 index 00000000000..f802b3f85aa --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeDataSource.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.mapred.nativetask.buffer.InputBuffer; + +/** + * NativeDataSource loads data from upstream + */ +@InterfaceAudience.Private +public interface NativeDataSource { + + /** + * get input buffer + */ + public InputBuffer getInputBuffer(); + + /** + * set listener. When data from upstream arrives, the listener will be activated. + */ + void setDataReceiver(DataReceiver handler); + + /** + * load data from upstream + */ + public void loadData() throws IOException; + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeDataTarget.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeDataTarget.java new file mode 100644 index 00000000000..d91070c8d73 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeDataTarget.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.mapred.nativetask.buffer.OutputBuffer; + +/** + * NativeDataTarge sends data to downstream + */ +@InterfaceAudience.Private +public interface NativeDataTarget { + + /** + * Sends a signal to indicate that the data has been stored in output buffer + */ + public void sendData() throws IOException; + + /** + * Sends a signal that there is no more data + */ + public void finishSendData() throws IOException; + + /** + * Gets the output buffer. + */ + public OutputBuffer getOutputBuffer(); + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeMapOutputCollectorDelegator.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeMapOutputCollectorDelegator.java new file mode 100644 index 00000000000..5a516c4c747 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeMapOutputCollectorDelegator.java @@ -0,0 +1,171 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask; + +import java.io.IOException; + +import com.google.common.base.Charsets; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.RawComparator; +import org.apache.hadoop.mapred.InvalidJobConfException; +import org.apache.hadoop.mapred.JobConf; +import org.apache.hadoop.mapred.MapOutputCollector; +import org.apache.hadoop.mapred.TaskAttemptID; +import org.apache.hadoop.mapred.nativetask.handlers.NativeCollectorOnlyHandler; +import org.apache.hadoop.mapred.nativetask.serde.INativeSerializer; +import org.apache.hadoop.mapred.nativetask.serde.NativeSerialization; +import org.apache.hadoop.mapreduce.MRConfig; +import org.apache.hadoop.mapreduce.MRJobConfig; +import org.apache.hadoop.mapreduce.TaskCounter; +import org.apache.hadoop.util.QuickSort; + +/** + * native map output collector wrapped in Java interface + */ +@InterfaceAudience.Private +public class NativeMapOutputCollectorDelegator implements MapOutputCollector { + + private static Log LOG = LogFactory.getLog(NativeMapOutputCollectorDelegator.class); + private JobConf job; + private NativeCollectorOnlyHandler handler; + + private Context context; + private StatusReportChecker updater; + + @Override + public void collect(K key, V value, int partition) throws IOException, InterruptedException { + handler.collect(key, value, partition); + } + + @Override + public void close() throws IOException, InterruptedException { + handler.close(); + if (null != updater) { + updater.stop(); + NativeRuntime.reportStatus(context.getReporter()); + } + } + + @Override + public void flush() throws IOException, InterruptedException, ClassNotFoundException { + handler.flush(); + } + + @SuppressWarnings("unchecked") + @Override + public void init(Context context) throws IOException, ClassNotFoundException { + this.context = context; + this.job = context.getJobConf(); + + Platforms.init(job); + + if (job.getNumReduceTasks() == 0) { + String message = "There is no reducer, no need to use native output collector"; + LOG.error(message); + throw new InvalidJobConfException(message); + } + + Class comparatorClass = job.getClass(MRJobConfig.KEY_COMPARATOR, null, + RawComparator.class); + if (comparatorClass != null && !Platforms.define(comparatorClass)) { + String message = "Native output collector doesn't support customized java comparator " + + job.get(MRJobConfig.KEY_COMPARATOR); + LOG.error(message); + throw new InvalidJobConfException(message); + } + + + + if (!QuickSort.class.getName().equals(job.get(Constants.MAP_SORT_CLASS))) { + String message = "Native-Task doesn't support sort class " + + job.get(Constants.MAP_SORT_CLASS); + LOG.error(message); + throw new InvalidJobConfException(message); + } + + if (job.getBoolean(MRConfig.SHUFFLE_SSL_ENABLED_KEY, false) == true) { + String message = "Native-Task doesn't support secure shuffle"; + LOG.error(message); + throw new InvalidJobConfException(message); + } + + final Class keyCls = job.getMapOutputKeyClass(); + try { + @SuppressWarnings("rawtypes") + final INativeSerializer serializer = NativeSerialization.getInstance().getSerializer(keyCls); + if (null == serializer) { + String message = "Key type not supported. Cannot find serializer for " + keyCls.getName(); + LOG.error(message); + throw new InvalidJobConfException(message); + } else if (!Platforms.support(keyCls.getName(), serializer, job)) { + String message = "Native output collector doesn't support this key, " + + "this key is not comparable in native: " + keyCls.getName(); + LOG.error(message); + throw new InvalidJobConfException(message); + } + } catch (final IOException e) { + String message = "Cannot find serializer for " + keyCls.getName(); + LOG.error(message); + throw new IOException(message); + } + + final boolean ret = NativeRuntime.isNativeLibraryLoaded(); + if (ret) { + if (job.getBoolean(MRJobConfig.MAP_OUTPUT_COMPRESS, false)) { + String codec = job.get(MRJobConfig.MAP_OUTPUT_COMPRESS_CODEC); + if (!NativeRuntime.supportsCompressionCodec(codec.getBytes(Charsets.UTF_8))) { + String message = "Native output collector doesn't support compression codec " + codec; + LOG.error(message); + throw new InvalidJobConfException(message); + } + } + NativeRuntime.configure(job); + + final long updateInterval = job.getLong(Constants.NATIVE_STATUS_UPDATE_INTERVAL, + Constants.NATIVE_STATUS_UPDATE_INTERVAL_DEFVAL); + updater = new StatusReportChecker(context.getReporter(), updateInterval); + updater.start(); + + } else { + String message = "NativeRuntime cannot be loaded, please check that " + + "libnativetask.so is in hadoop library dir"; + LOG.error(message); + throw new InvalidJobConfException(message); + } + + this.handler = null; + try { + final Class oKClass = (Class) job.getMapOutputKeyClass(); + final Class oVClass = (Class) job.getMapOutputValueClass(); + final TaskAttemptID id = context.getMapTask().getTaskID(); + final TaskContext taskContext = new TaskContext(job, null, null, oKClass, oVClass, + context.getReporter(), id); + handler = NativeCollectorOnlyHandler.create(taskContext); + } catch (final IOException e) { + String message = "Native output collector cannot be loaded;"; + LOG.error(message); + throw new IOException(message, e); + } + + LOG.info("Native output collector can be successfully enabled!"); + } + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeRuntime.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeRuntime.java new file mode 100644 index 00000000000..a0e88bd6249 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/NativeRuntime.java @@ -0,0 +1,197 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask; + +import java.io.IOException; + +import com.google.common.base.Charsets; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.io.DataInputBuffer; +import org.apache.hadoop.io.FloatWritable; +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapred.Task.TaskReporter; +import org.apache.hadoop.mapred.nativetask.util.ConfigUtil; +import org.apache.hadoop.util.VersionInfo; + +/** + * This class stands for the native runtime It has three functions: + * 1. Create native handlers for map, reduce, outputcollector, etc + * 2. Configure native task with provided MR configs + * 3. Provide file system api to native space, so that it can use File system like HDFS. + */ +@InterfaceAudience.Private +public class NativeRuntime { + private static Log LOG = LogFactory.getLog(NativeRuntime.class); + private static boolean nativeLibraryLoaded = false; + + private static Configuration conf = new Configuration(); + + static { + try { + System.loadLibrary("nativetask"); + LOG.info("Nativetask JNI library loaded."); + nativeLibraryLoaded = true; + } catch (final Throwable t) { + // Ignore failures + LOG.error("Failed to load nativetask JNI library with error: " + t); + LOG.info("java.library.path=" + System.getProperty("java.library.path")); + LOG.info("LD_LIBRARY_PATH=" + System.getenv("LD_LIBRARY_PATH")); + } + } + + private static void assertNativeLibraryLoaded() { + if (!nativeLibraryLoaded) { + throw new RuntimeException("Native runtime library not loaded"); + } + } + + public static boolean isNativeLibraryLoaded() { + return nativeLibraryLoaded; + } + + public static void configure(Configuration jobConf) { + assertNativeLibraryLoaded(); + conf = new Configuration(jobConf); + conf.set(Constants.NATIVE_HADOOP_VERSION, VersionInfo.getVersion()); + JNIConfigure(ConfigUtil.toBytes(conf)); + } + + /** + * create native object We use it to create native handlers + */ + public synchronized static long createNativeObject(String clazz) { + assertNativeLibraryLoaded(); + final long ret = JNICreateNativeObject(clazz.getBytes(Charsets.UTF_8)); + if (ret == 0) { + LOG.warn("Can't create NativeObject for class " + clazz + ", probably not exist."); + } + return ret; + } + + /** + * Register a customized library + */ + public synchronized static long registerLibrary(String libraryName, String clazz) { + assertNativeLibraryLoaded(); + final long ret = JNIRegisterModule(libraryName.getBytes(Charsets.UTF_8), + clazz.getBytes(Charsets.UTF_8)); + if (ret != 0) { + LOG.warn("Can't create NativeObject for class " + clazz + ", probably not exist."); + } + return ret; + } + + /** + * destroy native object We use to destory native handlers + */ + public synchronized static void releaseNativeObject(long addr) { + assertNativeLibraryLoaded(); + JNIReleaseNativeObject(addr); + } + + /** + * Get the status report from native space + */ + public static void reportStatus(TaskReporter reporter) throws IOException { + assertNativeLibraryLoaded(); + synchronized (reporter) { + final byte[] statusBytes = JNIUpdateStatus(); + final DataInputBuffer ib = new DataInputBuffer(); + ib.reset(statusBytes, statusBytes.length); + final FloatWritable progress = new FloatWritable(); + progress.readFields(ib); + reporter.setProgress(progress.get()); + final Text status = new Text(); + status.readFields(ib); + if (status.getLength() > 0) { + reporter.setStatus(status.toString()); + } + final IntWritable numCounters = new IntWritable(); + numCounters.readFields(ib); + if (numCounters.get() == 0) { + return; + } + final Text group = new Text(); + final Text name = new Text(); + final LongWritable amount = new LongWritable(); + for (int i = 0; i < numCounters.get(); i++) { + group.readFields(ib); + name.readFields(ib); + amount.readFields(ib); + reporter.incrCounter(group.toString(), name.toString(), amount.get()); + } + } + } + + + /******************************************************* + *** The following are JNI Apis + ********************************************************/ + + /** + * Check whether the native side has compression codec support built in + */ + public native static boolean supportsCompressionCodec(byte[] codec); + + /** + * Config the native runtime with mapreduce job configurations. + */ + private native static void JNIConfigure(byte[][] configs); + + /** + * create a native object in native space + */ + private native static long JNICreateNativeObject(byte[] clazz); + + /** + * create the default native object for certain type + */ + @Deprecated + private native static long JNICreateDefaultNativeObject(byte[] type); + + /** + * destroy native object in native space + */ + private native static void JNIReleaseNativeObject(long addr); + + /** + * Get status update from native side + * Encoding: + * progress:float + * status:Text + * number: int the count of the counters + * Counters: array [group:Text, name:Text, incrCount:Long] + */ + private native static byte[] JNIUpdateStatus(); + + /** + * Not used. + */ + private native static void JNIRelease(); + + /** + * Not used. + */ + private native static int JNIRegisterModule(byte[] path, byte[] name); +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/Platform.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/Platform.java new file mode 100644 index 00000000000..efec26c9619 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/Platform.java @@ -0,0 +1,100 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.mapred.JobConf; +import org.apache.hadoop.mapred.nativetask.serde.INativeSerializer; +import org.apache.hadoop.mapred.nativetask.serde.NativeSerialization; + +/** + * Base class for platforms. A platform is a framework running on top of + * MapReduce, like Hadoop, Hive, Pig, Mahout. Each framework defines its + * own key type and value type across a MapReduce job. For each platform, + * we should implement serializers such that we could communicate data with + * native side and native comparators so our native output collectors could + * sort them and write out. We've already provided the {@link HadoopPlatform} + * that supports all key types of Hadoop and users could implement their custom + * platform. + */ +@InterfaceAudience.Public +@InterfaceStability.Evolving +public abstract class Platform { + private final NativeSerialization serialization; + protected Set keyClassNames = new HashSet(); + + public Platform() { + this.serialization = NativeSerialization.getInstance(); + } + + /** + * initialize a platform, where we should call registerKey + */ + public abstract void init() throws IOException; + + /** + * @return name of a Platform, useful for logs and debug + */ + public abstract String name(); + + + /** + * associate a key class with its serializer and platform + * + * @param keyClassName map out key class name + * @param key key serializer class + */ + protected void registerKey(String keyClassName, Class key) throws IOException { + serialization.register(keyClassName, key); + keyClassNames.add(keyClassName); + } + + /** + * whether a platform supports a specific key should at least satisfy two conditions + * + * 1. the key belongs to the platform + * 2. the associated serializer must implement {@link INativeComparable} interface + * + * + * @param keyClassName map out put key class name + * @param serializer serializer associated with key via registerKey + * @param job job configuration + * @return true if the platform has implemented native comparators of the key and + * false otherwise + */ + protected abstract boolean support(String keyClassName, + INativeSerializer serializer, JobConf job); + + + /** + * whether it's the platform that has defined a custom Java comparator + * + * NativeTask doesn't support custom Java comparators + * (set with mapreduce.job.output.key.comparator.class) + * but a platform (e.g Pig) could also set that conf and implement native + * comparators so we shouldn't bail out. + * + * @param keyComparator comparator set with mapreduce.job.output.key.comparator.class + */ + protected abstract boolean define(Class keyComparator); +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/Platforms.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/Platforms.java new file mode 100644 index 00000000000..9fad3a5edd8 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/Platforms.java @@ -0,0 +1,79 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask; + +import java.io.IOException; +import java.util.ServiceLoader; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.mapred.JobConf; +import org.apache.hadoop.mapred.nativetask.serde.INativeSerializer; +import org.apache.hadoop.mapred.nativetask.serde.NativeSerialization; + + +/** + * this class will load in and init all platforms on classpath + * it is also the facade to check for key type support and other + * platform methods + */ +@InterfaceAudience.Private +public class Platforms { + + private static final Log LOG = LogFactory.getLog(Platforms.class); + private static final ServiceLoader platforms = ServiceLoader.load(Platform.class); + + public static void init(Configuration conf) throws IOException { + + NativeSerialization.getInstance().reset(); + synchronized (platforms) { + for (Platform platform : platforms) { + platform.init(); + } + } + } + + public static boolean support(String keyClassName, + INativeSerializer serializer, JobConf job) { + synchronized (platforms) { + for (Platform platform : platforms) { + if (platform.support(keyClassName, serializer, job)) { + LOG.debug("platform " + platform.name() + " support key class" + + keyClassName); + return true; + } + } + } + return false; + } + + public static boolean define(Class keyComparator) { + synchronized (platforms) { + for (Platform platform : platforms) { + if (platform.define(keyComparator)) { + LOG.debug("platform " + platform.name() + " define comparator " + + keyComparator.getName()); + return true; + } + } + } + return false; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/StatusReportChecker.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/StatusReportChecker.java new file mode 100644 index 00000000000..1e76d39036f --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/StatusReportChecker.java @@ -0,0 +1,99 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask; + +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.mapred.Task.TaskReporter; +import org.apache.hadoop.mapreduce.TaskCounter; +import org.apache.hadoop.mapreduce.lib.input.FileInputFormatCounter; + +/** + * Will periodically check status from native and report to MR framework. + * + */ +class StatusReportChecker implements Runnable { + + private static Log LOG = LogFactory.getLog(StatusReportChecker.class); + public static final int INTERVAL = 1000; // milliseconds + + private Thread checker; + private final TaskReporter reporter; + private final long interval; + + public StatusReportChecker(TaskReporter reporter) { + this(reporter, INTERVAL); + } + + public StatusReportChecker(TaskReporter reporter, long interval) { + this.reporter = reporter; + this.interval = interval; + } + + @Override + public void run() { + while (true) { + try { + Thread.sleep(interval); + } catch (final InterruptedException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("StatusUpdater thread exiting " + "since it got interrupted"); + } + break; + } + try { + NativeRuntime.reportStatus(reporter); + } catch (final IOException e) { + LOG.warn("Update native status got exception", e); + reporter.setStatus(e.toString()); + break; + } + } + } + + protected void initUsedCounters() { + reporter.getCounter(TaskCounter.MAP_INPUT_RECORDS); + reporter.getCounter(TaskCounter.MAP_OUTPUT_RECORDS); + reporter.getCounter(FileInputFormatCounter.BYTES_READ); + reporter.getCounter(TaskCounter.MAP_OUTPUT_BYTES); + reporter.getCounter(TaskCounter.MAP_OUTPUT_MATERIALIZED_BYTES); + reporter.getCounter(TaskCounter.COMBINE_INPUT_RECORDS); + reporter.getCounter(TaskCounter.COMBINE_OUTPUT_RECORDS); + reporter.getCounter(TaskCounter.SPILLED_RECORDS); + } + + public synchronized void start() { + if (checker == null) { + // init counters used by native side, + // so they will have correct display name + initUsedCounters(); + checker = new Thread(this); + checker.setDaemon(true); + checker.start(); + } + } + + public synchronized void stop() throws InterruptedException { + if (checker != null) { + checker.interrupt(); + checker.join(); + } + } +} \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/TaskContext.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/TaskContext.java new file mode 100644 index 00000000000..555ced1e04c --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/TaskContext.java @@ -0,0 +1,94 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.mapred.JobConf; +import org.apache.hadoop.mapred.Task.TaskReporter; +import org.apache.hadoop.mapred.TaskAttemptID; + +@InterfaceAudience.Private +public class TaskContext { + private final JobConf conf; + private Class iKClass; + private Class iVClass; + private Class oKClass; + private Class oVClass; + private final TaskReporter reporter; + private final TaskAttemptID taskAttemptID; + + public TaskContext(JobConf conf, Class iKClass, Class iVClass, + Class oKClass, Class oVClass, TaskReporter reporter, + TaskAttemptID id) { + this.conf = conf; + this.iKClass = iKClass; + this.iVClass = iVClass; + this.oKClass = oKClass; + this.oVClass = oVClass; + this.reporter = reporter; + this.taskAttemptID = id; + } + + public Class getInputKeyClass() { + return iKClass; + } + + public void setInputKeyClass(Class klass) { + this.iKClass = klass; + } + + public Class getInputValueClass() { + return iVClass; + } + + public void setInputValueClass(Class klass) { + this.iVClass = klass; + } + + public Class getOutputKeyClass() { + return this.oKClass; + } + + public void setOutputKeyClass(Class klass) { + this.oKClass = klass; + } + + public Class getOutputValueClass() { + return this.oVClass; + } + + public void setOutputValueClass(Class klass) { + this.oVClass = klass; + } + + public TaskReporter getTaskReporter() { + return this.reporter; + } + + public TaskAttemptID getTaskAttemptId() { + return this.taskAttemptID; + } + + public JobConf getConf() { + return this.conf; + } + + public TaskContext copyOf() { + return new TaskContext(conf, iKClass, iVClass, oKClass, oVClass, reporter, taskAttemptID); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/BufferType.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/BufferType.java new file mode 100644 index 00000000000..bbdcd546d81 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/BufferType.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.buffer; + +import org.apache.hadoop.classification.InterfaceAudience; + +@InterfaceAudience.Private +public enum BufferType { + DIRECT_BUFFER, + HEAP_BUFFER +}; \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/ByteBufferDataReader.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/ByteBufferDataReader.java new file mode 100644 index 00000000000..72c65f57d3d --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/ByteBufferDataReader.java @@ -0,0 +1,148 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.buffer; + +import java.io.EOFException; +import java.io.IOException; +import java.nio.ByteBuffer; +import org.apache.hadoop.classification.InterfaceAudience; + +/** + * read data from a input buffer + */ +@InterfaceAudience.Private +public class ByteBufferDataReader extends DataInputStream { + private ByteBuffer byteBuffer; + private java.io.DataInputStream javaReader; + + public ByteBufferDataReader(InputBuffer buffer) { + if (buffer != null) { + reset(buffer); + } + javaReader = new java.io.DataInputStream(this); + } + + public void reset(InputBuffer buffer) { + this.byteBuffer = buffer.getByteBuffer(); + } + + @Override + public int read() throws IOException { + return byteBuffer.get(); + } + + @Override + public int read(byte b[], int off, int len) throws IOException { + byteBuffer.get(b, off, len); + return len; + } + + @Override + public void readFully(byte[] b) throws IOException { + byteBuffer.get(b, 0, b.length); + } + + @Override + public void readFully(byte[] b, int off, int len) throws IOException { + byteBuffer.get(b, off, len); + } + + @Override + public int skipBytes(int n) throws IOException { + final int remains = byteBuffer.remaining(); + final int skip = (remains < n) ? remains : n; + final int current = byteBuffer.position(); + byteBuffer.position(current + skip); + return skip; + } + + @Override + public boolean readBoolean() throws IOException { + return (byteBuffer.get() == 1) ? true : false; + } + + @Override + public byte readByte() throws IOException { + return byteBuffer.get(); + } + + @Override + public int readUnsignedByte() throws IOException { + final int ch = byteBuffer.get(); + if (ch < 0) { + throw new EOFException(); + } + return ch; + } + + @Override + public short readShort() throws IOException { + return byteBuffer.getShort(); + } + + @Override + public int readUnsignedShort() throws IOException { + return byteBuffer.getShort(); + } + + @Override + public char readChar() throws IOException { + return byteBuffer.getChar(); + } + + @Override + public int readInt() throws IOException { + return byteBuffer.getInt(); + } + + @Override + public long readLong() throws IOException { + return byteBuffer.getLong(); + } + + @Override + public float readFloat() throws IOException { + return byteBuffer.getFloat(); + } + + @Override + public double readDouble() throws IOException { + return byteBuffer.getDouble(); + } + + @SuppressWarnings("deprecation") + @Override + public String readLine() throws IOException { + return javaReader.readLine(); + } + + @Override + public final String readUTF() throws IOException { + return javaReader.readUTF(); + } + + @Override + public void close() throws IOException { + super.close(); + } + + @Override + public boolean hasUnReadData() { + return null != byteBuffer && byteBuffer.hasRemaining(); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/ByteBufferDataWriter.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/ByteBufferDataWriter.java new file mode 100644 index 00000000000..3d8f78b66a7 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/ByteBufferDataWriter.java @@ -0,0 +1,169 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.buffer; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.mapred.nativetask.NativeDataTarget; + +import com.google.common.base.Preconditions; + +/** + * DataOutputStream implementation which buffers data in a fixed-size + * ByteBuffer. + * When the byte buffer has filled up, synchronously passes the buffer + * to a downstream NativeDataTarget. + */ +@InterfaceAudience.Private +public class ByteBufferDataWriter extends DataOutputStream { + private final ByteBuffer buffer; + private final NativeDataTarget target; + + private final static byte TRUE = (byte) 1; + private final static byte FALSE = (byte) 0; + private final java.io.DataOutputStream javaWriter; + + private void checkSizeAndFlushIfNecessary(int length) throws IOException { + if (buffer.position() > 0 && buffer.remaining() < length) { + flush(); + } + } + + public ByteBufferDataWriter(NativeDataTarget handler) { + Preconditions.checkNotNull(handler); + this.buffer = handler.getOutputBuffer().getByteBuffer(); + this.target = handler; + this.javaWriter = new java.io.DataOutputStream(this); + } + + @Override + public synchronized void write(int v) throws IOException { + checkSizeAndFlushIfNecessary(1); + buffer.put((byte) v); + } + + @Override + public boolean shortOfSpace(int dataLength) throws IOException { + if (buffer.remaining() < dataLength) { + return true; + } + return false; + } + + @Override + public synchronized void write(byte b[], int off, int len) throws IOException { + int remain = len; + int offset = off; + while (remain > 0) { + int currentFlush = 0; + if (buffer.remaining() > 0) { + currentFlush = Math.min(buffer.remaining(), remain); + buffer.put(b, offset, currentFlush); + remain -= currentFlush; + offset += currentFlush; + } else { + flush(); + } + } + } + + @Override + public void flush() throws IOException { + target.sendData(); + buffer.position(0); + } + + @Override + public void close() throws IOException { + if (hasUnFlushedData()) { + flush(); + } + target.finishSendData(); + } + + @Override + public final void writeBoolean(boolean v) throws IOException { + checkSizeAndFlushIfNecessary(1); + buffer.put(v ? TRUE : FALSE); + } + + @Override + public final void writeByte(int v) throws IOException { + checkSizeAndFlushIfNecessary(1); + buffer.put((byte) v); + } + + @Override + public final void writeShort(int v) throws IOException { + checkSizeAndFlushIfNecessary(2); + buffer.putShort((short) v); + } + + @Override + public final void writeChar(int v) throws IOException { + checkSizeAndFlushIfNecessary(2); + buffer.put((byte) ((v >>> 8) & 0xFF)); + buffer.put((byte) ((v >>> 0) & 0xFF)); + } + + @Override + public final void writeInt(int v) throws IOException { + checkSizeAndFlushIfNecessary(4); + buffer.putInt(v); + } + + @Override + public final void writeLong(long v) throws IOException { + checkSizeAndFlushIfNecessary(8); + buffer.putLong(v); + } + + @Override + public final void writeFloat(float v) throws IOException { + checkSizeAndFlushIfNecessary(4); + writeInt(Float.floatToIntBits(v)); + } + + @Override + public final void writeDouble(double v) throws IOException { + checkSizeAndFlushIfNecessary(8); + writeLong(Double.doubleToLongBits(v)); + } + + @Override + public final void writeBytes(String s) throws IOException { + javaWriter.writeBytes(s); + } + + @Override + public final void writeChars(String s) throws IOException { + javaWriter.writeChars(s); + } + + @Override + public final void writeUTF(String str) throws IOException { + javaWriter.writeUTF(str); + } + + @Override + public boolean hasUnFlushedData() { + return buffer.position() > 0; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/DataInputStream.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/DataInputStream.java new file mode 100644 index 00000000000..be17ef49d5a --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/DataInputStream.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.buffer; + +import java.io.DataInput; +import java.io.InputStream; +import org.apache.hadoop.classification.InterfaceAudience; + +@InterfaceAudience.Private +public abstract class DataInputStream extends InputStream implements DataInput { + public abstract boolean hasUnReadData(); +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/DataOutputStream.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/DataOutputStream.java new file mode 100644 index 00000000000..38f9dcbce73 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/DataOutputStream.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.buffer; + +import java.io.DataOutput; +import java.io.IOException; +import java.io.OutputStream; + +import org.apache.hadoop.classification.InterfaceAudience; + +@InterfaceAudience.Private +public abstract class DataOutputStream extends OutputStream implements DataOutput { + /** + * Check whether this buffer has enough space to store length of bytes + * + * @param length length of bytes + */ + public abstract boolean shortOfSpace(int length) throws IOException; + + /** + * Check whether there is unflushed data stored in the stream + */ + public abstract boolean hasUnFlushedData(); +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/InputBuffer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/InputBuffer.java new file mode 100644 index 00000000000..2120c6cf887 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/InputBuffer.java @@ -0,0 +1,136 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.buffer; + +import org.apache.hadoop.util.DirectBufferPool; +import org.apache.hadoop.classification.InterfaceAudience; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +@InterfaceAudience.Private +public class InputBuffer implements Closeable { + + static DirectBufferPool bufferPool = new DirectBufferPool(); + + private ByteBuffer byteBuffer; + private final BufferType type; + + public InputBuffer(BufferType type, int inputSize) throws IOException { + + final int capacity = inputSize; + this.type = type; + + if (capacity > 0) { + + switch (type) { + case DIRECT_BUFFER: + this.byteBuffer = bufferPool.getBuffer(capacity); + this.byteBuffer.order(ByteOrder.BIG_ENDIAN); + break; + case HEAP_BUFFER: + this.byteBuffer = ByteBuffer.allocate(capacity); + this.byteBuffer.order(ByteOrder.BIG_ENDIAN); + break; + } + byteBuffer.position(0); + byteBuffer.limit(0); + } + } + + public BufferType getType() { + return this.type; + } + + public InputBuffer(byte[] bytes) { + this.type = BufferType.HEAP_BUFFER; + if (bytes.length > 0) { + this.byteBuffer = ByteBuffer.wrap(bytes); + this.byteBuffer.order(ByteOrder.BIG_ENDIAN); + byteBuffer.position(0); + byteBuffer.limit(0); + } + } + + public ByteBuffer getByteBuffer() { + return this.byteBuffer; + } + + public int length() { + if (null == byteBuffer) { + return 0; + } + return byteBuffer.limit(); + } + + public void rewind(int startOffset, int length) { + if (null == byteBuffer) { + return; + } + byteBuffer.position(startOffset); + byteBuffer.limit(length); + } + + public int remaining() { + if (null == byteBuffer) { + return 0; + } + return byteBuffer.remaining(); + } + + public int position() { + if (null == byteBuffer) { + return 0; + } + return byteBuffer.position(); + } + + public int position(int pos) { + if (null == byteBuffer) { + return 0; + } + + byteBuffer.position(pos); + return pos; + } + + public int capacity() { + if (null == byteBuffer) { + return 0; + } + return byteBuffer.capacity(); + } + + public byte[] array() { + if (null == byteBuffer) { + return null; + } + return byteBuffer.array(); + } + + @Override + public void close() { + if (byteBuffer != null && byteBuffer.isDirect()) { + bufferPool.returnBuffer(byteBuffer); + byteBuffer = null; + } + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/OutputBuffer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/OutputBuffer.java new file mode 100644 index 00000000000..8f33946feef --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/buffer/OutputBuffer.java @@ -0,0 +1,76 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.buffer; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import org.apache.hadoop.classification.InterfaceAudience; + +@InterfaceAudience.Private +public class OutputBuffer { + protected ByteBuffer byteBuffer; + private final BufferType type; + + public OutputBuffer(BufferType type, int outputBufferCapacity) { + + this.type = type; + if (outputBufferCapacity > 0) { + switch (type) { + case DIRECT_BUFFER: + this.byteBuffer = ByteBuffer.allocateDirect(outputBufferCapacity); + this.byteBuffer.order(ByteOrder.BIG_ENDIAN); + break; + case HEAP_BUFFER: + this.byteBuffer = ByteBuffer.allocate(outputBufferCapacity); + this.byteBuffer.order(ByteOrder.BIG_ENDIAN); + break; + } + } + } + + public OutputBuffer(byte[] bytes) { + this.type = BufferType.HEAP_BUFFER; + final int outputBufferCapacity = bytes.length; + if (outputBufferCapacity > 0) { + this.byteBuffer = ByteBuffer.wrap(bytes); + this.byteBuffer.order(ByteOrder.BIG_ENDIAN); + this.byteBuffer.position(0); + } + } + + public BufferType getType() { + return this.type; + } + + public ByteBuffer getByteBuffer() { + return this.byteBuffer; + } + + public int length() { + return byteBuffer.position(); + } + + public void rewind() { + byteBuffer.position(0); + } + + public int limit() { + return byteBuffer.limit(); + } +} \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/BufferPullee.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/BufferPullee.java new file mode 100644 index 00000000000..9fd7a0488c2 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/BufferPullee.java @@ -0,0 +1,121 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.handlers; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.mapred.RawKeyValueIterator; +import org.apache.hadoop.mapred.nativetask.Constants; +import org.apache.hadoop.mapred.nativetask.NativeDataTarget; +import org.apache.hadoop.mapred.nativetask.buffer.ByteBufferDataWriter; +import org.apache.hadoop.mapred.nativetask.buffer.OutputBuffer; +import org.apache.hadoop.mapred.nativetask.serde.KVSerializer; +import org.apache.hadoop.mapred.nativetask.util.SizedWritable; + +/** + * load data into a buffer signaled by a {@link BufferPuller} + */ +@InterfaceAudience.Private +public class BufferPullee implements IDataLoader { + + public static final int KV_HEADER_LENGTH = Constants.SIZEOF_KV_LENGTH; + + private final SizedWritable tmpInputKey; + private final SizedWritable tmpInputValue; + private boolean inputKVBufferd = false; + private RawKeyValueIterator rIter; + private ByteBufferDataWriter nativeWriter; + protected KVSerializer serializer; + private final OutputBuffer outputBuffer; + private final NativeDataTarget target; + private boolean closed = false; + + public BufferPullee(Class iKClass, Class iVClass, + RawKeyValueIterator rIter, NativeDataTarget target) + throws IOException { + this.rIter = rIter; + tmpInputKey = new SizedWritable(iKClass); + tmpInputValue = new SizedWritable(iVClass); + + if (null != iKClass && null != iVClass) { + this.serializer = new KVSerializer(iKClass, iVClass); + } + this.outputBuffer = target.getOutputBuffer(); + this.target = target; + } + + @Override + public int load() throws IOException { + if (closed) { + return 0; + } + + if (null == outputBuffer) { + throw new IOException("output buffer not set"); + } + + this.nativeWriter = new ByteBufferDataWriter(target); + outputBuffer.rewind(); + + int written = 0; + boolean firstKV = true; + + if (inputKVBufferd) { + written += serializer.serializeKV(nativeWriter, tmpInputKey, tmpInputValue); + inputKVBufferd = false; + firstKV = false; + } + + while (rIter.next()) { + inputKVBufferd = false; + tmpInputKey.readFields(rIter.getKey()); + tmpInputValue.readFields(rIter.getValue()); + serializer.updateLength(tmpInputKey, tmpInputValue); + + final int kvSize = tmpInputKey.length + tmpInputValue.length + KV_HEADER_LENGTH; + + if (!firstKV && nativeWriter.shortOfSpace(kvSize)) { + inputKVBufferd = true; + break; + } else { + written += serializer.serializeKV(nativeWriter, tmpInputKey, tmpInputValue); + firstKV = false; + } + } + + if (nativeWriter.hasUnFlushedData()) { + nativeWriter.flush(); + } + return written; + } + + @Override + public void close() throws IOException { + if (closed) { + return; + } + if (null != rIter) { + rIter.close(); + } + if (null != nativeWriter) { + nativeWriter.close(); + } + closed = true; + } +} \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/BufferPuller.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/BufferPuller.java new file mode 100644 index 00000000000..b5dff9291d9 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/BufferPuller.java @@ -0,0 +1,203 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.handlers; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.DataInputBuffer; +import org.apache.hadoop.mapred.RawKeyValueIterator; +import org.apache.hadoop.mapred.nativetask.Constants; +import org.apache.hadoop.mapred.nativetask.DataReceiver; +import org.apache.hadoop.mapred.nativetask.NativeDataSource; +import org.apache.hadoop.mapred.nativetask.buffer.BufferType; +import org.apache.hadoop.mapred.nativetask.buffer.ByteBufferDataReader; +import org.apache.hadoop.mapred.nativetask.buffer.InputBuffer; +import org.apache.hadoop.util.Progress; + +/** + * actively signal a {@link BufferPullee} to load data into buffer and receive + */ +@InterfaceAudience.Private +public class BufferPuller implements RawKeyValueIterator, DataReceiver { + + private static Log LOG = LogFactory.getLog(BufferPuller.class); + + public final static int KV_HEADER_LENGTH = Constants.SIZEOF_KV_LENGTH; + + byte[] keyBytes = new byte[0]; + byte[] valueBytes = new byte[0]; + + private InputBuffer inputBuffer; + private InputBuffer asideBuffer; + + int remain = 0; + + private ByteBufferDataReader nativeReader; + + DataInputBuffer keyBuffer = new DataInputBuffer(); + DataInputBuffer valueBuffer = new DataInputBuffer(); + + private boolean noMoreData = false; + + private NativeDataSource input; + private boolean closed = false; + + public BufferPuller(NativeDataSource handler) throws IOException { + this.input = handler; + this.inputBuffer = handler.getInputBuffer(); + nativeReader = new ByteBufferDataReader(null); + this.asideBuffer = new InputBuffer(BufferType.HEAP_BUFFER, inputBuffer.capacity()); + } + + @Override + public DataInputBuffer getKey() throws IOException { + return keyBuffer; + } + + @Override + public DataInputBuffer getValue() throws IOException { + return valueBuffer; + } + + public void reset() { + noMoreData = false; + } + + @Override + public boolean next() throws IOException { + if (closed) { + return false; + } + + if (noMoreData) { + return false; + } + final int asideRemain = asideBuffer.remaining(); + final int inputRemain = inputBuffer.remaining(); + + if (asideRemain == 0 && inputRemain == 0) { + input.loadData(); + } + + if (asideBuffer.remaining() > 0) { + return nextKeyValue(asideBuffer); + } else if (inputBuffer.remaining() > 0) { + return nextKeyValue(inputBuffer); + } else { + noMoreData = true; + return false; + } + } + + private boolean nextKeyValue(InputBuffer buffer) throws IOException { + if (closed) { + return false; + } + + nativeReader.reset(buffer); + + final int keyLength = nativeReader.readInt(); + if (keyBytes.length < keyLength) { + keyBytes = new byte[keyLength]; + } + + final int valueLength = nativeReader.readInt(); + if (valueBytes.length < valueLength) { + valueBytes = new byte[valueLength]; + } + + IOUtils.readFully(nativeReader, keyBytes, 0, keyLength); + IOUtils.readFully(nativeReader, valueBytes, 0, valueLength); + + keyBuffer.reset(keyBytes, keyLength); + valueBuffer.reset(valueBytes, valueLength); + + return true; + } + + @Override + public boolean receiveData() throws IOException { + if (closed) { + return false; + } + + final ByteBuffer input = inputBuffer.getByteBuffer(); + + if (null != asideBuffer && asideBuffer.length() > 0) { + if (asideBuffer.remaining() > 0) { + final byte[] output = asideBuffer.getByteBuffer().array(); + final int write = Math.min(asideBuffer.remaining(), input.remaining()); + input.get(output, asideBuffer.position(), write); + asideBuffer.position(asideBuffer.position() + write); + } + + if (asideBuffer.remaining() == 0) { + asideBuffer.position(0); + } + } + + if (input.remaining() == 0) { + return true; + } + + if (input.remaining() < KV_HEADER_LENGTH) { + throw new IOException("incomplete data, input length is: " + input.remaining()); + } + final int position = input.position(); + final int keyLength = input.getInt(); + final int valueLength = input.getInt(); + input.position(position); + final int kvLength = keyLength + valueLength + KV_HEADER_LENGTH; + final int remaining = input.remaining(); + + if (kvLength > remaining) { + if (null == asideBuffer || asideBuffer.capacity() < kvLength) { + asideBuffer = new InputBuffer(BufferType.HEAP_BUFFER, kvLength); + } + asideBuffer.rewind(0, kvLength); + + input.get(asideBuffer.array(), 0, remaining); + asideBuffer.position(remaining); + } + return true; + } + + @Override + public Progress getProgress() { + return null; + } + + /** + * Closes the iterator so that the underlying streams can be closed. + */ + @Override + public void close() throws IOException { + if (closed) { + return; + } + if (null != nativeReader) { + nativeReader.close(); + } + closed = true; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/BufferPushee.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/BufferPushee.java new file mode 100644 index 00000000000..090882d1922 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/BufferPushee.java @@ -0,0 +1,151 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.handlers; + +import java.io.Closeable; +import java.io.IOException; +import java.nio.ByteBuffer; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.mapred.RecordWriter; +import org.apache.hadoop.mapred.nativetask.Constants; +import org.apache.hadoop.mapred.nativetask.buffer.BufferType; +import org.apache.hadoop.mapred.nativetask.buffer.ByteBufferDataReader; +import org.apache.hadoop.mapred.nativetask.buffer.InputBuffer; +import org.apache.hadoop.mapred.nativetask.serde.KVSerializer; +import org.apache.hadoop.mapred.nativetask.util.SizedWritable; + +/** + * collect data when signaled + */ +@InterfaceAudience.Private +public class BufferPushee implements Closeable { + + private static Log LOG = LogFactory.getLog(BufferPushee.class); + + public final static int KV_HEADER_LENGTH = Constants.SIZEOF_KV_LENGTH; + + private InputBuffer asideBuffer; + private final SizedWritable tmpOutputKey; + private final SizedWritable tmpOutputValue; + private RecordWriter writer; + private ByteBufferDataReader nativeReader; + + private KVSerializer deserializer; + private boolean closed = false; + + public BufferPushee(Class oKClass, Class oVClass, + RecordWriter writer) throws IOException { + tmpOutputKey = new SizedWritable(oKClass); + tmpOutputValue = new SizedWritable(oVClass); + + this.writer = writer; + + if (null != oKClass && null != oVClass) { + this.deserializer = new KVSerializer(oKClass, oVClass); + } + this.nativeReader = new ByteBufferDataReader(null); + } + + public boolean collect(InputBuffer buffer) throws IOException { + if (closed) { + return false; + } + + final ByteBuffer input = buffer.getByteBuffer(); + if (null != asideBuffer && asideBuffer.length() > 0) { + if (asideBuffer.remaining() > 0) { + final byte[] output = asideBuffer.getByteBuffer().array(); + final int write = Math.min(asideBuffer.remaining(), input.remaining()); + input.get(output, asideBuffer.position(), write); + asideBuffer.position(asideBuffer.position() + write); + } + + if (asideBuffer.remaining() == 0 && asideBuffer.position() > 0) { + asideBuffer.position(0); + write(asideBuffer); + asideBuffer.rewind(0, 0); + } + } + + if (input.remaining() == 0) { + return true; + } + + if (input.remaining() < KV_HEADER_LENGTH) { + throw new IOException("incomplete data, input length is: " + input.remaining()); + } + final int position = input.position(); + final int keyLength = input.getInt(); + final int valueLength = input.getInt(); + input.position(position); + final int kvLength = keyLength + valueLength + KV_HEADER_LENGTH; + final int remaining = input.remaining(); + + if (kvLength > remaining) { + if (null == asideBuffer || asideBuffer.capacity() < kvLength) { + asideBuffer = new InputBuffer(BufferType.HEAP_BUFFER, kvLength); + } + asideBuffer.rewind(0, kvLength); + + input.get(asideBuffer.array(), 0, remaining); + asideBuffer.position(remaining); + } else { + write(buffer); + } + return true; + } + + @SuppressWarnings("unchecked") + private boolean write(InputBuffer input) throws IOException { + if (closed) { + return false; + } + int totalRead = 0; + final int remain = input.remaining(); + this.nativeReader.reset(input); + while (remain > totalRead) { + final int read = deserializer.deserializeKV(nativeReader, tmpOutputKey, tmpOutputValue); + if (read != 0) { + totalRead += read; + writer.write((OK) (tmpOutputKey.v), (OV) (tmpOutputValue.v)); + } + } + if (remain != totalRead) { + throw new IOException("We expect to read " + remain + + ", but we actually read: " + totalRead); + } + return true; + } + + @Override + public void close() throws IOException { + if (closed) { + return; + } + if (null != writer) { + writer.close(null); + } + if (null != nativeReader) { + nativeReader.close(); + } + closed = true; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/BufferPusher.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/BufferPusher.java new file mode 100644 index 00000000000..454127cef93 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/BufferPusher.java @@ -0,0 +1,91 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.handlers; + +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.mapred.OutputCollector; +import org.apache.hadoop.mapred.nativetask.NativeDataTarget; +import org.apache.hadoop.mapred.nativetask.buffer.ByteBufferDataWriter; +import org.apache.hadoop.mapred.nativetask.serde.IKVSerializer; +import org.apache.hadoop.mapred.nativetask.serde.KVSerializer; +import org.apache.hadoop.mapred.nativetask.util.SizedWritable; + +/** + * actively push data into a buffer and signal a {@link BufferPushee} to collect it + */ +@InterfaceAudience.Private +public class BufferPusher implements OutputCollector { + + private static Log LOG = LogFactory.getLog(BufferPusher.class); + + private final SizedWritable tmpInputKey; + private final SizedWritable tmpInputValue; + private ByteBufferDataWriter out; + IKVSerializer serializer; + private boolean closed = false; + + public BufferPusher(Class iKClass, Class iVClass, + NativeDataTarget target) throws IOException { + tmpInputKey = new SizedWritable(iKClass); + tmpInputValue = new SizedWritable(iVClass); + + if (null != iKClass && null != iVClass) { + this.serializer = new KVSerializer(iKClass, iVClass); + } + this.out = new ByteBufferDataWriter(target); + } + + public void collect(K key, V value, int partition) throws IOException { + tmpInputKey.reset(key); + tmpInputValue.reset(value); + serializer.serializePartitionKV(out, partition, tmpInputKey, tmpInputValue); + }; + + @Override + public void collect(K key, V value) throws IOException { + if (closed) { + return; + } + tmpInputKey.reset(key); + tmpInputValue.reset(value); + serializer.serializeKV(out, tmpInputKey, tmpInputValue); + }; + + public void flush() throws IOException { + if (null != out) { + if (out.hasUnFlushedData()) { + out.flush(); + } + } + } + + public void close() throws IOException { + if (closed) { + return; + } + if (null != out) { + out.close(); + } + closed = true; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/CombinerHandler.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/CombinerHandler.java new file mode 100644 index 00000000000..fcaeca19595 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/CombinerHandler.java @@ -0,0 +1,145 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.handlers; + +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.mapred.Counters.Counter; +import org.apache.hadoop.mapred.JobConf; +import org.apache.hadoop.mapred.Task.CombinerRunner; +import org.apache.hadoop.mapred.nativetask.Command; +import org.apache.hadoop.mapred.nativetask.CommandDispatcher; +import org.apache.hadoop.mapred.nativetask.Constants; +import org.apache.hadoop.mapred.nativetask.DataChannel; +import org.apache.hadoop.mapred.nativetask.ICombineHandler; +import org.apache.hadoop.mapred.nativetask.INativeHandler; +import org.apache.hadoop.mapred.nativetask.NativeBatchProcessor; +import org.apache.hadoop.mapred.nativetask.TaskContext; +import org.apache.hadoop.mapred.nativetask.serde.SerializationFramework; +import org.apache.hadoop.mapred.nativetask.util.ReadWriteBuffer; +import org.apache.hadoop.mapreduce.MRJobConfig; +import org.apache.hadoop.mapreduce.TaskCounter; + +class CombinerHandler implements ICombineHandler, CommandDispatcher { + public static final String NAME = "NativeTask.CombineHandler"; + private static Log LOG = LogFactory.getLog(NativeCollectorOnlyHandler.class); + public static final Command LOAD = new Command(1, "Load"); + public static final Command COMBINE = new Command(4, "Combine"); + public final CombinerRunner combinerRunner; + + private final INativeHandler nativeHandler; + private final BufferPuller puller; + private final BufferPusher kvPusher; + private boolean closed = false; + + public static ICombineHandler create(TaskContext context) + throws IOException, ClassNotFoundException { + final JobConf conf = new JobConf(context.getConf()); + conf.set(Constants.SERIALIZATION_FRAMEWORK, + String.valueOf(SerializationFramework.WRITABLE_SERIALIZATION.getType())); + String combinerClazz = conf.get(Constants.MAPRED_COMBINER_CLASS); + if (null == combinerClazz) { + combinerClazz = conf.get(MRJobConfig.COMBINE_CLASS_ATTR); + } + + if (null == combinerClazz) { + return null; + } else { + LOG.info("NativeTask Combiner is enabled, class = " + combinerClazz); + } + + final Counter combineInputCounter = context.getTaskReporter().getCounter( + TaskCounter.COMBINE_INPUT_RECORDS); + + final CombinerRunner combinerRunner = CombinerRunner.create( + conf, context.getTaskAttemptId(), + combineInputCounter, context.getTaskReporter(), null); + + final INativeHandler nativeHandler = NativeBatchProcessor.create( + NAME, conf, DataChannel.INOUT); + @SuppressWarnings("unchecked") + final BufferPusher pusher = new BufferPusher((Class)context.getInputKeyClass(), + (Class)context.getInputValueClass(), + nativeHandler); + final BufferPuller puller = new BufferPuller(nativeHandler); + return new CombinerHandler(nativeHandler, combinerRunner, puller, pusher); + } + + public CombinerHandler(INativeHandler nativeHandler, CombinerRunner combiner, + BufferPuller puller, BufferPusher kvPusher) + throws IOException { + this.nativeHandler = nativeHandler; + this.combinerRunner = combiner; + this.puller = puller; + this.kvPusher = kvPusher; + nativeHandler.setCommandDispatcher(this); + nativeHandler.setDataReceiver(puller); + } + + @Override + public ReadWriteBuffer onCall(Command command, ReadWriteBuffer parameter) throws IOException { + if (null == command) { + return null; + } + if (command.equals(COMBINE)) { + combine(); + } + return null; + + } + + @Override + public void combine() throws IOException{ + try { + puller.reset(); + combinerRunner.combine(puller, kvPusher); + kvPusher.flush(); + return; + } catch (Exception e) { + throw new IOException(e); + } + } + + @Override + public long getId() { + return nativeHandler.getNativeHandler(); + } + + @Override + public void close() throws IOException { + + if (closed) { + return; + } + + if (null != puller) { + puller.close(); + } + + if (null != kvPusher) { + kvPusher.close(); + } + + if (null != nativeHandler) { + nativeHandler.close(); + } + closed = true; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/IDataLoader.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/IDataLoader.java new file mode 100644 index 00000000000..6eaf28bc792 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/IDataLoader.java @@ -0,0 +1,37 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.handlers; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; + +/** + * an IDataLoader loads data on demand + */ +@InterfaceAudience.Private +public interface IDataLoader { + + /** + * @return size of data loaded + */ + public int load() throws IOException; + + public void close() throws IOException; +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/NativeCollectorOnlyHandler.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/NativeCollectorOnlyHandler.java new file mode 100644 index 00000000000..34238ae2b88 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/handlers/NativeCollectorOnlyHandler.java @@ -0,0 +1,171 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.handlers; + +import java.io.Closeable; +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.mapred.TaskAttemptID; +import org.apache.hadoop.mapred.nativetask.Command; +import org.apache.hadoop.mapred.nativetask.CommandDispatcher; +import org.apache.hadoop.mapred.nativetask.DataChannel; +import org.apache.hadoop.mapred.nativetask.ICombineHandler; +import org.apache.hadoop.mapred.nativetask.INativeHandler; +import org.apache.hadoop.mapred.nativetask.NativeBatchProcessor; +import org.apache.hadoop.mapred.nativetask.TaskContext; +import org.apache.hadoop.mapred.nativetask.util.NativeTaskOutput; +import org.apache.hadoop.mapred.nativetask.util.OutputUtil; +import org.apache.hadoop.mapred.nativetask.util.ReadWriteBuffer; + +/** + * Java Record Reader + Java Mapper + Native Collector + */ +@SuppressWarnings("unchecked") +@InterfaceAudience.Private +public class NativeCollectorOnlyHandler implements CommandDispatcher, Closeable { + + public static final String NAME = "NativeTask.MCollectorOutputHandler"; + private static Log LOG = LogFactory.getLog(NativeCollectorOnlyHandler.class); + public static final Command GET_OUTPUT_PATH = + new Command(100, "GET_OUTPUT_PATH"); + public static final Command GET_OUTPUT_INDEX_PATH = + new Command(101, "GET_OUTPUT_INDEX_PATH"); + public static final Command GET_SPILL_PATH = + new Command(102, "GET_SPILL_PATH"); + public static final Command GET_COMBINE_HANDLER = + new Command(103, "GET_COMBINE_HANDLER"); + + private NativeTaskOutput output; + private int spillNumber = 0; + private ICombineHandler combinerHandler = null; + private final BufferPusher kvPusher; + private final INativeHandler nativeHandler; + private boolean closed = false; + + public static NativeCollectorOnlyHandler create(TaskContext context) + throws IOException { + + + ICombineHandler combinerHandler = null; + try { + final TaskContext combineContext = context.copyOf(); + combineContext.setInputKeyClass(context.getOutputKeyClass()); + combineContext.setInputValueClass(context.getOutputValueClass()); + + combinerHandler = CombinerHandler.create(combineContext); + } catch (final ClassNotFoundException e) { + throw new IOException(e); + } + + if (null != combinerHandler) { + LOG.info("[NativeCollectorOnlyHandler] combiner is not null"); + } + + final INativeHandler nativeHandler = NativeBatchProcessor.create( + NAME, context.getConf(), DataChannel.OUT); + final BufferPusher kvPusher = new BufferPusher( + (Class)context.getOutputKeyClass(), + (Class)context.getOutputValueClass(), + nativeHandler); + + return new NativeCollectorOnlyHandler(context, nativeHandler, kvPusher, combinerHandler); + } + + protected NativeCollectorOnlyHandler(TaskContext context, INativeHandler nativeHandler, + BufferPusher kvPusher, ICombineHandler combiner) throws IOException { + Configuration conf = context.getConf(); + TaskAttemptID id = context.getTaskAttemptId(); + if (null == id) { + this.output = OutputUtil.createNativeTaskOutput(conf, ""); + } else { + this.output = OutputUtil.createNativeTaskOutput(context.getConf(), context.getTaskAttemptId() + .toString()); + } + this.combinerHandler = combiner; + this.kvPusher = kvPusher; + this.nativeHandler = nativeHandler; + nativeHandler.setCommandDispatcher(this); + } + + public void collect(K key, V value, int partition) throws IOException { + kvPusher.collect(key, value, partition); + }; + + public void flush() throws IOException { + } + + @Override + public void close() throws IOException { + if (closed) { + return; + } + + if (null != kvPusher) { + kvPusher.close(); + } + + if (null != combinerHandler) { + combinerHandler.close(); + } + + if (null != nativeHandler) { + nativeHandler.close(); + } + closed = true; + } + + @Override + public ReadWriteBuffer onCall(Command command, ReadWriteBuffer parameter) throws IOException { + Path p = null; + if (null == command) { + return null; + } + + if (command.equals(GET_OUTPUT_PATH)) { + p = output.getOutputFileForWrite(-1); + } else if (command.equals(GET_OUTPUT_INDEX_PATH)) { + p = output.getOutputIndexFileForWrite(-1); + } else if (command.equals(GET_SPILL_PATH)) { + p = output.getSpillFileForWrite(spillNumber++, -1); + + } else if (command.equals(GET_COMBINE_HANDLER)) { + if (null == combinerHandler) { + return null; + } + final ReadWriteBuffer result = new ReadWriteBuffer(8); + + result.writeLong(combinerHandler.getId()); + return result; + } else { + throw new IOException("Illegal command: " + command.toString()); + } + if (p != null) { + final ReadWriteBuffer result = new ReadWriteBuffer(); + result.writeString(p.toUri().getPath()); + return result; + } else { + throw new IOException("MapOutputFile can't allocate spill/output file"); + } + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/BoolWritableSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/BoolWritableSerializer.java new file mode 100644 index 00000000000..a4e8a56d34a --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/BoolWritableSerializer.java @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapred.nativetask.INativeComparable; + +@InterfaceAudience.Private +public class BoolWritableSerializer extends DefaultSerializer implements + INativeComparable { + + @Override + public int getLength(Writable w) throws IOException { + return 1; + } +} \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/ByteWritableSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/ByteWritableSerializer.java new file mode 100644 index 00000000000..b029e67f6af --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/ByteWritableSerializer.java @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapred.nativetask.INativeComparable; + +@InterfaceAudience.Private +public class ByteWritableSerializer extends DefaultSerializer implements + INativeComparable { + + @Override + public int getLength(Writable w) throws IOException { + return 1; + } +} \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/BytesWritableSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/BytesWritableSerializer.java new file mode 100644 index 00000000000..48dccfa86e8 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/BytesWritableSerializer.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.BytesWritable; +import org.apache.hadoop.mapred.nativetask.INativeComparable; + +@InterfaceAudience.Private +public class BytesWritableSerializer + implements INativeComparable, INativeSerializer { + + @Override + public int getLength(BytesWritable w) throws IOException { + return w.getLength(); + } + + @Override + public void serialize(BytesWritable w, DataOutput out) throws IOException { + out.write(w.getBytes(), 0, w.getLength()); + } + + @Override + public void deserialize(DataInput in, int length, BytesWritable w) throws IOException { + w.setSize(length); + in.readFully(w.getBytes(), 0, length); + } +} \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/DefaultSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/DefaultSerializer.java new file mode 100644 index 00000000000..fcef779ff29 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/DefaultSerializer.java @@ -0,0 +1,71 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.ByteArrayOutputStream; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; +import org.apache.hadoop.io.Writable; + +@InterfaceAudience.Public +@InterfaceStability.Evolving +public class DefaultSerializer implements INativeSerializer { + + static class ModifiedByteArrayOutputStream extends ByteArrayOutputStream { + + public byte[] getBuffer() { + return this.buf; + } + } + + private final ModifiedByteArrayOutputStream outBuffer = new ModifiedByteArrayOutputStream(); + private final DataOutputStream outData = new DataOutputStream(outBuffer); + private Writable buffered = null; + private int bufferedLength = -1; + + @Override + public int getLength(Writable w) throws IOException { + // if (w == buffered) { + // return bufferedLength; + // } + buffered = null; + bufferedLength = -1; + + outBuffer.reset(); + w.write(outData); + bufferedLength = outBuffer.size(); + buffered = w; + return bufferedLength; + } + + @Override + public void serialize(Writable w, DataOutput out) throws IOException { + w.write(out); + } + + @Override + public void deserialize(DataInput in, int length, Writable w) throws IOException { + w.readFields(in); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/DoubleWritableSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/DoubleWritableSerializer.java new file mode 100644 index 00000000000..a171f6fbef1 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/DoubleWritableSerializer.java @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapred.nativetask.INativeComparable; + +@InterfaceAudience.Private +public class DoubleWritableSerializer extends DefaultSerializer implements + INativeComparable { + + @Override + public int getLength(Writable w) throws IOException { + return 8; + } +} \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/FloatWritableSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/FloatWritableSerializer.java new file mode 100644 index 00000000000..bf2c9590ded --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/FloatWritableSerializer.java @@ -0,0 +1,36 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapred.nativetask.INativeComparable; + + +@InterfaceAudience.Private +public class FloatWritableSerializer extends DefaultSerializer implements + INativeComparable { + + @Override + public int getLength(Writable w) throws IOException { + return 4; + } +} \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/IKVSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/IKVSerializer.java new file mode 100644 index 00000000000..15a2ef7ec52 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/IKVSerializer.java @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.mapred.nativetask.buffer.DataInputStream; +import org.apache.hadoop.mapred.nativetask.buffer.DataOutputStream; +import org.apache.hadoop.mapred.nativetask.util.SizedWritable; + +/** + * serializes key-value pair + */ +@InterfaceAudience.Private +public interface IKVSerializer { + + /** + * update the length field of SizedWritable + */ + public void updateLength(SizedWritable key, SizedWritable value) throws IOException; + + public int serializeKV(DataOutputStream out, SizedWritable key, + SizedWritable value) throws IOException; + + public int serializePartitionKV(DataOutputStream out, int partitionId, + SizedWritable key, SizedWritable value) + throws IOException; + + public int deserializeKV(DataInputStream in, SizedWritable key, SizedWritable value) + throws IOException; +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/INativeSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/INativeSerializer.java new file mode 100644 index 00000000000..c970394eda0 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/INativeSerializer.java @@ -0,0 +1,49 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.classification.InterfaceStability; + +/** + * an INativeSerializer serializes and deserializes data transferred between + * Java and native. {@link DefaultSerializer} provides default implementations. + * + * Note: if you implemented your customized NativeSerializer instead of DefaultSerializer, + * you have to make sure the native side can serialize it correctly. + * + */ +@InterfaceAudience.Public +@InterfaceStability.Evolving +public interface INativeSerializer { + + /** + * get length of data to be serialized. If the data length is already known (like IntWritable) + * and could immediately be returned from this method, it is good chance to implement customized + * NativeSerializer for efficiency + */ + public int getLength(T w) throws IOException; + + public void serialize(T w, DataOutput out) throws IOException; + + public void deserialize(DataInput in, int length, T w) throws IOException; +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/IntWritableSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/IntWritableSerializer.java new file mode 100644 index 00000000000..e79d1828160 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/IntWritableSerializer.java @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapred.nativetask.INativeComparable; + +@InterfaceAudience.Private +public class IntWritableSerializer extends DefaultSerializer implements + INativeComparable { + + @Override + public int getLength(Writable w) throws IOException { + return 4; + } +} \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/KVSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/KVSerializer.java new file mode 100644 index 00000000000..e6609b8dd59 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/KVSerializer.java @@ -0,0 +1,115 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapred.nativetask.Constants; +import org.apache.hadoop.mapred.nativetask.buffer.DataInputStream; +import org.apache.hadoop.mapred.nativetask.buffer.DataOutputStream; +import org.apache.hadoop.mapred.nativetask.util.SizedWritable; + + + +@InterfaceAudience.Private +public class KVSerializer implements IKVSerializer { + + private static final Log LOG = LogFactory.getLog(KVSerializer.class); + + public static final int KV_HEAD_LENGTH = Constants.SIZEOF_KV_LENGTH; + + private final INativeSerializer keySerializer; + private final INativeSerializer valueSerializer; + + public KVSerializer(Class kclass, Class vclass) throws IOException { + + this.keySerializer = NativeSerialization.getInstance().getSerializer(kclass); + this.valueSerializer = NativeSerialization.getInstance().getSerializer(vclass); + } + + @Override + public void updateLength(SizedWritable key, SizedWritable value) throws IOException { + key.length = keySerializer.getLength(key.v); + value.length = valueSerializer.getLength(value.v); + return; + } + + @Override + public int serializeKV(DataOutputStream out, SizedWritable key, SizedWritable value) + throws IOException { + return serializePartitionKV(out, -1, key, value); + } + + @Override + public int serializePartitionKV(DataOutputStream out, int partitionId, + SizedWritable key, SizedWritable value) + throws IOException { + + if (key.length == SizedWritable.INVALID_LENGTH || + value.length == SizedWritable.INVALID_LENGTH) { + updateLength(key, value); + } + + final int keyLength = key.length; + final int valueLength = value.length; + + int bytesWritten = KV_HEAD_LENGTH + keyLength + valueLength; + if (partitionId != -1) { + bytesWritten += Constants.SIZEOF_PARTITION_LENGTH; + } + + if (out.hasUnFlushedData() && out.shortOfSpace(bytesWritten)) { + out.flush(); + } + + if (partitionId != -1) { + out.writeInt(partitionId); + } + + out.writeInt(keyLength); + out.writeInt(valueLength); + + keySerializer.serialize(key.v, out); + valueSerializer.serialize(value.v, out); + + return bytesWritten; + } + + @Override + public int deserializeKV(DataInputStream in, SizedWritable key, + SizedWritable value) throws IOException { + + if (!in.hasUnReadData()) { + return 0; + } + + key.length = in.readInt(); + value.length = in.readInt(); + + keySerializer.deserialize(in, key.length, key.v); + valueSerializer.deserialize(in, value.length, value.v); + + return key.length + value.length + KV_HEAD_LENGTH; + } + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/LongWritableSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/LongWritableSerializer.java new file mode 100644 index 00000000000..d8a6595383b --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/LongWritableSerializer.java @@ -0,0 +1,34 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapred.nativetask.INativeComparable; + +@InterfaceAudience.Private +public class LongWritableSerializer extends DefaultSerializer implements + INativeComparable { + @Override + public int getLength(Writable w) throws IOException { + return 8; + } +} \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/NativeSerialization.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/NativeSerialization.java new file mode 100644 index 00000000000..11bde640cdb --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/NativeSerialization.java @@ -0,0 +1,91 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.IOException; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.Writable; + +@InterfaceAudience.Private +public class NativeSerialization { + + private final ConcurrentHashMap> map = + new ConcurrentHashMap>(); + + public boolean accept(Class c) { + return Writable.class.isAssignableFrom(c); + } + + @SuppressWarnings("unchecked") + public INativeSerializer getSerializer(Class c) throws IOException { + + if (null == c) { + return null; + } + if (!Writable.class.isAssignableFrom(c)) { + throw new IOException("Cannot serialize type " + c.getName() + + ", we only accept subclass of Writable"); + } + final String name = c.getName(); + final Class serializer = map.get(name); + + if (null != serializer) { + try { + return (INativeSerializer) serializer.newInstance(); + } catch (final Exception e) { + throw new IOException(e); + } + } + return new DefaultSerializer(); + } + + public void register(String klass, Class serializer) throws IOException { + if (null == klass || null == serializer) { + throw new IOException("invalid arguments, klass or serializer is null"); + } + + if (!INativeSerializer.class.isAssignableFrom(serializer)) { + throw new IOException("Serializer is not assigable from INativeSerializer"); + } + + final Class storedSerializer = map.get(klass); + if (null == storedSerializer) { + map.put(klass, serializer); + return; + } else { + if (!storedSerializer.getName().equals(serializer.getName())) { + throw new IOException("Error! Serializer already registered, existing: " + + storedSerializer.getName() + ", new: " + + serializer.getName()); + } + } + } + + public void reset() { + map.clear(); + } + + private static NativeSerialization instance = new NativeSerialization(); + + public static NativeSerialization getInstance() { + return instance; + } +} \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/NullWritableSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/NullWritableSerializer.java new file mode 100644 index 00000000000..f6e7cf5b4d8 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/NullWritableSerializer.java @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapred.nativetask.INativeComparable; + +@InterfaceAudience.Private +public class NullWritableSerializer extends DefaultSerializer implements + INativeComparable { + + @Override + public int getLength(Writable w) throws IOException { + return 0; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/SerializationFramework.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/SerializationFramework.java new file mode 100644 index 00000000000..8dee58fc844 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/SerializationFramework.java @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.serde; + +import org.apache.hadoop.classification.InterfaceAudience; + +@InterfaceAudience.Private +public enum SerializationFramework { + WRITABLE_SERIALIZATION(0), NATIVE_SERIALIZATION(1); + + private int type; + + SerializationFramework(int type) { + this.type = type; + } + + public int getType() { + return type; + } +}; diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/TextSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/TextSerializer.java new file mode 100644 index 00000000000..e702dfe3be8 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/TextSerializer.java @@ -0,0 +1,49 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapred.nativetask.INativeComparable; + +@InterfaceAudience.Private +public class TextSerializer implements INativeSerializer, INativeComparable { + + public TextSerializer() throws SecurityException, NoSuchMethodException { + } + + @Override + public int getLength(Text w) throws IOException { + return w.getLength(); + } + + @Override + public void serialize(Text w, DataOutput out) throws IOException { + out.write(w.getBytes(), 0, w.getLength()); + } + + @Override + public void deserialize(DataInput in, int length, Text w) throws IOException { + w.readWithKnownLength(in, length); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/VIntWritableSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/VIntWritableSerializer.java new file mode 100644 index 00000000000..0cbb9ef3a8d --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/VIntWritableSerializer.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.mapred.nativetask.INativeComparable; + +@InterfaceAudience.Private +public class VIntWritableSerializer extends DefaultSerializer implements + INativeComparable { +} \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/VLongWritableSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/VLongWritableSerializer.java new file mode 100644 index 00000000000..af40b77e173 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/serde/VLongWritableSerializer.java @@ -0,0 +1,27 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.serde; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.mapred.nativetask.INativeComparable; + +@InterfaceAudience.Private +public class VLongWritableSerializer extends DefaultSerializer implements + INativeComparable { +} \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/BytesUtil.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/BytesUtil.java new file mode 100644 index 00000000000..16f691919db --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/BytesUtil.java @@ -0,0 +1,172 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.util; + +import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; +import org.apache.hadoop.classification.InterfaceAudience; + +@InterfaceAudience.Private +public class BytesUtil { + + private static final char[] HEX_CHARS = + "0123456789abcdef".toCharArray(); + + /** + * Converts a big-endian byte array to a long value. + * + * @param bytes array of bytes + * @param offset offset into array + */ + public static long toLong(byte[] bytes, int offset) { + return Longs.fromBytes(bytes[offset], + bytes[offset + 1], + bytes[offset + 2], + bytes[offset + 3], + bytes[offset + 4], + bytes[offset + 5], + bytes[offset + 6], + bytes[offset + 7]); + } + + /** + * Convert a big-endian integer from a byte array to a primitive value. + * @param bytes the array to parse from + * @param offset the offset in the array + */ + public static int toInt(byte[] bytes, int offset) { + return Ints.fromBytes(bytes[offset], + bytes[offset + 1], + bytes[offset + 2], + bytes[offset + 3]); + } + + /** + * Presumes float encoded as IEEE 754 floating-point "single format" + * @param bytes byte array + * @return Float made from passed byte array. + */ + public static float toFloat(byte [] bytes) { + return toFloat(bytes, 0); + } + + /** + * Presumes float encoded as IEEE 754 floating-point "single format" + * @param bytes array to convert + * @param offset offset into array + * @return Float made from passed byte array. + */ + public static float toFloat(byte [] bytes, int offset) { + return Float.intBitsToFloat(toInt(bytes, offset)); + } + + /** + * @param bytes byte array + * @return Return double made from passed bytes. + */ + public static double toDouble(final byte [] bytes) { + return toDouble(bytes, 0); + } + + /** + * @param bytes byte array + * @param offset offset where double is + * @return Return double made from passed bytes. + */ + public static double toDouble(final byte [] bytes, final int offset) { + return Double.longBitsToDouble(toLong(bytes, offset)); + } + + /** + * Write a printable representation of a byte array. + * + * @param b byte array + * @return the printable presentation + * @see #toStringBinary(byte[], int, int) + */ + public static String toStringBinary(final byte [] b) { + if (b == null) + return "null"; + return toStringBinary(b, 0, b.length); + } + + /** + * Write a printable representation of a byte array. Non-printable + * characters are hex escaped in the format \\x%02X, eg: + * \x00 \x05 etc + * + * @param b array to write out + * @param off offset to start at + * @param len length to write + * @return string output + */ + public static String toStringBinary(final byte [] b, int off, int len) { + StringBuilder result = new StringBuilder(); + // Just in case we are passed a 'len' that is > buffer length... + if (off >= b.length) return result.toString(); + if (off + len > b.length) len = b.length - off; + for (int i = off; i < off + len ; ++i ) { + int ch = b[i] & 0xFF; + if ( (ch >= '0' && ch <= '9') + || (ch >= 'A' && ch <= 'Z') + || (ch >= 'a' && ch <= 'z') + || " `~!@#$%^&*()-_=+[]{}|;:'\",.<>/?".indexOf(ch) >= 0 ) { + result.append((char)ch); + } else { + result.append("\\x"); + result.append(HEX_CHARS[(ch >> 4) & 0x0F]); + result.append(HEX_CHARS[ch & 0x0F]); + } + } + return result.toString(); + } + + /** + * Convert a boolean to a byte array. True becomes -1 + * and false becomes 0. + * + * @param b value + * @return b encoded in a byte array. + */ + public static byte [] toBytes(final boolean b) { + return new byte[] { b ? (byte) -1 : (byte) 0 }; + } + + /** + * @param f float value + * @return the float represented as byte [] + */ + public static byte [] toBytes(final float f) { + // Encode it as int + return Ints.toByteArray(Float.floatToRawIntBits(f)); + } + + /** + * Serialize a double as the IEEE 754 double format output. The resultant + * array will be 8 bytes long. + * + * @param d value + * @return the double represented as byte [] + */ + public static byte [] toBytes(final double d) { + // Encode it as a long + return Longs.toByteArray(Double.doubleToRawLongBits(d)); + } + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/ConfigUtil.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/ConfigUtil.java new file mode 100644 index 00000000000..7870ac7e087 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/ConfigUtil.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import com.google.common.base.Charsets; +import org.apache.hadoop.conf.Configuration; + +import org.apache.hadoop.classification.InterfaceAudience; + +@InterfaceAudience.Private +public abstract class ConfigUtil { + public static byte[][] toBytes(Configuration conf) { + List nativeConfigs = new ArrayList(); + for (Map.Entry e : conf) { + nativeConfigs.add(e.getKey().getBytes(Charsets.UTF_8)); + nativeConfigs.add(e.getValue().getBytes(Charsets.UTF_8)); + } + return nativeConfigs.toArray(new byte[nativeConfigs.size()][]); + } + + public static String booleansToString(boolean[] value) { + StringBuilder sb = new StringBuilder(); + for (boolean b: value) { + sb.append(b ? 1 : 0); + } + return sb.toString(); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/LocalJobOutputFiles.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/LocalJobOutputFiles.java new file mode 100644 index 00000000000..aa97789db10 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/LocalJobOutputFiles.java @@ -0,0 +1,159 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.util; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.LocalDirAllocator; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.mapred.JobConf; +import org.apache.hadoop.mapred.TaskID; + +@InterfaceAudience.Private +public class LocalJobOutputFiles implements NativeTaskOutput { + + static final String TASKTRACKER_OUTPUT = "output"; + static final String REDUCE_INPUT_FILE_FORMAT_STRING = "%s/map_%d.out"; + static final String SPILL_FILE_FORMAT_STRING = "%s/spill%d.out"; + static final String SPILL_INDEX_FILE_FORMAT_STRING = "%s/spill%d.out.index"; + static final String OUTPUT_FILE_FORMAT_STRING = "%s/file.out"; + static final String OUTPUT_FILE_INDEX_FORMAT_STRING = "%s/file.out.index"; + + private JobConf conf; + private LocalDirAllocator lDirAlloc = new LocalDirAllocator("mapred.local.dir"); + + public LocalJobOutputFiles(Configuration conf, String id) { + this.conf = new JobConf(conf); + } + + /** + * Return the path to local map output file created earlier + */ + public Path getOutputFile() throws IOException { + String path = String.format(OUTPUT_FILE_FORMAT_STRING, TASKTRACKER_OUTPUT); + return lDirAlloc.getLocalPathToRead(path, conf); + } + + /** + * Create a local map output file name. + * + * @param size the size of the file + */ + public Path getOutputFileForWrite(long size) throws IOException { + String path = String.format(OUTPUT_FILE_FORMAT_STRING, TASKTRACKER_OUTPUT); + return lDirAlloc.getLocalPathForWrite(path, size, conf); + } + + /** + * Return the path to a local map output index file created earlier + */ + public Path getOutputIndexFile() throws IOException { + String path = String.format(OUTPUT_FILE_INDEX_FORMAT_STRING, TASKTRACKER_OUTPUT); + return lDirAlloc.getLocalPathToRead(path, conf); + } + + /** + * Create a local map output index file name. + * + * @param size the size of the file + */ + public Path getOutputIndexFileForWrite(long size) throws IOException { + String path = String.format(OUTPUT_FILE_INDEX_FORMAT_STRING, TASKTRACKER_OUTPUT); + return lDirAlloc.getLocalPathForWrite(path, size, conf); + } + + /** + * Return a local map spill file created earlier. + * + * @param spillNumber the number + */ + public Path getSpillFile(int spillNumber) throws IOException { + String path = String.format(SPILL_FILE_FORMAT_STRING, TASKTRACKER_OUTPUT, spillNumber); + return lDirAlloc.getLocalPathToRead(path, conf); + } + + /** + * Create a local map spill file name. + * + * @param spillNumber the number + * @param size the size of the file + */ + public Path getSpillFileForWrite(int spillNumber, long size) throws IOException { + String path = String.format(SPILL_FILE_FORMAT_STRING, TASKTRACKER_OUTPUT, spillNumber); + return lDirAlloc.getLocalPathForWrite(path, size, conf); + } + + /** + * Return a local map spill index file created earlier + * + * @param spillNumber the number + */ + public Path getSpillIndexFile(int spillNumber) throws IOException { + String path = String +.format(SPILL_INDEX_FILE_FORMAT_STRING, TASKTRACKER_OUTPUT, spillNumber); + return lDirAlloc.getLocalPathToRead(path, conf); + } + + /** + * Create a local map spill index file name. + * + * @param spillNumber the number + * @param size the size of the file + */ + public Path getSpillIndexFileForWrite(int spillNumber, long size) throws IOException { + String path = String +.format(SPILL_INDEX_FILE_FORMAT_STRING, TASKTRACKER_OUTPUT, spillNumber); + return lDirAlloc.getLocalPathForWrite(path, size, conf); + } + + /** + * Return a local reduce input file created earlier + * + * @param mapId a map task id + */ + public Path getInputFile(int mapId) throws IOException { + return lDirAlloc.getLocalPathToRead( + String.format(REDUCE_INPUT_FILE_FORMAT_STRING, TASKTRACKER_OUTPUT, Integer.valueOf(mapId)), + conf); + } + + /** + * Create a local reduce input file name. + * + * @param mapId a map task id + * @param size the size of the file + */ + public Path getInputFileForWrite(TaskID mapId, long size, Configuration conf) + throws IOException { + return lDirAlloc.getLocalPathForWrite( + String.format(REDUCE_INPUT_FILE_FORMAT_STRING, TASKTRACKER_OUTPUT, mapId.getId()), size, + conf); + } + + /** Removes all of the files related to a task. */ + public void removeAll() throws IOException { + conf.deleteLocalFiles(TASKTRACKER_OUTPUT); + } + + public String getOutputName(int partition) { + return String.format("part-%05d", partition); + } + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/NativeTaskOutput.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/NativeTaskOutput.java new file mode 100644 index 00000000000..7c9f4333a7f --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/NativeTaskOutput.java @@ -0,0 +1,106 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.util; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.mapred.TaskID; + +/** + * base class of output files manager. + */ +@InterfaceAudience.Private +public interface NativeTaskOutput { + + /** + * Return the path to local map output file created earlier + */ + public Path getOutputFile() throws IOException; + + /** + * Create a local map output file name. + * + * @param size the size of the file + */ + public Path getOutputFileForWrite(long size) throws IOException; + + /** + * Return the path to a local map output index file created earlier + */ + public Path getOutputIndexFile() throws IOException; + + /** + * Create a local map output index file name. + * + * @param size the size of the file + */ + public Path getOutputIndexFileForWrite(long size) throws IOException; + + /** + * Return a local map spill file created earlier. + * + * @param spillNumber the number + */ + public Path getSpillFile(int spillNumber) throws IOException; + + /** + * Create a local map spill file name. + * + * @param spillNumber the number + * @param size the size of the file + */ + public Path getSpillFileForWrite(int spillNumber, long size) throws IOException; + + /** + * Return a local map spill index file created earlier + * + * @param spillNumber the number + */ + public Path getSpillIndexFile(int spillNumber) throws IOException; + + /** + * Create a local map spill index file name. + * + r* @param spillNumber the number + * @param size the size of the file + */ + public Path getSpillIndexFileForWrite(int spillNumber, long size) throws IOException; + + /** + * Return a local reduce input file created earlier + * + * @param mapId a map task id + */ + public Path getInputFile(int mapId) throws IOException; + + /** + * Create a local reduce input file name. + * + * @param mapId a map task id + * @param size the size of the file + */ + public Path getInputFileForWrite(TaskID mapId, long size, Configuration conf) throws IOException; + + /** Removes all of the files related to a task. */ + public void removeAll() throws IOException; + + public String getOutputName(int partition); +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/NativeTaskOutputFiles.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/NativeTaskOutputFiles.java new file mode 100644 index 00000000000..d52ee1cd9e0 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/NativeTaskOutputFiles.java @@ -0,0 +1,170 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.util; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.LocalDirAllocator; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.mapred.JobConf; +import org.apache.hadoop.mapred.TaskID; + +/** + * Manipulate the working area for the transient store for maps and reduces. + * + * This class is used by map and reduce tasks to identify the directories that they need + * to write to/read from for intermediate files. The callers of these methods are from + * child space and see mapreduce.cluster.local.dir as + * taskTracker/jobCache/jobId/attemptId. + * + * This class should not be used from TaskTracker space. + */ +@InterfaceAudience.Private +public class NativeTaskOutputFiles implements NativeTaskOutput { + + static final String TASKTRACKER_OUTPUT = "output"; + static final String REDUCE_INPUT_FILE_FORMAT_STRING = "%s/map_%d.out"; + static final String SPILL_FILE_FORMAT_STRING = "%s/%s/spill%d.out"; + static final String SPILL_INDEX_FILE_FORMAT_STRING = "%s/%s/spill%d.out.index"; + static final String OUTPUT_FILE_FORMAT_STRING = "%s/%s/file.out"; + static final String OUTPUT_FILE_INDEX_FORMAT_STRING = "%s/%s/file.out.index"; + + private String id; + private JobConf conf; + private LocalDirAllocator lDirAlloc = new LocalDirAllocator("mapred.local.dir"); + + public NativeTaskOutputFiles(Configuration conf, String id) { + this.conf = new JobConf(conf); + this.id = id; + } + + /** + * Return the path to local map output file created earlier + */ + public Path getOutputFile() throws IOException { + String path = String.format(OUTPUT_FILE_FORMAT_STRING, TASKTRACKER_OUTPUT, id); + return lDirAlloc.getLocalPathToRead(path, conf); + } + + /** + * Create a local map output file name. + * + * @param size the size of the file + */ + public Path getOutputFileForWrite(long size) throws IOException { + String path = String.format(OUTPUT_FILE_FORMAT_STRING, TASKTRACKER_OUTPUT, id); + return lDirAlloc.getLocalPathForWrite(path, size, conf); + } + + /** + * Return the path to a local map output index file created earlier + */ + public Path getOutputIndexFile() throws IOException { + String path = String.format(OUTPUT_FILE_INDEX_FORMAT_STRING, TASKTRACKER_OUTPUT, id); + return lDirAlloc.getLocalPathToRead(path, conf); + } + + /** + * Create a local map output index file name. + * + * @param size the size of the file + */ + public Path getOutputIndexFileForWrite(long size) throws IOException { + String path = String.format(OUTPUT_FILE_INDEX_FORMAT_STRING, TASKTRACKER_OUTPUT, id); + return lDirAlloc.getLocalPathForWrite(path, size, conf); + } + + /** + * Return a local map spill file created earlier. + * + * @param spillNumber the number + */ + public Path getSpillFile(int spillNumber) throws IOException { + String path = String.format(SPILL_FILE_FORMAT_STRING, id, TASKTRACKER_OUTPUT, spillNumber); + return lDirAlloc.getLocalPathToRead(path, conf); + } + + /** + * Create a local map spill file name. + * + * @param spillNumber the number + * @param size the size of the file + */ + public Path getSpillFileForWrite(int spillNumber, long size) throws IOException { + String path = String.format(SPILL_FILE_FORMAT_STRING, id, TASKTRACKER_OUTPUT, spillNumber); + return lDirAlloc.getLocalPathForWrite(path, size, conf); + } + + /** + * Return a local map spill index file created earlier + * + * @param spillNumber the number + */ + public Path getSpillIndexFile(int spillNumber) throws IOException { + String path = String + .format(SPILL_INDEX_FILE_FORMAT_STRING, id, TASKTRACKER_OUTPUT, spillNumber); + return lDirAlloc.getLocalPathToRead(path, conf); + } + + /** + * Create a local map spill index file name. + * + * @param spillNumber the number + * @param size the size of the file + */ + public Path getSpillIndexFileForWrite(int spillNumber, long size) throws IOException { + String path = String + .format(SPILL_INDEX_FILE_FORMAT_STRING, id, TASKTRACKER_OUTPUT, spillNumber); + return lDirAlloc.getLocalPathForWrite(path, size, conf); + } + + /** + * Return a local reduce input file created earlier + * + * @param mapId a map task id + */ + public Path getInputFile(int mapId) throws IOException { + return lDirAlloc.getLocalPathToRead( + String.format(REDUCE_INPUT_FILE_FORMAT_STRING, TASKTRACKER_OUTPUT, Integer.valueOf(mapId)), + conf); + } + + /** + * Create a local reduce input file name. + * + * @param mapId a map task id + * @param size the size of the file + */ + public Path getInputFileForWrite(TaskID mapId, long size, Configuration conf) + throws IOException { + return lDirAlloc.getLocalPathForWrite( + String.format(REDUCE_INPUT_FILE_FORMAT_STRING, TASKTRACKER_OUTPUT, mapId.getId()), size, + conf); + } + + /** Removes all of the files related to a task. */ + public void removeAll() throws IOException { + conf.deleteLocalFiles(TASKTRACKER_OUTPUT); + } + + public String getOutputName(int partition) { + return String.format("part-%05d", partition); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/OutputUtil.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/OutputUtil.java new file mode 100644 index 00000000000..dd45edef4a8 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/OutputUtil.java @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.util; + +import java.lang.reflect.Constructor; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.conf.Configuration; + +@InterfaceAudience.Private +public class OutputUtil { + + private static Log LOG = LogFactory.getLog(OutputUtil.class); + public static final String NATIVE_TASK_OUTPUT_MANAGER = "nativetask.output.manager"; + + public static NativeTaskOutput createNativeTaskOutput(Configuration conf, String id) { + Class clazz = conf.getClass(OutputUtil.NATIVE_TASK_OUTPUT_MANAGER, + NativeTaskOutputFiles.class); + LOG.info(OutputUtil.NATIVE_TASK_OUTPUT_MANAGER + " = " + clazz.getName()); + try { + Constructor ctor = clazz.getConstructor(Configuration.class, String.class); + ctor.setAccessible(true); + NativeTaskOutput instance = (NativeTaskOutput) ctor.newInstance(conf, id); + return instance; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/ReadWriteBuffer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/ReadWriteBuffer.java new file mode 100644 index 00000000000..03df01663c1 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/ReadWriteBuffer.java @@ -0,0 +1,159 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.util; + +import com.google.common.base.Charsets; +import org.apache.hadoop.classification.InterfaceAudience; + +@InterfaceAudience.Private +public class ReadWriteBuffer { + private byte[] _buff; + private int _writePoint; + private int _readPoint; + final static int CACHE_LINE_SIZE = 16; + + public ReadWriteBuffer(int length) { + if (length > 0) { + _buff = new byte[length]; + } + } + + public ReadWriteBuffer() { + _buff = new byte[CACHE_LINE_SIZE]; + } + + public ReadWriteBuffer(byte[] bytes) { + _buff = bytes; + _writePoint = 0; + _readPoint = 0; + } + + public void reset(byte[] newBuff) { + _buff = newBuff; + _writePoint = 0; + _readPoint = 0; + } + + public void setReadPoint(int pos) { + _readPoint = pos; + } + + public void setWritePoint(int pos) { + _writePoint = pos; + } + + public byte[] getBuff() { + return _buff; + } + + public int getWritePoint() { + return _writePoint; + } + + public int getReadPoint() { + return _readPoint; + } + + public void writeInt(int v) { + checkWriteSpaceAndResizeIfNecessary(4); + + _buff[_writePoint + 0] = (byte) ((v >>> 0) & 0xFF); + _buff[_writePoint + 1] = (byte) ((v >>> 8) & 0xFF); + _buff[_writePoint + 2] = (byte) ((v >>> 16) & 0xFF); + _buff[_writePoint + 3] = (byte) ((v >>> 24) & 0xFF); + + _writePoint += 4; + } + + public void writeLong(long v) { + checkWriteSpaceAndResizeIfNecessary(8); + + _buff[_writePoint + 0] = (byte) (v >>> 0); + _buff[_writePoint + 1] = (byte) (v >>> 8); + _buff[_writePoint + 2] = (byte) (v >>> 16); + _buff[_writePoint + 3] = (byte) (v >>> 24); + _buff[_writePoint + 4] = (byte) (v >>> 32); + _buff[_writePoint + 5] = (byte) (v >>> 40); + _buff[_writePoint + 6] = (byte) (v >>> 48); + _buff[_writePoint + 7] = (byte) (v >>> 56); + + _writePoint += 8; + } + + public void writeBytes(byte b[], int off, int len) { + writeInt(len); + checkWriteSpaceAndResizeIfNecessary(len); + System.arraycopy(b, off, _buff, _writePoint, len); + _writePoint += len; + } + + public int readInt() { + final int ch4 = 0xff & (_buff[_readPoint + 0]); + final int ch3 = 0xff & (_buff[_readPoint + 1]); + final int ch2 = 0xff & (_buff[_readPoint + 2]); + final int ch1 = 0xff & (_buff[_readPoint + 3]); + _readPoint += 4; + return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); + } + + public long readLong() { + final long result = + ((_buff[_readPoint + 0] & 255) << 0) + + ((_buff[_readPoint + 1] & 255) << 8) + + ((_buff[_readPoint + 2] & 255) << 16) + + ((long) (_buff[_readPoint + 3] & 255) << 24) + + ((long) (_buff[_readPoint + 4] & 255) << 32) + + ((long) (_buff[_readPoint + 5] & 255) << 40) + + ((long) (_buff[_readPoint + 6] & 255) << 48) + + (((long) _buff[_readPoint + 7] << 56)); + + _readPoint += 8; + return result; + } + + public byte[] readBytes() { + final int length = readInt(); + final byte[] result = new byte[length]; + System.arraycopy(_buff, _readPoint, result, 0, length); + _readPoint += length; + return result; + } + + public void writeString(String str) { + final byte[] bytes = str.getBytes(Charsets.UTF_8); + writeBytes(bytes, 0, bytes.length); + } + + public String readString() { + final byte[] bytes = readBytes(); + return new String(bytes, Charsets.UTF_8); + } + + private void checkWriteSpaceAndResizeIfNecessary(int toBeWritten) { + + if (_buff.length - _writePoint >= toBeWritten) { + return; + } + final int newLength = (toBeWritten + _writePoint > CACHE_LINE_SIZE) ? + (toBeWritten + _writePoint) : CACHE_LINE_SIZE; + final byte[] newBuff = new byte[newLength]; + System.arraycopy(_buff, 0, newBuff, 0, _writePoint); + _buff = newBuff; + } + +}; diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/SizedWritable.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/SizedWritable.java new file mode 100644 index 00000000000..284661ff23b --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/java/org/apache/hadoop/mapred/nativetask/util/SizedWritable.java @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.util; + +import java.io.IOException; + +import org.apache.hadoop.classification.InterfaceAudience; +import org.apache.hadoop.io.DataInputBuffer; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.util.ReflectionUtils; + +@InterfaceAudience.Private +public class SizedWritable { + public static final int INVALID_LENGTH = -1; + + public int length = INVALID_LENGTH; + public Writable v; + + public SizedWritable(Class klass) { + if (null != klass) { + v = (Writable) ReflectionUtils.newInstance(klass, null); + } + length = INVALID_LENGTH; + } + + public void readFields(DataInputBuffer key) throws IOException { + if (null != key) { + this.v.readFields(key); + this.length = INVALID_LENGTH; + } else { + throw new IOException("input key is null"); + } + + } + + public void reset(T w) { + this.v = (Writable) w; + this.length = INVALID_LENGTH; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/gtest/gtest-all.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/gtest/gtest-all.cc new file mode 100644 index 00000000000..d17f17a725e --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/gtest/gtest-all.cc @@ -0,0 +1,9120 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// Google C++ Testing Framework (Google Test) +// +// Sometimes it's desirable to build Google Test by compiling a single file. +// This file serves this purpose. + +// This line ensures that gtest.h can be compiled on its own, even +// when it's fused. +#include "gtest/gtest.h" + +// The following lines pull in the real gtest *.cc files. +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) + +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Utilities for testing Google Test itself and code that uses Google Test +// (e.g. frameworks built on top of Google Test). + +#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ +#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ + + +namespace testing { + +// This helper class can be used to mock out Google Test failure reporting +// so that we can test Google Test or code that builds on Google Test. +// +// An object of this class appends a TestPartResult object to the +// TestPartResultArray object given in the constructor whenever a Google Test +// failure is reported. It can either intercept only failures that are +// generated in the same thread that created this object or it can intercept +// all generated failures. The scope of this mock object can be controlled with +// the second argument to the two arguments constructor. +class GTEST_API_ ScopedFakeTestPartResultReporter + : public TestPartResultReporterInterface { + public: + // The two possible mocking modes of this object. + enum InterceptMode { + INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. + INTERCEPT_ALL_THREADS // Intercepts all failures. + }; + + // The c'tor sets this object as the test part result reporter used + // by Google Test. The 'result' parameter specifies where to report the + // results. This reporter will only catch failures generated in the current + // thread. DEPRECATED + explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); + + // Same as above, but you can choose the interception scope of this object. + ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, + TestPartResultArray* result); + + // The d'tor restores the previous test part result reporter. + virtual ~ScopedFakeTestPartResultReporter(); + + // Appends the TestPartResult object to the TestPartResultArray + // received in the constructor. + // + // This method is from the TestPartResultReporterInterface + // interface. + virtual void ReportTestPartResult(const TestPartResult& result); + private: + void Init(); + + const InterceptMode intercept_mode_; + TestPartResultReporterInterface* old_reporter_; + TestPartResultArray* const result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); +}; + +namespace internal { + +// A helper class for implementing EXPECT_FATAL_FAILURE() and +// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +class GTEST_API_ SingleFailureChecker { + public: + // The constructor remembers the arguments. + SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, + const string& substr); + ~SingleFailureChecker(); + private: + const TestPartResultArray* const results_; + const TestPartResult::Type type_; + const string substr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); +}; + +} // namespace internal + +} // namespace testing + +// A set of macros for testing Google Test assertions or code that's expected +// to generate Google Test fatal failures. It verifies that the given +// statement will cause exactly one fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_FATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - 'statement' cannot reference local non-static variables or +// non-static members of the current object. +// - 'statement' cannot return a value. +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. The AcceptsMacroThatExpandsToUnprotectedComma test in +// gtest_unittest.cc will fail to compile if we do that. +#define EXPECT_FATAL_FAILURE(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ALL_THREADS, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +// A macro for testing Google Test assertions or code that's expected to +// generate Google Test non-fatal failures. It asserts that the given +// statement will cause exactly one non-fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// 'statement' is allowed to reference local variables and members of +// the current object. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. If we do that, the code won't compile when the user gives +// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that +// expands to code containing an unprotected comma. The +// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc +// catches that. +// +// For the same reason, we have to write +// if (::testing::internal::AlwaysTrue()) { statement; } +// instead of +// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) +// to avoid an MSVC warning on unreachable code. +#define EXPECT_NONFATAL_FAILURE(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\ + >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include // NOLINT +#include +#include + +#if GTEST_OS_LINUX + +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +# include // NOLINT +# include // NOLINT +# include // NOLINT +// Declares vsnprintf(). This header is not available on Windows. +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include + +#elif GTEST_OS_SYMBIAN +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT + +#elif GTEST_OS_ZOS +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT + +// On z/OS we additionally need strings.h for strcasecmp. +# include // NOLINT + +#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. + +# include // NOLINT + +#elif GTEST_OS_WINDOWS // We are on Windows proper. + +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT + +# if GTEST_OS_WINDOWS_MINGW +// MinGW has gettimeofday() but not _ftime64(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +// TODO(kenton@google.com): There are other ways to get the time on +// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW +// supports these. consider using them instead. +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT +# endif // GTEST_OS_WINDOWS_MINGW + +// cpplint thinks that the header is already included, so we want to +// silence it. +# include // NOLINT + +#else + +// Assume other platforms have gettimeofday(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +// cpplint thinks that the header is already included, so we want to +// silence it. +# include // NOLINT +# include // NOLINT + +#endif // GTEST_OS_LINUX + +#if GTEST_HAS_EXCEPTIONS +# include +#endif + +#if GTEST_CAN_STREAM_RESULTS_ +# include // NOLINT +# include // NOLINT +#endif + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Utility functions and classes used by the Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) +// +// This file contains purely Google Test's internal implementation. Please +// DO NOT #INCLUDE IT IN A USER PROGRAM. + +#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ +#define GTEST_SRC_GTEST_INTERNAL_INL_H_ + +// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is +// part of Google Test's implementation; otherwise it's undefined. +#if !GTEST_IMPLEMENTATION_ +// A user is trying to include this from his code - just say no. +# error "gtest-internal-inl.h is part of Google Test's internal implementation." +# error "It must not be included except by Google Test itself." +#endif // GTEST_IMPLEMENTATION_ + +#ifndef _WIN32_WCE +# include +#endif // !_WIN32_WCE +#include +#include // For strtoll/_strtoul64/malloc/free. +#include // For memmove. + +#include +#include +#include + + +#if GTEST_OS_WINDOWS +# include // NOLINT +#endif // GTEST_OS_WINDOWS + + +namespace testing { + +// Declares the flags. +// +// We don't want the users to modify this flag in the code, but want +// Google Test's own unit tests to be able to access it. Therefore we +// declare it here as opposed to in gtest.h. +GTEST_DECLARE_bool_(death_test_use_fork); + +namespace internal { + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; + +// Names of the flags (needed for parsing Google Test flags). +const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; +const char kBreakOnFailureFlag[] = "break_on_failure"; +const char kCatchExceptionsFlag[] = "catch_exceptions"; +const char kColorFlag[] = "color"; +const char kFilterFlag[] = "filter"; +const char kListTestsFlag[] = "list_tests"; +const char kOutputFlag[] = "output"; +const char kPrintTimeFlag[] = "print_time"; +const char kRandomSeedFlag[] = "random_seed"; +const char kRepeatFlag[] = "repeat"; +const char kShuffleFlag[] = "shuffle"; +const char kStackTraceDepthFlag[] = "stack_trace_depth"; +const char kStreamResultToFlag[] = "stream_result_to"; +const char kThrowOnFailureFlag[] = "throw_on_failure"; + +// A valid random seed must be in [1, kMaxRandomSeed]. +const int kMaxRandomSeed = 99999; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +GTEST_API_ extern bool g_help_flag; + +// Returns the current time in milliseconds. +GTEST_API_ TimeInMillis GetTimeInMillis(); + +// Returns true iff Google Test should use colors in the output. +GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); + +// Formats the given time in milliseconds as seconds. +GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); + +// Parses a string for an Int32 flag, in the form of "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +GTEST_API_ bool ParseInt32Flag( + const char* str, const char* flag, Int32* value); + +// Returns a random seed in range [1, kMaxRandomSeed] based on the +// given --gtest_random_seed flag value. +inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { + const unsigned int raw_seed = (random_seed_flag == 0) ? + static_cast(GetTimeInMillis()) : + static_cast(random_seed_flag); + + // Normalizes the actual seed to range [1, kMaxRandomSeed] such that + // it's easy to type. + const int normalized_seed = + static_cast((raw_seed - 1U) % + static_cast(kMaxRandomSeed)) + 1; + return normalized_seed; +} + +// Returns the first valid random seed after 'seed'. The behavior is +// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is +// considered to be 1. +inline int GetNextRandomSeed(int seed) { + GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) + << "Invalid random seed " << seed << " - must be in [1, " + << kMaxRandomSeed << "]."; + const int next_seed = seed + 1; + return (next_seed > kMaxRandomSeed) ? 1 : next_seed; +} + +// This class saves the values of all Google Test flags in its c'tor, and +// restores them in its d'tor. +class GTestFlagSaver { + public: + // The c'tor. + GTestFlagSaver() { + also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); + break_on_failure_ = GTEST_FLAG(break_on_failure); + catch_exceptions_ = GTEST_FLAG(catch_exceptions); + color_ = GTEST_FLAG(color); + death_test_style_ = GTEST_FLAG(death_test_style); + death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); + filter_ = GTEST_FLAG(filter); + internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); + list_tests_ = GTEST_FLAG(list_tests); + output_ = GTEST_FLAG(output); + print_time_ = GTEST_FLAG(print_time); + random_seed_ = GTEST_FLAG(random_seed); + repeat_ = GTEST_FLAG(repeat); + shuffle_ = GTEST_FLAG(shuffle); + stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); + stream_result_to_ = GTEST_FLAG(stream_result_to); + throw_on_failure_ = GTEST_FLAG(throw_on_failure); + } + + // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. + ~GTestFlagSaver() { + GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; + GTEST_FLAG(break_on_failure) = break_on_failure_; + GTEST_FLAG(catch_exceptions) = catch_exceptions_; + GTEST_FLAG(color) = color_; + GTEST_FLAG(death_test_style) = death_test_style_; + GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; + GTEST_FLAG(filter) = filter_; + GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; + GTEST_FLAG(list_tests) = list_tests_; + GTEST_FLAG(output) = output_; + GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(random_seed) = random_seed_; + GTEST_FLAG(repeat) = repeat_; + GTEST_FLAG(shuffle) = shuffle_; + GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; + GTEST_FLAG(stream_result_to) = stream_result_to_; + GTEST_FLAG(throw_on_failure) = throw_on_failure_; + } + private: + // Fields for saving the original values of flags. + bool also_run_disabled_tests_; + bool break_on_failure_; + bool catch_exceptions_; + String color_; + String death_test_style_; + bool death_test_use_fork_; + String filter_; + String internal_run_death_test_; + bool list_tests_; + String output_; + bool print_time_; + bool pretty_; + internal::Int32 random_seed_; + internal::Int32 repeat_; + bool shuffle_; + internal::Int32 stack_trace_depth_; + String stream_result_to_; + bool throw_on_failure_; +} GTEST_ATTRIBUTE_UNUSED_; + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str); + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars); + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded(); + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (e.g., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +GTEST_API_ bool ShouldShard(const char* total_shards_str, + const char* shard_index_str, + bool in_subprocess_for_death_test); + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error and +// and aborts. +GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +GTEST_API_ bool ShouldRunTestOnShard( + int total_shards, int shard_index, int test_id); + +// STL container utilities. + +// Returns the number of elements in the given container that satisfy +// the given predicate. +template +inline int CountIf(const Container& c, Predicate predicate) { + // Implemented as an explicit loop since std::count_if() in libCstd on + // Solaris has a non-standard signature. + int count = 0; + for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { + if (predicate(*it)) + ++count; + } + return count; +} + +// Applies a function/functor to each element in the container. +template +void ForEach(const Container& c, Functor functor) { + std::for_each(c.begin(), c.end(), functor); +} + +// Returns the i-th element of the vector, or default_value if i is not +// in range [0, v.size()). +template +inline E GetElementOr(const std::vector& v, int i, E default_value) { + return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; +} + +// Performs an in-place shuffle of a range of the vector's elements. +// 'begin' and 'end' are element indices as an STL-style range; +// i.e. [begin, end) are shuffled, where 'end' == size() means to +// shuffle to the end of the vector. +template +void ShuffleRange(internal::Random* random, int begin, int end, + std::vector* v) { + const int size = static_cast(v->size()); + GTEST_CHECK_(0 <= begin && begin <= size) + << "Invalid shuffle range start " << begin << ": must be in range [0, " + << size << "]."; + GTEST_CHECK_(begin <= end && end <= size) + << "Invalid shuffle range finish " << end << ": must be in range [" + << begin << ", " << size << "]."; + + // Fisher-Yates shuffle, from + // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + for (int range_width = end - begin; range_width >= 2; range_width--) { + const int last_in_range = begin + range_width - 1; + const int selected = begin + random->Generate(range_width); + std::swap((*v)[selected], (*v)[last_in_range]); + } +} + +// Performs an in-place shuffle of the vector's elements. +template +inline void Shuffle(internal::Random* random, std::vector* v) { + ShuffleRange(random, 0, static_cast(v->size()), v); +} + +// A function for deleting an object. Handy for being used as a +// functor. +template +static void Delete(T* x) { + delete x; +} + +// A predicate that checks the key of a TestProperty against a known key. +// +// TestPropertyKeyIs is copyable. +class TestPropertyKeyIs { + public: + // Constructor. + // + // TestPropertyKeyIs has NO default constructor. + explicit TestPropertyKeyIs(const char* key) + : key_(key) {} + + // Returns true iff the test name of test property matches on key_. + bool operator()(const TestProperty& test_property) const { + return String(test_property.key()).Compare(key_) == 0; + } + + private: + String key_; +}; + +// Class UnitTestOptions. +// +// This class contains functions for processing options the user +// specifies when running the tests. It has only static members. +// +// In most cases, the user can specify an option using either an +// environment variable or a command line flag. E.g. you can set the +// test filter using either GTEST_FILTER or --gtest_filter. If both +// the variable and the flag are present, the latter overrides the +// former. +class GTEST_API_ UnitTestOptions { + public: + // Functions for processing the gtest_output flag. + + // Returns the output format, or "" for normal printed output. + static String GetOutputFormat(); + + // Returns the absolute path of the requested output file, or the + // default (test_detail.xml in the original working directory) if + // none was explicitly specified. + static String GetAbsolutePathToOutputFile(); + + // Functions for processing the gtest_filter flag. + + // Returns true iff the wildcard pattern matches the string. The + // first ':' or '\0' character in pattern marks the end of it. + // + // This recursive algorithm isn't very efficient, but is clear and + // works well enough for matching test names, which are short. + static bool PatternMatchesString(const char *pattern, const char *str); + + // Returns true iff the user-specified filter matches the test case + // name and the test name. + static bool FilterMatchesTest(const String &test_case_name, + const String &test_name); + +#if GTEST_OS_WINDOWS + // Function for supporting the gtest_catch_exception flag. + + // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the + // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. + // This function is useful as an __except condition. + static int GTestShouldProcessSEH(DWORD exception_code); +#endif // GTEST_OS_WINDOWS + + // Returns true if "name" matches the ':' separated list of glob-style + // filters in "filter". + static bool MatchesFilter(const String& name, const char* filter); +}; + +// Returns the current application's name, removing directory path if that +// is present. Used by UnitTestOptions::GetOutputFile. +GTEST_API_ FilePath GetCurrentExecutableName(); + +// The role interface for getting the OS stack trace as a string. +class OsStackTraceGetterInterface { + public: + OsStackTraceGetterInterface() {} + virtual ~OsStackTraceGetterInterface() {} + + // Returns the current OS stack trace as a String. Parameters: + // + // max_depth - the maximum number of stack frames to be included + // in the trace. + // skip_count - the number of top frames to be skipped; doesn't count + // against max_depth. + virtual String CurrentStackTrace(int max_depth, int skip_count) = 0; + + // UponLeavingGTest() should be called immediately before Google Test calls + // user code. It saves some information about the current stack that + // CurrentStackTrace() will use to find and hide Google Test stack frames. + virtual void UponLeavingGTest() = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); +}; + +// A working implementation of the OsStackTraceGetterInterface interface. +class OsStackTraceGetter : public OsStackTraceGetterInterface { + public: + OsStackTraceGetter() : caller_frame_(NULL) {} + virtual String CurrentStackTrace(int max_depth, int skip_count); + virtual void UponLeavingGTest(); + + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + + private: + Mutex mutex_; // protects all internal state + + // We save the stack frame below the frame that calls user code. + // We do this because the address of the frame immediately below + // the user code changes between the call to UponLeavingGTest() + // and any calls to CurrentStackTrace() from within the user code. + void* caller_frame_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); +}; + +// Information about a Google Test trace point. +struct TraceInfo { + const char* file; + int line; + String message; +}; + +// This is the default global test part result reporter used in UnitTestImpl. +// This class should only be used by UnitTestImpl. +class DefaultGlobalTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. Reports the test part + // result in the current test. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); +}; + +// This is the default per thread test part result reporter used in +// UnitTestImpl. This class should only be used by UnitTestImpl. +class DefaultPerThreadTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. The implementation just + // delegates to the current global test part result reporter of *unit_test_. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); +}; + +// The private implementation of the UnitTest class. We don't protect +// the methods under a mutex, as this class is not accessible by a +// user and the UnitTest class that delegates work to this class does +// proper locking. +class GTEST_API_ UnitTestImpl { + public: + explicit UnitTestImpl(UnitTest* parent); + virtual ~UnitTestImpl(); + + // There are two different ways to register your own TestPartResultReporter. + // You can register your own repoter to listen either only for test results + // from the current thread or for results from all threads. + // By default, each per-thread test result repoter just passes a new + // TestPartResult to the global test result reporter, which registers the + // test part result for the currently running test. + + // Returns the global test part result reporter. + TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); + + // Sets the global test part result reporter. + void SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter); + + // Returns the test part result reporter for the current thread. + TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); + + // Sets the test part result reporter for the current thread. + void SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter); + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const { return !Failed(); } + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const { + return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[i]; + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i) { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[index]; + } + + // Provides access to the event listener list. + TestEventListeners* listeners() { return &listeners_; } + + // Returns the TestResult for the test that's currently running, or + // the TestResult for the ad hoc test if no test is running. + TestResult* current_test_result(); + + // Returns the TestResult for the ad hoc test. + const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } + + // Sets the OS stack trace getter. + // + // Does nothing if the input and the current OS stack trace getter + // are the same; otherwise, deletes the old getter and makes the + // input the current getter. + void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); + + // Returns the current OS stack trace getter if it is not NULL; + // otherwise, creates an OsStackTraceGetter, makes it the current + // getter, and returns it. + OsStackTraceGetterInterface* os_stack_trace_getter(); + + // Returns the current OS stack trace as a String. + // + // The maximum number of stack frames to be included is specified by + // the gtest_stack_trace_depth flag. The skip_count parameter + // specifies the number of top frames to be skipped, which doesn't + // count against the number of frames to be included. + // + // For example, if Foo() calls Bar(), which in turn calls + // CurrentOsStackTraceExceptTop(1), Foo() will be included in the + // trace but Bar() and CurrentOsStackTraceExceptTop() won't. + String CurrentOsStackTraceExceptTop(int skip_count); + + // Finds and returns a TestCase with the given name. If one doesn't + // exist, creates one and returns it. + // + // Arguments: + // + // test_case_name: name of the test case + // type_param: the name of the test's type parameter, or NULL if + // this is not a typed or a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase* GetTestCase(const char* test_case_name, + const char* type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Adds a TestInfo to the unit test. + // + // Arguments: + // + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + // test_info: the TestInfo object + void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + TestInfo* test_info) { + // In order to support thread-safe death tests, we need to + // remember the original working directory when the test program + // was first invoked. We cannot do this in RUN_ALL_TESTS(), as + // the user may have changed the current directory before calling + // RUN_ALL_TESTS(). Therefore we capture the current directory in + // AddTestInfo(), which is called to register a TEST or TEST_F + // before main() is reached. + if (original_working_dir_.IsEmpty()) { + original_working_dir_.Set(FilePath::GetCurrentDir()); + GTEST_CHECK_(!original_working_dir_.IsEmpty()) + << "Failed to get the current working directory."; + } + + GetTestCase(test_info->test_case_name(), + test_info->type_param(), + set_up_tc, + tear_down_tc)->AddTestInfo(test_info); + } + +#if GTEST_HAS_PARAM_TEST + // Returns ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { + return parameterized_test_registry_; + } +#endif // GTEST_HAS_PARAM_TEST + + // Sets the TestCase object for the test that's currently running. + void set_current_test_case(TestCase* a_current_test_case) { + current_test_case_ = a_current_test_case; + } + + // Sets the TestInfo object for the test that's currently running. If + // current_test_info is NULL, the assertion results will be stored in + // ad_hoc_test_result_. + void set_current_test_info(TestInfo* a_current_test_info) { + current_test_info_ = a_current_test_info; + } + + // Registers all parameterized tests defined using TEST_P and + // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter + // combination. This method can be called more then once; it has guards + // protecting from registering the tests more then once. If + // value-parameterized tests are disabled, RegisterParameterizedTests is + // present but does nothing. + void RegisterParameterizedTests(); + + // Runs all tests in this UnitTest object, prints the result, and + // returns true if all tests are successful. If any exception is + // thrown during a test, this test is considered to be failed, but + // the rest of the tests will still be run. + bool RunAllTests(); + + // Clears the results of all tests, except the ad hoc tests. + void ClearNonAdHocTestResult() { + ForEach(test_cases_, TestCase::ClearTestCaseResult); + } + + // Clears the results of ad-hoc test assertions. + void ClearAdHocTestResult() { + ad_hoc_test_result_.Clear(); + } + + enum ReactionToSharding { + HONOR_SHARDING_PROTOCOL, + IGNORE_SHARDING_PROTOCOL + }; + + // Matches the full name of each test against the user-specified + // filter to decide whether the test should run, then records the + // result in each TestCase and TestInfo object. + // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests + // based on sharding variables in the environment. + // Returns the number of tests that should run. + int FilterTests(ReactionToSharding shard_tests); + + // Prints the names of the tests matching the user-specified filter flag. + void ListTestsMatchingFilter(); + + const TestCase* current_test_case() const { return current_test_case_; } + TestInfo* current_test_info() { return current_test_info_; } + const TestInfo* current_test_info() const { return current_test_info_; } + + // Returns the vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector& environments() { return environments_; } + + // Getters for the per-thread Google Test trace stack. + std::vector& gtest_trace_stack() { + return *(gtest_trace_stack_.pointer()); + } + const std::vector& gtest_trace_stack() const { + return gtest_trace_stack_.get(); + } + +#if GTEST_HAS_DEATH_TEST + void InitDeathTestSubprocessControlInfo() { + internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); + } + // Returns a pointer to the parsed --gtest_internal_run_death_test + // flag, or NULL if that flag was not specified. + // This information is useful only in a death test child process. + // Must not be called before a call to InitGoogleTest. + const InternalRunDeathTestFlag* internal_run_death_test_flag() const { + return internal_run_death_test_flag_.get(); + } + + // Returns a pointer to the current death test factory. + internal::DeathTestFactory* death_test_factory() { + return death_test_factory_.get(); + } + + void SuppressTestEventsIfInSubprocess(); + + friend class ReplaceDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + + // Initializes the event listener performing XML output as specified by + // UnitTestOptions. Must not be called before InitGoogleTest. + void ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Initializes the event listener for streaming test results to a socket. + // Must not be called before InitGoogleTest. + void ConfigureStreamingOutput(); +#endif + + // Performs initialization dependent upon flag values obtained in + // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to + // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest + // this function is also called from RunAllTests. Since this function can be + // called more than once, it has to be idempotent. + void PostFlagParsingInit(); + + // Gets the random seed used at the start of the current test iteration. + int random_seed() const { return random_seed_; } + + // Gets the random number generator. + internal::Random* random() { return &random_; } + + // Shuffles all test cases, and the tests within each test case, + // making sure that death tests are still run first. + void ShuffleTests(); + + // Restores the test cases and tests to their order before the first shuffle. + void UnshuffleTests(); + + // Returns the value of GTEST_FLAG(catch_exceptions) at the moment + // UnitTest::Run() starts. + bool catch_exceptions() const { return catch_exceptions_; } + + private: + friend class ::testing::UnitTest; + + // Used by UnitTest::Run() to capture the state of + // GTEST_FLAG(catch_exceptions) at the moment it starts. + void set_catch_exceptions(bool value) { catch_exceptions_ = value; } + + // The UnitTest object that owns this implementation object. + UnitTest* const parent_; + + // The working directory when the first TEST() or TEST_F() was + // executed. + internal::FilePath original_working_dir_; + + // The default test part result reporters. + DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; + DefaultPerThreadTestPartResultReporter + default_per_thread_test_part_result_reporter_; + + // Points to (but doesn't own) the global test part result reporter. + TestPartResultReporterInterface* global_test_part_result_repoter_; + + // Protects read and write access to global_test_part_result_reporter_. + internal::Mutex global_test_part_result_reporter_mutex_; + + // Points to (but doesn't own) the per-thread test part result reporter. + internal::ThreadLocal + per_thread_test_part_result_reporter_; + + // The vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector environments_; + + // The vector of TestCases in their original order. It owns the + // elements in the vector. + std::vector test_cases_; + + // Provides a level of indirection for the test case list to allow + // easy shuffling and restoring the test case order. The i-th + // element of this vector is the index of the i-th test case in the + // shuffled order. + std::vector test_case_indices_; + +#if GTEST_HAS_PARAM_TEST + // ParameterizedTestRegistry object used to register value-parameterized + // tests. + internal::ParameterizedTestCaseRegistry parameterized_test_registry_; + + // Indicates whether RegisterParameterizedTests() has been called already. + bool parameterized_tests_registered_; +#endif // GTEST_HAS_PARAM_TEST + + // Index of the last death test case registered. Initially -1. + int last_death_test_case_; + + // This points to the TestCase for the currently running test. It + // changes as Google Test goes through one test case after another. + // When no test is running, this is set to NULL and Google Test + // stores assertion results in ad_hoc_test_result_. Initially NULL. + TestCase* current_test_case_; + + // This points to the TestInfo for the currently running test. It + // changes as Google Test goes through one test after another. When + // no test is running, this is set to NULL and Google Test stores + // assertion results in ad_hoc_test_result_. Initially NULL. + TestInfo* current_test_info_; + + // Normally, a user only writes assertions inside a TEST or TEST_F, + // or inside a function called by a TEST or TEST_F. Since Google + // Test keeps track of which test is current running, it can + // associate such an assertion with the test it belongs to. + // + // If an assertion is encountered when no TEST or TEST_F is running, + // Google Test attributes the assertion result to an imaginary "ad hoc" + // test, and records the result in ad_hoc_test_result_. + TestResult ad_hoc_test_result_; + + // The list of event listeners that can be used to track events inside + // Google Test. + TestEventListeners listeners_; + + // The OS stack trace getter. Will be deleted when the UnitTest + // object is destructed. By default, an OsStackTraceGetter is used, + // but the user can set this field to use a custom getter if that is + // desired. + OsStackTraceGetterInterface* os_stack_trace_getter_; + + // True iff PostFlagParsingInit() has been called. + bool post_flag_parse_init_performed_; + + // The random number seed used at the beginning of the test run. + int random_seed_; + + // Our random number generator. + internal::Random random_; + + // How long the test took to run, in milliseconds. + TimeInMillis elapsed_time_; + +#if GTEST_HAS_DEATH_TEST + // The decomposed components of the gtest_internal_run_death_test flag, + // parsed when RUN_ALL_TESTS is called. + internal::scoped_ptr internal_run_death_test_flag_; + internal::scoped_ptr death_test_factory_; +#endif // GTEST_HAS_DEATH_TEST + + // A per-thread stack of traces created by the SCOPED_TRACE() macro. + internal::ThreadLocal > gtest_trace_stack_; + + // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() + // starts. + bool catch_exceptions_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); +}; // class UnitTestImpl + +// Convenience function for accessing the global UnitTest +// implementation object. +inline UnitTestImpl* GetUnitTestImpl() { + return UnitTest::GetInstance()->impl(); +} + +#if GTEST_USES_SIMPLE_RE + +// Internal helper functions for implementing the simple regular +// expression matcher. +GTEST_API_ bool IsInSet(char ch, const char* str); +GTEST_API_ bool IsAsciiDigit(char ch); +GTEST_API_ bool IsAsciiPunct(char ch); +GTEST_API_ bool IsRepeat(char ch); +GTEST_API_ bool IsAsciiWhiteSpace(char ch); +GTEST_API_ bool IsAsciiWordChar(char ch); +GTEST_API_ bool IsValidEscape(char ch); +GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); +GTEST_API_ bool ValidateRegex(const char* regex); +GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); +GTEST_API_ bool MatchRepetitionAndRegexAtHead( + bool escaped, char ch, char repeat, const char* regex, const char* str); +GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); + +#endif // GTEST_USES_SIMPLE_RE + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); + +#if GTEST_HAS_DEATH_TEST + +// Returns the message describing the last system error, regardless of the +// platform. +GTEST_API_ String GetLastErrnoDescription(); + +# if GTEST_OS_WINDOWS +// Provides leak-safe Windows kernel handle ownership. +class AutoHandle { + public: + AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} + explicit AutoHandle(HANDLE handle) : handle_(handle) {} + + ~AutoHandle() { Reset(); } + + HANDLE Get() const { return handle_; } + void Reset() { Reset(INVALID_HANDLE_VALUE); } + void Reset(HANDLE handle) { + if (handle != handle_) { + if (handle_ != INVALID_HANDLE_VALUE) + ::CloseHandle(handle_); + handle_ = handle; + } + } + + private: + HANDLE handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; +# endif // GTEST_OS_WINDOWS + +// Attempts to parse a string into a positive integer pointed to by the +// number parameter. Returns true if that is possible. +// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use +// it here. +template +bool ParseNaturalNumber(const ::std::string& str, Integer* number) { + // Fail fast if the given string does not begin with a digit; + // this bypasses strtoXXX's "optional leading whitespace and plus + // or minus sign" semantics, which are undesirable here. + if (str.empty() || !IsDigit(str[0])) { + return false; + } + errno = 0; + + char* end; + // BiggestConvertible is the largest integer type that system-provided + // string-to-number conversion routines can return. + +# if GTEST_OS_WINDOWS && !defined(__GNUC__) + + // MSVC and C++ Builder define __int64 instead of the standard long long. + typedef unsigned __int64 BiggestConvertible; + const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); + +# else + + typedef unsigned long long BiggestConvertible; // NOLINT + const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); + +# endif // GTEST_OS_WINDOWS && !defined(__GNUC__) + + const bool parse_success = *end == '\0' && errno == 0; + + // TODO(vladl@google.com): Convert this to compile time assertion when it is + // available. + GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); + + const Integer result = static_cast(parsed); + if (parse_success && static_cast(result) == parsed) { + *number = result; + return true; + } + return false; +} +#endif // GTEST_HAS_DEATH_TEST + +// TestResult contains some private methods that should be hidden from +// Google Test user but are required for testing. This class allow our tests +// to access them. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. +class TestResultAccessor { + public: + static void RecordProperty(TestResult* test_result, + const TestProperty& property) { + test_result->RecordProperty(property); + } + + static void ClearTestPartResults(TestResult* test_result) { + test_result->ClearTestPartResults(); + } + + static const std::vector& test_part_results( + const TestResult& test_result) { + return test_result.test_part_results(); + } +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ +#undef GTEST_IMPLEMENTATION_ + +#if GTEST_OS_WINDOWS +# define vsnprintf _vsnprintf +#endif // GTEST_OS_WINDOWS + +namespace testing { + +using internal::CountIf; +using internal::ForEach; +using internal::GetElementOr; +using internal::Shuffle; + +// Constants. + +// A test whose test case name or test name matches this filter is +// disabled and not run. +static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; + +// A test case whose name matches this filter is considered a death +// test case and will be run before test cases whose name doesn't +// match this filter. +static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; + +// A test filter that matches everything. +static const char kUniversalFilter[] = "*"; + +// The default output file for XML output. +static const char kDefaultOutputFile[] = "test_detail.xml"; + +// The environment variable name for the test shard index. +static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; +// The environment variable name for the total number of test shards. +static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; +// The environment variable name for the test shard status file. +static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; + +namespace internal { + +// The text used in failure messages to indicate the start of the +// stack trace. +const char kStackTraceMarker[] = "\nStack trace:\n"; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +bool g_help_flag = false; + +} // namespace internal + +GTEST_DEFINE_bool_( + also_run_disabled_tests, + internal::BoolFromGTestEnv("also_run_disabled_tests", false), + "Run disabled tests too, in addition to the tests normally being run."); + +GTEST_DEFINE_bool_( + break_on_failure, + internal::BoolFromGTestEnv("break_on_failure", false), + "True iff a failed assertion should be a debugger break-point."); + +GTEST_DEFINE_bool_( + catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", true), + "True iff " GTEST_NAME_ + " should catch exceptions and treat them as test failures."); + +GTEST_DEFINE_string_( + color, + internal::StringFromGTestEnv("color", "auto"), + "Whether to use colors in the output. Valid values: yes, no, " + "and auto. 'auto' means to use colors if the output is " + "being sent to a terminal and the TERM environment variable " + "is set to xterm, xterm-color, xterm-256color, linux or cygwin."); + +GTEST_DEFINE_string_( + filter, + internal::StringFromGTestEnv("filter", kUniversalFilter), + "A colon-separated list of glob (not regex) patterns " + "for filtering the tests to run, optionally followed by a " + "'-' and a : separated list of negative patterns (tests to " + "exclude). A test is run if it matches one of the positive " + "patterns and does not match any of the negative patterns."); + +GTEST_DEFINE_bool_(list_tests, false, + "List all tests without running them."); + +GTEST_DEFINE_string_( + output, + internal::StringFromGTestEnv("output", ""), + "A format (currently must be \"xml\"), optionally followed " + "by a colon and an output file name or directory. A directory " + "is indicated by a trailing pathname separator. " + "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " + "If a directory is specified, output files will be created " + "within that directory, with file-names based on the test " + "executable's name and, if necessary, made unique by adding " + "digits."); + +GTEST_DEFINE_bool_( + print_time, + internal::BoolFromGTestEnv("print_time", true), + "True iff " GTEST_NAME_ + " should display elapsed time in text output."); + +GTEST_DEFINE_int32_( + random_seed, + internal::Int32FromGTestEnv("random_seed", 0), + "Random number seed to use when shuffling test orders. Must be in range " + "[1, 99999], or 0 to use a seed based on the current time."); + +GTEST_DEFINE_int32_( + repeat, + internal::Int32FromGTestEnv("repeat", 1), + "How many times to repeat each test. Specify a negative number " + "for repeating forever. Useful for shaking out flaky tests."); + +GTEST_DEFINE_bool_( + show_internal_stack_frames, false, + "True iff " GTEST_NAME_ " should include internal stack frames when " + "printing test failure stack traces."); + +GTEST_DEFINE_bool_( + shuffle, + internal::BoolFromGTestEnv("shuffle", false), + "True iff " GTEST_NAME_ + " should randomize tests' order on every run."); + +GTEST_DEFINE_int32_( + stack_trace_depth, + internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), + "The maximum number of stack frames to print when an " + "assertion fails. The valid range is 0 through 100, inclusive."); + +GTEST_DEFINE_string_( + stream_result_to, + internal::StringFromGTestEnv("stream_result_to", ""), + "This flag specifies the host name and the port number on which to stream " + "test results. Example: \"localhost:555\". The flag is effective only on " + "Linux."); + +GTEST_DEFINE_bool_( + throw_on_failure, + internal::BoolFromGTestEnv("throw_on_failure", false), + "When this flag is specified, a failed assertion will throw an exception " + "if exceptions are enabled or exit the program with a non-zero code " + "otherwise."); + +namespace internal { + +// Generates a random number from [0, range), using a Linear +// Congruential Generator (LCG). Crashes if 'range' is 0 or greater +// than kMaxRange. +UInt32 Random::Generate(UInt32 range) { + // These constants are the same as are used in glibc's rand(3). + state_ = (1103515245U*state_ + 12345U) % kMaxRange; + + GTEST_CHECK_(range > 0) + << "Cannot generate a number in the range [0, 0)."; + GTEST_CHECK_(range <= kMaxRange) + << "Generation of a number in [0, " << range << ") was requested, " + << "but this can only generate numbers in [0, " << kMaxRange << ")."; + + // Converting via modulus introduces a bit of downward bias, but + // it's simple, and a linear congruential generator isn't too good + // to begin with. + return state_ % range; +} + +// GTestIsInitialized() returns true iff the user has initialized +// Google Test. Useful for catching the user mistake of not initializing +// Google Test before calling RUN_ALL_TESTS(). +// +// A user must call testing::InitGoogleTest() to initialize Google +// Test. g_init_gtest_count is set to the number of times +// InitGoogleTest() has been called. We don't protect this variable +// under a mutex as it is only accessed in the main thread. +int g_init_gtest_count = 0; +static bool GTestIsInitialized() { return g_init_gtest_count != 0; } + +// Iterates over a vector of TestCases, keeping a running sum of the +// results of calling a given int-returning method on each. +// Returns the sum. +static int SumOverTestCaseList(const std::vector& case_list, + int (TestCase::*method)() const) { + int sum = 0; + for (size_t i = 0; i < case_list.size(); i++) { + sum += (case_list[i]->*method)(); + } + return sum; +} + +// Returns true iff the test case passed. +static bool TestCasePassed(const TestCase* test_case) { + return test_case->should_run() && test_case->Passed(); +} + +// Returns true iff the test case failed. +static bool TestCaseFailed(const TestCase* test_case) { + return test_case->should_run() && test_case->Failed(); +} + +// Returns true iff test_case contains at least one test that should +// run. +static bool ShouldRunTestCase(const TestCase* test_case) { + return test_case->should_run(); +} + +// AssertHelper constructor. +AssertHelper::AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message) + : data_(new AssertHelperData(type, file, line, message)) { +} + +AssertHelper::~AssertHelper() { + delete data_; +} + +// Message assignment, for assertion streaming support. +void AssertHelper::operator=(const Message& message) const { + UnitTest::GetInstance()-> + AddTestPartResult(data_->type, data_->file, data_->line, + AppendUserMessage(data_->message, message), + UnitTest::GetInstance()->impl() + ->CurrentOsStackTraceExceptTop(1) + // Skips the stack frame for this function itself. + ); // NOLINT +} + +// Mutex for linked pointers. +GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// Application pathname gotten in InitGoogleTest. +String g_executable_path; + +// Returns the current application's name, removing directory path if that +// is present. +FilePath GetCurrentExecutableName() { + FilePath result; + +#if GTEST_OS_WINDOWS + result.Set(FilePath(g_executable_path).RemoveExtension("exe")); +#else + result.Set(FilePath(g_executable_path)); +#endif // GTEST_OS_WINDOWS + + return result.RemoveDirectoryName(); +} + +// Functions for processing the gtest_output flag. + +// Returns the output format, or "" for normal printed output. +String UnitTestOptions::GetOutputFormat() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + return (colon == NULL) ? + String(gtest_output_flag) : + String(gtest_output_flag, colon - gtest_output_flag); +} + +// Returns the name of the requested output file, or the default if none +// was explicitly specified. +String UnitTestOptions::GetAbsolutePathToOutputFile() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) + return String(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + if (colon == NULL) + return String(internal::FilePath::ConcatPaths( + internal::FilePath( + UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(kDefaultOutputFile)).ToString() ); + + internal::FilePath output_name(colon + 1); + if (!output_name.IsAbsolutePath()) + // TODO(wan@google.com): on Windows \some\path is not an absolute + // path (as its meaning depends on the current drive), yet the + // following logic for turning it into an absolute path is wrong. + // Fix it. + output_name = internal::FilePath::ConcatPaths( + internal::FilePath(UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(colon + 1)); + + if (!output_name.IsDirectory()) + return output_name.ToString(); + + internal::FilePath result(internal::FilePath::GenerateUniqueFileName( + output_name, internal::GetCurrentExecutableName(), + GetOutputFormat().c_str())); + return result.ToString(); +} + +// Returns true iff the wildcard pattern matches the string. The +// first ':' or '\0' character in pattern marks the end of it. +// +// This recursive algorithm isn't very efficient, but is clear and +// works well enough for matching test names, which are short. +bool UnitTestOptions::PatternMatchesString(const char *pattern, + const char *str) { + switch (*pattern) { + case '\0': + case ':': // Either ':' or '\0' marks the end of the pattern. + return *str == '\0'; + case '?': // Matches any single character. + return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); + case '*': // Matches any string (possibly empty) of characters. + return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || + PatternMatchesString(pattern + 1, str); + default: // Non-special character. Matches itself. + return *pattern == *str && + PatternMatchesString(pattern + 1, str + 1); + } +} + +bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) { + const char *cur_pattern = filter; + for (;;) { + if (PatternMatchesString(cur_pattern, name.c_str())) { + return true; + } + + // Finds the next pattern in the filter. + cur_pattern = strchr(cur_pattern, ':'); + + // Returns if no more pattern can be found. + if (cur_pattern == NULL) { + return false; + } + + // Skips the pattern separater (the ':' character). + cur_pattern++; + } + return false; +} + +// TODO(keithray): move String function implementations to gtest-string.cc. + +// Returns true iff the user-specified filter matches the test case +// name and the test name. +bool UnitTestOptions::FilterMatchesTest(const String &test_case_name, + const String &test_name) { + const String& full_name = String::Format("%s.%s", + test_case_name.c_str(), + test_name.c_str()); + + // Split --gtest_filter at '-', if there is one, to separate into + // positive filter and negative filter portions + const char* const p = GTEST_FLAG(filter).c_str(); + const char* const dash = strchr(p, '-'); + String positive; + String negative; + if (dash == NULL) { + positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter + negative = String(""); + } else { + positive = String(p, dash - p); // Everything up to the dash + negative = String(dash+1); // Everything after the dash + if (positive.empty()) { + // Treat '-test1' as the same as '*-test1' + positive = kUniversalFilter; + } + } + + // A filter is a colon-separated list of patterns. It matches a + // test if any pattern in it matches the test. + return (MatchesFilter(full_name, positive.c_str()) && + !MatchesFilter(full_name, negative.c_str())); +} + +#if GTEST_HAS_SEH +// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the +// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. +// This function is useful as an __except condition. +int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { + // Google Test should handle a SEH exception if: + // 1. the user wants it to, AND + // 2. this is not a breakpoint exception, AND + // 3. this is not a C++ exception (VC++ implements them via SEH, + // apparently). + // + // SEH exception code for C++ exceptions. + // (see http://support.microsoft.com/kb/185294 for more information). + const DWORD kCxxExceptionCode = 0xe06d7363; + + bool should_handle = true; + + if (!GTEST_FLAG(catch_exceptions)) + should_handle = false; + else if (exception_code == EXCEPTION_BREAKPOINT) + should_handle = false; + else if (exception_code == kCxxExceptionCode) + should_handle = false; + + return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +} +#endif // GTEST_HAS_SEH + +} // namespace internal + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. Intercepts only failures from the current thread. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + TestPartResultArray* result) + : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), + result_(result) { + Init(); +} + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + InterceptMode intercept_mode, TestPartResultArray* result) + : intercept_mode_(intercept_mode), + result_(result) { + Init(); +} + +void ScopedFakeTestPartResultReporter::Init() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + old_reporter_ = impl->GetGlobalTestPartResultReporter(); + impl->SetGlobalTestPartResultReporter(this); + } else { + old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); + impl->SetTestPartResultReporterForCurrentThread(this); + } +} + +// The d'tor restores the test part result reporter used by Google Test +// before. +ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + impl->SetGlobalTestPartResultReporter(old_reporter_); + } else { + impl->SetTestPartResultReporterForCurrentThread(old_reporter_); + } +} + +// Increments the test part result count and remembers the result. +// This method is from the TestPartResultReporterInterface interface. +void ScopedFakeTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + result_->Append(result); +} + +namespace internal { + +// Returns the type ID of ::testing::Test. We should always call this +// instead of GetTypeId< ::testing::Test>() to get the type ID of +// testing::Test. This is to work around a suspected linker bug when +// using Google Test as a framework on Mac OS X. The bug causes +// GetTypeId< ::testing::Test>() to return different values depending +// on whether the call is from the Google Test framework itself or +// from user test code. GetTestTypeId() is guaranteed to always +// return the same value, as it always calls GetTypeId<>() from the +// gtest.cc, which is within the Google Test framework. +TypeId GetTestTypeId() { + return GetTypeId(); +} + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); + +// This predicate-formatter checks that 'results' contains a test part +// failure of the given type and that the failure message contains the +// given substring. +AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const string& substr) { + const String expected(type == TestPartResult::kFatalFailure ? + "1 fatal failure" : + "1 non-fatal failure"); + Message msg; + if (results.size() != 1) { + msg << "Expected: " << expected << "\n" + << " Actual: " << results.size() << " failures"; + for (int i = 0; i < results.size(); i++) { + msg << "\n" << results.GetTestPartResult(i); + } + return AssertionFailure() << msg; + } + + const TestPartResult& r = results.GetTestPartResult(0); + if (r.type() != type) { + return AssertionFailure() << "Expected: " << expected << "\n" + << " Actual:\n" + << r; + } + + if (strstr(r.message(), substr.c_str()) == NULL) { + return AssertionFailure() << "Expected: " << expected << " containing \"" + << substr << "\"\n" + << " Actual:\n" + << r; + } + + return AssertionSuccess(); +} + +// The constructor of SingleFailureChecker remembers where to look up +// test part results, what type of failure we expect, and what +// substring the failure message should contain. +SingleFailureChecker:: SingleFailureChecker( + const TestPartResultArray* results, + TestPartResult::Type type, + const string& substr) + : results_(results), + type_(type), + substr_(substr) {} + +// The destructor of SingleFailureChecker verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +SingleFailureChecker::~SingleFailureChecker() { + EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); +} + +DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultGlobalTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->current_test_result()->AddTestPartResult(result); + unit_test_->listeners()->repeater()->OnTestPartResult(result); +} + +DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); +} + +// Returns the global test part result reporter. +TestPartResultReporterInterface* +UnitTestImpl::GetGlobalTestPartResultReporter() { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + return global_test_part_result_repoter_; +} + +// Sets the global test part result reporter. +void UnitTestImpl::SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter) { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + global_test_part_result_repoter_ = reporter; +} + +// Returns the test part result reporter for the current thread. +TestPartResultReporterInterface* +UnitTestImpl::GetTestPartResultReporterForCurrentThread() { + return per_thread_test_part_result_reporter_.get(); +} + +// Sets the test part result reporter for the current thread. +void UnitTestImpl::SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter) { + per_thread_test_part_result_reporter_.set(reporter); +} + +// Gets the number of successful test cases. +int UnitTestImpl::successful_test_case_count() const { + return CountIf(test_cases_, TestCasePassed); +} + +// Gets the number of failed test cases. +int UnitTestImpl::failed_test_case_count() const { + return CountIf(test_cases_, TestCaseFailed); +} + +// Gets the number of all test cases. +int UnitTestImpl::total_test_case_count() const { + return static_cast(test_cases_.size()); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTestImpl::test_case_to_run_count() const { + return CountIf(test_cases_, ShouldRunTestCase); +} + +// Gets the number of successful tests. +int UnitTestImpl::successful_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); +} + +// Gets the number of failed tests. +int UnitTestImpl::failed_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); +} + +// Gets the number of disabled tests. +int UnitTestImpl::disabled_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); +} + +// Gets the number of all tests. +int UnitTestImpl::total_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); +} + +// Gets the number of tests that should run. +int UnitTestImpl::test_to_run_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); +} + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// CurrentOsStackTraceExceptTop(1), Foo() will be included in the +// trace but Bar() and CurrentOsStackTraceExceptTop() won't. +String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { + (void)skip_count; + return String(""); +} + +// Returns the current time in milliseconds. +TimeInMillis GetTimeInMillis() { +#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) + // Difference between 1970-01-01 and 1601-01-01 in milliseconds. + // http://analogous.blogspot.com/2005/04/epoch.html + const TimeInMillis kJavaEpochToWinFileTimeDelta = + static_cast(116444736UL) * 100000UL; + const DWORD kTenthMicrosInMilliSecond = 10000; + + SYSTEMTIME now_systime; + FILETIME now_filetime; + ULARGE_INTEGER now_int64; + // TODO(kenton@google.com): Shouldn't this just use + // GetSystemTimeAsFileTime()? + GetSystemTime(&now_systime); + if (SystemTimeToFileTime(&now_systime, &now_filetime)) { + now_int64.LowPart = now_filetime.dwLowDateTime; + now_int64.HighPart = now_filetime.dwHighDateTime; + now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - + kJavaEpochToWinFileTimeDelta; + return now_int64.QuadPart; + } + return 0; +#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ + __timeb64 now; + +# ifdef _MSC_VER + + // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 + // (deprecated function) there. + // TODO(kenton@google.com): Use GetTickCount()? Or use + // SystemTimeToFileTime() +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. + _ftime64(&now); +# pragma warning(pop) // Restores the warning state. +# else + + _ftime64(&now); + +# endif // _MSC_VER + + return static_cast(now.time) * 1000 + now.millitm; +#elif GTEST_HAS_GETTIMEOFDAY_ + struct timeval now; + gettimeofday(&now, NULL); + return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; +#else +# error "Don't know how to get the current time on your system." +#endif +} + +// Utilities + +// class String + +// Returns the input enclosed in double quotes if it's not NULL; +// otherwise returns "(null)". For example, "\"Hello\"" is returned +// for input "Hello". +// +// This is useful for printing a C string in the syntax of a literal. +// +// Known issue: escape sequences are not handled yet. +String String::ShowCStringQuoted(const char* c_str) { + return c_str ? String::Format("\"%s\"", c_str) : String("(null)"); +} + +// Copies at most length characters from str into a newly-allocated +// piece of memory of size length+1. The memory is allocated with new[]. +// A terminating null byte is written to the memory, and a pointer to it +// is returned. If str is NULL, NULL is returned. +static char* CloneString(const char* str, size_t length) { + if (str == NULL) { + return NULL; + } else { + char* const clone = new char[length + 1]; + posix::StrNCpy(clone, str, length); + clone[length] = '\0'; + return clone; + } +} + +// Clones a 0-terminated C string, allocating memory using new. The +// caller is responsible for deleting[] the return value. Returns the +// cloned string, or NULL if the input is NULL. +const char * String::CloneCString(const char* c_str) { + return (c_str == NULL) ? + NULL : CloneString(c_str, strlen(c_str)); +} + +#if GTEST_OS_WINDOWS_MOBILE +// Creates a UTF-16 wide string from the given ANSI string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the wide string, or NULL if the +// input is NULL. +LPCWSTR String::AnsiToUtf16(const char* ansi) { + if (!ansi) return NULL; + const int length = strlen(ansi); + const int unicode_length = + MultiByteToWideChar(CP_ACP, 0, ansi, length, + NULL, 0); + WCHAR* unicode = new WCHAR[unicode_length + 1]; + MultiByteToWideChar(CP_ACP, 0, ansi, length, + unicode, unicode_length); + unicode[unicode_length] = 0; + return unicode; +} + +// Creates an ANSI string from the given wide string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the ANSI string, or NULL if the +// input is NULL. +const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { + if (!utf16_str) return NULL; + const int ansi_length = + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + NULL, 0, NULL, NULL); + char* ansi = new char[ansi_length + 1]; + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + ansi, ansi_length, NULL, NULL); + ansi[ansi_length] = 0; + return ansi; +} + +#endif // GTEST_OS_WINDOWS_MOBILE + +// Compares two C strings. Returns true iff they have the same content. +// +// Unlike strcmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CStringEquals(const char * lhs, const char * rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + + return strcmp(lhs, rhs) == 0; +} + +#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +// Converts an array of wide chars to a narrow string using the UTF-8 +// encoding, and streams the result to the given Message object. +static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, + Message* msg) { + // TODO(wan): consider allowing a testing::String object to + // contain '\0'. This will make it behave more like std::string, + // and will allow ToUtf8String() to return the correct encoding + // for '\0' s.t. we can get rid of the conditional here (and in + // several other places). + for (size_t i = 0; i != length; ) { // NOLINT + if (wstr[i] != L'\0') { + *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); + while (i != length && wstr[i] != L'\0') + i++; + } else { + *msg << '\0'; + i++; + } + } +} + +#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +} // namespace internal + +#if GTEST_HAS_STD_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::std::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +// AssertionResult constructors. +// Used in EXPECT_TRUE/FALSE(assertion_result). +AssertionResult::AssertionResult(const AssertionResult& other) + : success_(other.success_), + message_(other.message_.get() != NULL ? + new ::std::string(*other.message_) : + static_cast< ::std::string*>(NULL)) { +} + +// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. +AssertionResult AssertionResult::operator!() const { + AssertionResult negation(!success_); + if (message_.get() != NULL) + negation << *message_; + return negation; +} + +// Makes a successful assertion result. +AssertionResult AssertionSuccess() { + return AssertionResult(true); +} + +// Makes a failed assertion result. +AssertionResult AssertionFailure() { + return AssertionResult(false); +} + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << message. +AssertionResult AssertionFailure(const Message& message) { + return AssertionFailure() << message; +} + +namespace internal { + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const String& expected_value, + const String& actual_value, + bool ignoring_case) { + Message msg; + msg << "Value of: " << actual_expression; + if (actual_value != actual_expression) { + msg << "\n Actual: " << actual_value; + } + + msg << "\nExpected: " << expected_expression; + if (ignoring_case) { + msg << " (ignoring case)"; + } + if (expected_value != expected_expression) { + msg << "\nWhich is: " << expected_value; + } + + return AssertionFailure() << msg; +} + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value) { + const char* actual_message = assertion_result.message(); + Message msg; + msg << "Value of: " << expression_text + << "\n Actual: " << actual_predicate_value; + if (actual_message[0] != '\0') + msg << " (" << actual_message << ")"; + msg << "\nExpected: " << expected_predicate_value; + return msg.GetString(); +} + +// Helper function for implementing ASSERT_NEAR. +AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error) { + const double diff = fabs(val1 - val2); + if (diff <= abs_error) return AssertionSuccess(); + + // TODO(wan): do not print the value of an expression if it's + // already a literal. + return AssertionFailure() + << "The difference between " << expr1 << " and " << expr2 + << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ", and\n" + << abs_error_expr << " evaluates to " << abs_error << "."; +} + + +// Helper template for implementing FloatLE() and DoubleLE(). +template +AssertionResult FloatingPointLE(const char* expr1, + const char* expr2, + RawType val1, + RawType val2) { + // Returns success if val1 is less than val2, + if (val1 < val2) { + return AssertionSuccess(); + } + + // or if val1 is almost equal to val2. + const FloatingPoint lhs(val1), rhs(val2); + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + // Note that the above two checks will both fail if either val1 or + // val2 is NaN, as the IEEE floating-point standard requires that + // any predicate involving a NaN must return false. + + ::std::stringstream val1_ss; + val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val1; + + ::std::stringstream val2_ss; + val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val2; + + return AssertionFailure() + << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" + << " Actual: " << StringStreamToString(&val1_ss) << " vs " + << StringStreamToString(&val2_ss); +} + +} // namespace internal + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +namespace internal { + +// The helper function for {ASSERT|EXPECT}_EQ with int or enum +// arguments. +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + if (expected == actual) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here +// just to avoid copy-and-paste of similar code. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + BiggestInt val1, BiggestInt val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + }\ +} + +// Implements the helper function for {ASSERT|EXPECT}_NE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(NE, !=) +// Implements the helper function for {ASSERT|EXPECT}_LE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LE, <=) +// Implements the helper function for {ASSERT|EXPECT}_LT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LT, < ) +// Implements the helper function for {ASSERT|EXPECT}_GE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GE, >=) +// Implements the helper function for {ASSERT|EXPECT}_GT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GT, > ) + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + false); +} + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CaseInsensitiveCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowCStringQuoted(expected), + String::ShowCStringQuoted(actual), + true); +} + +// The helper function for {ASSERT|EXPECT}_STRNE. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CaseInsensitiveCStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() + << "Expected: (" << s1_expression << ") != (" + << s2_expression << ") (ignoring case), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +} // namespace internal + +namespace { + +// Helper functions for implementing IsSubString() and IsNotSubstring(). + +// This group of overloaded functions return true iff needle is a +// substring of haystack. NULL is considered a substring of itself +// only. + +bool IsSubstringPred(const char* needle, const char* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return strstr(haystack, needle) != NULL; +} + +bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return wcsstr(haystack, needle) != NULL; +} + +// StringType here can be either ::std::string or ::std::wstring. +template +bool IsSubstringPred(const StringType& needle, + const StringType& haystack) { + return haystack.find(needle) != StringType::npos; +} + +// This function implements either IsSubstring() or IsNotSubstring(), +// depending on the value of the expected_to_be_substring parameter. +// StringType here can be const char*, const wchar_t*, ::std::string, +// or ::std::wstring. +template +AssertionResult IsSubstringImpl( + bool expected_to_be_substring, + const char* needle_expr, const char* haystack_expr, + const StringType& needle, const StringType& haystack) { + if (IsSubstringPred(needle, haystack) == expected_to_be_substring) + return AssertionSuccess(); + + const bool is_wide_string = sizeof(needle[0]) > 1; + const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + return AssertionFailure() + << "Value of: " << needle_expr << "\n" + << " Actual: " << begin_string_quote << needle << "\"\n" + << "Expected: " << (expected_to_be_substring ? "" : "not ") + << "a substring of " << haystack_expr << "\n" + << "Which is: " << begin_string_quote << haystack << "\""; +} + +} // namespace + +// IsSubstring() and IsNotSubstring() check whether needle is a +// substring of haystack (NULL is considered a substring of itself +// only), and return an appropriate error message when they fail. + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +#if GTEST_HAS_STD_WSTRING +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +#if GTEST_OS_WINDOWS + +namespace { + +// Helper function for IsHRESULT{SuccessFailure} predicates +AssertionResult HRESULTFailureHelper(const char* expr, + const char* expected, + long hr) { // NOLINT +# if GTEST_OS_WINDOWS_MOBILE + + // Windows CE doesn't support FormatMessage. + const char error_text[] = ""; + +# else + + // Looks up the human-readable system message for the HRESULT code + // and since we're not passing any params to FormatMessage, we don't + // want inserts expanded. + const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS; + const DWORD kBufSize = 4096; // String::Format can't exceed this length. + // Gets the system's human readable message string for this HRESULT. + char error_text[kBufSize] = { '\0' }; + DWORD message_length = ::FormatMessageA(kFlags, + 0, // no source, we're asking system + hr, // the error + 0, // no line width restrictions + error_text, // output buffer + kBufSize, // buf size + NULL); // no arguments for inserts + // Trims tailing white space (FormatMessage leaves a trailing cr-lf) + for (; message_length && IsSpace(error_text[message_length - 1]); + --message_length) { + error_text[message_length - 1] = '\0'; + } + +# endif // GTEST_OS_WINDOWS_MOBILE + + const String error_hex(String::Format("0x%08X ", hr)); + return ::testing::AssertionFailure() + << "Expected: " << expr << " " << expected << ".\n" + << " Actual: " << error_hex << error_text << "\n"; +} + +} // namespace + +AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT + if (SUCCEEDED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "succeeds", hr); +} + +AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT + if (FAILED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "fails", hr); +} + +#endif // GTEST_OS_WINDOWS + +// Utility functions for encoding Unicode text (wide strings) in +// UTF-8. + +// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 +// like this: +// +// Code-point length Encoding +// 0 - 7 bits 0xxxxxxx +// 8 - 11 bits 110xxxxx 10xxxxxx +// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx +// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + +// The maximum code-point a one-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; + +// The maximum code-point a two-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; + +// The maximum code-point a three-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; + +// The maximum code-point a four-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; + +// Chops off the n lowest bits from a bit pattern. Returns the n +// lowest bits. As a side effect, the original bit pattern will be +// shifted to the right by n bits. +inline UInt32 ChopLowBits(UInt32* bits, int n) { + const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); + *bits >>= n; + return low_bits; +} + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// The output buffer str must containt at least 32 characters. +// The function returns the address of the output buffer. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. +char* CodePointToUtf8(UInt32 code_point, char* str) { + if (code_point <= kMaxCodePoint1) { + str[1] = '\0'; + str[0] = static_cast(code_point); // 0xxxxxxx + } else if (code_point <= kMaxCodePoint2) { + str[2] = '\0'; + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xC0 | code_point); // 110xxxxx + } else if (code_point <= kMaxCodePoint3) { + str[3] = '\0'; + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xE0 | code_point); // 1110xxxx + } else if (code_point <= kMaxCodePoint4) { + str[4] = '\0'; + str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xF0 | code_point); // 11110xxx + } else { + // The longest string String::Format can produce when invoked + // with these parameters is 28 character long (not including + // the terminating nul character). We are asking for 32 character + // buffer just in case. This is also enough for strncpy to + // null-terminate the destination string. + posix::StrNCpy( + str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32); + str[31] = '\0'; // Makes sure no change in the format to strncpy leaves + // the result unterminated. + } + return str; +} + +// The following two functions only make sense if the the system +// uses UTF-16 for wide string encoding. All supported systems +// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. + +// Determines if the arguments constitute UTF-16 surrogate pair +// and thus should be combined into a single Unicode code point +// using CreateCodePointFromUtf16SurrogatePair. +inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { + return sizeof(wchar_t) == 2 && + (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; +} + +// Creates a Unicode code point from UTF16 surrogate pair. +inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, + wchar_t second) { + const UInt32 mask = (1 << 10) - 1; + return (sizeof(wchar_t) == 2) ? + (((first & mask) << 10) | (second & mask)) + 0x10000 : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + static_cast(first); +} + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +String WideStringToUtf8(const wchar_t* str, int num_chars) { + if (num_chars == -1) + num_chars = static_cast(wcslen(str)); + + ::std::stringstream stream; + for (int i = 0; i < num_chars; ++i) { + UInt32 unicode_code_point; + + if (str[i] == L'\0') { + break; + } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { + unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], + str[i + 1]); + i++; + } else { + unicode_code_point = static_cast(str[i]); + } + + char buffer[32]; // CodePointToUtf8 requires a buffer this big. + stream << CodePointToUtf8(unicode_code_point, buffer); + } + return StringStreamToString(&stream); +} + +// Converts a wide C string to a String using the UTF-8 encoding. +// NULL will be converted to "(null)". +String String::ShowWideCString(const wchar_t * wide_c_str) { + if (wide_c_str == NULL) return String("(null)"); + + return String(internal::WideStringToUtf8(wide_c_str, -1).c_str()); +} + +// Similar to ShowWideCString(), except that this function encloses +// the converted string in double quotes. +String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) { + if (wide_c_str == NULL) return String("(null)"); + + return String::Format("L\"%s\"", + String::ShowWideCString(wide_c_str).c_str()); +} + +// Compares two wide C strings. Returns true iff they have the same +// content. +// +// Unlike wcscmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + + return wcscmp(lhs, rhs) == 0; +} + +// Helper function for *_STREQ on wide strings. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual) { + if (String::WideCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + String::ShowWideCStringQuoted(expected), + String::ShowWideCStringQuoted(actual), + false); +} + +// Helper function for *_STRNE on wide strings. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2) { + if (!String::WideCStringEquals(s1, s2)) { + return AssertionSuccess(); + } + + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: " + << String::ShowWideCStringQuoted(s1) + << " vs " << String::ShowWideCStringQuoted(s2); +} + +// Compares two C strings, ignoring case. Returns true iff they have +// the same content. +// +// Unlike strcasecmp(), this function can handle NULL argument(s). A +// NULL C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { + if (lhs == NULL) + return rhs == NULL; + if (rhs == NULL) + return false; + return posix::StrCaseCmp(lhs, rhs) == 0; +} + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. +bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + +#if GTEST_OS_WINDOWS + return _wcsicmp(lhs, rhs) == 0; +#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID + return wcscasecmp(lhs, rhs) == 0; +#else + // Android, Mac OS X and Cygwin don't define wcscasecmp. + // Other unknown OSes may not define it either. + wint_t left, right; + do { + left = towlower(*lhs++); + right = towlower(*rhs++); + } while (left && left == right); + return left == right; +#endif // OS selector +} + +// Compares this with another String. +// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 +// if this is greater than rhs. +int String::Compare(const String & rhs) const { + const char* const lhs_c_str = c_str(); + const char* const rhs_c_str = rhs.c_str(); + + if (lhs_c_str == NULL) { + return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL + } else if (rhs_c_str == NULL) { + return 1; + } + + const size_t shorter_str_len = + length() <= rhs.length() ? length() : rhs.length(); + for (size_t i = 0; i != shorter_str_len; i++) { + if (lhs_c_str[i] < rhs_c_str[i]) { + return -1; + } else if (lhs_c_str[i] > rhs_c_str[i]) { + return 1; + } + } + return (length() < rhs.length()) ? -1 : + (length() > rhs.length()) ? 1 : 0; +} + +// Returns true iff this String ends with the given suffix. *Any* +// String is considered to end with a NULL or empty suffix. +bool String::EndsWith(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str() == NULL) return false; + + const size_t this_len = strlen(c_str()); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CStringEquals(c_str() + this_len - suffix_len, suffix); +} + +// Returns true iff this String ends with the given suffix, ignoring case. +// Any String is considered to end with a NULL or empty suffix. +bool String::EndsWithCaseInsensitive(const char* suffix) const { + if (suffix == NULL || CStringEquals(suffix, "")) return true; + + if (c_str() == NULL) return false; + + const size_t this_len = strlen(c_str()); + const size_t suffix_len = strlen(suffix); + return (this_len >= suffix_len) && + CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix); +} + +// Formats a list of arguments to a String, using the same format +// spec string as for printf. +// +// We do not use the StringPrintf class as it is not universally +// available. +// +// The result is limited to 4096 characters (including the tailing 0). +// If 4096 characters are not enough to format the input, or if +// there's an error, "" is +// returned. +String String::Format(const char * format, ...) { + va_list args; + va_start(args, format); + + char buffer[4096]; + const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]); + + // MSVC 8 deprecates vsnprintf(), so we want to suppress warning + // 4996 (deprecated function) there. +#ifdef _MSC_VER // We are using MSVC. +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. + + const int size = vsnprintf(buffer, kBufferSize, format, args); + +# pragma warning(pop) // Restores the warning state. +#else // We are not using MSVC. + const int size = vsnprintf(buffer, kBufferSize, format, args); +#endif // _MSC_VER + va_end(args); + + // vsnprintf()'s behavior is not portable. When the buffer is not + // big enough, it returns a negative value in MSVC, and returns the + // needed buffer size on Linux. When there is an output error, it + // always returns a negative value. For simplicity, we lump the two + // error cases together. + if (size < 0 || size >= kBufferSize) { + return String(""); + } else { + return String(buffer, size); + } +} + +// Converts the buffer in a stringstream to a String, converting NUL +// bytes to "\\0" along the way. +String StringStreamToString(::std::stringstream* ss) { + const ::std::string& str = ss->str(); + const char* const start = str.c_str(); + const char* const end = start + str.length(); + + // We need to use a helper stringstream to do this transformation + // because String doesn't support push_back(). + ::std::stringstream helper; + for (const char* ch = start; ch != end; ++ch) { + if (*ch == '\0') { + helper << "\\0"; // Replaces NUL with "\\0"; + } else { + helper.put(*ch); + } + } + + return String(helper.str().c_str()); +} + +// Appends the user-supplied message to the Google-Test-generated message. +String AppendUserMessage(const String& gtest_msg, + const Message& user_msg) { + // Appends the user message if it's non-empty. + const String user_msg_string = user_msg.GetString(); + if (user_msg_string.empty()) { + return gtest_msg; + } + + Message msg; + msg << gtest_msg << "\n" << user_msg_string; + + return msg.GetString(); +} + +} // namespace internal + +// class TestResult + +// Creates an empty TestResult. +TestResult::TestResult() + : death_test_count_(0), + elapsed_time_(0) { +} + +// D'tor. +TestResult::~TestResult() { +} + +// Returns the i-th test part result among all the results. i can +// range from 0 to total_part_count() - 1. If i is not in that range, +// aborts the program. +const TestPartResult& TestResult::GetTestPartResult(int i) const { + if (i < 0 || i >= total_part_count()) + internal::posix::Abort(); + return test_part_results_.at(i); +} + +// Returns the i-th test property. i can range from 0 to +// test_property_count() - 1. If i is not in that range, aborts the +// program. +const TestProperty& TestResult::GetTestProperty(int i) const { + if (i < 0 || i >= test_property_count()) + internal::posix::Abort(); + return test_properties_.at(i); +} + +// Clears the test part results. +void TestResult::ClearTestPartResults() { + test_part_results_.clear(); +} + +// Adds a test part result to the list. +void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { + test_part_results_.push_back(test_part_result); +} + +// Adds a test property to the list. If a property with the same key as the +// supplied property is already represented, the value of this test_property +// replaces the old value for that key. +void TestResult::RecordProperty(const TestProperty& test_property) { + if (!ValidateTestProperty(test_property)) { + return; + } + internal::MutexLock lock(&test_properites_mutex_); + const std::vector::iterator property_with_matching_key = + std::find_if(test_properties_.begin(), test_properties_.end(), + internal::TestPropertyKeyIs(test_property.key())); + if (property_with_matching_key == test_properties_.end()) { + test_properties_.push_back(test_property); + return; + } + property_with_matching_key->SetValue(test_property.value()); +} + +// Adds a failure if the key is a reserved attribute of Google Test +// testcase tags. Returns true if the property is valid. +bool TestResult::ValidateTestProperty(const TestProperty& test_property) { + internal::String key(test_property.key()); + if (key == "name" || key == "status" || key == "time" || key == "classname") { + ADD_FAILURE() + << "Reserved key used in RecordProperty(): " + << key + << " ('name', 'status', 'time', and 'classname' are reserved by " + << GTEST_NAME_ << ")"; + return false; + } + return true; +} + +// Clears the object. +void TestResult::Clear() { + test_part_results_.clear(); + test_properties_.clear(); + death_test_count_ = 0; + elapsed_time_ = 0; +} + +// Returns true iff the test failed. +bool TestResult::Failed() const { + for (int i = 0; i < total_part_count(); ++i) { + if (GetTestPartResult(i).failed()) + return true; + } + return false; +} + +// Returns true iff the test part fatally failed. +static bool TestPartFatallyFailed(const TestPartResult& result) { + return result.fatally_failed(); +} + +// Returns true iff the test fatally failed. +bool TestResult::HasFatalFailure() const { + return CountIf(test_part_results_, TestPartFatallyFailed) > 0; +} + +// Returns true iff the test part non-fatally failed. +static bool TestPartNonfatallyFailed(const TestPartResult& result) { + return result.nonfatally_failed(); +} + +// Returns true iff the test has a non-fatal failure. +bool TestResult::HasNonfatalFailure() const { + return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; +} + +// Gets the number of all test parts. This is the sum of the number +// of successful test parts and the number of failed test parts. +int TestResult::total_part_count() const { + return static_cast(test_part_results_.size()); +} + +// Returns the number of the test properties. +int TestResult::test_property_count() const { + return static_cast(test_properties_.size()); +} + +// class Test + +// Creates a Test object. + +// The c'tor saves the values of all Google Test flags. +Test::Test() + : gtest_flag_saver_(new internal::GTestFlagSaver) { +} + +// The d'tor restores the values of all Google Test flags. +Test::~Test() { + delete gtest_flag_saver_; +} + +// Sets up the test fixture. +// +// A sub-class may override this. +void Test::SetUp() { +} + +// Tears down the test fixture. +// +// A sub-class may override this. +void Test::TearDown() { +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, const char* value) { + UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value); +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const char* key, int value) { + Message value_message; + value_message << value; + RecordProperty(key, value_message.GetString().c_str()); +} + +namespace internal { + +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const String& message) { + // This function is a friend of UnitTest and as such has access to + // AddTestPartResult. + UnitTest::GetInstance()->AddTestPartResult( + result_type, + NULL, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. + message, + String()); // No stack trace, either. +} + +} // namespace internal + +// Google Test requires all tests in the same test case to use the same test +// fixture class. This function checks if the current test has the +// same fixture class as the first test in the current test case. If +// yes, it returns true; otherwise it generates a Google Test failure and +// returns false. +bool Test::HasSameFixtureClass() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + const TestCase* const test_case = impl->current_test_case(); + + // Info about the first test in the current test case. + const TestInfo* const first_test_info = test_case->test_info_list()[0]; + const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; + const char* const first_test_name = first_test_info->name(); + + // Info about the current test. + const TestInfo* const this_test_info = impl->current_test_info(); + const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; + const char* const this_test_name = this_test_info->name(); + + if (this_fixture_id != first_fixture_id) { + // Is the first test defined using TEST? + const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); + // Is this test defined using TEST? + const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); + + if (first_is_TEST || this_is_TEST) { + // The user mixed TEST and TEST_F in this test case - we'll tell + // him/her how to fix it. + + // Gets the name of the TEST and the name of the TEST_F. Note + // that first_is_TEST and this_is_TEST cannot both be true, as + // the fixture IDs are different for the two tests. + const char* const TEST_name = + first_is_TEST ? first_test_name : this_test_name; + const char* const TEST_F_name = + first_is_TEST ? this_test_name : first_test_name; + + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test case is\n" + << "illegal. In test case " << this_test_info->test_case_name() + << ",\n" + << "test " << TEST_F_name << " is defined using TEST_F but\n" + << "test " << TEST_name << " is defined using TEST. You probably\n" + << "want to change the TEST to TEST_F or move it to another test\n" + << "case."; + } else { + // The user defined two fixture classes with the same name in + // two namespaces - we'll tell him/her how to fix it. + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " + << this_test_info->test_case_name() << ",\n" + << "you defined test " << first_test_name + << " and test " << this_test_name << "\n" + << "using two different test fixture classes. This can happen if\n" + << "the two classes are from different namespaces or translation\n" + << "units and have the same name. You should probably rename one\n" + << "of the classes to put the tests into different test cases."; + } + return false; + } + + return true; +} + +#if GTEST_HAS_SEH + +// Adds an "exception thrown" fatal failure to the current test. This +// function returns its result via an output parameter pointer because VC++ +// prohibits creation of objects with destructors on stack in functions +// using __try (see error C2712). +static internal::String* FormatSehExceptionMessage(DWORD exception_code, + const char* location) { + Message message; + message << "SEH exception with code 0x" << std::setbase(16) << + exception_code << std::setbase(10) << " thrown in " << location << "."; + + return new internal::String(message.GetString()); +} + +#endif // GTEST_HAS_SEH + +#if GTEST_HAS_EXCEPTIONS + +// Adds an "exception thrown" fatal failure to the current test. +static internal::String FormatCxxExceptionMessage(const char* description, + const char* location) { + Message message; + if (description != NULL) { + message << "C++ exception with description \"" << description << "\""; + } else { + message << "Unknown C++ exception"; + } + message << " thrown in " << location << "."; + + return message.GetString(); +} + +static internal::String PrintTestPartResultToString( + const TestPartResult& test_part_result); + +// A failed Google Test assertion will throw an exception of this type when +// GTEST_FLAG(throw_on_failure) is true (if exceptions are enabled). We +// derive it from std::runtime_error, which is for errors presumably +// detectable only at run time. Since std::runtime_error inherits from +// std::exception, many testing frameworks know how to extract and print the +// message inside it. +class GoogleTestFailureException : public ::std::runtime_error { + public: + explicit GoogleTestFailureException(const TestPartResult& failure) + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} +}; +#endif // GTEST_HAS_EXCEPTIONS + +namespace internal { +// We put these helper functions in the internal namespace as IBM's xlC +// compiler rejects the code if they were declared static. + +// Runs the given method and handles SEH exceptions it throws, when +// SEH is supported; returns the 0-value for type Result in case of an +// SEH exception. (Microsoft compilers cannot handle SEH and C++ +// exceptions in the same function. Therefore, we provide a separate +// wrapper function for handling SEH exceptions.) +template +Result HandleSehExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { +#if GTEST_HAS_SEH + __try { + return (object->*method)(); + } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT + GetExceptionCode())) { + // We create the exception message on the heap because VC++ prohibits + // creation of objects with destructors on stack in functions using __try + // (see error C2712). + internal::String* exception_message = FormatSehExceptionMessage( + GetExceptionCode(), location); + internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, + *exception_message); + delete exception_message; + return static_cast(0); + } +#else + (void)location; + return (object->*method)(); +#endif // GTEST_HAS_SEH +} + +// Runs the given method and catches and reports C++ and/or SEH-style +// exceptions, if they are supported; returns the 0-value for type +// Result in case of an SEH exception. +template +Result HandleExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { + // NOTE: The user code can affect the way in which Google Test handles + // exceptions by setting GTEST_FLAG(catch_exceptions), but only before + // RUN_ALL_TESTS() starts. It is technically possible to check the flag + // after the exception is caught and either report or re-throw the + // exception based on the flag's value: + // + // try { + // // Perform the test method. + // } catch (...) { + // if (GTEST_FLAG(catch_exceptions)) + // // Report the exception as failure. + // else + // throw; // Re-throws the original exception. + // } + // + // However, the purpose of this flag is to allow the program to drop into + // the debugger when the exception is thrown. On most platforms, once the + // control enters the catch block, the exception origin information is + // lost and the debugger will stop the program at the point of the + // re-throw in this function -- instead of at the point of the original + // throw statement in the code under test. For this reason, we perform + // the check early, sacrificing the ability to affect Google Test's + // exception handling in the method where the exception is thrown. + if (internal::GetUnitTestImpl()->catch_exceptions()) { +#if GTEST_HAS_EXCEPTIONS + try { + return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const GoogleTestFailureException&) { // NOLINT + // This exception doesn't originate in code under test. It makes no + // sense to report it as a test failure. + throw; + } catch (const std::exception& e) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(e.what(), location)); + } catch (...) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(NULL, location)); + } + return static_cast(0); +#else + return HandleSehExceptionsInMethodIfSupported(object, method, location); +#endif // GTEST_HAS_EXCEPTIONS + } else { + return (object->*method)(); + } +} + +} // namespace internal + +// Runs the test and updates the test result. +void Test::Run() { + if (!HasSameFixtureClass()) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); + // We will run the test only if SetUp() was successful. + if (!HasFatalFailure()) { + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TestBody, "the test body"); + } + + // However, we want to clean up as much as possible. Hence we will + // always call TearDown(), even if SetUp() or the test body has + // failed. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TearDown, "TearDown()"); +} + +// Returns true iff the current test has a fatal failure. +bool Test::HasFatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); +} + +// Returns true iff the current test has a non-fatal failure. +bool Test::HasNonfatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()-> + HasNonfatalFailure(); +} + +// class TestInfo + +// Constructs a TestInfo object. It assumes ownership of the test factory +// object. +// TODO(vladl@google.com): Make a_test_case_name and a_name const string&'s +// to signify they cannot be NULLs. +TestInfo::TestInfo(const char* a_test_case_name, + const char* a_name, + const char* a_type_param, + const char* a_value_param, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory) + : test_case_name_(a_test_case_name), + name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + value_param_(a_value_param ? new std::string(a_value_param) : NULL), + fixture_class_id_(fixture_class_id), + should_run_(false), + is_disabled_(false), + matches_filter_(false), + factory_(factory), + result_() {} + +// Destructs a TestInfo object. +TestInfo::~TestInfo() { delete factory_; } + +namespace internal { + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// type_param: the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param: text representation of the test's value parameter, +// or NULL if this is not a value-parameterized test. +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* type_param, + const char* value_param, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory) { + TestInfo* const test_info = + new TestInfo(test_case_name, name, type_param, value_param, + fixture_class_id, factory); + GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); + return test_info; +} + +#if GTEST_HAS_PARAM_TEST +void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line) { + Message errors; + errors + << "Attempted redefinition of test case " << test_case_name << ".\n" + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " << test_case_name << ", you tried\n" + << "to define a test using a fixture class different from the one\n" + << "used earlier. This can happen if the two fixture classes are\n" + << "from different namespaces and have the same name. You should\n" + << "probably rename one of the classes to put the tests into different\n" + << "test cases."; + + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors.GetString().c_str()); +} +#endif // GTEST_HAS_PARAM_TEST + +} // namespace internal + +namespace { + +// A predicate that checks the test name of a TestInfo against a known +// value. +// +// This is used for implementation of the TestCase class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestNameIs is copyable. +class TestNameIs { + public: + // Constructor. + // + // TestNameIs has NO default constructor. + explicit TestNameIs(const char* name) + : name_(name) {} + + // Returns true iff the test name of test_info matches name_. + bool operator()(const TestInfo * test_info) const { + return test_info && internal::String(test_info->name()).Compare(name_) == 0; + } + + private: + internal::String name_; +}; + +} // namespace + +namespace internal { + +// This method expands all parameterized tests registered with macros TEST_P +// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. +// This will be done just once during the program runtime. +void UnitTestImpl::RegisterParameterizedTests() { +#if GTEST_HAS_PARAM_TEST + if (!parameterized_tests_registered_) { + parameterized_test_registry_.RegisterTests(); + parameterized_tests_registered_ = true; + } +#endif +} + +} // namespace internal + +// Creates the test object, runs it, records its result, and then +// deletes it. +void TestInfo::Run() { + if (!should_run_) return; + + // Tells UnitTest where to store test result. + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_info(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + // Notifies the unit test event listeners that a test is about to start. + repeater->OnTestStart(*this); + + const TimeInMillis start = internal::GetTimeInMillis(); + + impl->os_stack_trace_getter()->UponLeavingGTest(); + + // Creates the test object. + Test* const test = internal::HandleExceptionsInMethodIfSupported( + factory_, &internal::TestFactoryBase::CreateTest, + "the test fixture's constructor"); + + // Runs the test only if the test object was created and its + // constructor didn't generate a fatal failure. + if ((test != NULL) && !Test::HasFatalFailure()) { + // This doesn't throw as all user code that can throw are wrapped into + // exception handling code. + test->Run(); + } + + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + test, &Test::DeleteSelf_, "the test fixture's destructor"); + + result_.set_elapsed_time(internal::GetTimeInMillis() - start); + + // Notifies the unit test event listener that a test has just finished. + repeater->OnTestEnd(*this); + + // Tells UnitTest to stop associating assertion results to this + // test. + impl->set_current_test_info(NULL); +} + +// class TestCase + +// Gets the number of successful tests in this test case. +int TestCase::successful_test_count() const { + return CountIf(test_info_list_, TestPassed); +} + +// Gets the number of failed tests in this test case. +int TestCase::failed_test_count() const { + return CountIf(test_info_list_, TestFailed); +} + +int TestCase::disabled_test_count() const { + return CountIf(test_info_list_, TestDisabled); +} + +// Get the number of tests in this test case that should run. +int TestCase::test_to_run_count() const { + return CountIf(test_info_list_, ShouldRunTest); +} + +// Gets the number of all tests. +int TestCase::total_test_count() const { + return static_cast(test_info_list_.size()); +} + +// Creates a TestCase with the given name. +// +// Arguments: +// +// name: name of the test case +// a_type_param: the name of the test case's type parameter, or NULL if +// this is not a typed or a type-parameterized test case. +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase::TestCase(const char* a_name, const char* a_type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) + : name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + set_up_tc_(set_up_tc), + tear_down_tc_(tear_down_tc), + should_run_(false), + elapsed_time_(0) { +} + +// Destructor of TestCase. +TestCase::~TestCase() { + // Deletes every Test in the collection. + ForEach(test_info_list_, internal::Delete); +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +const TestInfo* TestCase::GetTestInfo(int i) const { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +TestInfo* TestCase::GetMutableTestInfo(int i) { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Adds a test to this test case. Will delete the test upon +// destruction of the TestCase object. +void TestCase::AddTestInfo(TestInfo * test_info) { + test_info_list_.push_back(test_info); + test_indices_.push_back(static_cast(test_indices_.size())); +} + +// Runs every test in this TestCase. +void TestCase::Run() { + if (!should_run_) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_case(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + repeater->OnTestCaseStart(*this); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); + + const internal::TimeInMillis start = internal::GetTimeInMillis(); + for (int i = 0; i < total_test_count(); i++) { + GetMutableTestInfo(i)->Run(); + } + elapsed_time_ = internal::GetTimeInMillis() - start; + + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); + + repeater->OnTestCaseEnd(*this); + impl->set_current_test_case(NULL); +} + +// Clears the results of all tests in this test case. +void TestCase::ClearResult() { + ForEach(test_info_list_, TestInfo::ClearTestResult); +} + +// Shuffles the tests in this test case. +void TestCase::ShuffleTests(internal::Random* random) { + Shuffle(random, &test_indices_); +} + +// Restores the test order to before the first shuffle. +void TestCase::UnshuffleTests() { + for (size_t i = 0; i < test_indices_.size(); i++) { + test_indices_[i] = static_cast(i); + } +} + +// Formats a countable noun. Depending on its quantity, either the +// singular form or the plural form is used. e.g. +// +// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". +// FormatCountableNoun(5, "book", "books") returns "5 books". +static internal::String FormatCountableNoun(int count, + const char * singular_form, + const char * plural_form) { + return internal::String::Format("%d %s", count, + count == 1 ? singular_form : plural_form); +} + +// Formats the count of tests. +static internal::String FormatTestCount(int test_count) { + return FormatCountableNoun(test_count, "test", "tests"); +} + +// Formats the count of test cases. +static internal::String FormatTestCaseCount(int test_case_count) { + return FormatCountableNoun(test_case_count, "test case", "test cases"); +} + +// Converts a TestPartResult::Type enum to human-friendly string +// representation. Both kNonFatalFailure and kFatalFailure are translated +// to "Failure", as the user usually doesn't care about the difference +// between the two when viewing the test result. +static const char * TestPartResultTypeToString(TestPartResult::Type type) { + switch (type) { + case TestPartResult::kSuccess: + return "Success"; + + case TestPartResult::kNonFatalFailure: + case TestPartResult::kFatalFailure: +#ifdef _MSC_VER + return "error: "; +#else + return "Failure\n"; +#endif + default: + return "Unknown result type"; + } +} + +// Prints a TestPartResult to a String. +static internal::String PrintTestPartResultToString( + const TestPartResult& test_part_result) { + return (Message() + << internal::FormatFileLocation(test_part_result.file_name(), + test_part_result.line_number()) + << " " << TestPartResultTypeToString(test_part_result.type()) + << test_part_result.message()).GetString(); +} + +// Prints a TestPartResult. +static void PrintTestPartResult(const TestPartResult& test_part_result) { + const internal::String& result = + PrintTestPartResultToString(test_part_result); + printf("%s\n", result.c_str()); + fflush(stdout); + // If the test program runs in Visual Studio or a debugger, the + // following statements add the test part result message to the Output + // window such that the user can double-click on it to jump to the + // corresponding source code location; otherwise they do nothing. +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + // We don't call OutputDebugString*() on Windows Mobile, as printing + // to stdout is done by OutputDebugString() there already - we don't + // want the same message printed twice. + ::OutputDebugStringA(result.c_str()); + ::OutputDebugStringA("\n"); +#endif +} + +// class PrettyUnitTestResultPrinter + +namespace internal { + +enum GTestColor { + COLOR_DEFAULT, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW +}; + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns the character attribute for the given color. +WORD GetColorAttribute(GTestColor color) { + switch (color) { + case COLOR_RED: return FOREGROUND_RED; + case COLOR_GREEN: return FOREGROUND_GREEN; + case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; + default: return 0; + } +} + +#else + +// Returns the ANSI color code for the given color. COLOR_DEFAULT is +// an invalid input. +char* GetAnsiColorCode(GTestColor color) { + switch (color) { + case COLOR_RED: return "1"; + case COLOR_GREEN: return "2"; + case COLOR_YELLOW: return "3"; + default: return NULL; + }; + return NULL; +} + +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns true iff Google Test should use colors in the output. +bool ShouldUseColor(bool stdout_is_tty) { + const char* const gtest_color = GTEST_FLAG(color).c_str(); + + if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { +#if GTEST_OS_WINDOWS + // On Windows the TERM variable is usually not set, but the + // console there does support colors. + return stdout_is_tty; +#else + // On non-Windows platforms, we rely on the TERM variable. + const char* const term = posix::GetEnv("TERM"); + const bool term_supports_color = + String::CStringEquals(term, "xterm") || + String::CStringEquals(term, "xterm-color") || + String::CStringEquals(term, "xterm-256color") || + String::CStringEquals(term, "screen") || + String::CStringEquals(term, "linux") || + String::CStringEquals(term, "cygwin"); + return stdout_is_tty && term_supports_color; +#endif // GTEST_OS_WINDOWS + } + + return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || + String::CaseInsensitiveCStringEquals(gtest_color, "true") || + String::CaseInsensitiveCStringEquals(gtest_color, "t") || + String::CStringEquals(gtest_color, "1"); + // We take "yes", "true", "t", and "1" as meaning "yes". If the + // value is neither one of these nor "auto", we treat it as "no" to + // be conservative. +} + +// Helpers for printing colored strings to stdout. Note that on Windows, we +// cannot simply emit special characters and have the terminal change colors. +// This routine must actually emit the characters rather than return a string +// that would be colored when printed, as can be done on Linux. +void ColoredPrintf(GTestColor color, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + const bool use_color = false; +#else + static const bool in_color_mode = + ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); + const bool use_color = in_color_mode && (color != COLOR_DEFAULT); +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + // The '!= 0' comparison is necessary to satisfy MSVC 7.1. + + if (!use_color) { + vprintf(fmt, args); + va_end(args); + return; + } + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + + // Gets the current text color. + CONSOLE_SCREEN_BUFFER_INFO buffer_info; + GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); + const WORD old_color_attrs = buffer_info.wAttributes; + + // We need to flush the stream buffers into the console before each + // SetConsoleTextAttribute call lest it affect the text that is already + // printed but has not yet reached the console. + fflush(stdout); + SetConsoleTextAttribute(stdout_handle, + GetColorAttribute(color) | FOREGROUND_INTENSITY); + vprintf(fmt, args); + + fflush(stdout); + // Restores the text color. + SetConsoleTextAttribute(stdout_handle, old_color_attrs); +#else + printf("\033[0;3%sm", GetAnsiColorCode(color)); + vprintf(fmt, args); + printf("\033[m"); // Resets the terminal to default. +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + va_end(args); +} + +void PrintFullTestCommentIfPresent(const TestInfo& test_info) { + const char* const type_param = test_info.type_param(); + const char* const value_param = test_info.value_param(); + + if (type_param != NULL || value_param != NULL) { + printf(", where "); + if (type_param != NULL) { + printf("TypeParam = %s", type_param); + if (value_param != NULL) + printf(" and "); + } + if (value_param != NULL) { + printf("GetParam() = %s", value_param); + } + } +} + +// This class implements the TestEventListener interface. +// +// Class PrettyUnitTestResultPrinter is copyable. +class PrettyUnitTestResultPrinter : public TestEventListener { + public: + PrettyUnitTestResultPrinter() {} + static void PrintTestName(const char * test_case, const char * test) { + printf("%s.%s", test_case, test); + } + + // The following methods override what's in the TestEventListener class. + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + + private: + static void PrintFailedTests(const UnitTest& unit_test); + + internal::String test_case_name_; +}; + + // Fired before each iteration of tests starts. +void PrettyUnitTestResultPrinter::OnTestIterationStart( + const UnitTest& unit_test, int iteration) { + if (GTEST_FLAG(repeat) != 1) + printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); + + const char* const filter = GTEST_FLAG(filter).c_str(); + + // Prints the filter if it's not *. This reminds the user that some + // tests may be skipped. + if (!internal::String::CStringEquals(filter, kUniversalFilter)) { + ColoredPrintf(COLOR_YELLOW, + "Note: %s filter = %s\n", GTEST_NAME_, filter); + } + + if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { + const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); + ColoredPrintf(COLOR_YELLOW, + "Note: This is test shard %d of %s.\n", + static_cast(shard_index) + 1, + internal::posix::GetEnv(kTestTotalShards)); + } + + if (GTEST_FLAG(shuffle)) { + ColoredPrintf(COLOR_YELLOW, + "Note: Randomizing tests' orders with a seed of %d .\n", + unit_test.random_seed()); + } + + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("Running %s from %s.\n", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment set-up.\n"); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { + test_case_name_ = test_case.name(); + const internal::String counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_case_name_.c_str()); + if (test_case.type_param() == NULL) { + printf("\n"); + } else { + printf(", where TypeParam = %s\n", test_case.type_param()); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { + ColoredPrintf(COLOR_GREEN, "[ RUN ] "); + PrintTestName(test_case_name_.c_str(), test_info.name()); + printf("\n"); + fflush(stdout); +} + +// Called after an assertion failure. +void PrettyUnitTestResultPrinter::OnTestPartResult( + const TestPartResult& result) { + // If the test part succeeded, we don't need to do anything. + if (result.type() == TestPartResult::kSuccess) + return; + + // Print failure message from the assertion (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { + if (test_info.result()->Passed()) { + ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else { + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + } + PrintTestName(test_case_name_.c_str(), test_info.name()); + if (test_info.result()->Failed()) + PrintFullTestCommentIfPresent(test_info); + + if (GTEST_FLAG(print_time)) { + printf(" (%s ms)\n", internal::StreamableToString( + test_info.result()->elapsed_time()).c_str()); + } else { + printf("\n"); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { + if (!GTEST_FLAG(print_time)) return; + + test_case_name_ = test_case.name(); + const internal::String counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", + counts.c_str(), test_case_name_.c_str(), + internal::StreamableToString(test_case.elapsed_time()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment tear-down\n"); + fflush(stdout); +} + +// Internal helper for printing the list of failed tests. +void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { + const int failed_test_count = unit_test.failed_test_count(); + if (failed_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + const TestCase& test_case = *unit_test.GetTestCase(i); + if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_case.total_test_count(); ++j) { + const TestInfo& test_info = *test_case.GetTestInfo(j); + if (!test_info.should_run() || test_info.result()->Passed()) { + continue; + } + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s.%s", test_case.name(), test_info.name()); + PrintFullTestCommentIfPresent(test_info); + printf("\n"); + } + } +} + +void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("%s from %s ran.", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms total)", + internal::StreamableToString(unit_test.elapsed_time()).c_str()); + } + printf("\n"); + ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); + printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); + + int num_failures = unit_test.failed_test_count(); + if (!unit_test.Passed()) { + const int failed_test_count = unit_test.failed_test_count(); + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); + PrintFailedTests(unit_test); + printf("\n%2d FAILED %s\n", num_failures, + num_failures == 1 ? "TEST" : "TESTS"); + } + + int num_disabled = unit_test.disabled_test_count(); + if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { + if (!num_failures) { + printf("\n"); // Add a spacer if no FAILURE banner is displayed. + } + ColoredPrintf(COLOR_YELLOW, + " YOU HAVE %d DISABLED %s\n\n", + num_disabled, + num_disabled == 1 ? "TEST" : "TESTS"); + } + // Ensure that Google Test output is printed before, e.g., heapchecker output. + fflush(stdout); +} + +// End PrettyUnitTestResultPrinter + +// class TestEventRepeater +// +// This class forwards events to other event listeners. +class TestEventRepeater : public TestEventListener { + public: + TestEventRepeater() : forwarding_enabled_(true) {} + virtual ~TestEventRepeater(); + void Append(TestEventListener *listener); + TestEventListener* Release(TestEventListener* listener); + + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled() const { return forwarding_enabled_; } + void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } + + virtual void OnTestProgramStart(const UnitTest& unit_test); + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& unit_test); + + private: + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled_; + // The list of listeners that receive events. + std::vector listeners_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); +}; + +TestEventRepeater::~TestEventRepeater() { + ForEach(listeners_, Delete); +} + +void TestEventRepeater::Append(TestEventListener *listener) { + listeners_.push_back(listener); +} + +// TODO(vladl@google.com): Factor the search functionality into Vector::Find. +TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { + for (size_t i = 0; i < listeners_.size(); ++i) { + if (listeners_[i] == listener) { + listeners_.erase(listeners_.begin() + i); + return listener; + } + } + + return NULL; +} + +// Since most methods are very similar, use macros to reduce boilerplate. +// This defines a member that forwards the call to all listeners. +#define GTEST_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (size_t i = 0; i < listeners_.size(); i++) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} +// This defines a member that forwards the call to all listeners in reverse +// order. +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} + +GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) +GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) +GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) +GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) +GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) + +#undef GTEST_REPEATER_METHOD_ +#undef GTEST_REVERSE_REPEATER_METHOD_ + +void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (size_t i = 0; i < listeners_.size(); i++) { + listeners_[i]->OnTestIterationStart(unit_test, iteration); + } + } +} + +void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { + listeners_[i]->OnTestIterationEnd(unit_test, iteration); + } + } +} + +// End TestEventRepeater + +// This class generates an XML output file. +class XmlUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit XmlUnitTestResultPrinter(const char* output_file); + + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + + private: + // Is c a whitespace character that is normalized to a space character + // when it appears in an XML attribute value? + static bool IsNormalizableWhitespace(char c) { + return c == 0x9 || c == 0xA || c == 0xD; + } + + // May c appear in a well-formed XML document? + static bool IsValidXmlCharacter(char c) { + return IsNormalizableWhitespace(c) || c >= 0x20; + } + + // Returns an XML-escaped copy of the input string str. If + // is_attribute is true, the text is meant to appear as an attribute + // value, and normalizable whitespace is preserved by replacing it + // with character references. + static String EscapeXml(const char* str, bool is_attribute); + + // Returns the given string with all characters invalid in XML removed. + static string RemoveInvalidXmlCharacters(const string& str); + + // Convenience wrapper around EscapeXml when str is an attribute value. + static String EscapeXmlAttribute(const char* str) { + return EscapeXml(str, true); + } + + // Convenience wrapper around EscapeXml when str is not an attribute value. + static String EscapeXmlText(const char* str) { return EscapeXml(str, false); } + + // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. + static void OutputXmlCDataSection(::std::ostream* stream, const char* data); + + // Streams an XML representation of a TestInfo object. + static void OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info); + + // Prints an XML representation of a TestCase object + static void PrintXmlTestCase(FILE* out, const TestCase& test_case); + + // Prints an XML summary of unit_test to output stream out. + static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as space + // delimited XML attributes based on the property key="value" pairs. + // When the String is not empty, it includes a space at the beginning, + // to delimit this attribute from prior attributes. + static String TestPropertiesAsXmlAttributes(const TestResult& result); + + // The output file. + const String output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); +}; + +// Creates a new XmlUnitTestResultPrinter. +XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.c_str() == NULL || output_file_.empty()) { + fprintf(stderr, "XML output file may not be null\n"); + fflush(stderr); + exit(EXIT_FAILURE); + } +} + +// Called after the unit test ends. +void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* xmlout = NULL; + FilePath output_file(output_file_); + FilePath output_dir(output_file.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + xmlout = posix::FOpen(output_file_.c_str(), "w"); + } + if (xmlout == NULL) { + // TODO(wan): report the reason of the failure. + // + // We don't do it for now as: + // + // 1. There is no urgent need for it. + // 2. It's a bit involved to make the errno variable thread-safe on + // all three operating systems (Linux, Windows, and Mac OS). + // 3. To interpret the meaning of errno in a thread-safe way, + // we need the strerror_r() function, which is not available on + // Windows. + fprintf(stderr, + "Unable to open file \"%s\"\n", + output_file_.c_str()); + fflush(stderr); + exit(EXIT_FAILURE); + } + PrintXmlUnitTest(xmlout, unit_test); + fclose(xmlout); +} + +// Returns an XML-escaped copy of the input string str. If is_attribute +// is true, the text is meant to appear as an attribute value, and +// normalizable whitespace is preserved by replacing it with character +// references. +// +// Invalid XML characters in str, if any, are stripped from the output. +// It is expected that most, if not all, of the text processed by this +// module will consist of ordinary English text. +// If this module is ever modified to produce version 1.1 XML output, +// most invalid characters can be retained using character references. +// TODO(wan): It might be nice to have a minimally invasive, human-readable +// escaping scheme for invalid characters, rather than dropping them. +String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) { + Message m; + + if (str != NULL) { + for (const char* src = str; *src; ++src) { + switch (*src) { + case '<': + m << "<"; + break; + case '>': + m << ">"; + break; + case '&': + m << "&"; + break; + case '\'': + if (is_attribute) + m << "'"; + else + m << '\''; + break; + case '"': + if (is_attribute) + m << """; + else + m << '"'; + break; + default: + if (IsValidXmlCharacter(*src)) { + if (is_attribute && IsNormalizableWhitespace(*src)) + m << String::Format("&#x%02X;", unsigned(*src)); + else + m << *src; + } + break; + } + } + } + + return m.GetString(); +} + +// Returns the given string with all characters invalid in XML removed. +// Currently invalid characters are dropped from the string. An +// alternative is to replace them with certain characters such as . or ?. +string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const string& str) { + string output; + output.reserve(str.size()); + for (string::const_iterator it = str.begin(); it != str.end(); ++it) + if (IsValidXmlCharacter(*it)) + output.push_back(*it); + + return output; +} + +// The following routines generate an XML representation of a UnitTest +// object. +// +// This is how Google Test concepts map to the DTD: +// +// <-- corresponds to a UnitTest object +// <-- corresponds to a TestCase object +// <-- corresponds to a TestInfo object +// ... +// ... +// ... +// <-- individual assertion failures +// +// +// + +// Formats the given time in milliseconds as seconds. +std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { + ::std::stringstream ss; + ss << ms/1000.0; + return ss.str(); +} + +// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. +void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, + const char* data) { + const char* segment = data; + *stream << ""); + if (next_segment != NULL) { + stream->write( + segment, static_cast(next_segment - segment)); + *stream << "]]>]]>"); + } else { + *stream << segment; + break; + } + } + *stream << "]]>"; +} + +// Prints an XML representation of a TestInfo object. +// TODO(wan): There is also value in printing properties with the plain printer. +void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + *stream << " \n"; + *stream << " "; + const string location = internal::FormatCompilerIndependentFileLocation( + part.file_name(), part.line_number()); + const string message = location + "\n" + part.message(); + OutputXmlCDataSection(stream, + RemoveInvalidXmlCharacters(message).c_str()); + *stream << "\n"; + } + } + + if (failures == 0) + *stream << " />\n"; + else + *stream << " \n"; +} + +// Prints an XML representation of a TestCase object +void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out, + const TestCase& test_case) { + fprintf(out, + " \n", + FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str()); + for (int i = 0; i < test_case.total_test_count(); ++i) { + ::std::stringstream stream; + OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i)); + fprintf(out, "%s", StringStreamToString(&stream).c_str()); + } + fprintf(out, " \n"); +} + +// Prints an XML summary of unit_test to output stream out. +void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out, + const UnitTest& unit_test) { + fprintf(out, "\n"); + fprintf(out, + "\n"); + for (int i = 0; i < unit_test.total_test_case_count(); ++i) + PrintXmlTestCase(out, *unit_test.GetTestCase(i)); + fprintf(out, "\n"); +} + +// Produces a string representing the test properties in a result as space +// delimited XML attributes based on the property key="value" pairs. +String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( + const TestResult& result) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << " " << property.key() << "=" + << "\"" << EscapeXmlAttribute(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End XmlUnitTestResultPrinter + +#if GTEST_CAN_STREAM_RESULTS_ + +// Streams test results to the given port on the given host machine. +class StreamingListener : public EmptyTestEventListener { + public: + // Escapes '=', '&', '%', and '\n' characters in str as "%xx". + static string UrlEncode(const char* str); + + StreamingListener(const string& host, const string& port) + : sockfd_(-1), host_name_(host), port_num_(port) { + MakeConnection(); + Send("gtest_streaming_protocol_version=1.0\n"); + } + + virtual ~StreamingListener() { + if (sockfd_ != -1) + CloseConnection(); + } + + void OnTestProgramStart(const UnitTest& /* unit_test */) { + Send("event=TestProgramStart\n"); + } + + void OnTestProgramEnd(const UnitTest& unit_test) { + // Note that Google Test current only report elapsed time for each + // test iteration, not for the entire test program. + Send(String::Format("event=TestProgramEnd&passed=%d\n", + unit_test.Passed())); + + // Notify the streaming server to stop. + CloseConnection(); + } + + void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { + Send(String::Format("event=TestIterationStart&iteration=%d\n", + iteration)); + } + + void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { + Send(String::Format("event=TestIterationEnd&passed=%d&elapsed_time=%sms\n", + unit_test.Passed(), + StreamableToString(unit_test.elapsed_time()).c_str())); + } + + void OnTestCaseStart(const TestCase& test_case) { + Send(String::Format("event=TestCaseStart&name=%s\n", test_case.name())); + } + + void OnTestCaseEnd(const TestCase& test_case) { + Send(String::Format("event=TestCaseEnd&passed=%d&elapsed_time=%sms\n", + test_case.Passed(), + StreamableToString(test_case.elapsed_time()).c_str())); + } + + void OnTestStart(const TestInfo& test_info) { + Send(String::Format("event=TestStart&name=%s\n", test_info.name())); + } + + void OnTestEnd(const TestInfo& test_info) { + Send(String::Format( + "event=TestEnd&passed=%d&elapsed_time=%sms\n", + (test_info.result())->Passed(), + StreamableToString((test_info.result())->elapsed_time()).c_str())); + } + + void OnTestPartResult(const TestPartResult& test_part_result) { + const char* file_name = test_part_result.file_name(); + if (file_name == NULL) + file_name = ""; + Send(String::Format("event=TestPartResult&file=%s&line=%d&message=", + UrlEncode(file_name).c_str(), + test_part_result.line_number())); + Send(UrlEncode(test_part_result.message()) + "\n"); + } + + private: + // Creates a client socket and connects to the server. + void MakeConnection(); + + // Closes the socket. + void CloseConnection() { + GTEST_CHECK_(sockfd_ != -1) + << "CloseConnection() can be called only when there is a connection."; + + close(sockfd_); + sockfd_ = -1; + } + + // Sends a string to the socket. + void Send(const string& message) { + GTEST_CHECK_(sockfd_ != -1) + << "Send() can be called only when there is a connection."; + + const int len = static_cast(message.length()); + if (write(sockfd_, message.c_str(), len) != len) { + GTEST_LOG_(WARNING) + << "stream_result_to: failed to stream to " + << host_name_ << ":" << port_num_; + } + } + + int sockfd_; // socket file descriptor + const string host_name_; + const string port_num_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); +}; // class StreamingListener + +// Checks if str contains '=', '&', '%' or '\n' characters. If yes, +// replaces them by "%xx" where xx is their hexadecimal value. For +// example, replaces "=" with "%3D". This algorithm is O(strlen(str)) +// in both time and space -- important as the input str may contain an +// arbitrarily long test failure message and stack trace. +string StreamingListener::UrlEncode(const char* str) { + string result; + result.reserve(strlen(str) + 1); + for (char ch = *str; ch != '\0'; ch = *++str) { + switch (ch) { + case '%': + case '=': + case '&': + case '\n': + result.append(String::Format("%%%02x", static_cast(ch))); + break; + default: + result.push_back(ch); + break; + } + } + return result; +} + +void StreamingListener::MakeConnection() { + GTEST_CHECK_(sockfd_ == -1) + << "MakeConnection() can't be called when there is already a connection."; + + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. + hints.ai_socktype = SOCK_STREAM; + addrinfo* servinfo = NULL; + + // Use the getaddrinfo() to get a linked list of IP addresses for + // the given host name. + const int error_num = getaddrinfo( + host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); + if (error_num != 0) { + GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " + << gai_strerror(error_num); + } + + // Loop through all the results and connect to the first we can. + for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; + cur_addr = cur_addr->ai_next) { + sockfd_ = socket( + cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); + if (sockfd_ != -1) { + // Connect the client socket to the server socket. + if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { + close(sockfd_); + sockfd_ = -1; + } + } + } + + freeaddrinfo(servinfo); // all done with this structure + + if (sockfd_ == -1) { + GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " + << host_name_ << ":" << port_num_; + } +} + +// End of class Streaming Listener +#endif // GTEST_CAN_STREAM_RESULTS__ + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +// L < UnitTest::mutex_ +ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) { + TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message = message.GetString(); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +// L < UnitTest::mutex_ +ScopedTrace::~ScopedTrace() { + UnitTest::GetInstance()->PopGTestTrace(); +} + + +// class OsStackTraceGetter + +// Returns the current OS stack trace as a String. Parameters: +// +// max_depth - the maximum number of stack frames to be included +// in the trace. +// skip_count - the number of top frames to be skipped; doesn't count +// against max_depth. +// +// L < mutex_ +// We use "L < mutex_" to denote that the function may acquire mutex_. +String OsStackTraceGetter::CurrentStackTrace(int, int) { + return String(""); +} + +// L < mutex_ +void OsStackTraceGetter::UponLeavingGTest() { +} + +const char* const +OsStackTraceGetter::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; + +} // namespace internal + +// class TestEventListeners + +TestEventListeners::TestEventListeners() + : repeater_(new internal::TestEventRepeater()), + default_result_printer_(NULL), + default_xml_generator_(NULL) { +} + +TestEventListeners::~TestEventListeners() { delete repeater_; } + +// Returns the standard listener responsible for the default console +// output. Can be removed from the listeners list to shut down default +// console output. Note that removing this object from the listener list +// with Release transfers its ownership to the user. +void TestEventListeners::Append(TestEventListener* listener) { + repeater_->Append(listener); +} + +// Removes the given event listener from the list and returns it. It then +// becomes the caller's responsibility to delete the listener. Returns +// NULL if the listener is not found in the list. +TestEventListener* TestEventListeners::Release(TestEventListener* listener) { + if (listener == default_result_printer_) + default_result_printer_ = NULL; + else if (listener == default_xml_generator_) + default_xml_generator_ = NULL; + return repeater_->Release(listener); +} + +// Returns repeater that broadcasts the TestEventListener events to all +// subscribers. +TestEventListener* TestEventListeners::repeater() { return repeater_; } + +// Sets the default_result_printer attribute to the provided listener. +// The listener is also added to the listener list and previous +// default_result_printer is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { + if (default_result_printer_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_result_printer_); + default_result_printer_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Sets the default_xml_generator attribute to the provided listener. The +// listener is also added to the listener list and previous +// default_xml_generator is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { + if (default_xml_generator_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_xml_generator_); + default_xml_generator_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Controls whether events will be forwarded by the repeater to the +// listeners in the list. +bool TestEventListeners::EventForwardingEnabled() const { + return repeater_->forwarding_enabled(); +} + +void TestEventListeners::SuppressEventForwarding() { + repeater_->set_forwarding_enabled(false); +} + +// class UnitTest + +// Gets the singleton UnitTest object. The first time this method is +// called, a UnitTest object is constructed and returned. Consecutive +// calls will return the same object. +// +// We don't protect this under mutex_ as a user is not supposed to +// call this before main() starts, from which point on the return +// value will never change. +UnitTest * UnitTest::GetInstance() { + // When compiled with MSVC 7.1 in optimized mode, destroying the + // UnitTest object upon exiting the program messes up the exit code, + // causing successful tests to appear failed. We have to use a + // different implementation in this case to bypass the compiler bug. + // This implementation makes the compiler happy, at the cost of + // leaking the UnitTest object. + + // CodeGear C++Builder insists on a public destructor for the + // default implementation. Use this implementation to keep good OO + // design with private destructor. + +#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) + static UnitTest* const instance = new UnitTest; + return instance; +#else + static UnitTest instance; + return &instance; +#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +} + +// Gets the number of successful test cases. +int UnitTest::successful_test_case_count() const { + return impl()->successful_test_case_count(); +} + +// Gets the number of failed test cases. +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_case_count(); +} + +// Gets the number of all test cases. +int UnitTest::total_test_case_count() const { + return impl()->total_test_case_count(); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTest::test_case_to_run_count() const { + return impl()->test_case_to_run_count(); +} + +// Gets the number of successful tests. +int UnitTest::successful_test_count() const { + return impl()->successful_test_count(); +} + +// Gets the number of failed tests. +int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } + +// Gets the number of disabled tests. +int UnitTest::disabled_test_count() const { + return impl()->disabled_test_count(); +} + +// Gets the number of all tests. +int UnitTest::total_test_count() const { return impl()->total_test_count(); } + +// Gets the number of tests that should run. +int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } + +// Gets the elapsed time, in milliseconds. +internal::TimeInMillis UnitTest::elapsed_time() const { + return impl()->elapsed_time(); +} + +// Returns true iff the unit test passed (i.e. all test cases passed). +bool UnitTest::Passed() const { return impl()->Passed(); } + +// Returns true iff the unit test failed (i.e. some test case failed +// or something outside of all tests failed). +bool UnitTest::Failed() const { return impl()->Failed(); } + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +const TestCase* UnitTest::GetTestCase(int i) const { + return impl()->GetTestCase(i); +} + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +TestCase* UnitTest::GetMutableTestCase(int i) { + return impl()->GetMutableTestCase(i); +} + +// Returns the list of event listeners that can be used to track events +// inside Google Test. +TestEventListeners& UnitTest::listeners() { + return *impl()->listeners(); +} + +// Registers and returns a global test environment. When a test +// program is run, all global test environments will be set-up in the +// order they were registered. After all tests in the program have +// finished, all global test environments will be torn-down in the +// *reverse* order they were registered. +// +// The UnitTest object takes ownership of the given environment. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +Environment* UnitTest::AddEnvironment(Environment* env) { + if (env == NULL) { + return NULL; + } + + impl_->environments().push_back(env); + return env; +} + +// Adds a TestPartResult to the current TestResult object. All Google Test +// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call +// this to report their results. The user code should use the +// assertion macros instead of calling this directly. +// L < mutex_ +void UnitTest::AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const internal::String& message, + const internal::String& os_stack_trace) { + Message msg; + msg << message; + + internal::MutexLock lock(&mutex_); + if (impl_->gtest_trace_stack().size() > 0) { + msg << "\n" << GTEST_NAME_ << " trace:"; + + for (int i = static_cast(impl_->gtest_trace_stack().size()); + i > 0; --i) { + const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; + msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) + << " " << trace.message; + } + } + + if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { + msg << internal::kStackTraceMarker << os_stack_trace; + } + + const TestPartResult result = + TestPartResult(result_type, file_name, line_number, + msg.GetString().c_str()); + impl_->GetTestPartResultReporterForCurrentThread()-> + ReportTestPartResult(result); + + if (result_type != TestPartResult::kSuccess) { + // gtest_break_on_failure takes precedence over + // gtest_throw_on_failure. This allows a user to set the latter + // in the code (perhaps in order to use Google Test assertions + // with another testing framework) and specify the former on the + // command line for debugging. + if (GTEST_FLAG(break_on_failure)) { +#if GTEST_OS_WINDOWS + // Using DebugBreak on Windows allows gtest to still break into a debugger + // when a failure happens and both the --gtest_break_on_failure and + // the --gtest_catch_exceptions flags are specified. + DebugBreak(); +#else + // Dereference NULL through a volatile pointer to prevent the compiler + // from removing. We use this rather than abort() or __builtin_trap() for + // portability: Symbian doesn't implement abort() well, and some debuggers + // don't correctly trap abort(). + *static_cast(NULL) = 1; +#endif // GTEST_OS_WINDOWS + } else if (GTEST_FLAG(throw_on_failure)) { +#if GTEST_HAS_EXCEPTIONS + throw GoogleTestFailureException(result); +#else + // We cannot call abort() as it generates a pop-up in debug mode + // that cannot be suppressed in VC 7.1 or below. + exit(1); +#endif + } + } +} + +// Creates and adds a property to the current TestResult. If a property matching +// the supplied value already exists, updates its value instead. +void UnitTest::RecordPropertyForCurrentTest(const char* key, + const char* value) { + const TestProperty test_property(key, value); + impl_->current_test_result()->RecordProperty(test_property); +} + +// Runs all tests in this UnitTest object and prints the result. +// Returns 0 if successful, or 1 otherwise. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +int UnitTest::Run() { + // Captures the value of GTEST_FLAG(catch_exceptions). This value will be + // used for the duration of the program. + impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); + +#if GTEST_HAS_SEH + const bool in_death_test_child_process = + internal::GTEST_FLAG(internal_run_death_test).length() > 0; + + // Either the user wants Google Test to catch exceptions thrown by the + // tests or this is executing in the context of death test child + // process. In either case the user does not want to see pop-up dialogs + // about crashes - they are expected. + if (impl()->catch_exceptions() || in_death_test_child_process) { + +# if !GTEST_OS_WINDOWS_MOBILE + // SetErrorMode doesn't exist on CE. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | + SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); +# endif // !GTEST_OS_WINDOWS_MOBILE + +# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE + // Death test children can be terminated with _abort(). On Windows, + // _abort() can show a dialog with a warning message. This forces the + // abort message to go to stderr instead. + _set_error_mode(_OUT_TO_STDERR); +# endif + +# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program. We need to suppress + // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement + // executed. Google Test will notify the user of any unexpected + // failure via stderr. + // + // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. + // Users of prior VC versions shall suffer the agony and pain of + // clicking through the countless debug dialogs. + // TODO(vladl@google.com): find a way to suppress the abort dialog() in the + // debug mode when compiled with VC 7.1 or lower. + if (!GTEST_FLAG(break_on_failure)) + _set_abort_behavior( + 0x0, // Clear the following flags: + _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. +# endif + + } +#endif // GTEST_HAS_SEH + + return internal::HandleExceptionsInMethodIfSupported( + impl(), + &internal::UnitTestImpl::RunAllTests, + "auxiliary test code (environments or event listeners)") ? 0 : 1; +} + +// Returns the working directory when the first TEST() or TEST_F() was +// executed. +const char* UnitTest::original_working_dir() const { + return impl_->original_working_dir_.c_str(); +} + +// Returns the TestCase object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestCase* UnitTest::current_test_case() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_case(); +} + +// Returns the TestInfo object for the test that's currently running, +// or NULL if no test is running. +// L < mutex_ +const TestInfo* UnitTest::current_test_info() const { + internal::MutexLock lock(&mutex_); + return impl_->current_test_info(); +} + +// Returns the random seed used at the start of the current test run. +int UnitTest::random_seed() const { return impl_->random_seed(); } + +#if GTEST_HAS_PARAM_TEST +// Returns ParameterizedTestCaseRegistry object used to keep track of +// value-parameterized tests and instantiate and register them. +// L < mutex_ +internal::ParameterizedTestCaseRegistry& + UnitTest::parameterized_test_registry() { + return impl_->parameterized_test_registry(); +} +#endif // GTEST_HAS_PARAM_TEST + +// Creates an empty UnitTest. +UnitTest::UnitTest() { + impl_ = new internal::UnitTestImpl(this); +} + +// Destructor of UnitTest. +UnitTest::~UnitTest() { + delete impl_; +} + +// Pushes a trace defined by SCOPED_TRACE() on to the per-thread +// Google Test trace stack. +// L < mutex_ +void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().push_back(trace); +} + +// Pops a trace from the per-thread Google Test trace stack. +// L < mutex_ +void UnitTest::PopGTestTrace() { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().pop_back(); +} + +namespace internal { + +UnitTestImpl::UnitTestImpl(UnitTest* parent) + : parent_(parent), +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4355) // Temporarily disables warning 4355 + // (using this in initializer). + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +# pragma warning(pop) // Restores the warning state again. +#else + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +#endif // _MSC_VER + global_test_part_result_repoter_( + &default_global_test_part_result_reporter_), + per_thread_test_part_result_reporter_( + &default_per_thread_test_part_result_reporter_), +#if GTEST_HAS_PARAM_TEST + parameterized_test_registry_(), + parameterized_tests_registered_(false), +#endif // GTEST_HAS_PARAM_TEST + last_death_test_case_(-1), + current_test_case_(NULL), + current_test_info_(NULL), + ad_hoc_test_result_(), + os_stack_trace_getter_(NULL), + post_flag_parse_init_performed_(false), + random_seed_(0), // Will be overridden by the flag before first use. + random_(0), // Will be reseeded before first use. + elapsed_time_(0), +#if GTEST_HAS_DEATH_TEST + internal_run_death_test_flag_(NULL), + death_test_factory_(new DefaultDeathTestFactory), +#endif + // Will be overridden by the flag before first use. + catch_exceptions_(false) { + listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); +} + +UnitTestImpl::~UnitTestImpl() { + // Deletes every TestCase. + ForEach(test_cases_, internal::Delete); + + // Deletes every Environment. + ForEach(environments_, internal::Delete); + + delete os_stack_trace_getter_; +} + +#if GTEST_HAS_DEATH_TEST +// Disables event forwarding if the control is currently in a death test +// subprocess. Must not be called before InitGoogleTest. +void UnitTestImpl::SuppressTestEventsIfInSubprocess() { + if (internal_run_death_test_flag_.get() != NULL) + listeners()->SuppressEventForwarding(); +} +#endif // GTEST_HAS_DEATH_TEST + +// Initializes event listeners performing XML output as specified by +// UnitTestOptions. Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureXmlOutput() { + const String& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml") { + listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format != "") { + printf("WARNING: unrecognized output format \"%s\" ignored.\n", + output_format.c_str()); + fflush(stdout); + } +} + +#if GTEST_CAN_STREAM_RESULTS_ +// Initializes event listeners for streaming test results in String form. +// Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureStreamingOutput() { + const string& target = GTEST_FLAG(stream_result_to); + if (!target.empty()) { + const size_t pos = target.find(':'); + if (pos != string::npos) { + listeners()->Append(new StreamingListener(target.substr(0, pos), + target.substr(pos+1))); + } else { + printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", + target.c_str()); + fflush(stdout); + } + } +} +#endif // GTEST_CAN_STREAM_RESULTS_ + +// Performs initialization dependent upon flag values obtained in +// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to +// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest +// this function is also called from RunAllTests. Since this function can be +// called more than once, it has to be idempotent. +void UnitTestImpl::PostFlagParsingInit() { + // Ensures that this function does not execute more than once. + if (!post_flag_parse_init_performed_) { + post_flag_parse_init_performed_ = true; + +#if GTEST_HAS_DEATH_TEST + InitDeathTestSubprocessControlInfo(); + SuppressTestEventsIfInSubprocess(); +#endif // GTEST_HAS_DEATH_TEST + + // Registers parameterized tests. This makes parameterized tests + // available to the UnitTest reflection API without running + // RUN_ALL_TESTS. + RegisterParameterizedTests(); + + // Configures listeners for XML output. This makes it possible for users + // to shut down the default XML output before invoking RUN_ALL_TESTS. + ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Configures listeners for streaming test results to the specified server. + ConfigureStreamingOutput(); +#endif // GTEST_CAN_STREAM_RESULTS_ + } +} + +// A predicate that checks the name of a TestCase against a known +// value. +// +// This is used for implementation of the UnitTest class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestCaseNameIs is copyable. +class TestCaseNameIs { + public: + // Constructor. + explicit TestCaseNameIs(const String& name) + : name_(name) {} + + // Returns true iff the name of test_case matches name_. + bool operator()(const TestCase* test_case) const { + return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + } + + private: + String name_; +}; + +// Finds and returns a TestCase with the given name. If one doesn't +// exist, creates one and returns it. It's the CALLER'S +// RESPONSIBILITY to ensure that this function is only called WHEN THE +// TESTS ARE NOT SHUFFLED. +// +// Arguments: +// +// test_case_name: name of the test case +// type_param: the name of the test case's type parameter, or NULL if +// this is not a typed or a type-parameterized test case. +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, + const char* type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) { + // Can we find a TestCase with the given name? + const std::vector::const_iterator test_case = + std::find_if(test_cases_.begin(), test_cases_.end(), + TestCaseNameIs(test_case_name)); + + if (test_case != test_cases_.end()) + return *test_case; + + // No. Let's create one. + TestCase* const new_test_case = + new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); + + // Is this a death test case? + if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), + kDeathTestCaseFilter)) { + // Yes. Inserts the test case after the last death test case + // defined so far. This only works when the test cases haven't + // been shuffled. Otherwise we may end up running a death test + // after a non-death test. + ++last_death_test_case_; + test_cases_.insert(test_cases_.begin() + last_death_test_case_, + new_test_case); + } else { + // No. Appends to the end of the list. + test_cases_.push_back(new_test_case); + } + + test_case_indices_.push_back(static_cast(test_case_indices_.size())); + return new_test_case; +} + +// Helpers for setting up / tearing down the given environment. They +// are for use in the ForEach() function. +static void SetUpEnvironment(Environment* env) { env->SetUp(); } +static void TearDownEnvironment(Environment* env) { env->TearDown(); } + +// Runs all tests in this UnitTest object, prints the result, and +// returns true if all tests are successful. If any exception is +// thrown during a test, the test is considered to be failed, but the +// rest of the tests will still be run. +// +// When parameterized tests are enabled, it expands and registers +// parameterized tests first in RegisterParameterizedTests(). +// All other functions called from RunAllTests() may safely assume that +// parameterized tests are ready to be counted and run. +bool UnitTestImpl::RunAllTests() { + // Makes sure InitGoogleTest() was called. + if (!GTestIsInitialized()) { + printf("%s", + "\nThis test program did NOT call ::testing::InitGoogleTest " + "before calling RUN_ALL_TESTS(). Please fix it.\n"); + return false; + } + + // Do not run any test if the --help flag was specified. + if (g_help_flag) + return true; + + // Repeats the call to the post-flag parsing initialization in case the + // user didn't call InitGoogleTest. + PostFlagParsingInit(); + + // Even if sharding is not on, test runners may want to use the + // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding + // protocol. + internal::WriteToShardStatusFileIfNeeded(); + + // True iff we are in a subprocess for running a thread-safe-style + // death test. + bool in_subprocess_for_death_test = false; + +#if GTEST_HAS_DEATH_TEST + in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); +#endif // GTEST_HAS_DEATH_TEST + + const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, + in_subprocess_for_death_test); + + // Compares the full test names with the filter to decide which + // tests to run. + const bool has_tests_to_run = FilterTests(should_shard + ? HONOR_SHARDING_PROTOCOL + : IGNORE_SHARDING_PROTOCOL) > 0; + + // Lists the tests and exits if the --gtest_list_tests flag was specified. + if (GTEST_FLAG(list_tests)) { + // This must be called *after* FilterTests() has been called. + ListTestsMatchingFilter(); + return true; + } + + random_seed_ = GTEST_FLAG(shuffle) ? + GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; + + // True iff at least one test has failed. + bool failed = false; + + TestEventListener* repeater = listeners()->repeater(); + + repeater->OnTestProgramStart(*parent_); + + // How many times to repeat the tests? We don't want to repeat them + // when we are inside the subprocess of a death test. + const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); + // Repeats forever if the repeat count is negative. + const bool forever = repeat < 0; + for (int i = 0; forever || i != repeat; i++) { + // We want to preserve failures generated by ad-hoc test + // assertions executed before RUN_ALL_TESTS(). + ClearNonAdHocTestResult(); + + const TimeInMillis start = GetTimeInMillis(); + + // Shuffles test cases and tests if requested. + if (has_tests_to_run && GTEST_FLAG(shuffle)) { + random()->Reseed(random_seed_); + // This should be done before calling OnTestIterationStart(), + // such that a test event listener can see the actual test order + // in the event. + ShuffleTests(); + } + + // Tells the unit test event listeners that the tests are about to start. + repeater->OnTestIterationStart(*parent_, i); + + // Runs each test case if there is at least one test to run. + if (has_tests_to_run) { + // Sets up all environments beforehand. + repeater->OnEnvironmentsSetUpStart(*parent_); + ForEach(environments_, SetUpEnvironment); + repeater->OnEnvironmentsSetUpEnd(*parent_); + + // Runs the tests only if there was no fatal failure during global + // set-up. + if (!Test::HasFatalFailure()) { + for (int test_index = 0; test_index < total_test_case_count(); + test_index++) { + GetMutableTestCase(test_index)->Run(); + } + } + + // Tears down all environments in reverse order afterwards. + repeater->OnEnvironmentsTearDownStart(*parent_); + std::for_each(environments_.rbegin(), environments_.rend(), + TearDownEnvironment); + repeater->OnEnvironmentsTearDownEnd(*parent_); + } + + elapsed_time_ = GetTimeInMillis() - start; + + // Tells the unit test event listener that the tests have just finished. + repeater->OnTestIterationEnd(*parent_, i); + + // Gets the result and clears it. + if (!Passed()) { + failed = true; + } + + // Restores the original test order after the iteration. This + // allows the user to quickly repro a failure that happens in the + // N-th iteration without repeating the first (N - 1) iterations. + // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in + // case the user somehow changes the value of the flag somewhere + // (it's always safe to unshuffle the tests). + UnshuffleTests(); + + if (GTEST_FLAG(shuffle)) { + // Picks a new random seed for each iteration. + random_seed_ = GetNextRandomSeed(random_seed_); + } + } + + repeater->OnTestProgramEnd(*parent_); + + return !failed; +} + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded() { + const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); + if (test_shard_file != NULL) { + FILE* const file = posix::FOpen(test_shard_file, "w"); + if (file == NULL) { + ColoredPrintf(COLOR_RED, + "Could not write to the test shard status file \"%s\" " + "specified by the %s environment variable.\n", + test_shard_file, kTestShardStatusFile); + fflush(stdout); + exit(EXIT_FAILURE); + } + fclose(file); + } +} + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (i.e., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +bool ShouldShard(const char* total_shards_env, + const char* shard_index_env, + bool in_subprocess_for_death_test) { + if (in_subprocess_for_death_test) { + return false; + } + + const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); + const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); + + if (total_shards == -1 && shard_index == -1) { + return false; + } else if (total_shards == -1 && shard_index != -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestShardIndex << " = " << shard_index + << ", but have left " << kTestTotalShards << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (total_shards != -1 && shard_index == -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestTotalShards << " = " << total_shards + << ", but have left " << kTestShardIndex << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (shard_index < 0 || shard_index >= total_shards) { + const Message msg = Message() + << "Invalid environment variables: we require 0 <= " + << kTestShardIndex << " < " << kTestTotalShards + << ", but you have " << kTestShardIndex << "=" << shard_index + << ", " << kTestTotalShards << "=" << total_shards << ".\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } + + return total_shards > 1; +} + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error +// and aborts. +Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { + const char* str_val = posix::GetEnv(var); + if (str_val == NULL) { + return default_val; + } + + Int32 result; + if (!ParseInt32(Message() << "The value of environment variable " << var, + str_val, &result)) { + exit(EXIT_FAILURE); + } + return result; +} + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { + return (test_id % total_shards) == shard_index; +} + +// Compares the name of each test with the user-specified filter to +// decide whether the test should be run, then records the result in +// each TestCase and TestInfo object. +// If shard_tests == true, further filters tests based on sharding +// variables in the environment - see +// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. +// Returns the number of tests that should run. +int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { + const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestTotalShards, -1) : -1; + const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestShardIndex, -1) : -1; + + // num_runnable_tests are the number of tests that will + // run across all shards (i.e., match filter and are not disabled). + // num_selected_tests are the number of tests to be run on + // this shard. + int num_runnable_tests = 0; + int num_selected_tests = 0; + for (size_t i = 0; i < test_cases_.size(); i++) { + TestCase* const test_case = test_cases_[i]; + const String &test_case_name = test_case->name(); + test_case->set_should_run(false); + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + TestInfo* const test_info = test_case->test_info_list()[j]; + const String test_name(test_info->name()); + // A test is disabled if test case name or test name matches + // kDisableTestFilter. + const bool is_disabled = + internal::UnitTestOptions::MatchesFilter(test_case_name, + kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter(test_name, + kDisableTestFilter); + test_info->is_disabled_ = is_disabled; + + const bool matches_filter = + internal::UnitTestOptions::FilterMatchesTest(test_case_name, + test_name); + test_info->matches_filter_ = matches_filter; + + const bool is_runnable = + (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && + matches_filter; + + const bool is_selected = is_runnable && + (shard_tests == IGNORE_SHARDING_PROTOCOL || + ShouldRunTestOnShard(total_shards, shard_index, + num_runnable_tests)); + + num_runnable_tests += is_runnable; + num_selected_tests += is_selected; + + test_info->should_run_ = is_selected; + test_case->set_should_run(test_case->should_run() || is_selected); + } + } + return num_selected_tests; +} + +// Prints the names of the tests matching the user-specified filter flag. +void UnitTestImpl::ListTestsMatchingFilter() { + for (size_t i = 0; i < test_cases_.size(); i++) { + const TestCase* const test_case = test_cases_[i]; + bool printed_test_case_name = false; + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + const TestInfo* const test_info = + test_case->test_info_list()[j]; + if (test_info->matches_filter_) { + if (!printed_test_case_name) { + printed_test_case_name = true; + printf("%s.\n", test_case->name()); + } + printf(" %s\n", test_info->name()); + } + } + } + fflush(stdout); +} + +// Sets the OS stack trace getter. +// +// Does nothing if the input and the current OS stack trace getter are +// the same; otherwise, deletes the old getter and makes the input the +// current getter. +void UnitTestImpl::set_os_stack_trace_getter( + OsStackTraceGetterInterface* getter) { + if (os_stack_trace_getter_ != getter) { + delete os_stack_trace_getter_; + os_stack_trace_getter_ = getter; + } +} + +// Returns the current OS stack trace getter if it is not NULL; +// otherwise, creates an OsStackTraceGetter, makes it the current +// getter, and returns it. +OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { + if (os_stack_trace_getter_ == NULL) { + os_stack_trace_getter_ = new OsStackTraceGetter; + } + + return os_stack_trace_getter_; +} + +// Returns the TestResult for the test that's currently running, or +// the TestResult for the ad hoc test if no test is running. +TestResult* UnitTestImpl::current_test_result() { + return current_test_info_ ? + &(current_test_info_->result_) : &ad_hoc_test_result_; +} + +// Shuffles all test cases, and the tests within each test case, +// making sure that death tests are still run first. +void UnitTestImpl::ShuffleTests() { + // Shuffles the death test cases. + ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); + + // Shuffles the non-death test cases. + ShuffleRange(random(), last_death_test_case_ + 1, + static_cast(test_cases_.size()), &test_case_indices_); + + // Shuffles the tests inside each test case. + for (size_t i = 0; i < test_cases_.size(); i++) { + test_cases_[i]->ShuffleTests(random()); + } +} + +// Restores the test cases and tests to their order before the first shuffle. +void UnitTestImpl::UnshuffleTests() { + for (size_t i = 0; i < test_cases_.size(); i++) { + // Unshuffles the tests in each test case. + test_cases_[i]->UnshuffleTests(); + // Resets the index of each test case. + test_case_indices_[i] = static_cast(i); + } +} + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, + int skip_count) { + // We pass skip_count + 1 to skip this wrapper function in addition + // to what the user really wants to skip. + return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); +} + +// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to +// suppress unreachable code warnings. +namespace { +class ClassUniqueToAlwaysTrue {}; +} + +bool IsTrue(bool condition) { return condition; } + +bool AlwaysTrue() { +#if GTEST_HAS_EXCEPTIONS + // This condition is always false so AlwaysTrue() never actually throws, + // but it makes the compiler think that it may throw. + if (IsTrue(false)) + throw ClassUniqueToAlwaysTrue(); +#endif // GTEST_HAS_EXCEPTIONS + return true; +} + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +bool SkipPrefix(const char* prefix, const char** pstr) { + const size_t prefix_len = strlen(prefix); + if (strncmp(*pstr, prefix, prefix_len) == 0) { + *pstr += prefix_len; + return true; + } + return false; +} + +// Parses a string as a command line flag. The string should have +// the format "--flag=value". When def_optional is true, the "=value" +// part can be omitted. +// +// Returns the value of the flag, or NULL if the parsing failed. +const char* ParseFlagValue(const char* str, + const char* flag, + bool def_optional) { + // str and flag must not be NULL. + if (str == NULL || flag == NULL) return NULL; + + // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. + const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag); + const size_t flag_len = flag_str.length(); + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + + // Skips the flag name. + const char* flag_end = str + flag_len; + + // When def_optional is true, it's OK to not have a "=value" part. + if (def_optional && (flag_end[0] == '\0')) { + return flag_end; + } + + // If def_optional is true and there are more characters after the + // flag name, or if def_optional is false, there must be a '=' after + // the flag name. + if (flag_end[0] != '=') return NULL; + + // Returns the string after "=". + return flag_end + 1; +} + +// Parses a string for a bool flag, in the form of either +// "--flag=value" or "--flag". +// +// In the former case, the value is taken as true as long as it does +// not start with '0', 'f', or 'F'. +// +// In the latter case, the value is taken as true. +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseBoolFlag(const char* str, const char* flag, bool* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, true); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Converts the string value to a bool. + *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); + return true; +} + +// Parses a string for an Int32 flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + return ParseInt32(Message() << "The value of flag --" << flag, + value_str, value); +} + +// Parses a string for a string flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseStringFlag(const char* str, const char* flag, String* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + *value = value_str; + return true; +} + +// Determines whether a string has a prefix that Google Test uses for its +// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. +// If Google Test detects that a command line flag has its prefix but is not +// recognized, it will print its help message. Flags starting with +// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test +// internal flags and do not trigger the help message. +static bool HasGoogleTestFlagPrefix(const char* str) { + return (SkipPrefix("--", &str) || + SkipPrefix("-", &str) || + SkipPrefix("/", &str)) && + !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && + (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || + SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); +} + +// Prints a string containing code-encoded text. The following escape +// sequences can be used in the string to control the text color: +// +// @@ prints a single '@' character. +// @R changes the color to red. +// @G changes the color to green. +// @Y changes the color to yellow. +// @D changes to the default terminal text color. +// +// TODO(wan@google.com): Write tests for this once we add stdout +// capturing to Google Test. +static void PrintColorEncoded(const char* str) { + GTestColor color = COLOR_DEFAULT; // The current color. + + // Conceptually, we split the string into segments divided by escape + // sequences. Then we print one segment at a time. At the end of + // each iteration, the str pointer advances to the beginning of the + // next segment. + for (;;) { + const char* p = strchr(str, '@'); + if (p == NULL) { + ColoredPrintf(color, "%s", str); + return; + } + + ColoredPrintf(color, "%s", String(str, p - str).c_str()); + + const char ch = p[1]; + str = p + 2; + if (ch == '@') { + ColoredPrintf(color, "@"); + } else if (ch == 'D') { + color = COLOR_DEFAULT; + } else if (ch == 'R') { + color = COLOR_RED; + } else if (ch == 'G') { + color = COLOR_GREEN; + } else if (ch == 'Y') { + color = COLOR_YELLOW; + } else { + --str; + } + } +} + +static const char kColorEncodedHelpMessage[] = +"This program contains tests written using " GTEST_NAME_ ". You can use the\n" +"following command line flags to control its behavior:\n" +"\n" +"Test Selection:\n" +" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" +" List the names of all tests instead of running them. The name of\n" +" TEST(Foo, Bar) is \"Foo.Bar\".\n" +" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" + "[@G-@YNEGATIVE_PATTERNS]@D\n" +" Run only the tests whose name matches one of the positive patterns but\n" +" none of the negative patterns. '?' matches any single character; '*'\n" +" matches any substring; ':' separates two patterns.\n" +" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" +" Run all disabled tests too.\n" +"\n" +"Test Execution:\n" +" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" +" Run the tests repeatedly; use a negative count to repeat forever.\n" +" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" +" Randomize tests' orders on every iteration.\n" +" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" +" Random number seed to use for shuffling test orders (between 1 and\n" +" 99999, or 0 to use a seed based on the current time).\n" +"\n" +"Test Output:\n" +" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" +" Enable/disable colored output. The default is @Gauto@D.\n" +" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" +" Don't print the elapsed time of each test.\n" +" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" + GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" +" Generate an XML report in the given directory or with the given file\n" +" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +#if GTEST_CAN_STREAM_RESULTS_ +" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" +" Stream test results to the given server.\n" +#endif // GTEST_CAN_STREAM_RESULTS_ +"\n" +"Assertion Behavior:\n" +#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" +" Set the default death test style.\n" +#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" +" Turn assertion failures into debugger break-points.\n" +" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" +" Turn assertion failures into C++ exceptions.\n" +" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" +" Do not report exceptions as test failures. Instead, allow them\n" +" to crash the program or throw a pop-up (on Windows).\n" +"\n" +"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " + "the corresponding\n" +"environment variable of a flag (all letters in upper-case). For example, to\n" +"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ + "color=no@D or set\n" +"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" +"\n" +"For more information, please read the " GTEST_NAME_ " documentation at\n" +"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" +"(not one in your own code or tests), please report it to\n" +"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. The type parameter CharType can be +// instantiated to either char or wchar_t. +template +void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { + for (int i = 1; i < *argc; i++) { + const String arg_string = StreamableToString(argv[i]); + const char* const arg = arg_string.c_str(); + + using internal::ParseBoolFlag; + using internal::ParseInt32Flag; + using internal::ParseStringFlag; + + // Do we see a Google Test flag? + if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, + >EST_FLAG(throw_on_failure)) + ) { + // Yes. Shift the remainder of the argv list left by one. Note + // that argv has (*argc + 1) elements, the last one always being + // NULL. The following loop moves the trailing NULL element as + // well. + for (int j = i; j != *argc; j++) { + argv[j] = argv[j + 1]; + } + + // Decrements the argument count. + (*argc)--; + + // We also need to decrement the iterator as we just removed + // an element. + i--; + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. + g_help_flag = true; + } + } + + if (g_help_flag) { + // We print the help here instead of in RUN_ALL_TESTS(), as the + // latter may not be called at all if the user is using Google + // Test with another testing framework. + PrintColorEncoded(kColorEncodedHelpMessage); + } +} + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +void ParseGoogleTestFlagsOnly(int* argc, char** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} +void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} + +// The internal implementation of InitGoogleTest(). +// +// The type parameter CharType can be instantiated to either char or +// wchar_t. +template +void InitGoogleTestImpl(int* argc, CharType** argv) { + g_init_gtest_count++; + + // We don't want to run the initialization code twice. + if (g_init_gtest_count != 1) return; + + if (*argc <= 0) return; + + internal::g_executable_path = internal::StreamableToString(argv[0]); + +#if GTEST_HAS_DEATH_TEST + + g_argvs.clear(); + for (int i = 0; i != *argc; i++) { + g_argvs.push_back(StreamableToString(argv[i])); + } + +#endif // GTEST_HAS_DEATH_TEST + + ParseGoogleTestFlagsOnly(argc, argv); + GetUnitTestImpl()->PostFlagParsingInit(); +} + +} // namespace internal + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +void InitGoogleTest(int* argc, char** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +void InitGoogleTest(int* argc, wchar_t** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +} // namespace testing +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) +// +// This file implements death tests. + + +#if GTEST_HAS_DEATH_TEST + +# if GTEST_OS_MAC +# include +# endif // GTEST_OS_MAC + +# include +# include +# include +# include + +# if GTEST_OS_WINDOWS +# include +# else +# include +# include +# endif // GTEST_OS_WINDOWS + +#endif // GTEST_HAS_DEATH_TEST + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +// Constants. + +// The default death test style. +static const char kDefaultDeathTestStyle[] = "fast"; + +GTEST_DEFINE_string_( + death_test_style, + internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), + "Indicates how to run a death test in a forked child process: " + "\"threadsafe\" (child process re-executes the test binary " + "from the beginning, running only the specific death test) or " + "\"fast\" (child process runs the death test immediately " + "after forking)."); + +GTEST_DEFINE_bool_( + death_test_use_fork, + internal::BoolFromGTestEnv("death_test_use_fork", false), + "Instructs to use fork()/_exit() instead of clone() in death tests. " + "Ignored and always uses fork() on POSIX systems where clone() is not " + "implemented. Useful when running under valgrind or similar tools if " + "those do not support clone(). Valgrind 3.3.1 will just fail if " + "it sees an unsupported combination of clone() flags. " + "It is not recommended to use this flag w/o valgrind though it will " + "work in 99% of the cases. Once valgrind is fixed, this flag will " + "most likely be removed."); + +namespace internal { +GTEST_DEFINE_string_( + internal_run_death_test, "", + "Indicates the file, line number, temporal index of " + "the single death test to run, and a file descriptor to " + "which a success code may be sent, all separated by " + "colons. This flag is specified if and only if the current " + "process is a sub-process launched for running a thread-safe " + "death test. FOR INTERNAL USE ONLY."); +} // namespace internal + +#if GTEST_HAS_DEATH_TEST + +// ExitedWithCode constructor. +ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { +} + +// ExitedWithCode function-call operator. +bool ExitedWithCode::operator()(int exit_status) const { +# if GTEST_OS_WINDOWS + + return exit_status == exit_code_; + +# else + + return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; + +# endif // GTEST_OS_WINDOWS +} + +# if !GTEST_OS_WINDOWS +// KilledBySignal constructor. +KilledBySignal::KilledBySignal(int signum) : signum_(signum) { +} + +// KilledBySignal function-call operator. +bool KilledBySignal::operator()(int exit_status) const { + return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; +} +# endif // !GTEST_OS_WINDOWS + +namespace internal { + +// Utilities needed for death tests. + +// Generates a textual description of a given exit code, in the format +// specified by wait(2). +static String ExitSummary(int exit_code) { + Message m; + +# if GTEST_OS_WINDOWS + + m << "Exited with exit status " << exit_code; + +# else + + if (WIFEXITED(exit_code)) { + m << "Exited with exit status " << WEXITSTATUS(exit_code); + } else if (WIFSIGNALED(exit_code)) { + m << "Terminated by signal " << WTERMSIG(exit_code); + } +# ifdef WCOREDUMP + if (WCOREDUMP(exit_code)) { + m << " (core dumped)"; + } +# endif +# endif // GTEST_OS_WINDOWS + + return m.GetString(); +} + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +bool ExitedUnsuccessfully(int exit_status) { + return !ExitedWithCode(0)(exit_status); +} + +# if !GTEST_OS_WINDOWS +// Generates a textual failure message when a death test finds more than +// one thread running, or cannot determine the number of threads, prior +// to executing the given statement. It is the responsibility of the +// caller not to pass a thread_count of 1. +static String DeathTestThreadWarning(size_t thread_count) { + Message msg; + msg << "Death tests use fork(), which is unsafe particularly" + << " in a threaded context. For this test, " << GTEST_NAME_ << " "; + if (thread_count == 0) + msg << "couldn't detect the number of threads."; + else + msg << "detected " << thread_count << " threads."; + return msg.GetString(); +} +# endif // !GTEST_OS_WINDOWS + +// Flag characters for reporting a death test that did not die. +static const char kDeathTestLived = 'L'; +static const char kDeathTestReturned = 'R'; +static const char kDeathTestThrew = 'T'; +static const char kDeathTestInternalError = 'I'; + +// An enumeration describing all of the possible ways that a death test can +// conclude. DIED means that the process died while executing the test +// code; LIVED means that process lived beyond the end of the test code; +// RETURNED means that the test statement attempted to execute a return +// statement, which is not allowed; THREW means that the test statement +// returned control by throwing an exception. IN_PROGRESS means the test +// has not yet concluded. +// TODO(vladl@google.com): Unify names and possibly values for +// AbortReason, DeathTestOutcome, and flag characters above. +enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; + +// Routine for aborting the program which is safe to call from an +// exec-style death test child process, in which case the error +// message is propagated back to the parent process. Otherwise, the +// message is simply printed to stderr. In either case, the program +// then exits with status 1. +void DeathTestAbort(const String& message) { + // On a POSIX system, this function may be called from a threadsafe-style + // death test child process, which operates on a very small stack. Use + // the heap for any additional non-minuscule memory requirements. + const InternalRunDeathTestFlag* const flag = + GetUnitTestImpl()->internal_run_death_test_flag(); + if (flag != NULL) { + FILE* parent = posix::FDOpen(flag->write_fd(), "w"); + fputc(kDeathTestInternalError, parent); + fprintf(parent, "%s", message.c_str()); + fflush(parent); + _exit(1); + } else { + fprintf(stderr, "%s", message.c_str()); + fflush(stderr); + posix::Abort(); + } +} + +// A replacement for CHECK that calls DeathTestAbort if the assertion +// fails. +# define GTEST_DEATH_TEST_CHECK_(expression) \ + do { \ + if (!::testing::internal::IsTrue(expression)) { \ + DeathTestAbort(::testing::internal::String::Format( \ + "CHECK failed: File %s, line %d: %s", \ + __FILE__, __LINE__, #expression)); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for +// evaluating any system call that fulfills two conditions: it must return +// -1 on failure, and set errno to EINTR when it is interrupted and +// should be tried again. The macro expands to a loop that repeatedly +// evaluates the expression as long as it evaluates to -1 and sets +// errno to EINTR. If the expression evaluates to -1 but errno is +// something other than EINTR, DeathTestAbort is called. +# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ + do { \ + int gtest_retval; \ + do { \ + gtest_retval = (expression); \ + } while (gtest_retval == -1 && errno == EINTR); \ + if (gtest_retval == -1) { \ + DeathTestAbort(::testing::internal::String::Format( \ + "CHECK failed: File %s, line %d: %s != -1", \ + __FILE__, __LINE__, #expression)); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// Returns the message describing the last system error in errno. +String GetLastErrnoDescription() { + return String(errno == 0 ? "" : posix::StrError(errno)); +} + +// This is called from a death test parent process to read a failure +// message from the death test child process and log it with the FATAL +// severity. On Windows, the message is read from a pipe handle. On other +// platforms, it is read from a file descriptor. +static void FailFromInternalError(int fd) { + Message error; + char buffer[256]; + int num_read; + + do { + while ((num_read = posix::Read(fd, buffer, 255)) > 0) { + buffer[num_read] = '\0'; + error << buffer; + } + } while (num_read == -1 && errno == EINTR); + + if (num_read == 0) { + GTEST_LOG_(FATAL) << error.GetString(); + } else { + const int last_error = errno; + GTEST_LOG_(FATAL) << "Error while reading death test internal: " + << GetLastErrnoDescription() << " [" << last_error << "]"; + } +} + +// Death test constructor. Increments the running death test count +// for the current test. +DeathTest::DeathTest() { + TestInfo* const info = GetUnitTestImpl()->current_test_info(); + if (info == NULL) { + DeathTestAbort("Cannot run a death test outside of a TEST or " + "TEST_F construct"); + } +} + +// Creates and returns a death test by dispatching to the current +// death test factory. +bool DeathTest::Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) { + return GetUnitTestImpl()->death_test_factory()->Create( + statement, regex, file, line, test); +} + +const char* DeathTest::LastMessage() { + return last_death_test_message_.c_str(); +} + +void DeathTest::set_last_death_test_message(const String& message) { + last_death_test_message_ = message; +} + +String DeathTest::last_death_test_message_; + +// Provides cross platform implementation for some death functionality. +class DeathTestImpl : public DeathTest { + protected: + DeathTestImpl(const char* a_statement, const RE* a_regex) + : statement_(a_statement), + regex_(a_regex), + spawned_(false), + status_(-1), + outcome_(IN_PROGRESS), + read_fd_(-1), + write_fd_(-1) {} + + // read_fd_ is expected to be closed and cleared by a derived class. + ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + + void Abort(AbortReason reason); + virtual bool Passed(bool status_ok); + + const char* statement() const { return statement_; } + const RE* regex() const { return regex_; } + bool spawned() const { return spawned_; } + void set_spawned(bool is_spawned) { spawned_ = is_spawned; } + int status() const { return status_; } + void set_status(int a_status) { status_ = a_status; } + DeathTestOutcome outcome() const { return outcome_; } + void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } + int read_fd() const { return read_fd_; } + void set_read_fd(int fd) { read_fd_ = fd; } + int write_fd() const { return write_fd_; } + void set_write_fd(int fd) { write_fd_ = fd; } + + // Called in the parent process only. Reads the result code of the death + // test child process via a pipe, interprets it to set the outcome_ + // member, and closes read_fd_. Outputs diagnostics and terminates in + // case of unexpected codes. + void ReadAndInterpretStatusByte(); + + private: + // The textual content of the code this object is testing. This class + // doesn't own this string and should not attempt to delete it. + const char* const statement_; + // The regular expression which test output must match. DeathTestImpl + // doesn't own this object and should not attempt to delete it. + const RE* const regex_; + // True if the death test child process has been successfully spawned. + bool spawned_; + // The exit status of the child process. + int status_; + // How the death test concluded. + DeathTestOutcome outcome_; + // Descriptor to the read end of the pipe to the child process. It is + // always -1 in the child process. The child keeps its write end of the + // pipe in write_fd_. + int read_fd_; + // Descriptor to the child's write end of the pipe to the parent process. + // It is always -1 in the parent process. The parent keeps its end of the + // pipe in read_fd_. + int write_fd_; +}; + +// Called in the parent process only. Reads the result code of the death +// test child process via a pipe, interprets it to set the outcome_ +// member, and closes read_fd_. Outputs diagnostics and terminates in +// case of unexpected codes. +void DeathTestImpl::ReadAndInterpretStatusByte() { + char flag; + int bytes_read; + + // The read() here blocks until data is available (signifying the + // failure of the death test) or until the pipe is closed (signifying + // its success), so it's okay to call this in the parent before + // the child process has exited. + do { + bytes_read = posix::Read(read_fd(), &flag, 1); + } while (bytes_read == -1 && errno == EINTR); + + if (bytes_read == 0) { + set_outcome(DIED); + } else if (bytes_read == 1) { + switch (flag) { + case kDeathTestReturned: + set_outcome(RETURNED); + break; + case kDeathTestThrew: + set_outcome(THREW); + break; + case kDeathTestLived: + set_outcome(LIVED); + break; + case kDeathTestInternalError: + FailFromInternalError(read_fd()); // Does not return. + break; + default: + GTEST_LOG_(FATAL) << "Death test child process reported " + << "unexpected status byte (" + << static_cast(flag) << ")"; + } + } else { + GTEST_LOG_(FATAL) << "Read from death test child process failed: " + << GetLastErrnoDescription(); + } + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); + set_read_fd(-1); +} + +// Signals that the death test code which should have exited, didn't. +// Should be called only in a death test child process. +// Writes a status byte to the child's status file descriptor, then +// calls _exit(1). +void DeathTestImpl::Abort(AbortReason reason) { + // The parent process considers the death test to be a failure if + // it finds any data in our pipe. So, here we write a single flag byte + // to the pipe, then exit. + const char status_ch = + reason == TEST_DID_NOT_DIE ? kDeathTestLived : + reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; + + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); + // We are leaking the descriptor here because on some platforms (i.e., + // when built as Windows DLL), destructors of global objects will still + // run after calling _exit(). On such systems, write_fd_ will be + // indirectly closed from the destructor of UnitTestImpl, causing double + // close if it is also closed here. On debug configurations, double close + // may assert. As there are no in-process buffers to flush here, we are + // relying on the OS to close the descriptor after the process terminates + // when the destructors are not run. + _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) +} + +// Returns an indented copy of stderr output for a death test. +// This makes distinguishing death test output lines from regular log lines +// much easier. +static ::std::string FormatDeathTestOutput(const ::std::string& output) { + ::std::string ret; + for (size_t at = 0; ; ) { + const size_t line_end = output.find('\n', at); + ret += "[ DEATH ] "; + if (line_end == ::std::string::npos) { + ret += output.substr(at); + break; + } + ret += output.substr(at, line_end + 1 - at); + at = line_end + 1; + } + return ret; +} + +// Assesses the success or failure of a death test, using both private +// members which have previously been set, and one argument: +// +// Private data members: +// outcome: An enumeration describing how the death test +// concluded: DIED, LIVED, THREW, or RETURNED. The death test +// fails in the latter three cases. +// status: The exit status of the child process. On *nix, it is in the +// in the format specified by wait(2). On Windows, this is the +// value supplied to the ExitProcess() API or a numeric code +// of the exception that terminated the program. +// regex: A regular expression object to be applied to +// the test's captured standard error output; the death test +// fails if it does not match. +// +// Argument: +// status_ok: true if exit_status is acceptable in the context of +// this particular death test, which fails if it is false +// +// Returns true iff all of the above conditions are met. Otherwise, the +// first failing condition, in the order given above, is the one that is +// reported. Also sets the last death test message string. +bool DeathTestImpl::Passed(bool status_ok) { + if (!spawned()) + return false; + + const String error_message = GetCapturedStderr(); + + bool success = false; + Message buffer; + + buffer << "Death test: " << statement() << "\n"; + switch (outcome()) { + case LIVED: + buffer << " Result: failed to die.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case THREW: + buffer << " Result: threw an exception.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case RETURNED: + buffer << " Result: illegal return in test statement.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case DIED: + if (status_ok) { + const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); + if (matched) { + success = true; + } else { + buffer << " Result: died but not with expected error.\n" + << " Expected: " << regex()->pattern() << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); + } + } else { + buffer << " Result: died but not with expected exit code:\n" + << " " << ExitSummary(status()) << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); + } + break; + case IN_PROGRESS: + default: + GTEST_LOG_(FATAL) + << "DeathTest::Passed somehow called before conclusion of test"; + } + + DeathTest::set_last_death_test_message(buffer.GetString()); + return success; +} + +# if GTEST_OS_WINDOWS +// WindowsDeathTest implements death tests on Windows. Due to the +// specifics of starting new processes on Windows, death tests there are +// always threadsafe, and Google Test considers the +// --gtest_death_test_style=fast setting to be equivalent to +// --gtest_death_test_style=threadsafe there. +// +// A few implementation notes: Like the Linux version, the Windows +// implementation uses pipes for child-to-parent communication. But due to +// the specifics of pipes on Windows, some extra steps are required: +// +// 1. The parent creates a communication pipe and stores handles to both +// ends of it. +// 2. The parent starts the child and provides it with the information +// necessary to acquire the handle to the write end of the pipe. +// 3. The child acquires the write end of the pipe and signals the parent +// using a Windows event. +// 4. Now the parent can release the write end of the pipe on its side. If +// this is done before step 3, the object's reference count goes down to +// 0 and it is destroyed, preventing the child from acquiring it. The +// parent now has to release it, or read operations on the read end of +// the pipe will not return when the child terminates. +// 5. The parent reads child's output through the pipe (outcome code and +// any possible error messages) from the pipe, and its stderr and then +// determines whether to fail the test. +// +// Note: to distinguish Win32 API calls from the local method and function +// calls, the former are explicitly resolved in the global namespace. +// +class WindowsDeathTest : public DeathTestImpl { + public: + WindowsDeathTest(const char* a_statement, + const RE* a_regex, + const char* file, + int line) + : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual TestRole AssumeRole(); + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + // Handle to the write end of the pipe to the child process. + AutoHandle write_handle_; + // Child process handle. + AutoHandle child_handle_; + // Event the child process uses to signal the parent that it has + // acquired the handle to the write end of the pipe. After seeing this + // event the parent can release its own handles to make sure its + // ReadFile() calls return when the child terminates. + AutoHandle event_handle_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int WindowsDeathTest::Wait() { + if (!spawned()) + return 0; + + // Wait until the child either signals that it has acquired the write end + // of the pipe or it dies. + const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; + switch (::WaitForMultipleObjects(2, + wait_handles, + FALSE, // Waits for any of the handles. + INFINITE)) { + case WAIT_OBJECT_0: + case WAIT_OBJECT_0 + 1: + break; + default: + GTEST_DEATH_TEST_CHECK_(false); // Should not get here. + } + + // The child has acquired the write end of the pipe or exited. + // We release the handle on our side and continue. + write_handle_.Reset(); + event_handle_.Reset(); + + ReadAndInterpretStatusByte(); + + // Waits for the child process to exit if it haven't already. This + // returns immediately if the child has already exited, regardless of + // whether previous calls to WaitForMultipleObjects synchronized on this + // handle or not. + GTEST_DEATH_TEST_CHECK_( + WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), + INFINITE)); + DWORD status_code; + GTEST_DEATH_TEST_CHECK_( + ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); + child_handle_.Reset(); + set_status(static_cast(status_code)); + return status(); +} + +// The AssumeRole process for a Windows death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole WindowsDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + // WindowsDeathTest uses an anonymous pipe to communicate results of + // a death test. + SECURITY_ATTRIBUTES handles_are_inheritable = { + sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + HANDLE read_handle, write_handle; + GTEST_DEATH_TEST_CHECK_( + ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, + 0) // Default buffer size. + != FALSE); + set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), + O_RDONLY)); + write_handle_.Reset(write_handle); + event_handle_.Reset(::CreateEvent( + &handles_are_inheritable, + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + NULL)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); + const String filter_flag = String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name(), + info->name()); + const String internal_flag = String::Format( + "--%s%s=%s|%d|%d|%u|%Iu|%Iu", + GTEST_FLAG_PREFIX_, + kInternalRunDeathTestFlag, + file_, line_, + death_test_index, + static_cast(::GetCurrentProcessId()), + // size_t has the same with as pointers on both 32-bit and 64-bit + // Windows platforms. + // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. + reinterpret_cast(write_handle), + reinterpret_cast(event_handle_.Get())); + + char executable_path[_MAX_PATH + 1]; // NOLINT + GTEST_DEATH_TEST_CHECK_( + _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, + executable_path, + _MAX_PATH)); + + String command_line = String::Format("%s %s \"%s\"", + ::GetCommandLineA(), + filter_flag.c_str(), + internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // The child process will share the standard handles with the parent. + STARTUPINFOA startup_info; + memset(&startup_info, 0, sizeof(STARTUPINFO)); + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); + startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); + + PROCESS_INFORMATION process_info; + GTEST_DEATH_TEST_CHECK_(::CreateProcessA( + executable_path, + const_cast(command_line.c_str()), + NULL, // Retuned process handle is not inheritable. + NULL, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + NULL, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), + &startup_info, + &process_info) != FALSE); + child_handle_.Reset(process_info.hProcess); + ::CloseHandle(process_info.hThread); + set_spawned(true); + return OVERSEE_TEST; +} +# else // We are not on Windows. + +// ForkingDeathTest provides implementations for most of the abstract +// methods of the DeathTest interface. Only the AssumeRole method is +// left undefined. +class ForkingDeathTest : public DeathTestImpl { + public: + ForkingDeathTest(const char* statement, const RE* regex); + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + + protected: + void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } + + private: + // PID of child process during death test; 0 in the child process itself. + pid_t child_pid_; +}; + +// Constructs a ForkingDeathTest. +ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) + : DeathTestImpl(a_statement, a_regex), + child_pid_(-1) {} + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int ForkingDeathTest::Wait() { + if (!spawned()) + return 0; + + ReadAndInterpretStatusByte(); + + int status_value; + GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); + set_status(status_value); + return status_value; +} + +// A concrete death test class that forks, then immediately runs the test +// in the child process. +class NoExecDeathTest : public ForkingDeathTest { + public: + NoExecDeathTest(const char* a_statement, const RE* a_regex) : + ForkingDeathTest(a_statement, a_regex) { } + virtual TestRole AssumeRole(); +}; + +// The AssumeRole process for a fork-and-run death test. It implements a +// straightforward fork, with a simple pipe to transmit the status byte. +DeathTest::TestRole NoExecDeathTest::AssumeRole() { + const size_t thread_count = GetThreadCount(); + if (thread_count != 1) { + GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + + DeathTest::set_last_death_test_message(""); + CaptureStderr(); + // When we fork the process below, the log file buffers are copied, but the + // file descriptors are shared. We flush all log files here so that closing + // the file descriptors in the child process doesn't throw off the + // synchronization between descriptors and buffers in the parent process. + // This is as close to the fork as possible to avoid a race condition in case + // there are multiple threads running before the death test, and another + // thread writes to the log file. + FlushInfoLog(); + + const pid_t child_pid = fork(); + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + set_child_pid(child_pid); + if (child_pid == 0) { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); + set_write_fd(pipe_fd[1]); + // Redirects all logging to stderr in the child process to prevent + // concurrent writes to the log files. We capture stderr in the parent + // process and append the child process' output to a log. + LogToStderr(); + // Event forwarding to the listeners of event listener API mush be shut + // down in death test subprocesses. + GetUnitTestImpl()->listeners()->SuppressEventForwarding(); + return EXECUTE_TEST; + } else { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; + } +} + +// A concrete death test class that forks and re-executes the main +// program from the beginning, with command-line flags set that cause +// only this specific death test to be run. +class ExecDeathTest : public ForkingDeathTest { + public: + ExecDeathTest(const char* a_statement, const RE* a_regex, + const char* file, int line) : + ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } + virtual TestRole AssumeRole(); + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { + args_.push_back(NULL); + } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + private: + std::vector args_; +}; + +// A struct that encompasses the arguments to the child process of a +// threadsafe-style death test process. +struct ExecDeathTestArgs { + char* const* argv; // Command-line arguments for the child's call to exec + int close_fd; // File descriptor to close; the read end of a pipe +}; + +# if GTEST_OS_MAC +inline char** GetEnviron() { + // When Google Test is built as a framework on MacOS X, the environ variable + // is unavailable. Apple's documentation (man environ) recommends using + // _NSGetEnviron() instead. + return *_NSGetEnviron(); +} +# else +// Some POSIX platforms expect you to declare environ. extern "C" makes +// it reside in the global namespace. +extern "C" char** environ; +inline char** GetEnviron() { return environ; } +# endif // GTEST_OS_MAC + +// The main function for a threadsafe-style death test child process. +// This function is called in a clone()-ed process and thus must avoid +// any potentially unsafe operations like malloc or libc functions. +static int ExecDeathTestChildMain(void* child_arg) { + ExecDeathTestArgs* const args = static_cast(child_arg); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); + + // We need to execute the test program in the same environment where + // it was originally invoked. Therefore we change to the original + // working directory first. + const char* const original_dir = + UnitTest::GetInstance()->original_working_dir(); + // We can safely call chdir() as it's a direct system call. + if (chdir(original_dir) != 0) { + DeathTestAbort(String::Format("chdir(\"%s\") failed: %s", + original_dir, + GetLastErrnoDescription().c_str())); + return EXIT_FAILURE; + } + + // We can safely call execve() as it's a direct system call. We + // cannot use execvp() as it's a libc function and thus potentially + // unsafe. Since execve() doesn't search the PATH, the user must + // invoke the test program via a valid path that contains at least + // one path separator. + execve(args->argv[0], args->argv, GetEnviron()); + DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s", + args->argv[0], + original_dir, + GetLastErrnoDescription().c_str())); + return EXIT_FAILURE; +} + +// Two utility routines that together determine the direction the stack +// grows. +// This could be accomplished more elegantly by a single recursive +// function, but we want to guard against the unlikely possibility of +// a smart compiler optimizing the recursion away. +// +// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining +// StackLowerThanAddress into StackGrowsDown, which then doesn't give +// correct answer. +bool StackLowerThanAddress(const void* ptr) GTEST_NO_INLINE_; +bool StackLowerThanAddress(const void* ptr) { + int dummy; + return &dummy < ptr; +} + +bool StackGrowsDown() { + int dummy; + return StackLowerThanAddress(&dummy); +} + +// A threadsafe implementation of fork(2) for threadsafe-style death tests +// that uses clone(2). It dies with an error message if anything goes +// wrong. +static pid_t ExecDeathTestFork(char* const* argv, int close_fd) { + ExecDeathTestArgs args = { argv, close_fd }; + pid_t child_pid = -1; + +# if GTEST_HAS_CLONE + const bool use_fork = GTEST_FLAG(death_test_use_fork); + + if (!use_fork) { + static const bool stack_grows_down = StackGrowsDown(); + const size_t stack_size = getpagesize(); + // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. + void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); + void* const stack_top = + static_cast(stack) + (stack_grows_down ? stack_size : 0); + + child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); + + GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); + } +# else + const bool use_fork = true; +# endif // GTEST_HAS_CLONE + + if (use_fork && (child_pid = fork()) == 0) { + ExecDeathTestChildMain(&args); + _exit(0); + } + + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + return child_pid; +} + +// The AssumeRole process for a fork-and-exec death test. It re-executes the +// main program from the beginning, setting the --gtest_filter +// and --gtest_internal_run_death_test flags to cause only the current +// death test to be re-run. +DeathTest::TestRole ExecDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + // Clear the close-on-exec flag on the write end of the pipe, lest + // it be closed when the child process does an exec: + GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); + + const String filter_flag = + String::Format("--%s%s=%s.%s", + GTEST_FLAG_PREFIX_, kFilterFlag, + info->test_case_name(), info->name()); + const String internal_flag = + String::Format("--%s%s=%s|%d|%d|%d", + GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag, + file_, line_, death_test_index, pipe_fd[1]); + Arguments args; + args.AddArguments(GetArgvs()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // See the comment in NoExecDeathTest::AssumeRole for why the next line + // is necessary. + FlushInfoLog(); + + const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_child_pid(child_pid); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; +} + +# endif // !GTEST_OS_WINDOWS + +// Creates a concrete DeathTest-derived class that depends on the +// --gtest_death_test_style flag, and sets the pointer pointed to +// by the "test" argument to its address. If the test should be +// skipped, sets that pointer to NULL. Returns true, unless the +// flag is set to an invalid value. +bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, + const char* file, int line, + DeathTest** test) { + UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const int death_test_index = impl->current_test_info() + ->increment_death_test_count(); + + if (flag != NULL) { + if (death_test_index > flag->index()) { + DeathTest::set_last_death_test_message(String::Format( + "Death test count (%d) somehow exceeded expected maximum (%d)", + death_test_index, flag->index())); + return false; + } + + if (!(flag->file() == file && flag->line() == line && + flag->index() == death_test_index)) { + *test = NULL; + return true; + } + } + +# if GTEST_OS_WINDOWS + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new WindowsDeathTest(statement, regex, file, line); + } + +# else + + if (GTEST_FLAG(death_test_style) == "threadsafe") { + *test = new ExecDeathTest(statement, regex, file, line); + } else if (GTEST_FLAG(death_test_style) == "fast") { + *test = new NoExecDeathTest(statement, regex); + } + +# endif // GTEST_OS_WINDOWS + + else { // NOLINT - this is more readable than unbalanced brackets inside #if. + DeathTest::set_last_death_test_message(String::Format( + "Unknown death test style \"%s\" encountered", + GTEST_FLAG(death_test_style).c_str())); + return false; + } + + return true; +} + +// Splits a given string on a given delimiter, populating a given +// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have +// ::std::string, so we can use it here. +static void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (::testing::internal::AlwaysTrue()) { + const ::std::string::size_type colon = str.find(delimiter, pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} + +# if GTEST_OS_WINDOWS +// Recreates the pipe and event handles from the provided parameters, +// signals the event, and returns a file descriptor wrapped around the pipe +// handle. This function is called in the child process only. +int GetStatusFileDescriptor(unsigned int parent_process_id, + size_t write_handle_as_size_t, + size_t event_handle_as_size_t) { + AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, + FALSE, // Non-inheritable. + parent_process_id)); + if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { + DeathTestAbort(String::Format("Unable to open parent process %u", + parent_process_id)); + } + + // TODO(vladl@google.com): Replace the following check with a + // compile-time assertion when available. + GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); + + const HANDLE write_handle = + reinterpret_cast(write_handle_as_size_t); + HANDLE dup_write_handle; + + // The newly initialized handle is accessible only in in the parent + // process. To obtain one accessible within the child, we need to use + // DuplicateHandle. + if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, + ::GetCurrentProcess(), &dup_write_handle, + 0x0, // Requested privileges ignored since + // DUPLICATE_SAME_ACCESS is used. + FALSE, // Request non-inheritable handler. + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the pipe handle %Iu from the parent process %u", + write_handle_as_size_t, parent_process_id)); + } + + const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); + HANDLE dup_event_handle; + + if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, + ::GetCurrentProcess(), &dup_event_handle, + 0x0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort(String::Format( + "Unable to duplicate the event handle %Iu from the parent process %u", + event_handle_as_size_t, parent_process_id)); + } + + const int write_fd = + ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); + if (write_fd == -1) { + DeathTestAbort(String::Format( + "Unable to convert pipe handle %Iu to a file descriptor", + write_handle_as_size_t)); + } + + // Signals the parent that the write end of the pipe has been acquired + // so the parent can release its own write end. + ::SetEvent(dup_event_handle); + + return write_fd; +} +# endif // GTEST_OS_WINDOWS + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { + if (GTEST_FLAG(internal_run_death_test) == "") return NULL; + + // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we + // can use it here. + int line = -1; + int index = -1; + ::std::vector< ::std::string> fields; + SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); + int write_fd = -1; + +# if GTEST_OS_WINDOWS + + unsigned int parent_process_id = 0; + size_t write_handle_as_size_t = 0; + size_t event_handle_as_size_t = 0; + + if (fields.size() != 6 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &parent_process_id) + || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) + || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } + write_fd = GetStatusFileDescriptor(parent_process_id, + write_handle_as_size_t, + event_handle_as_size_t); +# else + + if (fields.size() != 4 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &write_fd)) { + DeathTestAbort(String::Format( + "Bad --gtest_internal_run_death_test flag: %s", + GTEST_FLAG(internal_run_death_test).c_str())); + } + +# endif // GTEST_OS_WINDOWS + + return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); +} + +} // namespace internal + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: keith.ray@gmail.com (Keith Ray) + + +#include + +#if GTEST_OS_WINDOWS_MOBILE +# include +#elif GTEST_OS_WINDOWS +# include +# include +#elif GTEST_OS_SYMBIAN || GTEST_OS_NACL +// Symbian OpenC and NaCl have PATH_MAX in sys/syslimits.h +# include +#else +# include +# include // Some Linux distributions define PATH_MAX here. +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_MAX_ _MAX_PATH +#elif defined(PATH_MAX) +# define GTEST_PATH_MAX_ PATH_MAX +#elif defined(_XOPEN_PATH_MAX) +# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX +#else +# define GTEST_PATH_MAX_ _POSIX_PATH_MAX +#endif // GTEST_OS_WINDOWS + + +namespace testing { +namespace internal { + +#if GTEST_OS_WINDOWS +// On Windows, '\\' is the standard path separator, but many tools and the +// Windows API also accept '/' as an alternate path separator. Unless otherwise +// noted, a file path can contain either kind of path separators, or a mixture +// of them. +const char kPathSeparator = '\\'; +const char kAlternatePathSeparator = '/'; +const char kPathSeparatorString[] = "\\"; +const char kAlternatePathSeparatorString[] = "/"; +# if GTEST_OS_WINDOWS_MOBILE +// Windows CE doesn't have a current directory. You should not use +// the current directory in tests on Windows CE, but this at least +// provides a reasonable fallback. +const char kCurrentDirectoryString[] = "\\"; +// Windows CE doesn't define INVALID_FILE_ATTRIBUTES +const DWORD kInvalidFileAttributes = 0xffffffff; +# else +const char kCurrentDirectoryString[] = ".\\"; +# endif // GTEST_OS_WINDOWS_MOBILE +#else +const char kPathSeparator = '/'; +const char kPathSeparatorString[] = "/"; +const char kCurrentDirectoryString[] = "./"; +#endif // GTEST_OS_WINDOWS + +// Returns whether the given character is a valid path separator. +static bool IsPathSeparator(char c) { +#if GTEST_HAS_ALT_PATH_SEP_ + return (c == kPathSeparator) || (c == kAlternatePathSeparator); +#else + return c == kPathSeparator; +#endif +} + +// Returns the current working directory, or "" if unsuccessful. +FilePath FilePath::GetCurrentDir() { +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE doesn't have a current directory, so we just return + // something reasonable. + return FilePath(kCurrentDirectoryString); +#elif GTEST_OS_WINDOWS + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#else + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns a copy of the FilePath with the case-insensitive extension removed. +// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns +// FilePath("dir/file"). If a case-insensitive extension is not +// found, returns a copy of the original FilePath. +FilePath FilePath::RemoveExtension(const char* extension) const { + String dot_extension(String::Format(".%s", extension)); + if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) { + return FilePath(String(pathname_.c_str(), pathname_.length() - 4)); + } + return *this; +} + +// Returns a pointer to the last occurence of a valid path separator in +// the FilePath. On Windows, for example, both '/' and '\' are valid path +// separators. Returns NULL if no path separator was found. +const char* FilePath::FindLastPathSeparator() const { + const char* const last_sep = strrchr(c_str(), kPathSeparator); +#if GTEST_HAS_ALT_PATH_SEP_ + const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); + // Comparing two pointers of which only one is NULL is undefined. + if (last_alt_sep != NULL && + (last_sep == NULL || last_alt_sep > last_sep)) { + return last_alt_sep; + } +#endif + return last_sep; +} + +// Returns a copy of the FilePath with the directory part removed. +// Example: FilePath("path/to/file").RemoveDirectoryName() returns +// FilePath("file"). If there is no directory part ("just_a_file"), it returns +// the FilePath unmodified. If there is no file part ("just_a_dir/") it +// returns an empty FilePath (""). +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveDirectoryName() const { + const char* const last_sep = FindLastPathSeparator(); + return last_sep ? FilePath(String(last_sep + 1)) : *this; +} + +// RemoveFileName returns the directory path with the filename removed. +// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". +// If the FilePath is "a_file" or "/a_file", RemoveFileName returns +// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does +// not have a file, like "just/a/dir/", it returns the FilePath unmodified. +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveFileName() const { + const char* const last_sep = FindLastPathSeparator(); + String dir; + if (last_sep) { + dir = String(c_str(), last_sep + 1 - c_str()); + } else { + dir = kCurrentDirectoryString; + } + return FilePath(dir); +} + +// Helper functions for naming files in a directory for xml output. + +// Given directory = "dir", base_name = "test", number = 0, +// extension = "xml", returns "dir/test.xml". If number is greater +// than zero (e.g., 12), returns "dir/test_12.xml". +// On Windows platform, uses \ as the separator rather than /. +FilePath FilePath::MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension) { + String file; + if (number == 0) { + file = String::Format("%s.%s", base_name.c_str(), extension); + } else { + file = String::Format("%s_%d.%s", base_name.c_str(), number, extension); + } + return ConcatPaths(directory, FilePath(file)); +} + +// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". +// On Windows, uses \ as the separator rather than /. +FilePath FilePath::ConcatPaths(const FilePath& directory, + const FilePath& relative_path) { + if (directory.IsEmpty()) + return relative_path; + const FilePath dir(directory.RemoveTrailingPathSeparator()); + return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator, + relative_path.c_str())); +} + +// Returns true if pathname describes something findable in the file-system, +// either a file, directory, or whatever. +bool FilePath::FileOrDirectoryExists() const { +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + return attributes != kInvalidFileAttributes; +#else + posix::StatStruct file_stat; + return posix::Stat(pathname_.c_str(), &file_stat) == 0; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns true if pathname describes a directory in the file-system +// that exists. +bool FilePath::DirectoryExists() const { + bool result = false; +#if GTEST_OS_WINDOWS + // Don't strip off trailing separator if path is a root directory on + // Windows (like "C:\\"). + const FilePath& path(IsRootDirectory() ? *this : + RemoveTrailingPathSeparator()); +#else + const FilePath& path(*this); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + if ((attributes != kInvalidFileAttributes) && + (attributes & FILE_ATTRIBUTE_DIRECTORY)) { + result = true; + } +#else + posix::StatStruct file_stat; + result = posix::Stat(path.c_str(), &file_stat) == 0 && + posix::IsDir(file_stat); +#endif // GTEST_OS_WINDOWS_MOBILE + + return result; +} + +// Returns true if pathname describes a root directory. (Windows has one +// root directory per disk drive.) +bool FilePath::IsRootDirectory() const { +#if GTEST_OS_WINDOWS + // TODO(wan@google.com): on Windows a network share like + // \\server\share can be a root directory, although it cannot be the + // current directory. Handle this properly. + return pathname_.length() == 3 && IsAbsolutePath(); +#else + return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); +#endif +} + +// Returns true if pathname describes an absolute path. +bool FilePath::IsAbsolutePath() const { + const char* const name = pathname_.c_str(); +#if GTEST_OS_WINDOWS + return pathname_.length() >= 3 && + ((name[0] >= 'a' && name[0] <= 'z') || + (name[0] >= 'A' && name[0] <= 'Z')) && + name[1] == ':' && + IsPathSeparator(name[2]); +#else + return IsPathSeparator(name[0]); +#endif +} + +// Returns a pathname for a file that does not currently exist. The pathname +// will be directory/base_name.extension or +// directory/base_name_.extension if directory/base_name.extension +// already exists. The number will be incremented until a pathname is found +// that does not already exist. +// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. +// There could be a race condition if two or more processes are calling this +// function at the same time -- they could both pick the same filename. +FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension) { + FilePath full_pathname; + int number = 0; + do { + full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); + } while (full_pathname.FileOrDirectoryExists()); + return full_pathname; +} + +// Returns true if FilePath ends with a path separator, which indicates that +// it is intended to represent a directory. Returns false otherwise. +// This does NOT check that a directory (or file) actually exists. +bool FilePath::IsDirectory() const { + return !pathname_.empty() && + IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); +} + +// Create directories so that path exists. Returns true if successful or if +// the directories already exist; returns false if unable to create directories +// for any reason. +bool FilePath::CreateDirectoriesRecursively() const { + if (!this->IsDirectory()) { + return false; + } + + if (pathname_.length() == 0 || this->DirectoryExists()) { + return true; + } + + const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); + return parent.CreateDirectoriesRecursively() && this->CreateFolder(); +} + +// Create the directory so that path exists. Returns true if successful or +// if the directory already exists; returns false if unable to create the +// directory for any reason, including if the parent directory does not +// exist. Not named "CreateDirectory" because that's a macro on Windows. +bool FilePath::CreateFolder() const { +#if GTEST_OS_WINDOWS_MOBILE + FilePath removed_sep(this->RemoveTrailingPathSeparator()); + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + int result = CreateDirectory(unicode, NULL) ? 0 : -1; + delete [] unicode; +#elif GTEST_OS_WINDOWS + int result = _mkdir(pathname_.c_str()); +#else + int result = mkdir(pathname_.c_str(), 0777); +#endif // GTEST_OS_WINDOWS_MOBILE + + if (result == -1) { + return this->DirectoryExists(); // An error is OK if the directory exists. + } + return true; // No error. +} + +// If input name has a trailing separator character, remove it and return the +// name, otherwise return the name string unmodified. +// On Windows platform, uses \ as the separator, other platforms use /. +FilePath FilePath::RemoveTrailingPathSeparator() const { + return IsDirectory() + ? FilePath(String(pathname_.c_str(), pathname_.length() - 1)) + : *this; +} + +// Removes any redundant separators that might be in the pathname. +// For example, "bar///foo" becomes "bar/foo". Does not eliminate other +// redundancies that might be in a pathname involving "." or "..". +// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). +void FilePath::Normalize() { + if (pathname_.c_str() == NULL) { + pathname_ = ""; + return; + } + const char* src = pathname_.c_str(); + char* const dest = new char[pathname_.length() + 1]; + char* dest_ptr = dest; + memset(dest_ptr, 0, pathname_.length() + 1); + + while (*src != '\0') { + *dest_ptr = *src; + if (!IsPathSeparator(*src)) { + src++; + } else { +#if GTEST_HAS_ALT_PATH_SEP_ + if (*dest_ptr == kAlternatePathSeparator) { + *dest_ptr = kPathSeparator; + } +#endif + while (IsPathSeparator(*src)) + src++; + } + dest_ptr++; + } + *dest_ptr = '\0'; + pathname_ = dest; + delete[] dest; +} + +} // namespace internal +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + + +#include +#include +#include +#include + +#if GTEST_OS_WINDOWS_MOBILE +# include // For TerminateProcess() +#elif GTEST_OS_WINDOWS +# include +# include +#else +# include +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_MAC +# include +# include +# include +#endif // GTEST_OS_MAC + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { +namespace internal { + +#if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC and C++Builder do not provide a definition of STDERR_FILENO. +const int kStdOutFileno = 1; +const int kStdErrFileno = 2; +#else +const int kStdOutFileno = STDOUT_FILENO; +const int kStdErrFileno = STDERR_FILENO; +#endif // _MSC_VER + +#if GTEST_OS_MAC + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + const task_t task = mach_task_self(); + mach_msg_type_number_t thread_count; + thread_act_array_t thread_list; + const kern_return_t status = task_threads(task, &thread_list, &thread_count); + if (status == KERN_SUCCESS) { + // task_threads allocates resources in thread_list and we need to free them + // to avoid leaks. + vm_deallocate(task, + reinterpret_cast(thread_list), + sizeof(thread_t) * thread_count); + return static_cast(thread_count); + } else { + return 0; + } +} + +#else + +size_t GetThreadCount() { + // There's no portable way to detect the number of threads, so we just + // return 0 to indicate that we cannot detect it. + return 0; +} + +#endif // GTEST_OS_MAC + +#if GTEST_USES_POSIX_RE + +// Implements RE. Currently only needed for death tests. + +RE::~RE() { + if (is_valid_) { + // regfree'ing an invalid regex might crash because the content + // of the regex is undefined. Since the regex's are essentially + // the same, one cannot be valid (or invalid) without the other + // being so too. + regfree(&partial_regex_); + regfree(&full_regex_); + } + free(const_cast(pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.full_regex_, str, 1, &match, 0) == 0; +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = posix::StrDup(regex); + + // Reserves enough bytes to hold the regular expression used for a + // full match. + const size_t full_regex_len = strlen(regex) + 10; + char* const full_pattern = new char[full_regex_len]; + + snprintf(full_pattern, full_regex_len, "^(%s)$", regex); + is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; + // We want to call regcomp(&partial_regex_, ...) even if the + // previous expression returns false. Otherwise partial_regex_ may + // not be properly initialized can may cause trouble when it's + // freed. + // + // Some implementation of POSIX regex (e.g. on at least some + // versions of Cygwin) doesn't accept the empty string as a valid + // regex. We change it to an equivalent form "()" to be safe. + if (is_valid_) { + const char* const partial_regex = (*regex == '\0') ? "()" : regex; + is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; + } + EXPECT_TRUE(is_valid_) + << "Regular expression \"" << regex + << "\" is not a valid POSIX Extended regular expression."; + + delete[] full_pattern; +} + +#elif GTEST_USES_SIMPLE_RE + +// Returns true iff ch appears anywhere in str (excluding the +// terminating '\0' character). +bool IsInSet(char ch, const char* str) { + return ch != '\0' && strchr(str, ch) != NULL; +} + +// Returns true iff ch belongs to the given classification. Unlike +// similar functions in , these aren't affected by the +// current locale. +bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } +bool IsAsciiPunct(char ch) { + return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); +} +bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } +bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } +bool IsAsciiWordChar(char ch) { + return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || + ('0' <= ch && ch <= '9') || ch == '_'; +} + +// Returns true iff "\\c" is a supported escape sequence. +bool IsValidEscape(char c) { + return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); +} + +// Returns true iff the given atom (specified by escaped and pattern) +// matches ch. The result is undefined if the atom is invalid. +bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { + if (escaped) { // "\\p" where p is pattern_char. + switch (pattern_char) { + case 'd': return IsAsciiDigit(ch); + case 'D': return !IsAsciiDigit(ch); + case 'f': return ch == '\f'; + case 'n': return ch == '\n'; + case 'r': return ch == '\r'; + case 's': return IsAsciiWhiteSpace(ch); + case 'S': return !IsAsciiWhiteSpace(ch); + case 't': return ch == '\t'; + case 'v': return ch == '\v'; + case 'w': return IsAsciiWordChar(ch); + case 'W': return !IsAsciiWordChar(ch); + } + return IsAsciiPunct(pattern_char) && pattern_char == ch; + } + + return (pattern_char == '.' && ch != '\n') || pattern_char == ch; +} + +// Helper function used by ValidateRegex() to format error messages. +String FormatRegexSyntaxError(const char* regex, int index) { + return (Message() << "Syntax error at index " << index + << " in simple regular expression \"" << regex << "\": ").GetString(); +} + +// Generates non-fatal failures and returns false if regex is invalid; +// otherwise returns true. +bool ValidateRegex(const char* regex) { + if (regex == NULL) { + // TODO(wan@google.com): fix the source file location in the + // assertion failures to match where the regex is used in user + // code. + ADD_FAILURE() << "NULL is not a valid simple regular expression."; + return false; + } + + bool is_valid = true; + + // True iff ?, *, or + can follow the previous atom. + bool prev_repeatable = false; + for (int i = 0; regex[i]; i++) { + if (regex[i] == '\\') { // An escape sequence + i++; + if (regex[i] == '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "'\\' cannot appear at the end."; + return false; + } + + if (!IsValidEscape(regex[i])) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "invalid escape sequence \"\\" << regex[i] << "\"."; + is_valid = false; + } + prev_repeatable = true; + } else { // Not an escape sequence. + const char ch = regex[i]; + + if (ch == '^' && i > 0) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'^' can only appear at the beginning."; + is_valid = false; + } else if (ch == '$' && regex[i + 1] != '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'$' can only appear at the end."; + is_valid = false; + } else if (IsInSet(ch, "()[]{}|")) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' is unsupported."; + is_valid = false; + } else if (IsRepeat(ch) && !prev_repeatable) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' can only follow a repeatable token."; + is_valid = false; + } + + prev_repeatable = !IsInSet(ch, "^$?*+"); + } + } + + return is_valid; +} + +// Matches a repeated regex atom followed by a valid simple regular +// expression. The regex atom is defined as c if escaped is false, +// or \c otherwise. repeat is the repetition meta character (?, *, +// or +). The behavior is undefined if str contains too many +// characters to be indexable by size_t, in which case the test will +// probably time out anyway. We are fine with this limitation as +// std::string has it too. +bool MatchRepetitionAndRegexAtHead( + bool escaped, char c, char repeat, const char* regex, + const char* str) { + const size_t min_count = (repeat == '+') ? 1 : 0; + const size_t max_count = (repeat == '?') ? 1 : + static_cast(-1) - 1; + // We cannot call numeric_limits::max() as it conflicts with the + // max() macro on Windows. + + for (size_t i = 0; i <= max_count; ++i) { + // We know that the atom matches each of the first i characters in str. + if (i >= min_count && MatchRegexAtHead(regex, str + i)) { + // We have enough matches at the head, and the tail matches too. + // Since we only care about *whether* the pattern matches str + // (as opposed to *how* it matches), there is no need to find a + // greedy match. + return true; + } + if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) + return false; + } + return false; +} + +// Returns true iff regex matches a prefix of str. regex must be a +// valid simple regular expression and not start with "^", or the +// result is undefined. +bool MatchRegexAtHead(const char* regex, const char* str) { + if (*regex == '\0') // An empty regex matches a prefix of anything. + return true; + + // "$" only matches the end of a string. Note that regex being + // valid guarantees that there's nothing after "$" in it. + if (*regex == '$') + return *str == '\0'; + + // Is the first thing in regex an escape sequence? + const bool escaped = *regex == '\\'; + if (escaped) + ++regex; + if (IsRepeat(regex[1])) { + // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so + // here's an indirect recursion. It terminates as the regex gets + // shorter in each recursion. + return MatchRepetitionAndRegexAtHead( + escaped, regex[0], regex[1], regex + 2, str); + } else { + // regex isn't empty, isn't "$", and doesn't start with a + // repetition. We match the first atom of regex with the first + // character of str and recurse. + return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && + MatchRegexAtHead(regex + 1, str + 1); + } +} + +// Returns true iff regex matches any substring of str. regex must be +// a valid simple regular expression, or the result is undefined. +// +// The algorithm is recursive, but the recursion depth doesn't exceed +// the regex length, so we won't need to worry about running out of +// stack space normally. In rare cases the time complexity can be +// exponential with respect to the regex length + the string length, +// but usually it's must faster (often close to linear). +bool MatchRegexAnywhere(const char* regex, const char* str) { + if (regex == NULL || str == NULL) + return false; + + if (*regex == '^') + return MatchRegexAtHead(regex + 1, str); + + // A successful match can be anywhere in str. + do { + if (MatchRegexAtHead(regex, str)) + return true; + } while (*str++ != '\0'); + return false; +} + +// Implements the RE class. + +RE::~RE() { + free(const_cast(pattern_)); + free(const_cast(full_pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = full_pattern_ = NULL; + if (regex != NULL) { + pattern_ = posix::StrDup(regex); + } + + is_valid_ = ValidateRegex(regex); + if (!is_valid_) { + // No need to calculate the full pattern when the regex is invalid. + return; + } + + const size_t len = strlen(regex); + // Reserves enough bytes to hold the regular expression used for a + // full match: we need space to prepend a '^', append a '$', and + // terminate the string with '\0'. + char* buffer = static_cast(malloc(len + 3)); + full_pattern_ = buffer; + + if (*regex != '^') + *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. + + // We don't use snprintf or strncpy, as they trigger a warning when + // compiled with VC++ 8.0. + memcpy(buffer, regex, len); + buffer += len; + + if (len == 0 || regex[len - 1] != '$') + *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. + + *buffer = '\0'; +} + +#endif // GTEST_USES_POSIX_RE + +const char kUnknownFile[] = "unknown file"; + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { + const char* const file_name = file == NULL ? kUnknownFile : file; + + if (line < 0) { + return String::Format("%s:", file_name).c_str(); + } +#ifdef _MSC_VER + return String::Format("%s(%d):", file_name, line).c_str(); +#else + return String::Format("%s:%d:", file_name, line).c_str(); +#endif // _MSC_VER +} + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +// Note that FormatCompilerIndependentFileLocation() does NOT append colon +// to the file location it produces, unlike FormatFileLocation(). +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( + const char* file, int line) { + const char* const file_name = file == NULL ? kUnknownFile : file; + + if (line < 0) + return file_name; + else + return String::Format("%s:%d", file_name, line).c_str(); +} + + +GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) + : severity_(severity) { + const char* const marker = + severity == GTEST_INFO ? "[ INFO ]" : + severity == GTEST_WARNING ? "[WARNING]" : + severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; + GetStream() << ::std::endl << marker << " " + << FormatFileLocation(file, line).c_str() << ": "; +} + +// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. +GTestLog::~GTestLog() { + GetStream() << ::std::endl; + if (severity_ == GTEST_FATAL) { + fflush(stderr); + posix::Abort(); + } +} +// Disable Microsoft deprecation warnings for POSIX functions called from +// this class (creat, dup, dup2, and close) +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4996) +#endif // _MSC_VER + +#if GTEST_HAS_STREAM_REDIRECTION + +// Object that captures an output stream (stdout/stderr). +class CapturedStream { + public: + // The ctor redirects the stream to a temporary file. + CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { + +# if GTEST_OS_WINDOWS + char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT + char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT + + ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); + const UINT success = ::GetTempFileNameA(temp_dir_path, + "gtest_redir", + 0, // Generate unique file name. + temp_file_path); + GTEST_CHECK_(success != 0) + << "Unable to create a temporary file in " << temp_dir_path; + const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); + GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " + << temp_file_path; + filename_ = temp_file_path; +# else + // There's no guarantee that a test has write access to the + // current directory, so we create the temporary file in the /tmp + // directory instead. + char name_template[] = "/tmp/captured_stream.XXXXXX"; + const int captured_fd = mkstemp(name_template); + filename_ = name_template; +# endif // GTEST_OS_WINDOWS + fflush(NULL); + dup2(captured_fd, fd_); + close(captured_fd); + } + + ~CapturedStream() { + remove(filename_.c_str()); + } + + String GetCapturedString() { + if (uncaptured_fd_ != -1) { + // Restores the original stream. + fflush(NULL); + dup2(uncaptured_fd_, fd_); + close(uncaptured_fd_); + uncaptured_fd_ = -1; + } + + FILE* const file = posix::FOpen(filename_.c_str(), "r"); + const String content = ReadEntireFile(file); + posix::FClose(file); + return content; + } + + private: + // Reads the entire content of a file as a String. + static String ReadEntireFile(FILE* file); + + // Returns the size (in bytes) of a file. + static size_t GetFileSize(FILE* file); + + const int fd_; // A stream to capture. + int uncaptured_fd_; + // Name of the temporary file holding the stderr output. + ::std::string filename_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); +}; + +// Returns the size (in bytes) of a file. +size_t CapturedStream::GetFileSize(FILE* file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); +} + +// Reads the entire content of a file as a string. +String CapturedStream::ReadEntireFile(FILE* file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const String content(buffer, bytes_read); + delete[] buffer; + + return content; +} + +# ifdef _MSC_VER +# pragma warning(pop) +# endif // _MSC_VER + +static CapturedStream* g_captured_stderr = NULL; +static CapturedStream* g_captured_stdout = NULL; + +// Starts capturing an output stream (stdout/stderr). +void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { + if (*stream != NULL) { + GTEST_LOG_(FATAL) << "Only one " << stream_name + << " capturer can exist at a time."; + } + *stream = new CapturedStream(fd); +} + +// Stops capturing the output stream and returns the captured string. +String GetCapturedStream(CapturedStream** captured_stream) { + const String content = (*captured_stream)->GetCapturedString(); + + delete *captured_stream; + *captured_stream = NULL; + + return content; +} + +// Starts capturing stdout. +void CaptureStdout() { + CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); +} + +// Starts capturing stderr. +void CaptureStderr() { + CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); +} + +// Stops capturing stdout and returns the captured string. +String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } + +// Stops capturing stderr and returns the captured string. +String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } + +#endif // GTEST_HAS_STREAM_REDIRECTION + +#if GTEST_HAS_DEATH_TEST + +// A copy of all command line arguments. Set by InitGoogleTest(). +::std::vector g_argvs; + +// Returns the command line as a vector of strings. +const ::std::vector& GetArgvs() { return g_argvs; } + +#endif // GTEST_HAS_DEATH_TEST + +#if GTEST_OS_WINDOWS_MOBILE +namespace posix { +void Abort() { + DebugBreak(); + TerminateProcess(GetCurrentProcess(), 1); +} +} // namespace posix +#endif // GTEST_OS_WINDOWS_MOBILE + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "GTEST_FOO" in the open-source version. +static String FlagToEnvVar(const char* flag) { + const String full_flag = + (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); + + Message env_var; + for (size_t i = 0; i != full_flag.length(); i++) { + env_var << ToUpper(full_flag.c_str()[i]); + } + + return env_var.GetString(); +} + +// Parses 'str' for a 32-bit signed integer. If successful, writes +// the result to *value and returns true; otherwise leaves *value +// unchanged and returns false. +bool ParseInt32(const Message& src_text, const char* str, Int32* value) { + // Parses the environment variable as a decimal integer. + char* end = NULL; + const long long_value = strtol(str, &end, 10); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value \"" << str << "\".\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + // Is the parsed value in the range of an Int32? + const Int32 result = static_cast(long_value); + if (long_value == LONG_MAX || long_value == LONG_MIN || + // The parsed value overflows as a long. (strtol() returns + // LONG_MAX or LONG_MIN when the input overflows.) + result != long_value + // The parsed value overflows as an Int32. + ) { + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value " << str << ", which overflows.\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + *value = result; + return true; +} + +// Reads and returns the Boolean environment variable corresponding to +// the given flag; if it's not set, returns default_value. +// +// The value is considered true iff it's not "0". +bool BoolFromGTestEnv(const char* flag, bool default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + return string_value == NULL ? + default_value : strcmp(string_value, "0") != 0; +} + +// Reads and returns a 32-bit integer stored in the environment +// variable corresponding to the given flag; if it isn't set or +// doesn't represent a valid 32-bit integer, returns default_value. +Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + if (string_value == NULL) { + // The environment variable is not set. + return default_value; + } + + Int32 result = default_value; + if (!ParseInt32(Message() << "Environment variable " << env_var, + string_value, &result)) { + printf("The default value %s is used.\n", + (Message() << default_value).GetString().c_str()); + fflush(stdout); + return default_value; + } + + return result; +} + +// Reads and returns the string environment variable corresponding to +// the given flag; if it's not set, returns default_value. +const char* StringFromGTestEnv(const char* flag, const char* default_value) { + const String env_var = FlagToEnvVar(flag); + const char* const value = posix::GetEnv(env_var.c_str()); + return value == NULL ? default_value : value; +} + +} // namespace internal +} // namespace testing +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// It uses the << operator when possible, and prints the bytes in the +// object otherwise. A user can override its behavior for a class +// type Foo by defining either operator<<(::std::ostream&, const Foo&) +// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that +// defines Foo. + +#include +#include +#include // NOLINT +#include + +namespace testing { + +namespace { + +using ::std::ostream; + +#if GTEST_OS_WINDOWS_MOBILE // Windows CE does not define _snprintf_s. +# define snprintf _snprintf +#elif _MSC_VER >= 1400 // VC 8.0 and later deprecate snprintf and _snprintf. +# define snprintf _snprintf_s +#elif _MSC_VER +# define snprintf _snprintf +#endif // GTEST_OS_WINDOWS_MOBILE + +// Prints a segment of bytes in the given object. +void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, + size_t count, ostream* os) { + char text[5] = ""; + for (size_t i = 0; i != count; i++) { + const size_t j = start + i; + if (i != 0) { + // Organizes the bytes into groups of 2 for easy parsing by + // human. + if ((j % 2) == 0) + *os << ' '; + else + *os << '-'; + } + snprintf(text, sizeof(text), "%02X", obj_bytes[j]); + *os << text; + } +} + +// Prints the bytes in the given value to the given ostream. +void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, + ostream* os) { + // Tells the user how big the object is. + *os << count << "-byte object <"; + + const size_t kThreshold = 132; + const size_t kChunkSize = 64; + // If the object size is bigger than kThreshold, we'll have to omit + // some details by printing only the first and the last kChunkSize + // bytes. + // TODO(wan): let the user control the threshold using a flag. + if (count < kThreshold) { + PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); + } else { + PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); + *os << " ... "; + // Rounds up to 2-byte boundary. + const size_t resume_pos = (count - kChunkSize + 1)/2*2; + PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); + } + *os << ">"; +} + +} // namespace + +namespace internal2 { + +// Delegates to PrintBytesInObjectToImpl() to print the bytes in the +// given object. The delegation simplifies the implementation, which +// uses the << operator and thus is easier done outside of the +// ::testing::internal namespace, which contains a << operator that +// sometimes conflicts with the one in STL. +void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, + ostream* os) { + PrintBytesInObjectToImpl(obj_bytes, count, os); +} + +} // namespace internal2 + +namespace internal { + +// Depending on the value of a char (or wchar_t), we print it in one +// of three formats: +// - as is if it's a printable ASCII (e.g. 'a', '2', ' '), +// - as a hexidecimal escape sequence (e.g. '\x7F'), or +// - as a special escape sequence (e.g. '\r', '\n'). +enum CharFormat { + kAsIs, + kHexEscape, + kSpecialEscape +}; + +// Returns true if c is a printable ASCII character. We test the +// value of c directly instead of calling isprint(), which is buggy on +// Windows Mobile. +inline bool IsPrintableAscii(wchar_t c) { + return 0x20 <= c && c <= 0x7E; +} + +// Prints a wide or narrow char c as a character literal without the +// quotes, escaping it when necessary; returns how c was formatted. +// The template argument UnsignedChar is the unsigned version of Char, +// which is the type of c. +template +static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { + switch (static_cast(c)) { + case L'\0': + *os << "\\0"; + break; + case L'\'': + *os << "\\'"; + break; + case L'\\': + *os << "\\\\"; + break; + case L'\a': + *os << "\\a"; + break; + case L'\b': + *os << "\\b"; + break; + case L'\f': + *os << "\\f"; + break; + case L'\n': + *os << "\\n"; + break; + case L'\r': + *os << "\\r"; + break; + case L'\t': + *os << "\\t"; + break; + case L'\v': + *os << "\\v"; + break; + default: + if (IsPrintableAscii(c)) { + *os << static_cast(c); + return kAsIs; + } else { + *os << String::Format("\\x%X", static_cast(c)); + return kHexEscape; + } + } + return kSpecialEscape; +} + +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsWideStringLiteralTo(wchar_t c, ostream* os) { + switch (c) { + case L'\'': + *os << "'"; + return kAsIs; + case L'"': + *os << "\\\""; + return kSpecialEscape; + default: + return PrintAsCharLiteralTo(c, os); + } +} + +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsNarrowStringLiteralTo(char c, ostream* os) { + return PrintAsWideStringLiteralTo(static_cast(c), os); +} + +// Prints a wide or narrow character c and its code. '\0' is printed +// as "'\\0'", other unprintable characters are also properly escaped +// using the standard C++ escape sequence. The template argument +// UnsignedChar is the unsigned version of Char, which is the type of c. +template +void PrintCharAndCodeTo(Char c, ostream* os) { + // First, print c as a literal in the most readable form we can find. + *os << ((sizeof(c) > 1) ? "L'" : "'"); + const CharFormat format = PrintAsCharLiteralTo(c, os); + *os << "'"; + + // To aid user debugging, we also print c's code in decimal, unless + // it's 0 (in which case c was printed as '\\0', making the code + // obvious). + if (c == 0) + return; + *os << " (" << String::Format("%d", c).c_str(); + + // For more convenience, we print c's code again in hexidecimal, + // unless c was already printed in the form '\x##' or the code is in + // [1, 9]. + if (format == kHexEscape || (1 <= c && c <= 9)) { + // Do nothing. + } else { + *os << String::Format(", 0x%X", + static_cast(c)).c_str(); + } + *os << ")"; +} + +void PrintTo(unsigned char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} +void PrintTo(signed char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} + +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its code. L'\0' is printed as "L'\\0'". +void PrintTo(wchar_t wc, ostream* os) { + PrintCharAndCodeTo(wc, os); +} + +// Prints the given array of characters to the ostream. +// The array starts at *begin, the length is len, it may include '\0' characters +// and may not be null-terminated. +static void PrintCharsAsStringTo(const char* begin, size_t len, ostream* os) { + *os << "\""; + bool is_previous_hex = false; + for (size_t index = 0; index < len; ++index) { + const char cur = begin[index]; + if (is_previous_hex && IsXDigit(cur)) { + // Previous character is of '\x..' form and this character can be + // interpreted as another hexadecimal digit in its number. Break string to + // disambiguate. + *os << "\" \""; + } + is_previous_hex = PrintAsNarrowStringLiteralTo(cur, os) == kHexEscape; + } + *os << "\""; +} + +// Prints a (const) char array of 'len' elements, starting at address 'begin'. +void UniversalPrintArray(const char* begin, size_t len, ostream* os) { + PrintCharsAsStringTo(begin, len, os); +} + +// Prints the given array of wide characters to the ostream. +// The array starts at *begin, the length is len, it may include L'\0' +// characters and may not be null-terminated. +static void PrintWideCharsAsStringTo(const wchar_t* begin, size_t len, + ostream* os) { + *os << "L\""; + bool is_previous_hex = false; + for (size_t index = 0; index < len; ++index) { + const wchar_t cur = begin[index]; + if (is_previous_hex && isascii(cur) && IsXDigit(static_cast(cur))) { + // Previous character is of '\x..' form and this character can be + // interpreted as another hexadecimal digit in its number. Break string to + // disambiguate. + *os << "\" L\""; + } + is_previous_hex = PrintAsWideStringLiteralTo(cur, os) == kHexEscape; + } + *os << "\""; +} + +// Prints the given C string to the ostream. +void PrintTo(const char* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintCharsAsStringTo(s, strlen(s), os); + } +} + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Prints the given wide C string to the ostream. +void PrintTo(const wchar_t* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintWideCharsAsStringTo(s, wcslen(s), os); + } +} +#endif // wchar_t is native + +// Prints a ::string object. +#if GTEST_HAS_GLOBAL_STRING +void PrintStringTo(const ::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +void PrintStringTo(const ::std::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} + +// Prints a ::wstring object. +#if GTEST_HAS_GLOBAL_WSTRING +void PrintWideStringTo(const ::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +void PrintWideStringTo(const ::std::wstring& s, ostream* os) { + PrintWideCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_STD_WSTRING + +} // namespace internal + +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// +// The Google C++ Testing Framework (Google Test) + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +using internal::GetUnitTestImpl; + +// Gets the summary of the failure message by omitting the stack trace +// in it. +internal::String TestPartResult::ExtractSummary(const char* message) { + const char* const stack_trace = strstr(message, internal::kStackTraceMarker); + return stack_trace == NULL ? internal::String(message) : + internal::String(message, stack_trace - message); +} + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { + return os + << result.file_name() << ":" << result.line_number() << ": " + << (result.type() == TestPartResult::kSuccess ? "Success" : + result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : + "Non-fatal failure") << ":\n" + << result.message() << std::endl; +} + +// Appends a TestPartResult to the array. +void TestPartResultArray::Append(const TestPartResult& result) { + array_.push_back(result); +} + +// Returns the TestPartResult at the given index (0-based). +const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { + if (index < 0 || index >= size()) { + printf("\nInvalid index (%d) into TestPartResultArray.\n", index); + internal::posix::Abort(); + } + + return array_[index]; +} + +// Returns the number of TestPartResult objects in the array. +int TestPartResultArray::size() const { + return static_cast(array_.size()); +} + +namespace internal { + +HasNewFatalFailureHelper::HasNewFatalFailureHelper() + : has_new_fatal_failure_(false), + original_reporter_(GetUnitTestImpl()-> + GetTestPartResultReporterForCurrentThread()) { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); +} + +HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( + original_reporter_); +} + +void HasNewFatalFailureHelper::ReportTestPartResult( + const TestPartResult& result) { + if (result.fatally_failed()) + has_new_fatal_failure_ = true; + original_reporter_->ReportTestPartResult(result); +} + +} // namespace internal + +} // namespace testing +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + + +namespace testing { +namespace internal { + +#if GTEST_HAS_TYPED_TEST_P + +// Skips to the first non-space char in str. Returns an empty string if str +// contains only whitespace characters. +static const char* SkipSpaces(const char* str) { + while (IsSpace(*str)) + str++; + return str; +} + +// Verifies that registered_tests match the test names in +// defined_test_names_; returns registered_tests if successful, or +// aborts the program otherwise. +const char* TypedTestCasePState::VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests) { + typedef ::std::set::const_iterator DefinedTestIter; + registered_ = true; + + // Skip initial whitespace in registered_tests since some + // preprocessors prefix stringizied literals with whitespace. + registered_tests = SkipSpaces(registered_tests); + + Message errors; + ::std::set tests; + for (const char* names = registered_tests; names != NULL; + names = SkipComma(names)) { + const String name = GetPrefixUntilComma(names); + if (tests.count(name) != 0) { + errors << "Test " << name << " is listed more than once.\n"; + continue; + } + + bool found = false; + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (name == *it) { + found = true; + break; + } + } + + if (found) { + tests.insert(name); + } else { + errors << "No test named " << name + << " can be found in this test case.\n"; + } + } + + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (tests.count(*it) == 0) { + errors << "You forgot to list test " << *it << ".\n"; + } + } + + const String& errors_str = errors.GetString(); + if (errors_str != "") { + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors_str.c_str()); + fflush(stderr); + posix::Abort(); + } + + return registered_tests; +} + +#endif // GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/gtest/gtest_main.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/gtest/gtest_main.cc new file mode 100644 index 00000000000..a09bbe0c6c5 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/gtest/gtest_main.cc @@ -0,0 +1,39 @@ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "gtest/gtest.h" + +GTEST_API_ int main(int argc, char **argv) { + std::cout << "Running main() from gtest_main.cc\n"; + + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/gtest/include/gtest/gtest.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/gtest/include/gtest/gtest.h new file mode 100644 index 00000000000..b467822e022 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/gtest/include/gtest/gtest.h @@ -0,0 +1,19541 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for Google Test. It should be +// included by any test program that uses Google Test. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! +// +// Acknowledgment: Google Test borrowed the idea of automatic test +// registration from Barthelemy Dagenais' (barthelemy@prologique.com) +// easyUnit framework. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_H_ + +#include +#include + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares functions and macros used internally by +// Google Test. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan) +// +// Low-level types and utilities for porting Google Test to various +// platforms. They are subject to change without notice. DO NOT USE +// THEM IN USER CODE. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +// The user can define the following macros in the build script to +// control Google Test's behavior. If the user doesn't define a macro +// in this list, Google Test will define it. +// +// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) +// is/isn't available. +// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions +// are enabled. +// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::string, which is different to std::string). +// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::wstring, which is different to std::wstring). +// GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular +// expressions are/aren't available. +// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that +// is/isn't available. +// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't +// enabled. +// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that +// std::wstring does/doesn't work (Google Test can +// be used where std::wstring is unavailable). +// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple +// is/isn't available. +// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the +// compiler supports Microsoft's "Structured +// Exception Handling". +// GTEST_HAS_STREAM_REDIRECTION +// - Define it to 1/0 to indicate whether the +// platform supports I/O stream redirection using +// dup() and dup2(). +// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google +// Test's own tr1 tuple implementation should be +// used. Unused when the user sets +// GTEST_HAS_TR1_TUPLE to 0. +// GTEST_LINKED_AS_SHARED_LIBRARY +// - Define to 1 when compiling tests that use +// Google Test as a shared library (known as +// DLL on Windows). +// GTEST_CREATE_SHARED_LIBRARY +// - Define to 1 when compiling Google Test itself +// as a shared library. + +// This header defines the following utilities: +// +// Macros indicating the current platform (defined to 1 if compiled on +// the given platform; otherwise undefined): +// GTEST_OS_AIX - IBM AIX +// GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_HPUX - HP-UX +// GTEST_OS_LINUX - Linux +// GTEST_OS_LINUX_ANDROID - Google Android +// GTEST_OS_MAC - Mac OS X +// GTEST_OS_NACL - Google Native Client (NaCl) +// GTEST_OS_SOLARIS - Sun Solaris +// GTEST_OS_SYMBIAN - Symbian +// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) +// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop +// GTEST_OS_WINDOWS_MINGW - MinGW +// GTEST_OS_WINDOWS_MOBILE - Windows Mobile +// GTEST_OS_ZOS - z/OS +// +// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the +// most stable support. Since core members of the Google Test project +// don't have access to other platforms, support for them may be less +// stable. If you notice any problems on your platform, please notify +// googletestframework@googlegroups.com (patches for fixing them are +// even more welcome!). +// +// Note that it is possible that none of the GTEST_OS_* macros are defined. +// +// Macros indicating available Google Test features (defined to 1 if +// the corresponding feature is supported; otherwise undefined): +// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized +// tests) +// GTEST_HAS_DEATH_TEST - death tests +// GTEST_HAS_PARAM_TEST - value-parameterized tests +// GTEST_HAS_TYPED_TEST - typed tests +// GTEST_HAS_TYPED_TEST_P - type-parameterized tests +// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with +// GTEST_HAS_POSIX_RE (see above) which users can +// define themselves. +// GTEST_USES_SIMPLE_RE - our own simple regex is used; +// the above two are mutually exclusive. +// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). +// +// Macros for basic C++ coding: +// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. +// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a +// variable don't have to be used. +// GTEST_DISALLOW_ASSIGN_ - disables operator=. +// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. +// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. +// +// Synchronization: +// Mutex, MutexLock, ThreadLocal, GetThreadCount() +// - synchronization primitives. +// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above +// synchronization primitives have real implementations +// and Google Test is thread-safe; or 0 otherwise. +// +// Template meta programming: +// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. +// IteratorTraits - partial implementation of std::iterator_traits, which +// is not available in libCstd when compiled with Sun C++. +// +// Smart pointers: +// scoped_ptr - as in TR2. +// +// Regular expressions: +// RE - a simple regular expression class using the POSIX +// Extended Regular Expression syntax on UNIX-like +// platforms, or a reduced regular exception syntax on +// other platforms, including Windows. +// +// Logging: +// GTEST_LOG_() - logs messages at the specified severity level. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. +// +// Stdout and stderr capturing: +// CaptureStdout() - starts capturing stdout. +// GetCapturedStdout() - stops capturing stdout and returns the captured +// string. +// CaptureStderr() - starts capturing stderr. +// GetCapturedStderr() - stops capturing stderr and returns the captured +// string. +// +// Integer types: +// TypeWithSize - maps an integer to a int type. +// Int32, UInt32, Int64, UInt64, TimeInMillis +// - integers of known sizes. +// BiggestInt - the biggest signed integer type. +// +// Command-line utilities: +// GTEST_FLAG() - references a flag. +// GTEST_DECLARE_*() - declares a flag. +// GTEST_DEFINE_*() - defines a flag. +// GetArgvs() - returns the command line as a vector of strings. +// +// Environment variable utilities: +// GetEnv() - gets the value of an environment variable. +// BoolFromGTestEnv() - parses a bool environment variable. +// Int32FromGTestEnv() - parses an Int32 environment variable. +// StringFromGTestEnv() - parses a string environment variable. + +#include // for isspace, etc +#include // for ptrdiff_t +#include +#include +#include +#ifndef _WIN32_WCE +# include +# include +#endif // !_WIN32_WCE + +#include // NOLINT +#include // NOLINT +#include // NOLINT + +#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" +#define GTEST_FLAG_PREFIX_ "gtest_" +#define GTEST_FLAG_PREFIX_DASH_ "gtest-" +#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +#define GTEST_NAME_ "Google Test" +#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" + +// Determines the version of gcc that is used to compile this. +#ifdef __GNUC__ +// 40302 means version 4.3.2. +# define GTEST_GCC_VER_ \ + (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) +#endif // __GNUC__ + +// Determines the platform on which Google Test is compiled. +#ifdef __CYGWIN__ +# define GTEST_OS_CYGWIN 1 +#elif defined __SYMBIAN32__ +# define GTEST_OS_SYMBIAN 1 +#elif defined _WIN32 +# define GTEST_OS_WINDOWS 1 +# ifdef _WIN32_WCE +# define GTEST_OS_WINDOWS_MOBILE 1 +# elif defined(__MINGW__) || defined(__MINGW32__) +# define GTEST_OS_WINDOWS_MINGW 1 +# else +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif // _WIN32_WCE +#elif defined __APPLE__ +# define GTEST_OS_MAC 1 +#elif defined __linux__ +# define GTEST_OS_LINUX 1 +# ifdef ANDROID +# define GTEST_OS_LINUX_ANDROID 1 +# endif // ANDROID +#elif defined __MVS__ +# define GTEST_OS_ZOS 1 +#elif defined(__sun) && defined(__SVR4) +# define GTEST_OS_SOLARIS 1 +#elif defined(_AIX) +# define GTEST_OS_AIX 1 +#elif defined(__hpux) +# define GTEST_OS_HPUX 1 +#elif defined __native_client__ +# define GTEST_OS_NACL 1 +#endif // __CYGWIN__ + +// Brings in definitions for functions used in the testing::internal::posix +// namespace (read, write, close, chdir, isatty, stat). We do not currently +// use them on Windows Mobile. +#if !GTEST_OS_WINDOWS +// This assumes that non-Windows OSes provide unistd.h. For OSes where this +// is not the case, we need to include headers that provide the functions +// mentioned above. +# include +# if !GTEST_OS_NACL +// TODO(vladl@google.com): Remove this condition when Native Client SDK adds +// strings.h (tracked in +// http://code.google.com/p/nativeclient/issues/detail?id=1175). +# include // Native Client doesn't provide strings.h. +# endif +#elif !GTEST_OS_WINDOWS_MOBILE +# include +# include +#endif + +// Defines this to true iff Google Test can use POSIX regular expressions. +#ifndef GTEST_HAS_POSIX_RE +# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) +#endif + +#if GTEST_HAS_POSIX_RE + +// On some platforms, needs someone to define size_t, and +// won't compile otherwise. We can #include it here as we already +// included , which is guaranteed to define size_t through +// . +# include // NOLINT + +# define GTEST_USES_POSIX_RE 1 + +#elif GTEST_OS_WINDOWS + +// is not available on Windows. Use our own simple regex +// implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#else + +// may not be available on this platform. Use our own +// simple regex implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#endif // GTEST_HAS_POSIX_RE + +#ifndef GTEST_HAS_EXCEPTIONS +// The user didn't tell us whether exceptions are enabled, so we need +// to figure it out. +# if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS +// macro to enable exceptions, so we'll do the same. +// Assumes that exceptions are enabled by default. +# ifndef _HAS_EXCEPTIONS +# define _HAS_EXCEPTIONS 1 +# endif // _HAS_EXCEPTIONS +# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS +# elif defined(__GNUC__) && __EXCEPTIONS +// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__SUNPRO_CC) +// Sun Pro CC supports exceptions. However, there is no compile-time way of +// detecting whether they are enabled or not. Therefore, we assume that +// they are enabled unless the user tells us otherwise. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__IBMCPP__) && __EXCEPTIONS +// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__HP_aCC) +// Exception handling is in effect by default in HP aCC compiler. It has to +// be turned of by +noeh compiler option if desired. +# define GTEST_HAS_EXCEPTIONS 1 +# else +// For other compilers, we assume exceptions are disabled to be +// conservative. +# define GTEST_HAS_EXCEPTIONS 0 +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +#endif // GTEST_HAS_EXCEPTIONS + +#if !defined(GTEST_HAS_STD_STRING) +// Even though we don't use this macro any longer, we keep it in case +// some clients still depend on it. +# define GTEST_HAS_STD_STRING 1 +#elif !GTEST_HAS_STD_STRING +// The user told us that ::std::string isn't available. +# error "Google Test cannot be used where ::std::string isn't available." +#endif // !defined(GTEST_HAS_STD_STRING) + +#ifndef GTEST_HAS_GLOBAL_STRING +// The user didn't tell us whether ::string is available, so we need +// to figure it out. + +# define GTEST_HAS_GLOBAL_STRING 0 + +#endif // GTEST_HAS_GLOBAL_STRING + +#ifndef GTEST_HAS_STD_WSTRING +// The user didn't tell us whether ::std::wstring is available, so we need +// to figure it out. +// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring +// is available. + +// Cygwin 1.7 and below doesn't support ::std::wstring. +// Solaris' libc++ doesn't support it either. Android has +// no support for it at least as recent as Froyo (2.2). +# define GTEST_HAS_STD_WSTRING \ + (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) + +#endif // GTEST_HAS_STD_WSTRING + +#ifndef GTEST_HAS_GLOBAL_WSTRING +// The user didn't tell us whether ::wstring is available, so we need +// to figure it out. +# define GTEST_HAS_GLOBAL_WSTRING \ + (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) +#endif // GTEST_HAS_GLOBAL_WSTRING + +// Determines whether RTTI is available. +#ifndef GTEST_HAS_RTTI +// The user didn't tell us whether RTTI is enabled, so we need to +// figure it out. + +# ifdef _MSC_VER + +# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. +# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) + +# ifdef __GXX_RTTI +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif // __GXX_RTTI + +// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if +// both the typeid and dynamic_cast features are present. +# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) + +# ifdef __RTTI_ALL__ +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +# else + +// For all other compilers, we assume RTTI is enabled. +# define GTEST_HAS_RTTI 1 + +# endif // _MSC_VER + +#endif // GTEST_HAS_RTTI + +// It's this header's responsibility to #include when RTTI +// is enabled. +#if GTEST_HAS_RTTI +# include +#endif + +// Determines whether Google Test can use the pthreads library. +#ifndef GTEST_HAS_PTHREAD +// The user didn't tell us explicitly, so we assume pthreads support is +// available on Linux and Mac. +// +// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 +// to your compiler flags. +# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX) +#endif // GTEST_HAS_PTHREAD + +#if GTEST_HAS_PTHREAD +// gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is +// true. +# include // NOLINT + +// For timespec and nanosleep, used below. +# include // NOLINT +#endif + +// Determines whether Google Test can use tr1/tuple. You can define +// this macro to 0 to prevent Google Test from using tuple (any +// feature depending on tuple with be disabled in this mode). +#ifndef GTEST_HAS_TR1_TUPLE +// The user didn't tell us not to do it, so we assume it's OK. +# define GTEST_HAS_TR1_TUPLE 1 +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether Google Test's own tr1 tuple implementation +// should be used. +#ifndef GTEST_USE_OWN_TR1_TUPLE +// The user didn't tell us, so we need to figure it out. + +// We use our own TR1 tuple if we aren't sure the user has an +// implementation of it already. At this time, GCC 4.0.0+ and MSVC +// 2010 are the only mainstream compilers that come with a TR1 tuple +// implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by +// defining __GNUC__ and friends, but cannot compile GCC's tuple +// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB +// Feature Pack download, which we cannot assume the user has. +# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \ + || _MSC_VER >= 1600 +# define GTEST_USE_OWN_TR1_TUPLE 0 +# else +# define GTEST_USE_OWN_TR1_TUPLE 1 +# endif + +#endif // GTEST_USE_OWN_TR1_TUPLE + +// To avoid conditional compilation everywhere, we make it +// gtest-port.h's responsibility to #include the header implementing +// tr1/tuple. +#if GTEST_HAS_TR1_TUPLE + +# if GTEST_USE_OWN_TR1_TUPLE +// This file was GENERATED by a script. DO NOT EDIT BY HAND!!! + +// Copyright 2009 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Implements a subset of TR1 tuple needed by Google Test and Google Mock. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ + +#include // For ::std::pair. + +// The compiler used in Symbian has a bug that prevents us from declaring the +// tuple template as a friend (it complains that tuple is redefined). This +// hack bypasses the bug by declaring the members that should otherwise be +// private as public. +// Sun Studio versions < 12 also have the above bug. +#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: +#else +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ + template friend class tuple; \ + private: +#endif + +// GTEST_n_TUPLE_(T) is the type of an n-tuple. +#define GTEST_0_TUPLE_(T) tuple<> +#define GTEST_1_TUPLE_(T) tuple +#define GTEST_2_TUPLE_(T) tuple +#define GTEST_3_TUPLE_(T) tuple +#define GTEST_4_TUPLE_(T) tuple +#define GTEST_5_TUPLE_(T) tuple +#define GTEST_6_TUPLE_(T) tuple +#define GTEST_7_TUPLE_(T) tuple +#define GTEST_8_TUPLE_(T) tuple +#define GTEST_9_TUPLE_(T) tuple +#define GTEST_10_TUPLE_(T) tuple + +// GTEST_n_TYPENAMES_(T) declares a list of n typenames. +#define GTEST_0_TYPENAMES_(T) +#define GTEST_1_TYPENAMES_(T) typename T##0 +#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 +#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 +#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3 +#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4 +#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5 +#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6 +#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 +#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8 +#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8, typename T##9 + +// In theory, defining stuff in the ::std namespace is undefined +// behavior. We can do this as we are playing the role of a standard +// library vendor. +namespace std { +namespace tr1 { + +template +class tuple; + +// Anything in namespace gtest_internal is Google Test's INTERNAL +// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. +namespace gtest_internal { + +// ByRef::type is T if T is a reference; otherwise it's const T&. +template +struct ByRef { typedef const T& type; }; // NOLINT +template +struct ByRef { typedef T& type; }; // NOLINT + +// A handy wrapper for ByRef. +#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type + +// AddRef::type is T if T is a reference; otherwise it's T&. This +// is the same as tr1::add_reference::type. +template +struct AddRef { typedef T& type; }; // NOLINT +template +struct AddRef { typedef T& type; }; // NOLINT + +// A handy wrapper for AddRef. +#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type + +// A helper for implementing get(). +template class Get; + +// A helper for implementing tuple_element. kIndexValid is true +// iff k < the number of fields in tuple type T. +template +struct TupleElement; + +template +struct TupleElement { typedef T0 type; }; + +template +struct TupleElement { typedef T1 type; }; + +template +struct TupleElement { typedef T2 type; }; + +template +struct TupleElement { typedef T3 type; }; + +template +struct TupleElement { typedef T4 type; }; + +template +struct TupleElement { typedef T5 type; }; + +template +struct TupleElement { typedef T6 type; }; + +template +struct TupleElement { typedef T7 type; }; + +template +struct TupleElement { typedef T8 type; }; + +template +struct TupleElement { typedef T9 type; }; + +} // namespace gtest_internal + +template <> +class tuple<> { + public: + tuple() {} + tuple(const tuple& /* t */) {} + tuple& operator=(const tuple& /* t */) { return *this; } +}; + +template +class GTEST_1_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} + + tuple(const tuple& t) : f0_(t.f0_) {} + + template + tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_1_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { + f0_ = t.f0_; + return *this; + } + + T0 f0_; +}; + +template +class GTEST_2_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), + f1_(f1) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} + + template + tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} + template + tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_2_TUPLE_(U)& t) { + return CopyFrom(t); + } + template + tuple& operator=(const ::std::pair& p) { + f0_ = p.first; + f1_ = p.second; + return *this; + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + return *this; + } + + T0 f0_; + T1 f1_; +}; + +template +class GTEST_3_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + template + tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_3_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; +}; + +template +class GTEST_4_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} + + template + tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_4_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; +}; + +template +class GTEST_5_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, + GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_) {} + + template + tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_5_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; +}; + +template +class GTEST_6_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_) {} + + template + tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_6_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; +}; + +template +class GTEST_7_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + template + tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_7_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; +}; + +template +class GTEST_8_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, + GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + template + tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_8_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; +}; + +template +class GTEST_9_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + template + tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_9_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; +}; + +template +class tuple { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), + f9_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} + + template + tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), + f9_(t.f9_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_10_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + f9_ = t.f9_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; + T9 f9_; +}; + +// 6.1.3.2 Tuple creation functions. + +// Known limitations: we don't support passing an +// std::tr1::reference_wrapper to make_tuple(). And we don't +// implement tie(). + +inline tuple<> make_tuple() { return tuple<>(); } + +template +inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { + return GTEST_1_TUPLE_(T)(f0); +} + +template +inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { + return GTEST_2_TUPLE_(T)(f0, f1); +} + +template +inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { + return GTEST_3_TUPLE_(T)(f0, f1, f2); +} + +template +inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3) { + return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); +} + +template +inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4) { + return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); +} + +template +inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5) { + return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); +} + +template +inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6) { + return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); +} + +template +inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { + return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); +} + +template +inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8) { + return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); +} + +template +inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8, const T9& f9) { + return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); +} + +// 6.1.3.3 Tuple helper classes. + +template struct tuple_size; + +template +struct tuple_size { static const int value = 0; }; + +template +struct tuple_size { static const int value = 1; }; + +template +struct tuple_size { static const int value = 2; }; + +template +struct tuple_size { static const int value = 3; }; + +template +struct tuple_size { static const int value = 4; }; + +template +struct tuple_size { static const int value = 5; }; + +template +struct tuple_size { static const int value = 6; }; + +template +struct tuple_size { static const int value = 7; }; + +template +struct tuple_size { static const int value = 8; }; + +template +struct tuple_size { static const int value = 9; }; + +template +struct tuple_size { static const int value = 10; }; + +template +struct tuple_element { + typedef typename gtest_internal::TupleElement< + k < (tuple_size::value), k, Tuple>::type type; +}; + +#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type + +// 6.1.3.4 Element access. + +namespace gtest_internal { + +template <> +class Get<0> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + Field(Tuple& t) { return t.f0_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + ConstField(const Tuple& t) { return t.f0_; } +}; + +template <> +class Get<1> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + Field(Tuple& t) { return t.f1_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + ConstField(const Tuple& t) { return t.f1_; } +}; + +template <> +class Get<2> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + Field(Tuple& t) { return t.f2_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + ConstField(const Tuple& t) { return t.f2_; } +}; + +template <> +class Get<3> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + Field(Tuple& t) { return t.f3_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + ConstField(const Tuple& t) { return t.f3_; } +}; + +template <> +class Get<4> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + Field(Tuple& t) { return t.f4_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + ConstField(const Tuple& t) { return t.f4_; } +}; + +template <> +class Get<5> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + Field(Tuple& t) { return t.f5_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + ConstField(const Tuple& t) { return t.f5_; } +}; + +template <> +class Get<6> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + Field(Tuple& t) { return t.f6_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + ConstField(const Tuple& t) { return t.f6_; } +}; + +template <> +class Get<7> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + Field(Tuple& t) { return t.f7_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + ConstField(const Tuple& t) { return t.f7_; } +}; + +template <> +class Get<8> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + Field(Tuple& t) { return t.f8_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + ConstField(const Tuple& t) { return t.f8_; } +}; + +template <> +class Get<9> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + Field(Tuple& t) { return t.f9_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + ConstField(const Tuple& t) { return t.f9_; } +}; + +} // namespace gtest_internal + +template +GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::Field(t); +} + +template +GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(const GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::ConstField(t); +} + +// 6.1.3.5 Relational operators + +// We only implement == and !=, as we don't have a need for the rest yet. + +namespace gtest_internal { + +// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the +// first k fields of t1 equals the first k fields of t2. +// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if +// k1 != k2. +template +struct SameSizeTuplePrefixComparator; + +template <> +struct SameSizeTuplePrefixComparator<0, 0> { + template + static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { + return true; + } +}; + +template +struct SameSizeTuplePrefixComparator { + template + static bool Eq(const Tuple1& t1, const Tuple2& t2) { + return SameSizeTuplePrefixComparator::Eq(t1, t2) && + ::std::tr1::get(t1) == ::std::tr1::get(t2); + } +}; + +} // namespace gtest_internal + +template +inline bool operator==(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { + return gtest_internal::SameSizeTuplePrefixComparator< + tuple_size::value, + tuple_size::value>::Eq(t, u); +} + +template +inline bool operator!=(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { return !(t == u); } + +// 6.1.4 Pairs. +// Unimplemented. + +} // namespace tr1 +} // namespace std + +#undef GTEST_0_TUPLE_ +#undef GTEST_1_TUPLE_ +#undef GTEST_2_TUPLE_ +#undef GTEST_3_TUPLE_ +#undef GTEST_4_TUPLE_ +#undef GTEST_5_TUPLE_ +#undef GTEST_6_TUPLE_ +#undef GTEST_7_TUPLE_ +#undef GTEST_8_TUPLE_ +#undef GTEST_9_TUPLE_ +#undef GTEST_10_TUPLE_ + +#undef GTEST_0_TYPENAMES_ +#undef GTEST_1_TYPENAMES_ +#undef GTEST_2_TYPENAMES_ +#undef GTEST_3_TYPENAMES_ +#undef GTEST_4_TYPENAMES_ +#undef GTEST_5_TYPENAMES_ +#undef GTEST_6_TYPENAMES_ +#undef GTEST_7_TYPENAMES_ +#undef GTEST_8_TYPENAMES_ +#undef GTEST_9_TYPENAMES_ +#undef GTEST_10_TYPENAMES_ + +#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ +#undef GTEST_BY_REF_ +#undef GTEST_ADD_REF_ +#undef GTEST_TUPLE_ELEMENT_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +# elif GTEST_OS_SYMBIAN + +// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to +// use STLport's tuple implementation, which unfortunately doesn't +// work as the copy of STLport distributed with Symbian is incomplete. +// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to +// use its own tuple implementation. +# ifdef BOOST_HAS_TR1_TUPLE +# undef BOOST_HAS_TR1_TUPLE +# endif // BOOST_HAS_TR1_TUPLE + +// This prevents , which defines +// BOOST_HAS_TR1_TUPLE, from being #included by Boost's . +# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED +# include + +# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) +// GCC 4.0+ implements tr1/tuple in the header. This does +// not conform to the TR1 spec, which requires the header to be . + +# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 +// Until version 4.3.2, gcc has a bug that causes , +// which is #included by , to not compile when RTTI is +// disabled. _TR1_FUNCTIONAL is the header guard for +// . Hence the following #define is a hack to prevent +// from being included. +# define _TR1_FUNCTIONAL 1 +# include +# undef _TR1_FUNCTIONAL // Allows the user to #include + // if he chooses to. +# else +# include // NOLINT +# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 + +# else +// If the compiler is not GCC 4.0+, we assume the user is using a +// spec-conforming TR1 implementation. +# include // NOLINT +# endif // GTEST_USE_OWN_TR1_TUPLE + +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether clone(2) is supported. +// Usually it will only be available on Linux, excluding +// Linux on the Itanium architecture. +// Also see http://linux.die.net/man/2/clone. +#ifndef GTEST_HAS_CLONE +// The user didn't tell us, so we need to figure it out. + +# if GTEST_OS_LINUX && !defined(__ia64__) +# define GTEST_HAS_CLONE 1 +# else +# define GTEST_HAS_CLONE 0 +# endif // GTEST_OS_LINUX && !defined(__ia64__) + +#endif // GTEST_HAS_CLONE + +// Determines whether to support stream redirection. This is used to test +// output correctness and to implement death tests. +#ifndef GTEST_HAS_STREAM_REDIRECTION +// By default, we assume that stream redirection is supported on all +// platforms except known mobile ones. +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN +# define GTEST_HAS_STREAM_REDIRECTION 0 +# else +# define GTEST_HAS_STREAM_REDIRECTION 1 +# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN +#endif // GTEST_HAS_STREAM_REDIRECTION + +// Determines whether to support death tests. +// Google Test does not support death tests for VC 7.1 and earlier as +// abort() in a VC 7.1 application compiled as GUI in debug config +// pops up a dialog window that cannot be suppressed programmatically. +#if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ + GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX) +# define GTEST_HAS_DEATH_TEST 1 +# include // NOLINT +#endif + +// We don't support MSVC 7.1 with exceptions disabled now. Therefore +// all the compilers we care about are adequate for supporting +// value-parameterized tests. +#define GTEST_HAS_PARAM_TEST 1 + +// Determines whether to support type-driven tests. + +// Typed tests need and variadic macros, which GCC, VC++ 8.0, +// Sun Pro CC, IBM Visual Age, and HP aCC support. +#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ + defined(__IBMCPP__) || defined(__HP_aCC) +# define GTEST_HAS_TYPED_TEST 1 +# define GTEST_HAS_TYPED_TEST_P 1 +#endif + +// Determines whether to support Combine(). This only makes sense when +// value-parameterized tests are enabled. The implementation doesn't +// work on Sun Studio since it doesn't understand templated conversion +// operators. +#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) +# define GTEST_HAS_COMBINE 1 +#endif + +// Determines whether the system compiler uses UTF-16 for encoding wide strings. +#define GTEST_WIDE_STRING_USES_UTF16_ \ + (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) + +// Determines whether test results can be streamed to a socket. +#if GTEST_OS_LINUX +# define GTEST_CAN_STREAM_RESULTS_ 1 +#endif + +// Defines some utility macros. + +// The GNU compiler emits a warning if nested "if" statements are followed by +// an "else" statement and braces are not used to explicitly disambiguate the +// "else" binding. This leads to problems with code like: +// +// if (gate) +// ASSERT_*(condition) << "Some message"; +// +// The "switch (0) case 0:" idiom is used to suppress this. +#ifdef __INTEL_COMPILER +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ +#else +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT +#endif + +// Use this annotation at the end of a struct/class definition to +// prevent the compiler from optimizing away instances that are never +// used. This is useful when all interesting logic happens inside the +// c'tor and / or d'tor. Example: +// +// struct Foo { +// Foo() { ... } +// } GTEST_ATTRIBUTE_UNUSED_; +// +// Also use it after a variable or parameter declaration to tell the +// compiler the variable/parameter does not have to be used. +#if defined(__GNUC__) && !defined(COMPILER_ICC) +# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +#else +# define GTEST_ATTRIBUTE_UNUSED_ +#endif + +// A macro to disallow operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_ASSIGN_(type)\ + void operator=(type const &) + +// A macro to disallow copy constructor and operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ + type(type const &);\ + GTEST_DISALLOW_ASSIGN_(type) + +// Tell the compiler to warn about unused return values for functions declared +// with this macro. The macro should be used on function declarations +// following the argument list: +// +// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; +#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) +# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) +#else +# define GTEST_MUST_USE_RESULT_ +#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC + +// Determine whether the compiler supports Microsoft's Structured Exception +// Handling. This is supported by several Windows compilers but generally +// does not exist on any other system. +#ifndef GTEST_HAS_SEH +// The user didn't tell us, so we need to figure it out. + +# if defined(_MSC_VER) || defined(__BORLANDC__) +// These two compilers are known to support SEH. +# define GTEST_HAS_SEH 1 +# else +// Assume no SEH. +# define GTEST_HAS_SEH 0 +# endif + +#endif // GTEST_HAS_SEH + +#ifdef _MSC_VER + +# if GTEST_LINKED_AS_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllimport) +# elif GTEST_CREATE_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllexport) +# endif + +#endif // _MSC_VER + +#ifndef GTEST_API_ +# define GTEST_API_ +#endif + +#ifdef __GNUC__ +// Ask the compiler to never inline a given function. +# define GTEST_NO_INLINE_ __attribute__((noinline)) +#else +# define GTEST_NO_INLINE_ +#endif + +namespace testing { + +class Message; + +namespace internal { + +class String; + +// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +template +struct CompileAssert { +}; + +#define GTEST_COMPILE_ASSERT_(expr, msg) \ + typedef ::testing::internal::CompileAssert<(bool(expr))> \ + msg[bool(expr) ? 1 : -1] + +// Implementation details of GTEST_COMPILE_ASSERT_: +// +// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 +// elements (and thus is invalid) when the expression is false. +// +// - The simpler definition +// +// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] +// +// does not work, as gcc supports variable-length arrays whose sizes +// are determined at run-time (this is gcc's extension and not part +// of the C++ standard). As a result, gcc fails to reject the +// following code with the simple definition: +// +// int foo; +// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is +// // not a compile-time constant. +// +// - By using the type CompileAssert<(bool(expr))>, we ensures that +// expr is a compile-time constant. (Template arguments must be +// determined at compile-time.) +// +// - The outter parentheses in CompileAssert<(bool(expr))> are necessary +// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written +// +// CompileAssert +// +// instead, these compilers will refuse to compile +// +// GTEST_COMPILE_ASSERT_(5 > 0, some_message); +// +// (They seem to think the ">" in "5 > 0" marks the end of the +// template argument list.) +// +// - The array size is (bool(expr) ? 1 : -1), instead of simply +// +// ((expr) ? 1 : -1). +// +// This is to avoid running into a bug in MS VC 7.1, which +// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. + +// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. +// +// This template is declared, but intentionally undefined. +template +struct StaticAssertTypeEqHelper; + +template +struct StaticAssertTypeEqHelper {}; + +#if GTEST_HAS_GLOBAL_STRING +typedef ::string string; +#else +typedef ::std::string string; +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_GLOBAL_WSTRING +typedef ::wstring wstring; +#elif GTEST_HAS_STD_WSTRING +typedef ::std::wstring wstring; +#endif // GTEST_HAS_GLOBAL_WSTRING + +// A helper for suppressing warnings on constant condition. It just +// returns 'condition'. +GTEST_API_ bool IsTrue(bool condition); + +// Defines scoped_ptr. + +// This implementation of scoped_ptr is PARTIAL - it only contains +// enough stuff to satisfy Google Test's need. +template +class scoped_ptr { + public: + typedef T element_type; + + explicit scoped_ptr(T* p = NULL) : ptr_(p) {} + ~scoped_ptr() { reset(); } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + T* get() const { return ptr_; } + + T* release() { + T* const ptr = ptr_; + ptr_ = NULL; + return ptr; + } + + void reset(T* p = NULL) { + if (p != ptr_) { + if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. + delete ptr_; + } + ptr_ = p; + } + } + private: + T* ptr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); +}; + +// Defines RE. + +// A simple C++ wrapper for . It uses the POSIX Extended +// Regular Expression syntax. +class GTEST_API_ RE { + public: + // A copy constructor is required by the Standard to initialize object + // references from r-values. + RE(const RE& other) { Init(other.pattern()); } + + // Constructs an RE from a string. + RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT + +#if GTEST_HAS_GLOBAL_STRING + + RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT + +#endif // GTEST_HAS_GLOBAL_STRING + + RE(const char* regex) { Init(regex); } // NOLINT + ~RE(); + + // Returns the string representation of the regex. + const char* pattern() const { return pattern_; } + + // FullMatch(str, re) returns true iff regular expression re matches + // the entire str. + // PartialMatch(str, re) returns true iff regular expression re + // matches a substring of str (including str itself). + // + // TODO(wan@google.com): make FullMatch() and PartialMatch() work + // when str contains NUL characters. + static bool FullMatch(const ::std::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::std::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + +#if GTEST_HAS_GLOBAL_STRING + + static bool FullMatch(const ::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + +#endif // GTEST_HAS_GLOBAL_STRING + + static bool FullMatch(const char* str, const RE& re); + static bool PartialMatch(const char* str, const RE& re); + + private: + void Init(const char* regex); + + // We use a const char* instead of a string, as Google Test may be used + // where string is not available. We also do not use Google Test's own + // String type here, in order to simplify dependencies between the + // files. + const char* pattern_; + bool is_valid_; + +#if GTEST_USES_POSIX_RE + + regex_t full_regex_; // For FullMatch(). + regex_t partial_regex_; // For PartialMatch(). + +#else // GTEST_USES_SIMPLE_RE + + const char* full_pattern_; // For FullMatch(); + +#endif + + GTEST_DISALLOW_ASSIGN_(RE); +}; + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, + int line); + +// Defines logging utilities: +// GTEST_LOG_(severity) - logs messages at the specified severity level. The +// message itself is streamed into the macro. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. + +enum GTestLogSeverity { + GTEST_INFO, + GTEST_WARNING, + GTEST_ERROR, + GTEST_FATAL +}; + +// Formats log entry severity, provides a stream object for streaming the +// log message, and terminates the message with a newline when going out of +// scope. +class GTEST_API_ GTestLog { + public: + GTestLog(GTestLogSeverity severity, const char* file, int line); + + // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. + ~GTestLog(); + + ::std::ostream& GetStream() { return ::std::cerr; } + + private: + const GTestLogSeverity severity_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); +}; + +#define GTEST_LOG_(severity) \ + ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ + __FILE__, __LINE__).GetStream() + +inline void LogToStderr() {} +inline void FlushInfoLog() { fflush(NULL); } + +// INTERNAL IMPLEMENTATION - DO NOT USE. +// +// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition +// is not satisfied. +// Synopsys: +// GTEST_CHECK_(boolean_condition); +// or +// GTEST_CHECK_(boolean_condition) << "Additional message"; +// +// This checks the condition and if the condition is not satisfied +// it prints message about the condition violation, including the +// condition itself, plus additional message streamed into it, if any, +// and then it aborts the program. It aborts the program irrespective of +// whether it is built in the debug mode or not. +#define GTEST_CHECK_(condition) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::IsTrue(condition)) \ + ; \ + else \ + GTEST_LOG_(FATAL) << "Condition " #condition " failed. " + +// An all-mode assert to verify that the given POSIX-style function +// call returns 0 (indicating success). Known limitation: this +// doesn't expand to a balanced 'if' statement, so enclose the macro +// in {} if you need to use it as the only statement in an 'if' +// branch. +#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ + if (const int gtest_error = (posix_call)) \ + GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ + << gtest_error + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Use ImplicitCast_ as a safe version of static_cast for upcasting in +// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a +// const Foo*). When you use ImplicitCast_, the compiler checks that +// the cast is safe. Such explicit ImplicitCast_s are necessary in +// surprisingly many situations where C++ demands an exact type match +// instead of an argument type convertable to a target type. +// +// The syntax for using ImplicitCast_ is the same as for static_cast: +// +// ImplicitCast_(expr) +// +// ImplicitCast_ would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., implicit_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template +inline To ImplicitCast_(To x) { return x; } + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., down_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template // use like this: DownCast_(foo); +inline To DownCast_(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) { + const To to = NULL; + ::testing::internal::ImplicitCast_(to); + } + +#if GTEST_HAS_RTTI + // RTTI: debug mode only! + GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); +#endif + return static_cast(f); +} + +// Downcasts the pointer of type Base to Derived. +// Derived must be a subclass of Base. The parameter MUST +// point to a class of type Derived, not any subclass of it. +// When RTTI is available, the function performs a runtime +// check to enforce this. +template +Derived* CheckedDowncastToActualType(Base* base) { +#if GTEST_HAS_RTTI + GTEST_CHECK_(typeid(*base) == typeid(Derived)); + return dynamic_cast(base); // NOLINT +#else + return static_cast(base); // Poor man's downcast. +#endif +} + +#if GTEST_HAS_STREAM_REDIRECTION + +// Defines the stderr capturer: +// CaptureStdout - starts capturing stdout. +// GetCapturedStdout - stops capturing stdout and returns the captured string. +// CaptureStderr - starts capturing stderr. +// GetCapturedStderr - stops capturing stderr and returns the captured string. +// +GTEST_API_ void CaptureStdout(); +GTEST_API_ String GetCapturedStdout(); +GTEST_API_ void CaptureStderr(); +GTEST_API_ String GetCapturedStderr(); + +#endif // GTEST_HAS_STREAM_REDIRECTION + + +#if GTEST_HAS_DEATH_TEST + +// A copy of all command line arguments. Set by InitGoogleTest(). +extern ::std::vector g_argvs; + +// GTEST_HAS_DEATH_TEST implies we have ::std::string. +const ::std::vector& GetArgvs(); + +#endif // GTEST_HAS_DEATH_TEST + +// Defines synchronization primitives. + +#if GTEST_HAS_PTHREAD + +// Sleeps for (roughly) n milli-seconds. This function is only for +// testing Google Test's own constructs. Don't use it in user tests, +// either directly or indirectly. +inline void SleepMilliseconds(int n) { + const timespec time = { + 0, // 0 seconds. + n * 1000L * 1000L, // And n ms. + }; + nanosleep(&time, NULL); +} + +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class Notification { + public: + Notification() : notified_(false) {} + + // Notifies all threads created with this notification to start. Must + // be called from the controller thread. + void Notify() { notified_ = true; } + + // Blocks until the controller thread notifies. Must be called from a test + // thread. + void WaitForNotification() { + while(!notified_) { + SleepMilliseconds(10); + } + } + + private: + volatile bool notified_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; + +// As a C-function, ThreadFuncWithCLinkage cannot be templated itself. +// Consequently, it cannot select a correct instantiation of ThreadWithParam +// in order to call its Run(). Introducing ThreadWithParamBase as a +// non-templated base class for ThreadWithParam allows us to bypass this +// problem. +class ThreadWithParamBase { + public: + virtual ~ThreadWithParamBase() {} + virtual void Run() = 0; +}; + +// pthread_create() accepts a pointer to a function type with the C linkage. +// According to the Standard (7.5/1), function types with different linkages +// are different even if they are otherwise identical. Some compilers (for +// example, SunStudio) treat them as different types. Since class methods +// cannot be defined with C-linkage we need to define a free C-function to +// pass into pthread_create(). +extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { + static_cast(thread)->Run(); + return NULL; +} + +// Helper class for testing Google Test's multi-threading constructs. +// To use it, write: +// +// void ThreadFunc(int param) { /* Do things with param */ } +// Notification thread_can_start; +// ... +// // The thread_can_start parameter is optional; you can supply NULL. +// ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); +// thread_can_start.Notify(); +// +// These classes are only for testing Google Test's own constructs. Do +// not use them in user tests, either directly or indirectly. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void (*UserThreadFunc)(T); + + ThreadWithParam( + UserThreadFunc func, T param, Notification* thread_can_start) + : func_(func), + param_(param), + thread_can_start_(thread_can_start), + finished_(false) { + ThreadWithParamBase* const base = this; + // The thread can be created only after all fields except thread_ + // have been initialized. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); + } + ~ThreadWithParam() { Join(); } + + void Join() { + if (!finished_) { + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); + finished_ = true; + } + } + + virtual void Run() { + if (thread_can_start_ != NULL) + thread_can_start_->WaitForNotification(); + func_(param_); + } + + private: + const UserThreadFunc func_; // User-supplied thread function. + const T param_; // User-supplied parameter to the thread function. + // When non-NULL, used to block execution until the controller thread + // notifies. + Notification* const thread_can_start_; + bool finished_; // true iff we know that the thread function has finished. + pthread_t thread_; // The native thread object. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; + +// MutexBase and Mutex implement mutex on pthreads-based platforms. They +// are used in conjunction with class MutexLock: +// +// Mutex mutex; +// ... +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end +// // of the current scope. +// +// MutexBase implements behavior for both statically and dynamically +// allocated mutexes. Do not use MutexBase directly. Instead, write +// the following to define a static mutex: +// +// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// +// You can forward declare a static mutex like this: +// +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// To create a dynamic mutex, just define an object of type Mutex. +class MutexBase { + public: + // Acquires this mutex. + void Lock() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); + owner_ = pthread_self(); + } + + // Releases this mutex. + void Unlock() { + // We don't protect writing to owner_ here, as it's the caller's + // responsibility to ensure that the current thread holds the + // mutex when this is called. + owner_ = 0; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); + } + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld() const { + GTEST_CHECK_(owner_ == pthread_self()) + << "The current thread is not holding the mutex @" << this; + } + + // A static mutex may be used before main() is entered. It may even + // be used before the dynamic initialization stage. Therefore we + // must be able to initialize a static mutex object at link time. + // This means MutexBase has to be a POD and its member variables + // have to be public. + public: + pthread_mutex_t mutex_; // The underlying pthread mutex. + pthread_t owner_; // The thread holding the mutex; 0 means no one holds it. +}; + +// Forward-declares a static mutex. +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex + +// Defines and statically (i.e. at link time) initializes a static mutex. +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 } + +// The Mutex class can only be used for mutexes created at runtime. It +// shares its API with MutexBase otherwise. +class Mutex : public MutexBase { + public: + Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + owner_ = 0; + } + ~Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +// We cannot name this class MutexLock as the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(MutexBase* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + MutexBase* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Helpers for ThreadLocal. + +// pthread_key_create() requires DeleteThreadLocalValue() to have +// C-linkage. Therefore it cannot be templatized to access +// ThreadLocal. Hence the need for class +// ThreadLocalValueHolderBase. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Called by pthread to delete thread-local data stored by +// pthread_setspecific(). +extern "C" inline void DeleteThreadLocalValue(void* value_holder) { + delete static_cast(value_holder); +} + +// Implements thread-local storage on pthreads-based systems. +// +// // Thread 1 +// ThreadLocal tl(100); // 100 is the default value for each thread. +// +// // Thread 2 +// tl.set(150); // Changes the value for thread 2 only. +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); +// +// The template type argument T must have a public copy constructor. +// In addition, the default ThreadLocal constructor requires T to have +// a public default constructor. +// +// An object managed for a thread by a ThreadLocal instance is deleted +// when the thread exits. Or, if the ThreadLocal instance dies in +// that thread, when the ThreadLocal dies. It's the user's +// responsibility to ensure that all other threads using a ThreadLocal +// have exited when it dies, or the per-thread objects for those +// threads will not be deleted. +// +// Google Test only uses global ThreadLocal objects. That means they +// will die after main() has returned. Therefore, no per-thread +// object managed by Google Test will be leaked as long as all threads +// using Google Test have exited when main() returns. +template +class ThreadLocal { + public: + ThreadLocal() : key_(CreateKey()), + default_() {} + explicit ThreadLocal(const T& value) : key_(CreateKey()), + default_(value) {} + + ~ThreadLocal() { + // Destroys the managed object for the current thread, if any. + DeleteThreadLocalValue(pthread_getspecific(key_)); + + // Releases resources associated with the key. This will *not* + // delete managed objects for other threads. + GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); + } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of type T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + static pthread_key_t CreateKey() { + pthread_key_t key; + // When a thread exits, DeleteThreadLocalValue() will be called on + // the object managed for that thread. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_key_create(&key, &DeleteThreadLocalValue)); + return key; + } + + T* GetOrCreateValue() const { + ThreadLocalValueHolderBase* const holder = + static_cast(pthread_getspecific(key_)); + if (holder != NULL) { + return CheckedDowncastToActualType(holder)->pointer(); + } + + ValueHolder* const new_holder = new ValueHolder(default_); + ThreadLocalValueHolderBase* const holder_base = new_holder; + GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); + return new_holder->pointer(); + } + + // A key pthreads uses for looking up per-thread values. + const pthread_key_t key_; + const T default_; // The default value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +# define GTEST_IS_THREADSAFE 1 + +#else // GTEST_HAS_PTHREAD + +// A dummy implementation of synchronization primitives (mutex, lock, +// and thread-local variable). Necessary for compiling Google Test where +// mutex is not supported - using Google Test in multiple threads is not +// supported on such platforms. + +class Mutex { + public: + Mutex() {} + void AssertHeld() const {} +}; + +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex + +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex*) {} // NOLINT +}; + +typedef GTestMutexLock MutexLock; + +template +class ThreadLocal { + public: + ThreadLocal() : value_() {} + explicit ThreadLocal(const T& value) : value_(value) {} + T* pointer() { return &value_; } + const T* pointer() const { return &value_; } + const T& get() const { return value_; } + void set(const T& value) { value_ = value; } + private: + T value_; +}; + +// The above synchronization primitives have dummy implementations. +// Therefore Google Test is not thread-safe. +# define GTEST_IS_THREADSAFE 0 + +#endif // GTEST_HAS_PTHREAD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +GTEST_API_ size_t GetThreadCount(); + +// Passing non-POD classes through ellipsis (...) crashes the ARM +// compiler and generates a warning in Sun Studio. The Nokia Symbian +// and the IBM XL C/C++ compiler try to instantiate a copy constructor +// for objects passed through ellipsis (...), failing for uncopyable +// objects. We define this to ensure that only POD is passed through +// ellipsis on these systems. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +# define GTEST_ELLIPSIS_NEEDS_POD_ 1 +#else +# define GTEST_CAN_COMPARE_NULL 1 +#endif + +// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between +// const T& and const T* in a function template. These compilers +// _can_ decide between class template specializations for T and T*, +// so a tr1::type_traits-like is_pointer works. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) +# define GTEST_NEEDS_IS_POINTER_ 1 +#endif + +template +struct bool_constant { + typedef bool_constant type; + static const bool value = bool_value; +}; +template const bool bool_constant::value; + +typedef bool_constant false_type; +typedef bool_constant true_type; + +template +struct is_pointer : public false_type {}; + +template +struct is_pointer : public true_type {}; + +template +struct IteratorTraits { + typedef typename Iterator::value_type value_type; +}; + +template +struct IteratorTraits { + typedef T value_type; +}; + +template +struct IteratorTraits { + typedef T value_type; +}; + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_SEP_ "\\" +# define GTEST_HAS_ALT_PATH_SEP_ 1 +// The biggest signed integer type the compiler supports. +typedef __int64 BiggestInt; +#else +# define GTEST_PATH_SEP_ "/" +# define GTEST_HAS_ALT_PATH_SEP_ 0 +typedef long long BiggestInt; // NOLINT +#endif // GTEST_OS_WINDOWS + +// Utilities for char. + +// isspace(int ch) and friends accept an unsigned char or EOF. char +// may be signed, depending on the compiler (or compiler flags). +// Therefore we need to cast a char to unsigned char before calling +// isspace(), etc. + +inline bool IsAlpha(char ch) { + return isalpha(static_cast(ch)) != 0; +} +inline bool IsAlNum(char ch) { + return isalnum(static_cast(ch)) != 0; +} +inline bool IsDigit(char ch) { + return isdigit(static_cast(ch)) != 0; +} +inline bool IsLower(char ch) { + return islower(static_cast(ch)) != 0; +} +inline bool IsSpace(char ch) { + return isspace(static_cast(ch)) != 0; +} +inline bool IsUpper(char ch) { + return isupper(static_cast(ch)) != 0; +} +inline bool IsXDigit(char ch) { + return isxdigit(static_cast(ch)) != 0; +} + +inline char ToLower(char ch) { + return static_cast(tolower(static_cast(ch))); +} +inline char ToUpper(char ch) { + return static_cast(toupper(static_cast(ch))); +} + +// The testing::internal::posix namespace holds wrappers for common +// POSIX functions. These wrappers hide the differences between +// Windows/MSVC and POSIX systems. Since some compilers define these +// standard functions as macros, the wrapper cannot have the same name +// as the wrapped function. + +namespace posix { + +// Functions with a different name on Windows. + +#if GTEST_OS_WINDOWS + +typedef struct _stat StatStruct; + +# ifdef __BORLANDC__ +inline int IsATTY(int fd) { return isatty(fd); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +# else // !__BORLANDC__ +# if GTEST_OS_WINDOWS_MOBILE +inline int IsATTY(int /* fd */) { return 0; } +# else +inline int IsATTY(int fd) { return _isatty(fd); } +# endif // GTEST_OS_WINDOWS_MOBILE +inline int StrCaseCmp(const char* s1, const char* s2) { + return _stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return _strdup(src); } +# endif // __BORLANDC__ + +# if GTEST_OS_WINDOWS_MOBILE +inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } +// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this +// time and thus not defined there. +# else +inline int FileNo(FILE* file) { return _fileno(file); } +inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } +inline int RmDir(const char* dir) { return _rmdir(dir); } +inline bool IsDir(const StatStruct& st) { + return (_S_IFDIR & st.st_mode) != 0; +} +# endif // GTEST_OS_WINDOWS_MOBILE + +#else + +typedef struct stat StatStruct; + +inline int FileNo(FILE* file) { return fileno(file); } +inline int IsATTY(int fd) { return isatty(fd); } +inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +inline int RmDir(const char* dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } + +#endif // GTEST_OS_WINDOWS + +// Functions deprecated by MSVC 8.0. + +#ifdef _MSC_VER +// Temporarily disable warning 4996 (deprecated function). +# pragma warning(push) +# pragma warning(disable:4996) +#endif + +inline const char* StrNCpy(char* dest, const char* src, size_t n) { + return strncpy(dest, src, n); +} + +// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and +// StrError() aren't needed on Windows CE at this time and thus not +// defined there. + +#if !GTEST_OS_WINDOWS_MOBILE +inline int ChDir(const char* dir) { return chdir(dir); } +#endif +inline FILE* FOpen(const char* path, const char* mode) { + return fopen(path, mode); +} +#if !GTEST_OS_WINDOWS_MOBILE +inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { + return freopen(path, mode, stream); +} +inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } +#endif +inline int FClose(FILE* fp) { return fclose(fp); } +#if !GTEST_OS_WINDOWS_MOBILE +inline int Read(int fd, void* buf, unsigned int count) { + return static_cast(read(fd, buf, count)); +} +inline int Write(int fd, const void* buf, unsigned int count) { + return static_cast(write(fd, buf, count)); +} +inline int Close(int fd) { return close(fd); } +inline const char* StrError(int errnum) { return strerror(errnum); } +#endif +inline const char* GetEnv(const char* name) { +#if GTEST_OS_WINDOWS_MOBILE + // We are on Windows CE, which has no environment variables. + return NULL; +#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) + // Environment variables which we programmatically clear will be set to the + // empty string rather than unset (NULL). Handle that case. + const char* const env = getenv(name); + return (env != NULL && env[0] != '\0') ? env : NULL; +#else + return getenv(name); +#endif +} + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif + +#if GTEST_OS_WINDOWS_MOBILE +// Windows CE has no C library. The abort() function is used in +// several places in Google Test. This implementation provides a reasonable +// imitation of standard behaviour. +void Abort(); +#else +inline void Abort() { abort(); } +#endif // GTEST_OS_WINDOWS_MOBILE + +} // namespace posix + +// The maximum number a BiggestInt can represent. This definition +// works no matter BiggestInt is represented in one's complement or +// two's complement. +// +// We cannot rely on numeric_limits in STL, as __int64 and long long +// are not part of standard C++ and numeric_limits doesn't need to be +// defined for them. +const BiggestInt kMaxBiggestInt = + ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); + +// This template class serves as a compile-time function from size to +// type. It maps a size in bytes to a primitive type with that +// size. e.g. +// +// TypeWithSize<4>::UInt +// +// is typedef-ed to be unsigned int (unsigned integer made up of 4 +// bytes). +// +// Such functionality should belong to STL, but I cannot find it +// there. +// +// Google Test uses this class in the implementation of floating-point +// comparison. +// +// For now it only handles UInt (unsigned int) as that's all Google Test +// needs. Other types can be easily added in the future if need +// arises. +template +class TypeWithSize { + public: + // This prevents the user from using TypeWithSize with incorrect + // values of N. + typedef void UInt; +}; + +// The specialization for size 4. +template <> +class TypeWithSize<4> { + public: + // unsigned int has size 4 in both gcc and MSVC. + // + // As base/basictypes.h doesn't compile on Windows, we cannot use + // uint32, uint64, and etc here. + typedef int Int; + typedef unsigned int UInt; +}; + +// The specialization for size 8. +template <> +class TypeWithSize<8> { + public: + +#if GTEST_OS_WINDOWS + typedef __int64 Int; + typedef unsigned __int64 UInt; +#else + typedef long long Int; // NOLINT + typedef unsigned long long UInt; // NOLINT +#endif // GTEST_OS_WINDOWS +}; + +// Integer types of known sizes. +typedef TypeWithSize<4>::Int Int32; +typedef TypeWithSize<4>::UInt UInt32; +typedef TypeWithSize<8>::Int Int64; +typedef TypeWithSize<8>::UInt UInt64; +typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. + +// Utilities for command line flags and environment variables. + +// Macro for referencing flags. +#define GTEST_FLAG(name) FLAGS_gtest_##name + +// Macros for declaring flags. +#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) +#define GTEST_DECLARE_int32_(name) \ + GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) +#define GTEST_DECLARE_string_(name) \ + GTEST_API_ extern ::testing::internal::String GTEST_FLAG(name) + +// Macros for defining flags. +#define GTEST_DEFINE_bool_(name, default_val, doc) \ + GTEST_API_ bool GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_int32_(name, default_val, doc) \ + GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_string_(name, default_val, doc) \ + GTEST_API_ ::testing::internal::String GTEST_FLAG(name) = (default_val) + +// Parses 'str' for a 32-bit signed integer. If successful, writes the result +// to *value and returns true; otherwise leaves *value unchanged and returns +// false. +// TODO(chandlerc): Find a better way to refactor flag and environment parsing +// out of both gtest-port.cc and gtest.cc to avoid exporting this utility +// function. +bool ParseInt32(const Message& src_text, const char* str, Int32* value); + +// Parses a bool/Int32/string from the environment variable +// corresponding to the given Google Test flag. +bool BoolFromGTestEnv(const char* flag, bool default_val); +GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); +const char* StringFromGTestEnv(const char* flag, const char* default_val); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +#if GTEST_OS_LINUX +# include +# include +# include +# include +#endif // GTEST_OS_LINUX + +#include +#include +#include +#include +#include + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares the String class and functions used internally by +// Google Test. They are subject to change without notice. They should not used +// by code external to Google Test. +// +// This header file is #included by . +// It should not be #included by other files. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ + +#ifdef __BORLANDC__ +// string.h is not guaranteed to provide strcpy on C++ Builder. +# include +#endif + +#include + +#include + +namespace testing { +namespace internal { + +// String - a UTF-8 string class. +// +// For historic reasons, we don't use std::string. +// +// TODO(wan@google.com): replace this class with std::string or +// implement it in terms of the latter. +// +// Note that String can represent both NULL and the empty string, +// while std::string cannot represent NULL. +// +// NULL and the empty string are considered different. NULL is less +// than anything (including the empty string) except itself. +// +// This class only provides minimum functionality necessary for +// implementing Google Test. We do not intend to implement a full-fledged +// string class here. +// +// Since the purpose of this class is to provide a substitute for +// std::string on platforms where it cannot be used, we define a copy +// constructor and assignment operators such that we don't need +// conditional compilation in a lot of places. +// +// In order to make the representation efficient, the d'tor of String +// is not virtual. Therefore DO NOT INHERIT FROM String. +class GTEST_API_ String { + public: + // Static utility methods + + // Returns the input enclosed in double quotes if it's not NULL; + // otherwise returns "(null)". For example, "\"Hello\"" is returned + // for input "Hello". + // + // This is useful for printing a C string in the syntax of a literal. + // + // Known issue: escape sequences are not handled yet. + static String ShowCStringQuoted(const char* c_str); + + // Clones a 0-terminated C string, allocating memory using new. The + // caller is responsible for deleting the return value using + // delete[]. Returns the cloned string, or NULL if the input is + // NULL. + // + // This is different from strdup() in string.h, which allocates + // memory using malloc(). + static const char* CloneCString(const char* c_str); + +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be + // able to pass strings to Win32 APIs on CE we need to convert them + // to 'Unicode', UTF-16. + + // Creates a UTF-16 wide string from the given ANSI string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the wide string, or NULL if the + // input is NULL. + // + // The wide string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static LPCWSTR AnsiToUtf16(const char* c_str); + + // Creates an ANSI string from the given wide string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the ANSI string, or NULL if the + // input is NULL. + // + // The returned string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static const char* Utf16ToAnsi(LPCWSTR utf16_str); +#endif + + // Compares two C strings. Returns true iff they have the same content. + // + // Unlike strcmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CStringEquals(const char* lhs, const char* rhs); + + // Converts a wide C string to a String using the UTF-8 encoding. + // NULL will be converted to "(null)". If an error occurred during + // the conversion, "(failed to convert from wide string)" is + // returned. + static String ShowWideCString(const wchar_t* wide_c_str); + + // Similar to ShowWideCString(), except that this function encloses + // the converted string in double quotes. + static String ShowWideCStringQuoted(const wchar_t* wide_c_str); + + // Compares two wide C strings. Returns true iff they have the same + // content. + // + // Unlike wcscmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); + + // Compares two C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike strcasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CaseInsensitiveCStringEquals(const char* lhs, + const char* rhs); + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. + static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs); + + // Formats a list of arguments to a String, using the same format + // spec string as for printf. + // + // We do not use the StringPrintf class as it is not universally + // available. + // + // The result is limited to 4096 characters (including the tailing + // 0). If 4096 characters are not enough to format the input, + // "" is returned. + static String Format(const char* format, ...); + + // C'tors + + // The default c'tor constructs a NULL string. + String() : c_str_(NULL), length_(0) {} + + // Constructs a String by cloning a 0-terminated C string. + String(const char* a_c_str) { // NOLINT + if (a_c_str == NULL) { + c_str_ = NULL; + length_ = 0; + } else { + ConstructNonNull(a_c_str, strlen(a_c_str)); + } + } + + // Constructs a String by copying a given number of chars from a + // buffer. E.g. String("hello", 3) creates the string "hel", + // String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "", + // and String(NULL, 1) results in access violation. + String(const char* buffer, size_t a_length) { + ConstructNonNull(buffer, a_length); + } + + // The copy c'tor creates a new copy of the string. The two + // String objects do not share content. + String(const String& str) : c_str_(NULL), length_(0) { *this = str; } + + // D'tor. String is intended to be a final class, so the d'tor + // doesn't need to be virtual. + ~String() { delete[] c_str_; } + + // Allows a String to be implicitly converted to an ::std::string or + // ::string, and vice versa. Converting a String containing a NULL + // pointer to ::std::string or ::string is undefined behavior. + // Converting a ::std::string or ::string containing an embedded NUL + // character to a String will result in the prefix up to the first + // NUL character. + String(const ::std::string& str) { + ConstructNonNull(str.c_str(), str.length()); + } + + operator ::std::string() const { return ::std::string(c_str(), length()); } + +#if GTEST_HAS_GLOBAL_STRING + String(const ::string& str) { + ConstructNonNull(str.c_str(), str.length()); + } + + operator ::string() const { return ::string(c_str(), length()); } +#endif // GTEST_HAS_GLOBAL_STRING + + // Returns true iff this is an empty string (i.e. ""). + bool empty() const { return (c_str() != NULL) && (length() == 0); } + + // Compares this with another String. + // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0 + // if this is greater than rhs. + int Compare(const String& rhs) const; + + // Returns true iff this String equals the given C string. A NULL + // string and a non-NULL string are considered not equal. + bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; } + + // Returns true iff this String is less than the given String. A + // NULL string is considered less than "". + bool operator<(const String& rhs) const { return Compare(rhs) < 0; } + + // Returns true iff this String doesn't equal the given C string. A NULL + // string and a non-NULL string are considered not equal. + bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); } + + // Returns true iff this String ends with the given suffix. *Any* + // String is considered to end with a NULL or empty suffix. + bool EndsWith(const char* suffix) const; + + // Returns true iff this String ends with the given suffix, not considering + // case. Any String is considered to end with a NULL or empty suffix. + bool EndsWithCaseInsensitive(const char* suffix) const; + + // Returns the length of the encapsulated string, or 0 if the + // string is NULL. + size_t length() const { return length_; } + + // Gets the 0-terminated C string this String object represents. + // The String object still owns the string. Therefore the caller + // should NOT delete the return value. + const char* c_str() const { return c_str_; } + + // Assigns a C string to this object. Self-assignment works. + const String& operator=(const char* a_c_str) { + return *this = String(a_c_str); + } + + // Assigns a String object to this object. Self-assignment works. + const String& operator=(const String& rhs) { + if (this != &rhs) { + delete[] c_str_; + if (rhs.c_str() == NULL) { + c_str_ = NULL; + length_ = 0; + } else { + ConstructNonNull(rhs.c_str(), rhs.length()); + } + } + + return *this; + } + + private: + // Constructs a non-NULL String from the given content. This + // function can only be called when c_str_ has not been allocated. + // ConstructNonNull(NULL, 0) results in an empty string (""). + // ConstructNonNull(NULL, non_zero) is undefined behavior. + void ConstructNonNull(const char* buffer, size_t a_length) { + char* const str = new char[a_length + 1]; + memcpy(str, buffer, a_length); + str[a_length] = '\0'; + c_str_ = str; + length_ = a_length; + } + + const char* c_str_; + size_t length_; +}; // class String + +// Streams a String to an ostream. Each '\0' character in the String +// is replaced with "\\0". +inline ::std::ostream& operator<<(::std::ostream& os, const String& str) { + if (str.c_str() == NULL) { + os << "(null)"; + } else { + const char* const c_str = str.c_str(); + for (size_t i = 0; i != str.length(); i++) { + if (c_str[i] == '\0') { + os << "\\0"; + } else { + os << c_str[i]; + } + } + } + return os; +} + +// Gets the content of the stringstream's buffer as a String. Each '\0' +// character in the buffer is replaced with "\\0". +GTEST_API_ String StringStreamToString(::std::stringstream* stream); + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". + +// Declared here but defined in gtest.h, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: keith.ray@gmail.com (Keith Ray) +// +// Google Test filepath utilities +// +// This header file declares classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included in . +// Do not include this header file separately! + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ + + +namespace testing { +namespace internal { + +// FilePath - a class for file and directory pathname manipulation which +// handles platform-specific conventions (like the pathname separator). +// Used for helper functions for naming files in a directory for xml output. +// Except for Set methods, all methods are const or static, which provides an +// "immutable value object" -- useful for peace of mind. +// A FilePath with a value ending in a path separator ("like/this/") represents +// a directory, otherwise it is assumed to represent a file. In either case, +// it may or may not represent an actual file or directory in the file system. +// Names are NOT checked for syntax correctness -- no checking for illegal +// characters, malformed paths, etc. + +class GTEST_API_ FilePath { + public: + FilePath() : pathname_("") { } + FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } + + explicit FilePath(const char* pathname) : pathname_(pathname) { + Normalize(); + } + + explicit FilePath(const String& pathname) : pathname_(pathname) { + Normalize(); + } + + FilePath& operator=(const FilePath& rhs) { + Set(rhs); + return *this; + } + + void Set(const FilePath& rhs) { + pathname_ = rhs.pathname_; + } + + String ToString() const { return pathname_; } + const char* c_str() const { return pathname_.c_str(); } + + // Returns the current working directory, or "" if unsuccessful. + static FilePath GetCurrentDir(); + + // Given directory = "dir", base_name = "test", number = 0, + // extension = "xml", returns "dir/test.xml". If number is greater + // than zero (e.g., 12), returns "dir/test_12.xml". + // On Windows platform, uses \ as the separator rather than /. + static FilePath MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension); + + // Given directory = "dir", relative_path = "test.xml", + // returns "dir/test.xml". + // On Windows, uses \ as the separator rather than /. + static FilePath ConcatPaths(const FilePath& directory, + const FilePath& relative_path); + + // Returns a pathname for a file that does not currently exist. The pathname + // will be directory/base_name.extension or + // directory/base_name_.extension if directory/base_name.extension + // already exists. The number will be incremented until a pathname is found + // that does not already exist. + // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. + // There could be a race condition if two or more processes are calling this + // function at the same time -- they could both pick the same filename. + static FilePath GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension); + + // Returns true iff the path is NULL or "". + bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; } + + // If input name has a trailing separator character, removes it and returns + // the name, otherwise return the name string unmodified. + // On Windows platform, uses \ as the separator, other platforms use /. + FilePath RemoveTrailingPathSeparator() const; + + // Returns a copy of the FilePath with the directory part removed. + // Example: FilePath("path/to/file").RemoveDirectoryName() returns + // FilePath("file"). If there is no directory part ("just_a_file"), it returns + // the FilePath unmodified. If there is no file part ("just_a_dir/") it + // returns an empty FilePath (""). + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveDirectoryName() const; + + // RemoveFileName returns the directory path with the filename removed. + // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". + // If the FilePath is "a_file" or "/a_file", RemoveFileName returns + // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does + // not have a file, like "just/a/dir/", it returns the FilePath unmodified. + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveFileName() const; + + // Returns a copy of the FilePath with the case-insensitive extension removed. + // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns + // FilePath("dir/file"). If a case-insensitive extension is not + // found, returns a copy of the original FilePath. + FilePath RemoveExtension(const char* extension) const; + + // Creates directories so that path exists. Returns true if successful or if + // the directories already exist; returns false if unable to create + // directories for any reason. Will also return false if the FilePath does + // not represent a directory (that is, it doesn't end with a path separator). + bool CreateDirectoriesRecursively() const; + + // Create the directory so that path exists. Returns true if successful or + // if the directory already exists; returns false if unable to create the + // directory for any reason, including if the parent directory does not + // exist. Not named "CreateDirectory" because that's a macro on Windows. + bool CreateFolder() const; + + // Returns true if FilePath describes something in the file-system, + // either a file, directory, or whatever, and that something exists. + bool FileOrDirectoryExists() const; + + // Returns true if pathname describes a directory in the file-system + // that exists. + bool DirectoryExists() const; + + // Returns true if FilePath ends with a path separator, which indicates that + // it is intended to represent a directory. Returns false otherwise. + // This does NOT check that a directory (or file) actually exists. + bool IsDirectory() const; + + // Returns true if pathname describes a root directory. (Windows has one + // root directory per disk drive.) + bool IsRootDirectory() const; + + // Returns true if pathname describes an absolute path. + bool IsAbsolutePath() const; + + private: + // Replaces multiple consecutive separators with a single separator. + // For example, "bar///foo" becomes "bar/foo". Does not eliminate other + // redundancies that might be in a pathname involving "." or "..". + // + // A pathname with multiple consecutive separators may occur either through + // user error or as a result of some scripts or APIs that generate a pathname + // with a trailing separator. On other platforms the same API or script + // may NOT generate a pathname with a trailing "/". Then elsewhere that + // pathname may have another "/" and pathname components added to it, + // without checking for the separator already being there. + // The script language and operating system may allow paths like "foo//bar" + // but some of the functions in FilePath will not handle that correctly. In + // particular, RemoveTrailingPathSeparator() only removes one separator, and + // it is called in CreateDirectoriesRecursively() assuming that it will change + // a pathname from directory syntax (trailing separator) to filename syntax. + // + // On Windows this method also replaces the alternate path separator '/' with + // the primary path separator '\\', so that for example "bar\\/\\foo" becomes + // "bar\\foo". + + void Normalize(); + + // Returns a pointer to the last occurence of a valid path separator in + // the FilePath. On Windows, for example, both '/' and '\' are valid path + // separators. Returns NULL if no path separator was found. + const char* FindLastPathSeparator() const; + + String pathname_; +}; // class FilePath + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +// This file was GENERATED by command: +// pump.py gtest-type-util.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Type utilities needed for implementing typed and type-parameterized +// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently we support at most 50 types in a list, and at most 50 +// type-parameterized tests in one type-parameterized test case. +// Please contact googletestframework@googlegroups.com if you need +// more. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + + +// #ifdef __GNUC__ is too general here. It is possible to use gcc without using +// libstdc++ (which is where cxxabi.h comes from). +# ifdef __GLIBCXX__ +# include +# elif defined(__HP_aCC) +# include +# endif // __GLIBCXX__ + +namespace testing { +namespace internal { + +// GetTypeName() returns a human-readable name of type T. +// NB: This function is also used in Google Mock, so don't move it inside of +// the typed-test-only section below. +template +String GetTypeName() { +# if GTEST_HAS_RTTI + + const char* const name = typeid(T).name(); +# if defined(__GLIBCXX__) || defined(__HP_aCC) + int status = 0; + // gcc's implementation of typeid(T).name() mangles the type name, + // so we have to demangle it. +# ifdef __GLIBCXX__ + using abi::__cxa_demangle; +# endif // __GLIBCXX__ + char* const readable_name = __cxa_demangle(name, 0, 0, &status); + const String name_str(status == 0 ? readable_name : name); + free(readable_name); + return name_str; +# else + return name; +# endif // __GLIBCXX__ || __HP_aCC + +# else + + return ""; + +# endif // GTEST_HAS_RTTI +} + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// AssertyTypeEq::type is defined iff T1 and T2 are the same +// type. This can be used as a compile-time assertion to ensure that +// two types are equal. + +template +struct AssertTypeEq; + +template +struct AssertTypeEq { + typedef bool type; +}; + +// A unique type used as the default value for the arguments of class +// template Types. This allows us to simulate variadic templates +// (e.g. Types, Type, and etc), which C++ doesn't +// support directly. +struct None {}; + +// The following family of struct and struct templates are used to +// represent type lists. In particular, TypesN +// represents a type list with N types (T1, T2, ..., and TN) in it. +// Except for Types0, every struct in the family has two member types: +// Head for the first type in the list, and Tail for the rest of the +// list. + +// The empty type list. +struct Types0 {}; + +// Type lists of length 1, 2, 3, and so on. + +template +struct Types1 { + typedef T1 Head; + typedef Types0 Tail; +}; +template +struct Types2 { + typedef T1 Head; + typedef Types1 Tail; +}; + +template +struct Types3 { + typedef T1 Head; + typedef Types2 Tail; +}; + +template +struct Types4 { + typedef T1 Head; + typedef Types3 Tail; +}; + +template +struct Types5 { + typedef T1 Head; + typedef Types4 Tail; +}; + +template +struct Types6 { + typedef T1 Head; + typedef Types5 Tail; +}; + +template +struct Types7 { + typedef T1 Head; + typedef Types6 Tail; +}; + +template +struct Types8 { + typedef T1 Head; + typedef Types7 Tail; +}; + +template +struct Types9 { + typedef T1 Head; + typedef Types8 Tail; +}; + +template +struct Types10 { + typedef T1 Head; + typedef Types9 Tail; +}; + +template +struct Types11 { + typedef T1 Head; + typedef Types10 Tail; +}; + +template +struct Types12 { + typedef T1 Head; + typedef Types11 Tail; +}; + +template +struct Types13 { + typedef T1 Head; + typedef Types12 Tail; +}; + +template +struct Types14 { + typedef T1 Head; + typedef Types13 Tail; +}; + +template +struct Types15 { + typedef T1 Head; + typedef Types14 Tail; +}; + +template +struct Types16 { + typedef T1 Head; + typedef Types15 Tail; +}; + +template +struct Types17 { + typedef T1 Head; + typedef Types16 Tail; +}; + +template +struct Types18 { + typedef T1 Head; + typedef Types17 Tail; +}; + +template +struct Types19 { + typedef T1 Head; + typedef Types18 Tail; +}; + +template +struct Types20 { + typedef T1 Head; + typedef Types19 Tail; +}; + +template +struct Types21 { + typedef T1 Head; + typedef Types20 Tail; +}; + +template +struct Types22 { + typedef T1 Head; + typedef Types21 Tail; +}; + +template +struct Types23 { + typedef T1 Head; + typedef Types22 Tail; +}; + +template +struct Types24 { + typedef T1 Head; + typedef Types23 Tail; +}; + +template +struct Types25 { + typedef T1 Head; + typedef Types24 Tail; +}; + +template +struct Types26 { + typedef T1 Head; + typedef Types25 Tail; +}; + +template +struct Types27 { + typedef T1 Head; + typedef Types26 Tail; +}; + +template +struct Types28 { + typedef T1 Head; + typedef Types27 Tail; +}; + +template +struct Types29 { + typedef T1 Head; + typedef Types28 Tail; +}; + +template +struct Types30 { + typedef T1 Head; + typedef Types29 Tail; +}; + +template +struct Types31 { + typedef T1 Head; + typedef Types30 Tail; +}; + +template +struct Types32 { + typedef T1 Head; + typedef Types31 Tail; +}; + +template +struct Types33 { + typedef T1 Head; + typedef Types32 Tail; +}; + +template +struct Types34 { + typedef T1 Head; + typedef Types33 Tail; +}; + +template +struct Types35 { + typedef T1 Head; + typedef Types34 Tail; +}; + +template +struct Types36 { + typedef T1 Head; + typedef Types35 Tail; +}; + +template +struct Types37 { + typedef T1 Head; + typedef Types36 Tail; +}; + +template +struct Types38 { + typedef T1 Head; + typedef Types37 Tail; +}; + +template +struct Types39 { + typedef T1 Head; + typedef Types38 Tail; +}; + +template +struct Types40 { + typedef T1 Head; + typedef Types39 Tail; +}; + +template +struct Types41 { + typedef T1 Head; + typedef Types40 Tail; +}; + +template +struct Types42 { + typedef T1 Head; + typedef Types41 Tail; +}; + +template +struct Types43 { + typedef T1 Head; + typedef Types42 Tail; +}; + +template +struct Types44 { + typedef T1 Head; + typedef Types43 Tail; +}; + +template +struct Types45 { + typedef T1 Head; + typedef Types44 Tail; +}; + +template +struct Types46 { + typedef T1 Head; + typedef Types45 Tail; +}; + +template +struct Types47 { + typedef T1 Head; + typedef Types46 Tail; +}; + +template +struct Types48 { + typedef T1 Head; + typedef Types47 Tail; +}; + +template +struct Types49 { + typedef T1 Head; + typedef Types48 Tail; +}; + +template +struct Types50 { + typedef T1 Head; + typedef Types49 Tail; +}; + + +} // namespace internal + +// We don't want to require the users to write TypesN<...> directly, +// as that would require them to count the length. Types<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Types +// will appear as Types in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Types, and Google Test will translate +// that to TypesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Types template. +template +struct Types { + typedef internal::Types50 type; +}; + +template <> +struct Types { + typedef internal::Types0 type; +}; +template +struct Types { + typedef internal::Types1 type; +}; +template +struct Types { + typedef internal::Types2 type; +}; +template +struct Types { + typedef internal::Types3 type; +}; +template +struct Types { + typedef internal::Types4 type; +}; +template +struct Types { + typedef internal::Types5 type; +}; +template +struct Types { + typedef internal::Types6 type; +}; +template +struct Types { + typedef internal::Types7 type; +}; +template +struct Types { + typedef internal::Types8 type; +}; +template +struct Types { + typedef internal::Types9 type; +}; +template +struct Types { + typedef internal::Types10 type; +}; +template +struct Types { + typedef internal::Types11 type; +}; +template +struct Types { + typedef internal::Types12 type; +}; +template +struct Types { + typedef internal::Types13 type; +}; +template +struct Types { + typedef internal::Types14 type; +}; +template +struct Types { + typedef internal::Types15 type; +}; +template +struct Types { + typedef internal::Types16 type; +}; +template +struct Types { + typedef internal::Types17 type; +}; +template +struct Types { + typedef internal::Types18 type; +}; +template +struct Types { + typedef internal::Types19 type; +}; +template +struct Types { + typedef internal::Types20 type; +}; +template +struct Types { + typedef internal::Types21 type; +}; +template +struct Types { + typedef internal::Types22 type; +}; +template +struct Types { + typedef internal::Types23 type; +}; +template +struct Types { + typedef internal::Types24 type; +}; +template +struct Types { + typedef internal::Types25 type; +}; +template +struct Types { + typedef internal::Types26 type; +}; +template +struct Types { + typedef internal::Types27 type; +}; +template +struct Types { + typedef internal::Types28 type; +}; +template +struct Types { + typedef internal::Types29 type; +}; +template +struct Types { + typedef internal::Types30 type; +}; +template +struct Types { + typedef internal::Types31 type; +}; +template +struct Types { + typedef internal::Types32 type; +}; +template +struct Types { + typedef internal::Types33 type; +}; +template +struct Types { + typedef internal::Types34 type; +}; +template +struct Types { + typedef internal::Types35 type; +}; +template +struct Types { + typedef internal::Types36 type; +}; +template +struct Types { + typedef internal::Types37 type; +}; +template +struct Types { + typedef internal::Types38 type; +}; +template +struct Types { + typedef internal::Types39 type; +}; +template +struct Types { + typedef internal::Types40 type; +}; +template +struct Types { + typedef internal::Types41 type; +}; +template +struct Types { + typedef internal::Types42 type; +}; +template +struct Types { + typedef internal::Types43 type; +}; +template +struct Types { + typedef internal::Types44 type; +}; +template +struct Types { + typedef internal::Types45 type; +}; +template +struct Types { + typedef internal::Types46 type; +}; +template +struct Types { + typedef internal::Types47 type; +}; +template +struct Types { + typedef internal::Types48 type; +}; +template +struct Types { + typedef internal::Types49 type; +}; + +namespace internal { + +# define GTEST_TEMPLATE_ template class + +// The template "selector" struct TemplateSel is used to +// represent Tmpl, which must be a class template with one type +// parameter, as a type. TemplateSel::Bind::type is defined +// as the type Tmpl. This allows us to actually instantiate the +// template "selected" by TemplateSel. +// +// This trick is necessary for simulating typedef for class templates, +// which C++ doesn't support directly. +template +struct TemplateSel { + template + struct Bind { + typedef Tmpl type; + }; +}; + +# define GTEST_BIND_(TmplSel, T) \ + TmplSel::template Bind::type + +// A unique struct template used as the default value for the +// arguments of class template Templates. This allows us to simulate +// variadic templates (e.g. Templates, Templates, +// and etc), which C++ doesn't support directly. +template +struct NoneT {}; + +// The following family of struct and struct templates are used to +// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except +// for Templates0, every struct in the family has two member types: +// Head for the selector of the first template in the list, and Tail +// for the rest of the list. + +// The empty template list. +struct Templates0 {}; + +// Template lists of length 1, 2, 3, and so on. + +template +struct Templates1 { + typedef TemplateSel Head; + typedef Templates0 Tail; +}; +template +struct Templates2 { + typedef TemplateSel Head; + typedef Templates1 Tail; +}; + +template +struct Templates3 { + typedef TemplateSel Head; + typedef Templates2 Tail; +}; + +template +struct Templates4 { + typedef TemplateSel Head; + typedef Templates3 Tail; +}; + +template +struct Templates5 { + typedef TemplateSel Head; + typedef Templates4 Tail; +}; + +template +struct Templates6 { + typedef TemplateSel Head; + typedef Templates5 Tail; +}; + +template +struct Templates7 { + typedef TemplateSel Head; + typedef Templates6 Tail; +}; + +template +struct Templates8 { + typedef TemplateSel Head; + typedef Templates7 Tail; +}; + +template +struct Templates9 { + typedef TemplateSel Head; + typedef Templates8 Tail; +}; + +template +struct Templates10 { + typedef TemplateSel Head; + typedef Templates9 Tail; +}; + +template +struct Templates11 { + typedef TemplateSel Head; + typedef Templates10 Tail; +}; + +template +struct Templates12 { + typedef TemplateSel Head; + typedef Templates11 Tail; +}; + +template +struct Templates13 { + typedef TemplateSel Head; + typedef Templates12 Tail; +}; + +template +struct Templates14 { + typedef TemplateSel Head; + typedef Templates13 Tail; +}; + +template +struct Templates15 { + typedef TemplateSel Head; + typedef Templates14 Tail; +}; + +template +struct Templates16 { + typedef TemplateSel Head; + typedef Templates15 Tail; +}; + +template +struct Templates17 { + typedef TemplateSel Head; + typedef Templates16 Tail; +}; + +template +struct Templates18 { + typedef TemplateSel Head; + typedef Templates17 Tail; +}; + +template +struct Templates19 { + typedef TemplateSel Head; + typedef Templates18 Tail; +}; + +template +struct Templates20 { + typedef TemplateSel Head; + typedef Templates19 Tail; +}; + +template +struct Templates21 { + typedef TemplateSel Head; + typedef Templates20 Tail; +}; + +template +struct Templates22 { + typedef TemplateSel Head; + typedef Templates21 Tail; +}; + +template +struct Templates23 { + typedef TemplateSel Head; + typedef Templates22 Tail; +}; + +template +struct Templates24 { + typedef TemplateSel Head; + typedef Templates23 Tail; +}; + +template +struct Templates25 { + typedef TemplateSel Head; + typedef Templates24 Tail; +}; + +template +struct Templates26 { + typedef TemplateSel Head; + typedef Templates25 Tail; +}; + +template +struct Templates27 { + typedef TemplateSel Head; + typedef Templates26 Tail; +}; + +template +struct Templates28 { + typedef TemplateSel Head; + typedef Templates27 Tail; +}; + +template +struct Templates29 { + typedef TemplateSel Head; + typedef Templates28 Tail; +}; + +template +struct Templates30 { + typedef TemplateSel Head; + typedef Templates29 Tail; +}; + +template +struct Templates31 { + typedef TemplateSel Head; + typedef Templates30 Tail; +}; + +template +struct Templates32 { + typedef TemplateSel Head; + typedef Templates31 Tail; +}; + +template +struct Templates33 { + typedef TemplateSel Head; + typedef Templates32 Tail; +}; + +template +struct Templates34 { + typedef TemplateSel Head; + typedef Templates33 Tail; +}; + +template +struct Templates35 { + typedef TemplateSel Head; + typedef Templates34 Tail; +}; + +template +struct Templates36 { + typedef TemplateSel Head; + typedef Templates35 Tail; +}; + +template +struct Templates37 { + typedef TemplateSel Head; + typedef Templates36 Tail; +}; + +template +struct Templates38 { + typedef TemplateSel Head; + typedef Templates37 Tail; +}; + +template +struct Templates39 { + typedef TemplateSel Head; + typedef Templates38 Tail; +}; + +template +struct Templates40 { + typedef TemplateSel Head; + typedef Templates39 Tail; +}; + +template +struct Templates41 { + typedef TemplateSel Head; + typedef Templates40 Tail; +}; + +template +struct Templates42 { + typedef TemplateSel Head; + typedef Templates41 Tail; +}; + +template +struct Templates43 { + typedef TemplateSel Head; + typedef Templates42 Tail; +}; + +template +struct Templates44 { + typedef TemplateSel Head; + typedef Templates43 Tail; +}; + +template +struct Templates45 { + typedef TemplateSel Head; + typedef Templates44 Tail; +}; + +template +struct Templates46 { + typedef TemplateSel Head; + typedef Templates45 Tail; +}; + +template +struct Templates47 { + typedef TemplateSel Head; + typedef Templates46 Tail; +}; + +template +struct Templates48 { + typedef TemplateSel Head; + typedef Templates47 Tail; +}; + +template +struct Templates49 { + typedef TemplateSel Head; + typedef Templates48 Tail; +}; + +template +struct Templates50 { + typedef TemplateSel Head; + typedef Templates49 Tail; +}; + + +// We don't want to require the users to write TemplatesN<...> directly, +// as that would require them to count the length. Templates<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Templates +// will appear as Templates in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Templates, and Google Test will translate +// that to TemplatesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Templates template. +template +struct Templates { + typedef Templates50 type; +}; + +template <> +struct Templates { + typedef Templates0 type; +}; +template +struct Templates { + typedef Templates1 type; +}; +template +struct Templates { + typedef Templates2 type; +}; +template +struct Templates { + typedef Templates3 type; +}; +template +struct Templates { + typedef Templates4 type; +}; +template +struct Templates { + typedef Templates5 type; +}; +template +struct Templates { + typedef Templates6 type; +}; +template +struct Templates { + typedef Templates7 type; +}; +template +struct Templates { + typedef Templates8 type; +}; +template +struct Templates { + typedef Templates9 type; +}; +template +struct Templates { + typedef Templates10 type; +}; +template +struct Templates { + typedef Templates11 type; +}; +template +struct Templates { + typedef Templates12 type; +}; +template +struct Templates { + typedef Templates13 type; +}; +template +struct Templates { + typedef Templates14 type; +}; +template +struct Templates { + typedef Templates15 type; +}; +template +struct Templates { + typedef Templates16 type; +}; +template +struct Templates { + typedef Templates17 type; +}; +template +struct Templates { + typedef Templates18 type; +}; +template +struct Templates { + typedef Templates19 type; +}; +template +struct Templates { + typedef Templates20 type; +}; +template +struct Templates { + typedef Templates21 type; +}; +template +struct Templates { + typedef Templates22 type; +}; +template +struct Templates { + typedef Templates23 type; +}; +template +struct Templates { + typedef Templates24 type; +}; +template +struct Templates { + typedef Templates25 type; +}; +template +struct Templates { + typedef Templates26 type; +}; +template +struct Templates { + typedef Templates27 type; +}; +template +struct Templates { + typedef Templates28 type; +}; +template +struct Templates { + typedef Templates29 type; +}; +template +struct Templates { + typedef Templates30 type; +}; +template +struct Templates { + typedef Templates31 type; +}; +template +struct Templates { + typedef Templates32 type; +}; +template +struct Templates { + typedef Templates33 type; +}; +template +struct Templates { + typedef Templates34 type; +}; +template +struct Templates { + typedef Templates35 type; +}; +template +struct Templates { + typedef Templates36 type; +}; +template +struct Templates { + typedef Templates37 type; +}; +template +struct Templates { + typedef Templates38 type; +}; +template +struct Templates { + typedef Templates39 type; +}; +template +struct Templates { + typedef Templates40 type; +}; +template +struct Templates { + typedef Templates41 type; +}; +template +struct Templates { + typedef Templates42 type; +}; +template +struct Templates { + typedef Templates43 type; +}; +template +struct Templates { + typedef Templates44 type; +}; +template +struct Templates { + typedef Templates45 type; +}; +template +struct Templates { + typedef Templates46 type; +}; +template +struct Templates { + typedef Templates47 type; +}; +template +struct Templates { + typedef Templates48 type; +}; +template +struct Templates { + typedef Templates49 type; +}; + +// The TypeList template makes it possible to use either a single type +// or a Types<...> list in TYPED_TEST_CASE() and +// INSTANTIATE_TYPED_TEST_CASE_P(). + +template +struct TypeList { typedef Types1 type; }; + +template +struct TypeList > { + typedef typename Types::type type; +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + +// Due to C++ preprocessor weirdness, we need double indirection to +// concatenate two tokens when one of them is __LINE__. Writing +// +// foo ## __LINE__ +// +// will result in the token foo__LINE__, instead of foo followed by +// the current line number. For more details, see +// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 +#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) +#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar + +// Google Test defines the testing::Message class to allow construction of +// test messages via the << operator. The idea is that anything +// streamable to std::ostream can be streamed to a testing::Message. +// This allows a user to use his own types in Google Test assertions by +// overloading the << operator. +// +// util/gtl/stl_logging-inl.h overloads << for STL containers. These +// overloads cannot be defined in the std namespace, as that will be +// undefined behavior. Therefore, they are defined in the global +// namespace instead. +// +// C++'s symbol lookup rule (i.e. Koenig lookup) says that these +// overloads are visible in either the std namespace or the global +// namespace, but not other namespaces, including the testing +// namespace which Google Test's Message class is in. +// +// To allow STL containers (and other types that has a << operator +// defined in the global namespace) to be used in Google Test assertions, +// testing::Message must access the custom << operator from the global +// namespace. Hence this helper function. +// +// Note: Jeffrey Yasskin suggested an alternative fix by "using +// ::operator<<;" in the definition of Message's operator<<. That fix +// doesn't require a helper function, but unfortunately doesn't +// compile with MSVC. +template +inline void GTestStreamToHelper(std::ostream* os, const T& val) { + *os << val; +} + +class ProtocolMessage; +namespace proto2 { class Message; } + +namespace testing { + +// Forward declarations. + +class AssertionResult; // Result of an assertion. +class Message; // Represents a failure message. +class Test; // Represents a test. +class TestInfo; // Information about a test. +class TestPartResult; // Result of a test part. +class UnitTest; // A collection of test cases. + +template +::std::string PrintToString(const T& value); + +namespace internal { + +struct TraceInfo; // Information about a trace point. +class ScopedTrace; // Implements scoped trace. +class TestInfoImpl; // Opaque implementation of TestInfo +class UnitTestImpl; // Opaque implementation of UnitTest + +// How many times InitGoogleTest() has been called. +extern int g_init_gtest_count; + +// The text used in failure messages to indicate the start of the +// stack trace. +GTEST_API_ extern const char kStackTraceMarker[]; + +// A secret type that Google Test users don't know about. It has no +// definition on purpose. Therefore it's impossible to create a +// Secret object, which is what we want. +class Secret; + +// Two overloaded helpers for checking at compile time whether an +// expression is a null pointer literal (i.e. NULL or any 0-valued +// compile-time integral constant). Their return values have +// different sizes, so we can use sizeof() to test which version is +// picked by the compiler. These helpers have no implementations, as +// we only need their signatures. +// +// Given IsNullLiteralHelper(x), the compiler will pick the first +// version if x can be implicitly converted to Secret*, and pick the +// second version otherwise. Since Secret is a secret and incomplete +// type, the only expression a user can write that has type Secret* is +// a null pointer literal. Therefore, we know that x is a null +// pointer literal if and only if the first version is picked by the +// compiler. +char IsNullLiteralHelper(Secret* p); +char (&IsNullLiteralHelper(...))[2]; // NOLINT + +// A compile-time bool constant that is true if and only if x is a +// null pointer literal (i.e. NULL or any 0-valued compile-time +// integral constant). +#ifdef GTEST_ELLIPSIS_NEEDS_POD_ +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +# define GTEST_IS_NULL_LITERAL_(x) false +#else +# define GTEST_IS_NULL_LITERAL_(x) \ + (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) +#endif // GTEST_ELLIPSIS_NEEDS_POD_ + +// Appends the user-supplied message to the Google-Test-generated message. +GTEST_API_ String AppendUserMessage(const String& gtest_msg, + const Message& user_msg); + +// A helper class for creating scoped traces in user programs. +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + ScopedTrace(const char* file, int line, const Message& message); + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +// Declared here but defined in gtest.h, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable); + +// The Symbian compiler has a bug that prevents it from selecting the +// correct overload of FormatForComparisonFailureMessage (see below) +// unless we pass the first argument by reference. If we do that, +// however, Visual Age C++ 10.1 generates a compiler error. Therefore +// we only apply the work-around for Symbian. +#if defined(__SYMBIAN32__) +# define GTEST_CREF_WORKAROUND_ const& +#else +# define GTEST_CREF_WORKAROUND_ +#endif + +// When this operand is a const char* or char*, if the other operand +// is a ::std::string or ::string, we print this operand as a C string +// rather than a pointer (we do the same for wide strings); otherwise +// we print it as a pointer to be safe. + +// This internal macro is used to avoid duplicated code. +#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\ +inline String FormatForComparisonFailureMessage(\ + operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \ + const operand2_type& /*operand2*/) {\ + return operand1_printer(str);\ +}\ +inline String FormatForComparisonFailureMessage(\ + const operand2_type::value_type* GTEST_CREF_WORKAROUND_ str, \ + const operand2_type& /*operand2*/) {\ + return operand1_printer(str);\ +} + +GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted) +#if GTEST_HAS_STD_WSTRING +GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted) +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_STRING +GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted) +#endif // GTEST_HAS_GLOBAL_STRING +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted) +#endif // GTEST_HAS_GLOBAL_WSTRING + +#undef GTEST_FORMAT_IMPL_ + +// The next four overloads handle the case where the operand being +// printed is a char/wchar_t pointer and the other operand is not a +// string/wstring object. In such cases, we just print the operand as +// a pointer to be safe. +#define GTEST_FORMAT_CHAR_PTR_IMPL_(CharType) \ + template \ + String FormatForComparisonFailureMessage(CharType* GTEST_CREF_WORKAROUND_ p, \ + const T&) { \ + return PrintToString(static_cast(p)); \ + } + +GTEST_FORMAT_CHAR_PTR_IMPL_(char) +GTEST_FORMAT_CHAR_PTR_IMPL_(const char) +GTEST_FORMAT_CHAR_PTR_IMPL_(wchar_t) +GTEST_FORMAT_CHAR_PTR_IMPL_(const wchar_t) + +#undef GTEST_FORMAT_CHAR_PTR_IMPL_ + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +GTEST_API_ AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const String& expected_value, + const String& actual_value, + bool ignoring_case); + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +GTEST_API_ String GetBoolAssertionFailureMessage( + const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value); + +// This template class represents an IEEE floating-point number +// (either single-precision or double-precision, depending on the +// template parameters). +// +// The purpose of this class is to do more sophisticated number +// comparison. (Due to round-off error, etc, it's very unlikely that +// two floating-points will be equal exactly. Hence a naive +// comparison by the == operation often doesn't work.) +// +// Format of IEEE floating-point: +// +// The most-significant bit being the leftmost, an IEEE +// floating-point looks like +// +// sign_bit exponent_bits fraction_bits +// +// Here, sign_bit is a single bit that designates the sign of the +// number. +// +// For float, there are 8 exponent bits and 23 fraction bits. +// +// For double, there are 11 exponent bits and 52 fraction bits. +// +// More details can be found at +// http://en.wikipedia.org/wiki/IEEE_floating-point_standard. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +template +class FloatingPoint { + public: + // Defines the unsigned integer type that has the same size as the + // floating point number. + typedef typename TypeWithSize::UInt Bits; + + // Constants. + + // # of bits in a number. + static const size_t kBitCount = 8*sizeof(RawType); + + // # of fraction bits in a number. + static const size_t kFractionBitCount = + std::numeric_limits::digits - 1; + + // # of exponent bits in a number. + static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; + + // The mask for the sign bit. + static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); + + // The mask for the fraction bits. + static const Bits kFractionBitMask = + ~static_cast(0) >> (kExponentBitCount + 1); + + // The mask for the exponent bits. + static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); + + // How many ULP's (Units in the Last Place) we want to tolerate when + // comparing two numbers. The larger the value, the more error we + // allow. A 0 value means that two numbers must be exactly the same + // to be considered equal. + // + // The maximum error of a single floating-point operation is 0.5 + // units in the last place. On Intel CPU's, all floating-point + // calculations are done with 80-bit precision, while double has 64 + // bits. Therefore, 4 should be enough for ordinary use. + // + // See the following article for more details on ULP: + // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm. + static const size_t kMaxUlps = 4; + + // Constructs a FloatingPoint from a raw floating-point number. + // + // On an Intel CPU, passing a non-normalized NAN (Not a Number) + // around may change its bits, although the new value is guaranteed + // to be also a NAN. Therefore, don't expect this constructor to + // preserve the bits in x when x is a NAN. + explicit FloatingPoint(const RawType& x) { u_.value_ = x; } + + // Static methods + + // Reinterprets a bit pattern as a floating-point number. + // + // This function is needed to test the AlmostEquals() method. + static RawType ReinterpretBits(const Bits bits) { + FloatingPoint fp(0); + fp.u_.bits_ = bits; + return fp.u_.value_; + } + + // Returns the floating-point number that represent positive infinity. + static RawType Infinity() { + return ReinterpretBits(kExponentBitMask); + } + + // Non-static methods + + // Returns the bits that represents this number. + const Bits &bits() const { return u_.bits_; } + + // Returns the exponent bits of this number. + Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } + + // Returns the fraction bits of this number. + Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } + + // Returns the sign bit of this number. + Bits sign_bit() const { return kSignBitMask & u_.bits_; } + + // Returns true iff this is NAN (not a number). + bool is_nan() const { + // It's a NAN if the exponent bits are all ones and the fraction + // bits are not entirely zeros. + return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); + } + + // Returns true iff this number is at most kMaxUlps ULP's away from + // rhs. In particular, this function: + // + // - returns false if either number is (or both are) NAN. + // - treats really large numbers as almost equal to infinity. + // - thinks +0.0 and -0.0 are 0 DLP's apart. + bool AlmostEquals(const FloatingPoint& rhs) const { + // The IEEE standard says that any comparison operation involving + // a NAN must return false. + if (is_nan() || rhs.is_nan()) return false; + + return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) + <= kMaxUlps; + } + + private: + // The data type used to store the actual floating-point number. + union FloatingPointUnion { + RawType value_; // The raw floating-point number. + Bits bits_; // The bits that represent the number. + }; + + // Converts an integer from the sign-and-magnitude representation to + // the biased representation. More precisely, let N be 2 to the + // power of (kBitCount - 1), an integer x is represented by the + // unsigned number x + N. + // + // For instance, + // + // -N + 1 (the most negative number representable using + // sign-and-magnitude) is represented by 1; + // 0 is represented by N; and + // N - 1 (the biggest number representable using + // sign-and-magnitude) is represented by 2N - 1. + // + // Read http://en.wikipedia.org/wiki/Signed_number_representations + // for more details on signed number representations. + static Bits SignAndMagnitudeToBiased(const Bits &sam) { + if (kSignBitMask & sam) { + // sam represents a negative number. + return ~sam + 1; + } else { + // sam represents a positive number. + return kSignBitMask | sam; + } + } + + // Given two numbers in the sign-and-magnitude representation, + // returns the distance between them as an unsigned number. + static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, + const Bits &sam2) { + const Bits biased1 = SignAndMagnitudeToBiased(sam1); + const Bits biased2 = SignAndMagnitudeToBiased(sam2); + return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); + } + + FloatingPointUnion u_; +}; + +// Typedefs the instances of the FloatingPoint template class that we +// care to use. +typedef FloatingPoint Float; +typedef FloatingPoint Double; + +// In order to catch the mistake of putting tests that use different +// test fixture classes in the same test case, we need to assign +// unique IDs to fixture classes and compare them. The TypeId type is +// used to hold such IDs. The user should treat TypeId as an opaque +// type: the only operation allowed on TypeId values is to compare +// them for equality using the == operator. +typedef const void* TypeId; + +template +class TypeIdHelper { + public: + // dummy_ must not have a const type. Otherwise an overly eager + // compiler (e.g. MSVC 7.1 & 8.0) may try to merge + // TypeIdHelper::dummy_ for different Ts as an "optimization". + static bool dummy_; +}; + +template +bool TypeIdHelper::dummy_ = false; + +// GetTypeId() returns the ID of type T. Different values will be +// returned for different types. Calling the function twice with the +// same type argument is guaranteed to return the same ID. +template +TypeId GetTypeId() { + // The compiler is required to allocate a different + // TypeIdHelper::dummy_ variable for each T used to instantiate + // the template. Therefore, the address of dummy_ is guaranteed to + // be unique. + return &(TypeIdHelper::dummy_); +} + +// Returns the type ID of ::testing::Test. Always call this instead +// of GetTypeId< ::testing::Test>() to get the type ID of +// ::testing::Test, as the latter may give the wrong result due to a +// suspected linker bug when compiling Google Test as a Mac OS X +// framework. +GTEST_API_ TypeId GetTestTypeId(); + +// Defines the abstract factory interface that creates instances +// of a Test object. +class TestFactoryBase { + public: + virtual ~TestFactoryBase() {} + + // Creates a test instance to run. The instance is both created and destroyed + // within TestInfoImpl::Run() + virtual Test* CreateTest() = 0; + + protected: + TestFactoryBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); +}; + +// This class provides implementation of TeastFactoryBase interface. +// It is used in TEST and TEST_F macros. +template +class TestFactoryImpl : public TestFactoryBase { + public: + virtual Test* CreateTest() { return new TestClass; } +}; + +#if GTEST_OS_WINDOWS + +// Predicate-formatters for implementing the HRESULT checking macros +// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} +// We pass a long instead of HRESULT to avoid causing an +// include dependency for the HRESULT type. +GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, + long hr); // NOLINT +GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, + long hr); // NOLINT + +#endif // GTEST_OS_WINDOWS + +// Types of SetUpTestCase() and TearDownTestCase() functions. +typedef void (*SetUpTestCaseFunc)(); +typedef void (*TearDownTestCaseFunc)(); + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// type_param the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param text representation of the test's value parameter, +// or NULL if this is not a type-parameterized test. +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +GTEST_API_ TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* type_param, + const char* value_param, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory); + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// State of the definition of a type-parameterized test case. +class GTEST_API_ TypedTestCasePState { + public: + TypedTestCasePState() : registered_(false) {} + + // Adds the given test name to defined_test_names_ and return true + // if the test case hasn't been registered; otherwise aborts the + // program. + bool AddTestName(const char* file, int line, const char* case_name, + const char* test_name) { + if (registered_) { + fprintf(stderr, "%s Test %s must be defined before " + "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", + FormatFileLocation(file, line).c_str(), test_name, case_name); + fflush(stderr); + posix::Abort(); + } + defined_test_names_.insert(test_name); + return true; + } + + // Verifies that registered_tests match the test names in + // defined_test_names_; returns registered_tests if successful, or + // aborts the program otherwise. + const char* VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests); + + private: + bool registered_; + ::std::set defined_test_names_; +}; + +// Skips to the first non-space char after the first comma in 'str'; +// returns NULL if no comma is found in 'str'. +inline const char* SkipComma(const char* str) { + const char* comma = strchr(str, ','); + if (comma == NULL) { + return NULL; + } + while (IsSpace(*(++comma))) {} + return comma; +} + +// Returns the prefix of 'str' before the first comma in it; returns +// the entire string if it contains no comma. +inline String GetPrefixUntilComma(const char* str) { + const char* comma = strchr(str, ','); + return comma == NULL ? String(str) : String(str, comma - str); +} + +// TypeParameterizedTest::Register() +// registers a list of type-parameterized tests with Google Test. The +// return value is insignificant - we just need to return something +// such that we can call this function in a namespace scope. +// +// Implementation note: The GTEST_TEMPLATE_ macro declares a template +// template parameter. It's defined in gtest-type-util.h. +template +class TypeParameterizedTest { + public: + // 'index' is the index of the test in the type list 'Types' + // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, + // Types). Valid values for 'index' are [0, N - 1] where N is the + // length of Types. + static bool Register(const char* prefix, const char* case_name, + const char* test_names, int index) { + typedef typename Types::Head Type; + typedef Fixture FixtureClass; + typedef typename GTEST_BIND_(TestSel, Type) TestClass; + + // First, registers the first type-parameterized test in the type + // list. + MakeAndRegisterTestInfo( + String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/", + case_name, index).c_str(), + GetPrefixUntilComma(test_names).c_str(), + GetTypeName().c_str(), + NULL, // No value parameter. + GetTypeId(), + TestClass::SetUpTestCase, + TestClass::TearDownTestCase, + new TestFactoryImpl); + + // Next, recurses (at compile time) with the tail of the type list. + return TypeParameterizedTest + ::Register(prefix, case_name, test_names, index + 1); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTest { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/, int /*index*/) { + return true; + } +}; + +// TypeParameterizedTestCase::Register() +// registers *all combinations* of 'Tests' and 'Types' with Google +// Test. The return value is insignificant - we just need to return +// something such that we can call this function in a namespace scope. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* prefix, const char* case_name, + const char* test_names) { + typedef typename Tests::Head Head; + + // First, register the first test in 'Test' for each type in 'Types'. + TypeParameterizedTest::Register( + prefix, case_name, test_names, 0); + + // Next, recurses (at compile time) with the tail of the test list. + return TypeParameterizedTestCase + ::Register(prefix, case_name, SkipComma(test_names)); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/) { + return true; + } +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// Returns the current OS stack trace as a String. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +GTEST_API_ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test, + int skip_count); + +// Helpers for suppressing warnings on unreachable code or constant +// condition. + +// Always returns true. +GTEST_API_ bool AlwaysTrue(); + +// Always returns false. +inline bool AlwaysFalse() { return !AlwaysTrue(); } + +// Helper for suppressing false warning from Clang on a const char* +// variable declared in a conditional expression always being NULL in +// the else branch. +struct GTEST_API_ ConstCharPtr { + ConstCharPtr(const char* str) : value(str) {} + operator bool() const { return true; } + const char* value; +}; + +// A simple Linear Congruential Generator for generating random +// numbers with a uniform distribution. Unlike rand() and srand(), it +// doesn't use global state (and therefore can't interfere with user +// code). Unlike rand_r(), it's portable. An LCG isn't very random, +// but it's good enough for our purposes. +class GTEST_API_ Random { + public: + static const UInt32 kMaxRange = 1u << 31; + + explicit Random(UInt32 seed) : state_(seed) {} + + void Reseed(UInt32 seed) { state_ = seed; } + + // Generates a random number from [0, range). Crashes if 'range' is + // 0 or greater than kMaxRange. + UInt32 Generate(UInt32 range); + + private: + UInt32 state_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); +}; + +// Defining a variable of type CompileAssertTypesEqual will cause a +// compiler error iff T1 and T2 are different types. +template +struct CompileAssertTypesEqual; + +template +struct CompileAssertTypesEqual { +}; + +// Removes the reference from a type if it is a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::remove_reference, which is not widely available yet. +template +struct RemoveReference { typedef T type; }; // NOLINT +template +struct RemoveReference { typedef T type; }; // NOLINT + +// A handy wrapper around RemoveReference that works when the argument +// T depends on template parameters. +#define GTEST_REMOVE_REFERENCE_(T) \ + typename ::testing::internal::RemoveReference::type + +// Removes const from a type if it is a const type, otherwise leaves +// it unchanged. This is the same as tr1::remove_const, which is not +// widely available yet. +template +struct RemoveConst { typedef T type; }; // NOLINT +template +struct RemoveConst { typedef T type; }; // NOLINT + +// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above +// definition to fail to remove the const in 'const int[3]' and 'const +// char[3][4]'. The following specialization works around the bug. +// However, it causes trouble with GCC and thus needs to be +// conditionally compiled. +#if defined(_MSC_VER) || defined(__SUNPRO_CC) || defined(__IBMCPP__) +template +struct RemoveConst { + typedef typename RemoveConst::type type[N]; +}; +#endif + +// A handy wrapper around RemoveConst that works when the argument +// T depends on template parameters. +#define GTEST_REMOVE_CONST_(T) \ + typename ::testing::internal::RemoveConst::type + +// Turns const U&, U&, const U, and U all into U. +#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ + GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) + +// Adds reference to a type if it is not a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::add_reference, which is not widely available yet. +template +struct AddReference { typedef T& type; }; // NOLINT +template +struct AddReference { typedef T& type; }; // NOLINT + +// A handy wrapper around AddReference that works when the argument T +// depends on template parameters. +#define GTEST_ADD_REFERENCE_(T) \ + typename ::testing::internal::AddReference::type + +// Adds a reference to const on top of T as necessary. For example, +// it transforms +// +// char ==> const char& +// const char ==> const char& +// char& ==> const char& +// const char& ==> const char& +// +// The argument T must depend on some template parameters. +#define GTEST_REFERENCE_TO_CONST_(T) \ + GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) + +// ImplicitlyConvertible::value is a compile-time bool +// constant that's true iff type From can be implicitly converted to +// type To. +template +class ImplicitlyConvertible { + private: + // We need the following helper functions only for their types. + // They have no implementations. + + // MakeFrom() is an expression whose type is From. We cannot simply + // use From(), as the type From may not have a public default + // constructor. + static From MakeFrom(); + + // These two functions are overloaded. Given an expression + // Helper(x), the compiler will pick the first version if x can be + // implicitly converted to type To; otherwise it will pick the + // second version. + // + // The first version returns a value of size 1, and the second + // version returns a value of size 2. Therefore, by checking the + // size of Helper(x), which can be done at compile time, we can tell + // which version of Helper() is used, and hence whether x can be + // implicitly converted to type To. + static char Helper(To); + static char (&Helper(...))[2]; // NOLINT + + // We have to put the 'public' section after the 'private' section, + // or MSVC refuses to compile the code. + public: + // MSVC warns about implicitly converting from double to int for + // possible loss of data, so we need to temporarily disable the + // warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4244) // Temporarily disables warning 4244. + + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +# pragma warning(pop) // Restores the warning state. +#elif defined(__BORLANDC__) + // C++Builder cannot use member overload resolution during template + // instantiation. The simplest workaround is to use its C++0x type traits + // functions (C++Builder 2009 and above only). + static const bool value = __is_convertible(From, To); +#else + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +#endif // _MSV_VER +}; +template +const bool ImplicitlyConvertible::value; + +// IsAProtocolMessage::value is a compile-time bool constant that's +// true iff T is type ProtocolMessage, proto2::Message, or a subclass +// of those. +template +struct IsAProtocolMessage + : public bool_constant< + ImplicitlyConvertible::value || + ImplicitlyConvertible::value> { +}; + +// When the compiler sees expression IsContainerTest(0), if C is an +// STL-style container class, the first overload of IsContainerTest +// will be viable (since both C::iterator* and C::const_iterator* are +// valid types and NULL can be implicitly converted to them). It will +// be picked over the second overload as 'int' is a perfect match for +// the type of argument 0. If C::iterator or C::const_iterator is not +// a valid type, the first overload is not viable, and the second +// overload will be picked. Therefore, we can determine whether C is +// a container class by checking the type of IsContainerTest(0). +// The value of the expression is insignificant. +// +// Note that we look for both C::iterator and C::const_iterator. The +// reason is that C++ injects the name of a class as a member of the +// class itself (e.g. you can refer to class iterator as either +// 'iterator' or 'iterator::iterator'). If we look for C::iterator +// only, for example, we would mistakenly think that a class named +// iterator is an STL container. +// +// Also note that the simpler approach of overloading +// IsContainerTest(typename C::const_iterator*) and +// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. +typedef int IsContainer; +template +IsContainer IsContainerTest(int /* dummy */, + typename C::iterator* /* it */ = NULL, + typename C::const_iterator* /* const_it */ = NULL) { + return 0; +} + +typedef char IsNotContainer; +template +IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } + +// EnableIf::type is void when 'Cond' is true, and +// undefined when 'Cond' is false. To use SFINAE to make a function +// overload only apply when a particular expression is true, add +// "typename EnableIf::type* = 0" as the last parameter. +template struct EnableIf; +template<> struct EnableIf { typedef void type; }; // NOLINT + +// Utilities for native arrays. + +// ArrayEq() compares two k-dimensional native arrays using the +// elements' operator==, where k can be any integer >= 0. When k is +// 0, ArrayEq() degenerates into comparing a single pair of values. + +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs); + +// This generic version is used when k is 0. +template +inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } + +// This overload is used when k >= 1. +template +inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { + return internal::ArrayEq(lhs, N, rhs); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous ArrayEq() function, arrays with different sizes would +// lead to different copies of the template code. +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs) { + for (size_t i = 0; i != size; i++) { + if (!internal::ArrayEq(lhs[i], rhs[i])) + return false; + } + return true; +} + +// Finds the first element in the iterator range [begin, end) that +// equals elem. Element may be a native array type itself. +template +Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { + for (Iter it = begin; it != end; ++it) { + if (internal::ArrayEq(*it, elem)) + return it; + } + return end; +} + +// CopyArray() copies a k-dimensional native array using the elements' +// operator=, where k can be any integer >= 0. When k is 0, +// CopyArray() degenerates into copying a single value. + +template +void CopyArray(const T* from, size_t size, U* to); + +// This generic version is used when k is 0. +template +inline void CopyArray(const T& from, U* to) { *to = from; } + +// This overload is used when k >= 1. +template +inline void CopyArray(const T(&from)[N], U(*to)[N]) { + internal::CopyArray(from, N, *to); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous CopyArray() function, arrays with different sizes +// would lead to different copies of the template code. +template +void CopyArray(const T* from, size_t size, U* to) { + for (size_t i = 0; i != size; i++) { + internal::CopyArray(from[i], to + i); + } +} + +// The relation between an NativeArray object (see below) and the +// native array it represents. +enum RelationToSource { + kReference, // The NativeArray references the native array. + kCopy // The NativeArray makes a copy of the native array and + // owns the copy. +}; + +// Adapts a native array to a read-only STL-style container. Instead +// of the complete STL container concept, this adaptor only implements +// members useful for Google Mock's container matchers. New members +// should be added as needed. To simplify the implementation, we only +// support Element being a raw type (i.e. having no top-level const or +// reference modifier). It's the client's responsibility to satisfy +// this requirement. Element can be an array type itself (hence +// multi-dimensional arrays are supported). +template +class NativeArray { + public: + // STL-style container typedefs. + typedef Element value_type; + typedef Element* iterator; + typedef const Element* const_iterator; + + // Constructs from a native array. + NativeArray(const Element* array, size_t count, RelationToSource relation) { + Init(array, count, relation); + } + + // Copy constructor. + NativeArray(const NativeArray& rhs) { + Init(rhs.array_, rhs.size_, rhs.relation_to_source_); + } + + ~NativeArray() { + // Ensures that the user doesn't instantiate NativeArray with a + // const or reference type. + static_cast(StaticAssertTypeEqHelper()); + if (relation_to_source_ == kCopy) + delete[] array_; + } + + // STL-style container methods. + size_t size() const { return size_; } + const_iterator begin() const { return array_; } + const_iterator end() const { return array_ + size_; } + bool operator==(const NativeArray& rhs) const { + return size() == rhs.size() && + ArrayEq(begin(), size(), rhs.begin()); + } + + private: + // Initializes this object; makes a copy of the input array if + // 'relation' is kCopy. + void Init(const Element* array, size_t a_size, RelationToSource relation) { + if (relation == kReference) { + array_ = array; + } else { + Element* const copy = new Element[a_size]; + CopyArray(array, a_size, copy); + array_ = copy; + } + size_ = a_size; + relation_to_source_ = relation; + } + + const Element* array_; + size_t size_; + RelationToSource relation_to_source_; + + GTEST_DISALLOW_ASSIGN_(NativeArray); +}; + +} // namespace internal +} // namespace testing + +#define GTEST_MESSAGE_AT_(file, line, message, result_type) \ + ::testing::internal::AssertHelper(result_type, file, line, message) \ + = ::testing::Message() + +#define GTEST_MESSAGE_(message, result_type) \ + GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) + +#define GTEST_FATAL_FAILURE_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) + +#define GTEST_NONFATAL_FAILURE_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) + +#define GTEST_SUCCESS_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) + +// Suppresses MSVC warnings 4072 (unreachable code) for the code following +// statement if it returns or throws (or doesn't return or throw in some +// situations). +#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ + if (::testing::internal::AlwaysTrue()) { statement; } + +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::ConstCharPtr gtest_msg = "") { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (expected_exception const&) { \ + gtest_caught_expected = true; \ + } \ + catch (...) { \ + gtest_msg.value = \ + "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws a different type."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg.value = \ + "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ + fail(gtest_msg.value) + +#define GTEST_TEST_NO_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ + fail("Expected: " #statement " doesn't throw an exception.\n" \ + " Actual: it throws.") + +#define GTEST_TEST_ANY_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + bool gtest_caught_any = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + gtest_caught_any = true; \ + } \ + if (!gtest_caught_any) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ + fail("Expected: " #statement " throws an exception.\n" \ + " Actual: it doesn't.") + + +// Implements Boolean test assertions such as EXPECT_TRUE. expression can be +// either a boolean expression or an AssertionResult. text is a textual +// represenation of expression as it was passed into the EXPECT_TRUE. +#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar_ = \ + ::testing::AssertionResult(expression)) \ + ; \ + else \ + fail(::testing::internal::GetBoolAssertionFailureMessage(\ + gtest_ar_, text, #actual, #expected).c_str()) + +#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ + fail("Expected: " #statement " doesn't generate new fatal " \ + "failures in the current thread.\n" \ + " Actual: it does.") + +// Expands to the name of the class that implements the given test. +#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + test_case_name##_##test_name##_Test + +// Helper macro for defining tests. +#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ +class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ + public:\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ + private:\ + virtual void TestBody();\ + static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ +};\ +\ +::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ + ::test_info_ =\ + ::testing::internal::MakeAndRegisterTestInfo(\ + #test_case_name, #test_name, NULL, NULL, \ + (parent_id), \ + parent_class::SetUpTestCase, \ + parent_class::TearDownTestCase, \ + new ::testing::internal::TestFactoryImpl<\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ +void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for death tests. It is +// #included by gtest.h so a user doesn't need to include this +// directly. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines internal utilities needed for implementing +// death tests. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + + +#include + +namespace testing { +namespace internal { + +GTEST_DECLARE_string_(internal_run_death_test); + +// Names of the flags (needed for parsing Google Test flags). +const char kDeathTestStyleFlag[] = "death_test_style"; +const char kDeathTestUseFork[] = "death_test_use_fork"; +const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; + +#if GTEST_HAS_DEATH_TEST + +// DeathTest is a class that hides much of the complexity of the +// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method +// returns a concrete class that depends on the prevailing death test +// style, as defined by the --gtest_death_test_style and/or +// --gtest_internal_run_death_test flags. + +// In describing the results of death tests, these terms are used with +// the corresponding definitions: +// +// exit status: The integer exit information in the format specified +// by wait(2) +// exit code: The integer code passed to exit(3), _exit(2), or +// returned from main() +class GTEST_API_ DeathTest { + public: + // Create returns false if there was an error determining the + // appropriate action to take for the current death test; for example, + // if the gtest_death_test_style flag is set to an invalid value. + // The LastMessage method will return a more detailed message in that + // case. Otherwise, the DeathTest pointer pointed to by the "test" + // argument is set. If the death test should be skipped, the pointer + // is set to NULL; otherwise, it is set to the address of a new concrete + // DeathTest object that controls the execution of the current test. + static bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); + DeathTest(); + virtual ~DeathTest() { } + + // A helper class that aborts a death test when it's deleted. + class ReturnSentinel { + public: + explicit ReturnSentinel(DeathTest* test) : test_(test) { } + ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } + private: + DeathTest* const test_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); + } GTEST_ATTRIBUTE_UNUSED_; + + // An enumeration of possible roles that may be taken when a death + // test is encountered. EXECUTE means that the death test logic should + // be executed immediately. OVERSEE means that the program should prepare + // the appropriate environment for a child process to execute the death + // test, then wait for it to complete. + enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; + + // An enumeration of the three reasons that a test might be aborted. + enum AbortReason { + TEST_ENCOUNTERED_RETURN_STATEMENT, + TEST_THREW_EXCEPTION, + TEST_DID_NOT_DIE + }; + + // Assumes one of the above roles. + virtual TestRole AssumeRole() = 0; + + // Waits for the death test to finish and returns its status. + virtual int Wait() = 0; + + // Returns true if the death test passed; that is, the test process + // exited during the test, its exit status matches a user-supplied + // predicate, and its stderr output matches a user-supplied regular + // expression. + // The user-supplied predicate may be a macro expression rather + // than a function pointer or functor, or else Wait and Passed could + // be combined. + virtual bool Passed(bool exit_status_ok) = 0; + + // Signals that the death test did not die as expected. + virtual void Abort(AbortReason reason) = 0; + + // Returns a human-readable outcome message regarding the outcome of + // the last death test. + static const char* LastMessage(); + + static void set_last_death_test_message(const String& message); + + private: + // A string containing a description of the outcome of the last death test. + static String last_death_test_message_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); +}; + +// Factory interface for death tests. May be mocked out for testing. +class DeathTestFactory { + public: + virtual ~DeathTestFactory() { } + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) = 0; +}; + +// A concrete DeathTestFactory implementation for normal use. +class DefaultDeathTestFactory : public DeathTestFactory { + public: + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); +}; + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +GTEST_API_ bool ExitedUnsuccessfully(int exit_status); + +// Traps C++ exceptions escaping statement and reports them as test +// failures. Note that trapping SEH exceptions is not implemented here. +# if GTEST_HAS_EXCEPTIONS +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (const ::std::exception& gtest_exception) { \ + fprintf(\ + stderr, \ + "\n%s: Caught std::exception-derived exception escaping the " \ + "death test statement. Exception message: %s\n", \ + ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ + gtest_exception.what()); \ + fflush(stderr); \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } catch (...) { \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } + +# else +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) + +# endif + +// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, +// ASSERT_EXIT*, and EXPECT_EXIT*. +# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + const ::testing::internal::RE& gtest_regex = (regex); \ + ::testing::internal::DeathTest* gtest_dt; \ + if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ + __FILE__, __LINE__, >est_dt)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + if (gtest_dt != NULL) { \ + ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ + gtest_dt_ptr(gtest_dt); \ + switch (gtest_dt->AssumeRole()) { \ + case ::testing::internal::DeathTest::OVERSEE_TEST: \ + if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + break; \ + case ::testing::internal::DeathTest::EXECUTE_TEST: { \ + ::testing::internal::DeathTest::ReturnSentinel \ + gtest_sentinel(gtest_dt); \ + GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ + gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ + break; \ + } \ + default: \ + break; \ + } \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ + fail(::testing::internal::DeathTest::LastMessage()) +// The symbol "fail" here expands to something into which a message +// can be streamed. + +// A class representing the parsed contents of the +// --gtest_internal_run_death_test flag, as it existed when +// RUN_ALL_TESTS was called. +class InternalRunDeathTestFlag { + public: + InternalRunDeathTestFlag(const String& a_file, + int a_line, + int an_index, + int a_write_fd) + : file_(a_file), line_(a_line), index_(an_index), + write_fd_(a_write_fd) {} + + ~InternalRunDeathTestFlag() { + if (write_fd_ >= 0) + posix::Close(write_fd_); + } + + String file() const { return file_; } + int line() const { return line_; } + int index() const { return index_; } + int write_fd() const { return write_fd_; } + + private: + String file_; + int line_; + int index_; + int write_fd_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); +}; + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); + +#else // GTEST_HAS_DEATH_TEST + +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on +// systems that support death tests. This allows one to write such a macro +// on a system that does not support death tests and be sure that it will +// compile on a death-test supporting system. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter iff EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + +namespace testing { + +// This flag controls the style of death tests. Valid values are "threadsafe", +// meaning that the death test child process will re-execute the test binary +// from the start, running only a single death test, or "fast", +// meaning that the child process will execute the test logic immediately +// after forking. +GTEST_DECLARE_string_(death_test_style); + +#if GTEST_HAS_DEATH_TEST + +// The following macros are useful for writing death tests. + +// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is +// executed: +// +// 1. It generates a warning if there is more than one active +// thread. This is because it's safe to fork() or clone() only +// when there is a single thread. +// +// 2. The parent process clone()s a sub-process and runs the death +// test in it; the sub-process exits with code 0 at the end of the +// death test, if it hasn't exited already. +// +// 3. The parent process waits for the sub-process to terminate. +// +// 4. The parent process checks the exit code and error message of +// the sub-process. +// +// Examples: +// +// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); +// for (int i = 0; i < 5; i++) { +// EXPECT_DEATH(server.ProcessRequest(i), +// "Invalid request .* in ProcessRequest()") +// << "Failed to die on request " << i); +// } +// +// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); +// +// bool KilledBySIGHUP(int exit_code) { +// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; +// } +// +// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); +// +// On the regular expressions used in death tests: +// +// On POSIX-compliant systems (*nix), we use the library, +// which uses the POSIX extended regex syntax. +// +// On other platforms (e.g. Windows), we only support a simple regex +// syntax implemented as part of Google Test. This limited +// implementation should be enough most of the time when writing +// death tests; though it lacks many features you can find in PCRE +// or POSIX extended regex syntax. For example, we don't support +// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and +// repetition count ("x{5,7}"), among others. +// +// Below is the syntax that we do support. We chose it to be a +// subset of both PCRE and POSIX extended regex, so it's easy to +// learn wherever you come from. In the following: 'A' denotes a +// literal character, period (.), or a single \\ escape sequence; +// 'x' and 'y' denote regular expressions; 'm' and 'n' are for +// natural numbers. +// +// c matches any literal character c +// \\d matches any decimal digit +// \\D matches any character that's not a decimal digit +// \\f matches \f +// \\n matches \n +// \\r matches \r +// \\s matches any ASCII whitespace, including \n +// \\S matches any character that's not a whitespace +// \\t matches \t +// \\v matches \v +// \\w matches any letter, _, or decimal digit +// \\W matches any character that \\w doesn't match +// \\c matches any literal character c, which must be a punctuation +// . matches any single character except \n +// A? matches 0 or 1 occurrences of A +// A* matches 0 or many occurrences of A +// A+ matches 1 or many occurrences of A +// ^ matches the beginning of a string (not that of each line) +// $ matches the end of a string (not that of each line) +// xy matches x followed by y +// +// If you accidentally use PCRE or POSIX extended regex features +// not implemented by us, you will get a run-time failure. In that +// case, please try to rewrite your regular expression within the +// above syntax. +// +// This implementation is *not* meant to be as highly tuned or robust +// as a compiled regex library, but should perform well enough for a +// death test, which already incurs significant overhead by launching +// a child process. +// +// Known caveats: +// +// A "threadsafe" style death test obtains the path to the test +// program from argv[0] and re-executes it in the sub-process. For +// simplicity, the current implementation doesn't search the PATH +// when launching the sub-process. This means that the user must +// invoke the test program via a path that contains at least one +// path separator (e.g. path/to/foo_test and +// /absolute/path/to/bar_test are fine, but foo_test is not). This +// is rarely a problem as people usually don't put the test binary +// directory in PATH. +// +// TODO(wan@google.com): make thread-safe death tests search the PATH. + +// Asserts that a given statement causes the program to exit, with an +// integer exit status that satisfies predicate, and emitting error output +// that matches regex. +# define ASSERT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) + +// Like ASSERT_EXIT, but continues on to successive tests in the +// test case, if any: +# define EXPECT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) + +// Asserts that a given statement causes the program to exit, either by +// explicitly exiting with a nonzero exit code or being killed by a +// signal, and emitting error output that matches regex. +# define ASSERT_DEATH(statement, regex) \ + ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Like ASSERT_DEATH, but continues on to successive tests in the +// test case, if any: +# define EXPECT_DEATH(statement, regex) \ + EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: + +// Tests that an exit code describes a normal exit with a given exit code. +class GTEST_API_ ExitedWithCode { + public: + explicit ExitedWithCode(int exit_code); + bool operator()(int exit_status) const; + private: + // No implementation - assignment is unsupported. + void operator=(const ExitedWithCode& other); + + const int exit_code_; +}; + +# if !GTEST_OS_WINDOWS +// Tests that an exit code describes an exit due to termination by a +// given signal. +class GTEST_API_ KilledBySignal { + public: + explicit KilledBySignal(int signum); + bool operator()(int exit_status) const; + private: + const int signum_; +}; +# endif // !GTEST_OS_WINDOWS + +// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. +// The death testing framework causes this to have interesting semantics, +// since the sideeffects of the call are only visible in opt mode, and not +// in debug mode. +// +// In practice, this can be used to test functions that utilize the +// LOG(DFATAL) macro using the following style: +// +// int DieInDebugOr12(int* sideeffect) { +// if (sideeffect) { +// *sideeffect = 12; +// } +// LOG(DFATAL) << "death"; +// return 12; +// } +// +// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { +// int sideeffect = 0; +// // Only asserts in dbg. +// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); +// +// #ifdef NDEBUG +// // opt-mode has sideeffect visible. +// EXPECT_EQ(12, sideeffect); +// #else +// // dbg-mode no visible sideeffect. +// EXPECT_EQ(0, sideeffect); +// #endif +// } +// +// This will assert that DieInDebugReturn12InOpt() crashes in debug +// mode, usually due to a DCHECK or LOG(DFATAL), but returns the +// appropriate fallback value (12 in this case) in opt mode. If you +// need to test that a function has appropriate side-effects in opt +// mode, include assertions against the side-effects. A general +// pattern for this is: +// +// EXPECT_DEBUG_DEATH({ +// // Side-effects here will have an effect after this statement in +// // opt mode, but none in debug mode. +// EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); +// }, "death"); +// +# ifdef NDEBUG + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + do { statement; } while (::testing::internal::AlwaysFalse()) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + do { statement; } while (::testing::internal::AlwaysFalse()) + +# else + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + EXPECT_DEATH(statement, regex) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + ASSERT_DEATH(statement, regex) + +# endif // NDEBUG for EXPECT_DEBUG_DEATH +#endif // GTEST_HAS_DEATH_TEST + +// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and +// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if +// death tests are supported; otherwise they just issue a warning. This is +// useful when you are combining death test assertions with normal test +// assertions in one test. +#if GTEST_HAS_DEATH_TEST +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + EXPECT_DEATH(statement, regex) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + ASSERT_DEATH(statement, regex) +#else +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) +#endif + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the Message class. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! + +#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ + +#include + + +namespace testing { + +// The Message class works like an ostream repeater. +// +// Typical usage: +// +// 1. You stream a bunch of values to a Message object. +// It will remember the text in a stringstream. +// 2. Then you stream the Message object to an ostream. +// This causes the text in the Message to be streamed +// to the ostream. +// +// For example; +// +// testing::Message foo; +// foo << 1 << " != " << 2; +// std::cout << foo; +// +// will print "1 != 2". +// +// Message is not intended to be inherited from. In particular, its +// destructor is not virtual. +// +// Note that stringstream behaves differently in gcc and in MSVC. You +// can stream a NULL char pointer to it in the former, but not in the +// latter (it causes an access violation if you do). The Message +// class hides this difference by treating a NULL char pointer as +// "(null)". +class GTEST_API_ Message { + private: + // The type of basic IO manipulators (endl, ends, and flush) for + // narrow streams. + typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); + + public: + // Constructs an empty Message. + // We allocate the stringstream separately because otherwise each use of + // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's + // stack frame leading to huge stack frames in some cases; gcc does not reuse + // the stack space. + Message() : ss_(new ::std::stringstream) { + // By default, we want there to be enough precision when printing + // a double to a Message. + *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); + } + + // Copy constructor. + Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT + *ss_ << msg.GetString(); + } + + // Constructs a Message from a C-string. + explicit Message(const char* str) : ss_(new ::std::stringstream) { + *ss_ << str; + } + +#if GTEST_OS_SYMBIAN + // Streams a value (either a pointer or not) to this object. + template + inline Message& operator <<(const T& value) { + StreamHelper(typename internal::is_pointer::type(), value); + return *this; + } +#else + // Streams a non-pointer value to this object. + template + inline Message& operator <<(const T& val) { + ::GTestStreamToHelper(ss_.get(), val); + return *this; + } + + // Streams a pointer value to this object. + // + // This function is an overload of the previous one. When you + // stream a pointer to a Message, this definition will be used as it + // is more specialized. (The C++ Standard, section + // [temp.func.order].) If you stream a non-pointer, then the + // previous definition will be used. + // + // The reason for this overload is that streaming a NULL pointer to + // ostream is undefined behavior. Depending on the compiler, you + // may get "0", "(nil)", "(null)", or an access violation. To + // ensure consistent result across compilers, we always treat NULL + // as "(null)". + template + inline Message& operator <<(T* const& pointer) { // NOLINT + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + ::GTestStreamToHelper(ss_.get(), pointer); + } + return *this; + } +#endif // GTEST_OS_SYMBIAN + + // Since the basic IO manipulators are overloaded for both narrow + // and wide streams, we have to provide this specialized definition + // of operator <<, even though its body is the same as the + // templatized version above. Without this definition, streaming + // endl or other basic IO manipulators to Message will confuse the + // compiler. + Message& operator <<(BasicNarrowIoManip val) { + *ss_ << val; + return *this; + } + + // Instead of 1/0, we want to see true/false for bool values. + Message& operator <<(bool b) { + return *this << (b ? "true" : "false"); + } + + // These two overloads allow streaming a wide C string to a Message + // using the UTF-8 encoding. + Message& operator <<(const wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); + } + Message& operator <<(wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); + } + +#if GTEST_HAS_STD_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::std::wstring& wstr); +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::wstring& wstr); +#endif // GTEST_HAS_GLOBAL_WSTRING + + // Gets the text streamed to this object so far as a String. + // Each '\0' character in the buffer is replaced with "\\0". + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::String GetString() const { + return internal::StringStreamToString(ss_.get()); + } + + private: + +#if GTEST_OS_SYMBIAN + // These are needed as the Nokia Symbian Compiler cannot decide between + // const T& and const T* in a function template. The Nokia compiler _can_ + // decide between class template specializations for T and T*, so a + // tr1::type_traits-like is_pointer works, and we can overload on that. + template + inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) { + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + ::GTestStreamToHelper(ss_.get(), pointer); + } + } + template + inline void StreamHelper(internal::false_type /*dummy*/, const T& value) { + ::GTestStreamToHelper(ss_.get(), value); + } +#endif // GTEST_OS_SYMBIAN + + // We'll hold the text streamed to this object here. + const internal::scoped_ptr< ::std::stringstream> ss_; + + // We declare (but don't implement) this to prevent the compiler + // from implementing the assignment operator. + void operator=(const Message&); +}; + +// Streams a Message to an ostream. +inline std::ostream& operator <<(std::ostream& os, const Message& sb) { + return os << sb.GetString(); +} + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +// This file was GENERATED by command: +// pump.py gtest-param-test.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: vladl@google.com (Vlad Losev) +// +// Macros and functions for implementing parameterized tests +// in Google C++ Testing Framework (Google Test) +// +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ + + +// Value-parameterized tests allow you to test your code with different +// parameters without writing multiple copies of the same test. +// +// Here is how you use value-parameterized tests: + +#if 0 + +// To write value-parameterized tests, first you should define a fixture +// class. It is usually derived from testing::TestWithParam (see below for +// another inheritance scheme that's sometimes useful in more complicated +// class hierarchies), where the type of your parameter values. +// TestWithParam is itself derived from testing::Test. T can be any +// copyable type. If it's a raw pointer, you are responsible for managing the +// lifespan of the pointed values. + +class FooTest : public ::testing::TestWithParam { + // You can implement all the usual class fixture members here. +}; + +// Then, use the TEST_P macro to define as many parameterized tests +// for this fixture as you want. The _P suffix is for "parameterized" +// or "pattern", whichever you prefer to think. + +TEST_P(FooTest, DoesBlah) { + // Inside a test, access the test parameter with the GetParam() method + // of the TestWithParam class: + EXPECT_TRUE(foo.Blah(GetParam())); + ... +} + +TEST_P(FooTest, HasBlahBlah) { + ... +} + +// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test +// case with any set of parameters you want. Google Test defines a number +// of functions for generating test parameters. They return what we call +// (surprise!) parameter generators. Here is a summary of them, which +// are all in the testing namespace: +// +// +// Range(begin, end [, step]) - Yields values {begin, begin+step, +// begin+step+step, ...}. The values do not +// include end. step defaults to 1. +// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. +// ValuesIn(container) - Yields values from a C-style array, an STL +// ValuesIn(begin,end) container, or an iterator range [begin, end). +// Bool() - Yields sequence {false, true}. +// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product +// for the math savvy) of the values generated +// by the N generators. +// +// For more details, see comments at the definitions of these functions below +// in this file. +// +// The following statement will instantiate tests from the FooTest test case +// each with parameter values "meeny", "miny", and "moe". + +INSTANTIATE_TEST_CASE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); + +// To distinguish different instances of the pattern, (yes, you +// can instantiate it more then once) the first argument to the +// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the +// actual test case name. Remember to pick unique prefixes for different +// instantiations. The tests from the instantiation above will have +// these names: +// +// * InstantiationName/FooTest.DoesBlah/0 for "meeny" +// * InstantiationName/FooTest.DoesBlah/1 for "miny" +// * InstantiationName/FooTest.DoesBlah/2 for "moe" +// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" +// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" +// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" +// +// You can use these names in --gtest_filter. +// +// This statement will instantiate all tests from FooTest again, each +// with parameter values "cat" and "dog": + +const char* pets[] = {"cat", "dog"}; +INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); + +// The tests from the instantiation above will have these names: +// +// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" +// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" +// +// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests +// in the given test case, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_CASE_P statement. +// +// Please also note that generator expressions (including parameters to the +// generators) are evaluated in InitGoogleTest(), after main() has started. +// This allows the user on one hand, to adjust generator parameters in order +// to dynamically determine a set of tests to run and on the other hand, +// give the user a chance to inspect the generated tests with Google Test +// reflection API before RUN_ALL_TESTS() is executed. +// +// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc +// for more examples. +// +// In the future, we plan to publish the API for defining new parameter +// generators. But for now this interface remains part of the internal +// implementation and is subject to change. +// +// +// A parameterized test fixture must be derived from testing::Test and from +// testing::WithParamInterface, where T is the type of the parameter +// values. Inheriting from TestWithParam satisfies that requirement because +// TestWithParam inherits from both Test and WithParamInterface. In more +// complicated hierarchies, however, it is occasionally useful to inherit +// separately from Test and WithParamInterface. For example: + +class BaseTest : public ::testing::Test { + // You can inherit all the usual members for a non-parameterized test + // fixture here. +}; + +class DerivedTest : public BaseTest, public ::testing::WithParamInterface { + // The usual test fixture members go here too. +}; + +TEST_F(BaseTest, HasFoo) { + // This is an ordinary non-parameterized test. +} + +TEST_P(DerivedTest, DoesBlah) { + // GetParam works just the same here as if you inherit from TestWithParam. + EXPECT_TRUE(foo.Blah(GetParam())); +} + +#endif // 0 + + +#if !GTEST_OS_SYMBIAN +# include +#endif + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ + +#include +#include +#include + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +// Copyright 2003 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Authors: Dan Egnor (egnor@google.com) +// +// A "smart" pointer type with reference tracking. Every pointer to a +// particular object is kept on a circular linked list. When the last pointer +// to an object is destroyed or reassigned, the object is deleted. +// +// Used properly, this deletes the object when the last reference goes away. +// There are several caveats: +// - Like all reference counting schemes, cycles lead to leaks. +// - Each smart pointer is actually two pointers (8 bytes instead of 4). +// - Every time a pointer is assigned, the entire list of pointers to that +// object is traversed. This class is therefore NOT SUITABLE when there +// will often be more than two or three pointers to a particular object. +// - References are only tracked as long as linked_ptr<> objects are copied. +// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS +// will happen (double deletion). +// +// A good use of this class is storing object references in STL containers. +// You can safely put linked_ptr<> in a vector<>. +// Other uses may not be as good. +// +// Note: If you use an incomplete type with linked_ptr<>, the class +// *containing* linked_ptr<> must have a constructor and destructor (even +// if they do nothing!). +// +// Bill Gibbons suggested we use something like this. +// +// Thread Safety: +// Unlike other linked_ptr implementations, in this implementation +// a linked_ptr object is thread-safe in the sense that: +// - it's safe to copy linked_ptr objects concurrently, +// - it's safe to copy *from* a linked_ptr and read its underlying +// raw pointer (e.g. via get()) concurrently, and +// - it's safe to write to two linked_ptrs that point to the same +// shared object concurrently. +// TODO(wan@google.com): rename this to safe_linked_ptr to avoid +// confusion with normal linked_ptr. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ + +#include +#include + + +namespace testing { +namespace internal { + +// Protects copying of all linked_ptr objects. +GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// This is used internally by all instances of linked_ptr<>. It needs to be +// a non-template class because different types of linked_ptr<> can refer to +// the same object (linked_ptr(obj) vs linked_ptr(obj)). +// So, it needs to be possible for different types of linked_ptr to participate +// in the same circular linked list, so we need a single class type here. +// +// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. +class linked_ptr_internal { + public: + // Create a new circle that includes only this instance. + void join_new() { + next_ = this; + } + + // Many linked_ptr operations may change p.link_ for some linked_ptr + // variable p in the same circle as this object. Therefore we need + // to prevent two such operations from occurring concurrently. + // + // Note that different types of linked_ptr objects can coexist in a + // circle (e.g. linked_ptr, linked_ptr, and + // linked_ptr). Therefore we must use a single mutex to + // protect all linked_ptr objects. This can create serious + // contention in production code, but is acceptable in a testing + // framework. + + // Join an existing circle. + // L < g_linked_ptr_mutex + void join(linked_ptr_internal const* ptr) { + MutexLock lock(&g_linked_ptr_mutex); + + linked_ptr_internal const* p = ptr; + while (p->next_ != ptr) p = p->next_; + p->next_ = this; + next_ = ptr; + } + + // Leave whatever circle we're part of. Returns true if we were the + // last member of the circle. Once this is done, you can join() another. + // L < g_linked_ptr_mutex + bool depart() { + MutexLock lock(&g_linked_ptr_mutex); + + if (next_ == this) return true; + linked_ptr_internal const* p = next_; + while (p->next_ != this) p = p->next_; + p->next_ = next_; + return false; + } + + private: + mutable linked_ptr_internal const* next_; +}; + +template +class linked_ptr { + public: + typedef T element_type; + + // Take over ownership of a raw pointer. This should happen as soon as + // possible after the object is created. + explicit linked_ptr(T* ptr = NULL) { capture(ptr); } + ~linked_ptr() { depart(); } + + // Copy an existing linked_ptr<>, adding ourselves to the list of references. + template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } + linked_ptr(linked_ptr const& ptr) { // NOLINT + assert(&ptr != this); + copy(&ptr); + } + + // Assignment releases the old value and acquires the new. + template linked_ptr& operator=(linked_ptr const& ptr) { + depart(); + copy(&ptr); + return *this; + } + + linked_ptr& operator=(linked_ptr const& ptr) { + if (&ptr != this) { + depart(); + copy(&ptr); + } + return *this; + } + + // Smart pointer members. + void reset(T* ptr = NULL) { + depart(); + capture(ptr); + } + T* get() const { return value_; } + T* operator->() const { return value_; } + T& operator*() const { return *value_; } + + bool operator==(T* p) const { return value_ == p; } + bool operator!=(T* p) const { return value_ != p; } + template + bool operator==(linked_ptr const& ptr) const { + return value_ == ptr.get(); + } + template + bool operator!=(linked_ptr const& ptr) const { + return value_ != ptr.get(); + } + + private: + template + friend class linked_ptr; + + T* value_; + linked_ptr_internal link_; + + void depart() { + if (link_.depart()) delete value_; + } + + void capture(T* ptr) { + value_ = ptr; + link_.join_new(); + } + + template void copy(linked_ptr const* ptr) { + value_ = ptr->get(); + if (value_) + link_.join(&ptr->link_); + else + link_.join_new(); + } +}; + +template inline +bool operator==(T* ptr, const linked_ptr& x) { + return ptr == x.get(); +} + +template inline +bool operator!=(T* ptr, const linked_ptr& x) { + return ptr != x.get(); +} + +// A function to convert T* into linked_ptr +// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation +// for linked_ptr >(new FooBarBaz(arg)) +template +linked_ptr make_linked_ptr(T* ptr) { + return linked_ptr(ptr); +} + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// A user can teach this function how to print a class type T by +// defining either operator<<() or PrintTo() in the namespace that +// defines T. More specifically, the FIRST defined function in the +// following list will be used (assuming T is defined in namespace +// foo): +// +// 1. foo::PrintTo(const T&, ostream*) +// 2. operator<<(ostream&, const T&) defined in either foo or the +// global namespace. +// +// If none of the above is defined, it will print the debug string of +// the value if it is a protocol buffer, or print the raw bytes in the +// value otherwise. +// +// To aid debugging: when T is a reference type, the address of the +// value is also printed; when T is a (const) char pointer, both the +// pointer value and the NUL-terminated string it points to are +// printed. +// +// We also provide some convenient wrappers: +// +// // Prints a value to a string. For a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// std::string ::testing::PrintToString(const T& value); +// +// // Prints a value tersely: for a reference type, the referenced +// // value (but not the address) is printed; for a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// void ::testing::internal::UniversalTersePrint(const T& value, ostream*); +// +// // Prints value using the type inferred by the compiler. The difference +// // from UniversalTersePrint() is that this function prints both the +// // pointer and the NUL-terminated string for a (const or not) char pointer. +// void ::testing::internal::UniversalPrint(const T& value, ostream*); +// +// // Prints the fields of a tuple tersely to a string vector, one +// // element for each field. Tuple support must be enabled in +// // gtest-port.h. +// std::vector UniversalTersePrintTupleFieldsToStrings( +// const Tuple& value); +// +// Known limitation: +// +// The print primitives print the elements of an STL-style container +// using the compiler-inferred type of *iter where iter is a +// const_iterator of the container. When const_iterator is an input +// iterator but not a forward iterator, this inferred type may not +// match value_type, and the print output may be incorrect. In +// practice, this is rarely a problem as for most containers +// const_iterator is a forward iterator. We'll fix this if there's an +// actual need for it. Note that this fix cannot rely on value_type +// being defined as many user-defined container types don't have +// value_type. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ + +#include // NOLINT +#include +#include +#include +#include + +namespace testing { + +// Definitions in the 'internal' and 'internal2' name spaces are +// subject to change without notice. DO NOT USE THEM IN USER CODE! +namespace internal2 { + +// Prints the given number of bytes in the given object to the given +// ostream. +GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, + size_t count, + ::std::ostream* os); + +// For selecting which printer to use when a given type has neither << +// nor PrintTo(). +enum TypeKind { + kProtobuf, // a protobuf type + kConvertibleToInteger, // a type implicitly convertible to BiggestInt + // (e.g. a named or unnamed enum type) + kOtherType // anything else +}; + +// TypeWithoutFormatter::PrintValue(value, os) is called +// by the universal printer to print a value of type T when neither +// operator<< nor PrintTo() is defined for T, where kTypeKind is the +// "kind" of T as defined by enum TypeKind. +template +class TypeWithoutFormatter { + public: + // This default version is called when kTypeKind is kOtherType. + static void PrintValue(const T& value, ::std::ostream* os) { + PrintBytesInObjectTo(reinterpret_cast(&value), + sizeof(value), os); + } +}; + +// We print a protobuf using its ShortDebugString() when the string +// doesn't exceed this many characters; otherwise we print it using +// DebugString() for better readability. +const size_t kProtobufOneLinerMaxLength = 50; + +template +class TypeWithoutFormatter { + public: + static void PrintValue(const T& value, ::std::ostream* os) { + const ::testing::internal::string short_str = value.ShortDebugString(); + const ::testing::internal::string pretty_str = + short_str.length() <= kProtobufOneLinerMaxLength ? + short_str : ("\n" + value.DebugString()); + *os << ("<" + pretty_str + ">"); + } +}; + +template +class TypeWithoutFormatter { + public: + // Since T has no << operator or PrintTo() but can be implicitly + // converted to BiggestInt, we print it as a BiggestInt. + // + // Most likely T is an enum type (either named or unnamed), in which + // case printing it as an integer is the desired behavior. In case + // T is not an enum, printing it as an integer is the best we can do + // given that it has no user-defined printer. + static void PrintValue(const T& value, ::std::ostream* os) { + const internal::BiggestInt kBigInt = value; + *os << kBigInt; + } +}; + +// Prints the given value to the given ostream. If the value is a +// protocol message, its debug string is printed; if it's an enum or +// of a type implicitly convertible to BiggestInt, it's printed as an +// integer; otherwise the bytes in the value are printed. This is +// what UniversalPrinter::Print() does when it knows nothing about +// type T and T has neither << operator nor PrintTo(). +// +// A user can override this behavior for a class type Foo by defining +// a << operator in the namespace where Foo is defined. +// +// We put this operator in namespace 'internal2' instead of 'internal' +// to simplify the implementation, as much code in 'internal' needs to +// use << in STL, which would conflict with our own << were it defined +// in 'internal'. +// +// Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If +// we define it to take an std::ostream instead, we'll get an +// "ambiguous overloads" compiler error when trying to print a type +// Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether +// operator<<(std::ostream&, const T&) or +// operator<<(std::basic_stream, const Foo&) is more +// specific. +template +::std::basic_ostream& operator<<( + ::std::basic_ostream& os, const T& x) { + TypeWithoutFormatter::value ? kProtobuf : + internal::ImplicitlyConvertible::value ? + kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); + return os; +} + +} // namespace internal2 +} // namespace testing + +// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up +// magic needed for implementing UniversalPrinter won't work. +namespace testing_internal { + +// Used to print a value that is not an STL-style container when the +// user doesn't define PrintTo() for it. +template +void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { + // With the following statement, during unqualified name lookup, + // testing::internal2::operator<< appears as if it was declared in + // the nearest enclosing namespace that contains both + // ::testing_internal and ::testing::internal2, i.e. the global + // namespace. For more details, refer to the C++ Standard section + // 7.3.4-1 [namespace.udir]. This allows us to fall back onto + // testing::internal2::operator<< in case T doesn't come with a << + // operator. + // + // We cannot write 'using ::testing::internal2::operator<<;', which + // gcc 3.3 fails to compile due to a compiler bug. + using namespace ::testing::internal2; // NOLINT + + // Assuming T is defined in namespace foo, in the next statement, + // the compiler will consider all of: + // + // 1. foo::operator<< (thanks to Koenig look-up), + // 2. ::operator<< (as the current namespace is enclosed in ::), + // 3. testing::internal2::operator<< (thanks to the using statement above). + // + // The operator<< whose type matches T best will be picked. + // + // We deliberately allow #2 to be a candidate, as sometimes it's + // impossible to define #1 (e.g. when foo is ::std, defining + // anything in it is undefined behavior unless you are a compiler + // vendor.). + *os << value; +} + +} // namespace testing_internal + +namespace testing { +namespace internal { + +// UniversalPrinter::Print(value, ostream_ptr) prints the given +// value to the given ostream. The caller must ensure that +// 'ostream_ptr' is not NULL, or the behavior is undefined. +// +// We define UniversalPrinter as a class template (as opposed to a +// function template), as we need to partially specialize it for +// reference types, which cannot be done with function templates. +template +class UniversalPrinter; + +template +void UniversalPrint(const T& value, ::std::ostream* os); + +// Used to print an STL-style container when the user doesn't define +// a PrintTo() for it. +template +void DefaultPrintTo(IsContainer /* dummy */, + false_type /* is not a pointer */, + const C& container, ::std::ostream* os) { + const size_t kMaxCount = 32; // The maximum number of elements to print. + *os << '{'; + size_t count = 0; + for (typename C::const_iterator it = container.begin(); + it != container.end(); ++it, ++count) { + if (count > 0) { + *os << ','; + if (count == kMaxCount) { // Enough has been printed. + *os << " ..."; + break; + } + } + *os << ' '; + // We cannot call PrintTo(*it, os) here as PrintTo() doesn't + // handle *it being a native array. + internal::UniversalPrint(*it, os); + } + + if (count > 0) { + *os << ' '; + } + *os << '}'; +} + +// Used to print a pointer that is neither a char pointer nor a member +// pointer, when the user doesn't define PrintTo() for it. (A member +// variable pointer or member function pointer doesn't really point to +// a location in the address space. Their representation is +// implementation-defined. Therefore they will be printed as raw +// bytes.) +template +void DefaultPrintTo(IsNotContainer /* dummy */, + true_type /* is a pointer */, + T* p, ::std::ostream* os) { + if (p == NULL) { + *os << "NULL"; + } else { + // C++ doesn't allow casting from a function pointer to any object + // pointer. + // + // IsTrue() silences warnings: "Condition is always true", + // "unreachable code". + if (IsTrue(ImplicitlyConvertible::value)) { + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. However, we cannot cast it to const void* directly, + // even using reinterpret_cast, as earlier versions of gcc + // (e.g. 3.4.5) cannot compile the cast when p is a function + // pointer. Casting to UInt64 first solves the problem. + *os << reinterpret_cast( + reinterpret_cast(p)); + } + } +} + +// Used to print a non-container, non-pointer value when the user +// doesn't define PrintTo() for it. +template +void DefaultPrintTo(IsNotContainer /* dummy */, + false_type /* is not a pointer */, + const T& value, ::std::ostream* os) { + ::testing_internal::DefaultPrintNonContainerTo(value, os); +} + +// Prints the given value using the << operator if it has one; +// otherwise prints the bytes in it. This is what +// UniversalPrinter::Print() does when PrintTo() is not specialized +// or overloaded for type T. +// +// A user can override this behavior for a class type Foo by defining +// an overload of PrintTo() in the namespace where Foo is defined. We +// give the user this option as sometimes defining a << operator for +// Foo is not desirable (e.g. the coding style may prevent doing it, +// or there is already a << operator but it doesn't do what the user +// wants). +template +void PrintTo(const T& value, ::std::ostream* os) { + // DefaultPrintTo() is overloaded. The type of its first two + // arguments determine which version will be picked. If T is an + // STL-style container, the version for container will be called; if + // T is a pointer, the pointer version will be called; otherwise the + // generic version will be called. + // + // Note that we check for container types here, prior to we check + // for protocol message types in our operator<<. The rationale is: + // + // For protocol messages, we want to give people a chance to + // override Google Mock's format by defining a PrintTo() or + // operator<<. For STL containers, other formats can be + // incompatible with Google Mock's format for the container + // elements; therefore we check for container types here to ensure + // that our format is used. + // + // The second argument of DefaultPrintTo() is needed to bypass a bug + // in Symbian's C++ compiler that prevents it from picking the right + // overload between: + // + // PrintTo(const T& x, ...); + // PrintTo(T* x, ...); + DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); +} + +// The following list of PrintTo() overloads tells +// UniversalPrinter::Print() how to print standard types (built-in +// types, strings, plain arrays, and pointers). + +// Overloads for various char types. +GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); +GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); +inline void PrintTo(char c, ::std::ostream* os) { + // When printing a plain char, we always treat it as unsigned. This + // way, the output won't be affected by whether the compiler thinks + // char is signed or not. + PrintTo(static_cast(c), os); +} + +// Overloads for other simple built-in types. +inline void PrintTo(bool x, ::std::ostream* os) { + *os << (x ? "true" : "false"); +} + +// Overload for wchar_t type. +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its decimal code (except for L'\0'). +// The L'\0' char is printed as "L'\\0'". The decimal code is printed +// as signed integer when wchar_t is implemented by the compiler +// as a signed type and is printed as an unsigned integer when wchar_t +// is implemented as an unsigned type. +GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); + +// Overloads for C strings. +GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); +inline void PrintTo(char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// signed/unsigned char is often used for representing binary data, so +// we print pointers to it as void* to be safe. +inline void PrintTo(const signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(const unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// MSVC can be configured to define wchar_t as a typedef of unsigned +// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native +// type. When wchar_t is a typedef, defining an overload for const +// wchar_t* would cause unsigned short* be printed as a wide string, +// possibly causing invalid memory accesses. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Overloads for wide C strings +GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); +inline void PrintTo(wchar_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +#endif + +// Overload for C arrays. Multi-dimensional arrays are printed +// properly. + +// Prints the given number of elements in an array, without printing +// the curly braces. +template +void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { + UniversalPrint(a[0], os); + for (size_t i = 1; i != count; i++) { + *os << ", "; + UniversalPrint(a[i], os); + } +} + +// Overloads for ::string and ::std::string. +#if GTEST_HAS_GLOBAL_STRING +GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); +inline void PrintTo(const ::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); +inline void PrintTo(const ::std::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} + +// Overloads for ::wstring and ::std::wstring. +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_TR1_TUPLE +// Overload for ::std::tr1::tuple. Needed for printing function arguments, +// which are packed as tuples. + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T& t, ::std::ostream* os); + +// Overloaded PrintTo() for tuples of various arities. We support +// tuples of up-to 10 fields. The following implementation works +// regardless of whether tr1::tuple is implemented using the +// non-standard variadic template feature or not. + +inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo( + const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} +#endif // GTEST_HAS_TR1_TUPLE + +// Overload for std::pair. +template +void PrintTo(const ::std::pair& value, ::std::ostream* os) { + *os << '('; + // We cannot use UniversalPrint(value.first, os) here, as T1 may be + // a reference type. The same for printing value.second. + UniversalPrinter::Print(value.first, os); + *os << ", "; + UniversalPrinter::Print(value.second, os); + *os << ')'; +} + +// Implements printing a non-reference type T by letting the compiler +// pick the right overload of PrintTo() for T. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + // Note: we deliberately don't call this PrintTo(), as that name + // conflicts with ::testing::internal::PrintTo in the body of the + // function. + static void Print(const T& value, ::std::ostream* os) { + // By default, ::testing::internal::PrintTo() is used for printing + // the value. + // + // Thanks to Koenig look-up, if T is a class and has its own + // PrintTo() function defined in its namespace, that function will + // be visible here. Since it is more specific than the generic ones + // in ::testing::internal, it will be picked by the compiler in the + // following statement - exactly what we want. + PrintTo(value, os); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +// UniversalPrintArray(begin, len, os) prints an array of 'len' +// elements, starting at address 'begin'. +template +void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { + if (len == 0) { + *os << "{}"; + } else { + *os << "{ "; + const size_t kThreshold = 18; + const size_t kChunkSize = 8; + // If the array has more than kThreshold elements, we'll have to + // omit some details by printing only the first and the last + // kChunkSize elements. + // TODO(wan@google.com): let the user control the threshold using a flag. + if (len <= kThreshold) { + PrintRawArrayTo(begin, len, os); + } else { + PrintRawArrayTo(begin, kChunkSize, os); + *os << ", ..., "; + PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); + } + *os << " }"; + } +} +// This overload prints a (const) char array compactly. +GTEST_API_ void UniversalPrintArray(const char* begin, + size_t len, + ::std::ostream* os); + +// Implements printing an array type T[N]. +template +class UniversalPrinter { + public: + // Prints the given array, omitting some elements when there are too + // many. + static void Print(const T (&a)[N], ::std::ostream* os) { + UniversalPrintArray(a, N, os); + } +}; + +// Implements printing a reference type T&. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + static void Print(const T& value, ::std::ostream* os) { + // Prints the address of the value. We use reinterpret_cast here + // as static_cast doesn't compile when T is a function type. + *os << "@" << reinterpret_cast(&value) << " "; + + // Then prints the value itself. + UniversalPrint(value, os); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +// Prints a value tersely: for a reference type, the referenced value +// (but not the address) is printed; for a (const) char pointer, the +// NUL-terminated string (but not the pointer) is printed. +template +void UniversalTersePrint(const T& value, ::std::ostream* os) { + UniversalPrint(value, os); +} +inline void UniversalTersePrint(const char* str, ::std::ostream* os) { + if (str == NULL) { + *os << "NULL"; + } else { + UniversalPrint(string(str), os); + } +} +inline void UniversalTersePrint(char* str, ::std::ostream* os) { + UniversalTersePrint(static_cast(str), os); +} + +// Prints a value using the type inferred by the compiler. The +// difference between this and UniversalTersePrint() is that for a +// (const) char pointer, this prints both the pointer and the +// NUL-terminated string. +template +void UniversalPrint(const T& value, ::std::ostream* os) { + UniversalPrinter::Print(value, os); +} + +#if GTEST_HAS_TR1_TUPLE +typedef ::std::vector Strings; + +// This helper template allows PrintTo() for tuples and +// UniversalTersePrintTupleFieldsToStrings() to be defined by +// induction on the number of tuple fields. The idea is that +// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N +// fields in tuple t, and can be defined in terms of +// TuplePrefixPrinter. + +// The inductive case. +template +struct TuplePrefixPrinter { + // Prints the first N fields of a tuple. + template + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + TuplePrefixPrinter::PrintPrefixTo(t, os); + *os << ", "; + UniversalPrinter::type> + ::Print(::std::tr1::get(t), os); + } + + // Tersely prints the first N fields of a tuple to a string vector, + // one element for each field. + template + static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { + TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); + ::std::stringstream ss; + UniversalTersePrint(::std::tr1::get(t), &ss); + strings->push_back(ss.str()); + } +}; + +// Base cases. +template <> +struct TuplePrefixPrinter<0> { + template + static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} + + template + static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} +}; +// We have to specialize the entire TuplePrefixPrinter<> class +// template here, even though the definition of +// TersePrintPrefixToStrings() is the same as the generic version, as +// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't +// support specializing a method template of a class template. +template <> +struct TuplePrefixPrinter<1> { + template + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + UniversalPrinter::type>:: + Print(::std::tr1::get<0>(t), os); + } + + template + static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { + ::std::stringstream ss; + UniversalTersePrint(::std::tr1::get<0>(t), &ss); + strings->push_back(ss.str()); + } +}; + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T& t, ::std::ostream* os) { + *os << "("; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + PrintPrefixTo(t, os); + *os << ")"; +} + +// Prints the fields of a tuple tersely to a string vector, one +// element for each field. See the comment before +// UniversalTersePrint() for how we define "tersely". +template +Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { + Strings result; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + TersePrintPrefixToStrings(value, &result); + return result; +} +#endif // GTEST_HAS_TR1_TUPLE + +} // namespace internal + +template +::std::string PrintToString(const T& value) { + ::std::stringstream ss; + internal::UniversalTersePrint(value, &ss); + return ss.str(); +} + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ + +#if GTEST_HAS_PARAM_TEST + +namespace testing { +namespace internal { + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Outputs a message explaining invalid registration of different +// fixture class for the same test case. This may happen when +// TEST_P macro is used to define two tests with the same name +// but in different namespaces. +GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line); + +template class ParamGeneratorInterface; +template class ParamGenerator; + +// Interface for iterating over elements provided by an implementation +// of ParamGeneratorInterface. +template +class ParamIteratorInterface { + public: + virtual ~ParamIteratorInterface() {} + // A pointer to the base generator instance. + // Used only for the purposes of iterator comparison + // to make sure that two iterators belong to the same generator. + virtual const ParamGeneratorInterface* BaseGenerator() const = 0; + // Advances iterator to point to the next element + // provided by the generator. The caller is responsible + // for not calling Advance() on an iterator equal to + // BaseGenerator()->End(). + virtual void Advance() = 0; + // Clones the iterator object. Used for implementing copy semantics + // of ParamIterator. + virtual ParamIteratorInterface* Clone() const = 0; + // Dereferences the current iterator and provides (read-only) access + // to the pointed value. It is the caller's responsibility not to call + // Current() on an iterator equal to BaseGenerator()->End(). + // Used for implementing ParamGenerator::operator*(). + virtual const T* Current() const = 0; + // Determines whether the given iterator and other point to the same + // element in the sequence generated by the generator. + // Used for implementing ParamGenerator::operator==(). + virtual bool Equals(const ParamIteratorInterface& other) const = 0; +}; + +// Class iterating over elements provided by an implementation of +// ParamGeneratorInterface. It wraps ParamIteratorInterface +// and implements the const forward iterator concept. +template +class ParamIterator { + public: + typedef T value_type; + typedef const T& reference; + typedef ptrdiff_t difference_type; + + // ParamIterator assumes ownership of the impl_ pointer. + ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} + ParamIterator& operator=(const ParamIterator& other) { + if (this != &other) + impl_.reset(other.impl_->Clone()); + return *this; + } + + const T& operator*() const { return *impl_->Current(); } + const T* operator->() const { return impl_->Current(); } + // Prefix version of operator++. + ParamIterator& operator++() { + impl_->Advance(); + return *this; + } + // Postfix version of operator++. + ParamIterator operator++(int /*unused*/) { + ParamIteratorInterface* clone = impl_->Clone(); + impl_->Advance(); + return ParamIterator(clone); + } + bool operator==(const ParamIterator& other) const { + return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); + } + bool operator!=(const ParamIterator& other) const { + return !(*this == other); + } + + private: + friend class ParamGenerator; + explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} + scoped_ptr > impl_; +}; + +// ParamGeneratorInterface is the binary interface to access generators +// defined in other translation units. +template +class ParamGeneratorInterface { + public: + typedef T ParamType; + + virtual ~ParamGeneratorInterface() {} + + // Generator interface definition + virtual ParamIteratorInterface* Begin() const = 0; + virtual ParamIteratorInterface* End() const = 0; +}; + +// Wraps ParamGeneratorInterface and provides general generator syntax +// compatible with the STL Container concept. +// This class implements copy initialization semantics and the contained +// ParamGeneratorInterface instance is shared among all copies +// of the original object. This is possible because that instance is immutable. +template +class ParamGenerator { + public: + typedef ParamIterator iterator; + + explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} + ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} + + ParamGenerator& operator=(const ParamGenerator& other) { + impl_ = other.impl_; + return *this; + } + + iterator begin() const { return iterator(impl_->Begin()); } + iterator end() const { return iterator(impl_->End()); } + + private: + linked_ptr > impl_; +}; + +// Generates values from a range of two comparable values. Can be used to +// generate sequences of user-defined types that implement operator+() and +// operator<(). +// This class is used in the Range() function. +template +class RangeGenerator : public ParamGeneratorInterface { + public: + RangeGenerator(T begin, T end, IncrementT step) + : begin_(begin), end_(end), + step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} + virtual ~RangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, begin_, 0, step_); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, end_, end_index_, step_); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, T value, int index, + IncrementT step) + : base_(base), value_(value), index_(index), step_(step) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + value_ = value_ + step_; + index_++; + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const T* Current() const { return &value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const int other_index = + CheckedDowncastToActualType(&other)->index_; + return index_ == other_index; + } + + private: + Iterator(const Iterator& other) + : ParamIteratorInterface(), + base_(other.base_), value_(other.value_), index_(other.index_), + step_(other.step_) {} + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + T value_; + int index_; + const IncrementT step_; + }; // class RangeGenerator::Iterator + + static int CalculateEndIndex(const T& begin, + const T& end, + const IncrementT& step) { + int end_index = 0; + for (T i = begin; i < end; i = i + step) + end_index++; + return end_index; + } + + // No implementation - assignment is unsupported. + void operator=(const RangeGenerator& other); + + const T begin_; + const T end_; + const IncrementT step_; + // The index for the end() iterator. All the elements in the generated + // sequence are indexed (0-based) to aid iterator comparison. + const int end_index_; +}; // class RangeGenerator + + +// Generates values from a pair of STL-style iterators. Used in the +// ValuesIn() function. The elements are copied from the source range +// since the source can be located on the stack, and the generator +// is likely to persist beyond that stack frame. +template +class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { + public: + template + ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) + : container_(begin, end) {} + virtual ~ValuesInIteratorRangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, container_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, container_.end()); + } + + private: + typedef typename ::std::vector ContainerType; + + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + typename ContainerType::const_iterator iterator) + : base_(base), iterator_(iterator) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + ++iterator_; + value_.reset(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + // We need to use cached value referenced by iterator_ because *iterator_ + // can return a temporary object (and of type other then T), so just + // having "return &*iterator_;" doesn't work. + // value_ is updated here and not in Advance() because Advance() + // can advance iterator_ beyond the end of the range, and we cannot + // detect that fact. The client code, on the other hand, is + // responsible for not calling Current() on an out-of-range iterator. + virtual const T* Current() const { + if (value_.get() == NULL) + value_.reset(new T(*iterator_)); + return value_.get(); + } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + return iterator_ == + CheckedDowncastToActualType(&other)->iterator_; + } + + private: + Iterator(const Iterator& other) + // The explicit constructor call suppresses a false warning + // emitted by gcc when supplied with the -Wextra option. + : ParamIteratorInterface(), + base_(other.base_), + iterator_(other.iterator_) {} + + const ParamGeneratorInterface* const base_; + typename ContainerType::const_iterator iterator_; + // A cached value of *iterator_. We keep it here to allow access by + // pointer in the wrapping iterator's operator->(). + // value_ needs to be mutable to be accessed in Current(). + // Use of scoped_ptr helps manage cached value's lifetime, + // which is bound by the lifespan of the iterator itself. + mutable scoped_ptr value_; + }; // class ValuesInIteratorRangeGenerator::Iterator + + // No implementation - assignment is unsupported. + void operator=(const ValuesInIteratorRangeGenerator& other); + + const ContainerType container_; +}; // class ValuesInIteratorRangeGenerator + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Stores a parameter value and later creates tests parameterized with that +// value. +template +class ParameterizedTestFactory : public TestFactoryBase { + public: + typedef typename TestClass::ParamType ParamType; + explicit ParameterizedTestFactory(ParamType parameter) : + parameter_(parameter) {} + virtual Test* CreateTest() { + TestClass::SetParam(¶meter_); + return new TestClass(); + } + + private: + const ParamType parameter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactoryBase is a base class for meta-factories that create +// test factories for passing into MakeAndRegisterTestInfo function. +template +class TestMetaFactoryBase { + public: + virtual ~TestMetaFactoryBase() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactory creates test factories for passing into +// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives +// ownership of test factory pointer, same factory object cannot be passed +// into that method twice. But ParameterizedTestCaseInfo is going to call +// it for each Test/Parameter value combination. Thus it needs meta factory +// creator class. +template +class TestMetaFactory + : public TestMetaFactoryBase { + public: + typedef typename TestCase::ParamType ParamType; + + TestMetaFactory() {} + + virtual ~TestMetaFactory () { + + } + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { + return new ParameterizedTestFactory(parameter); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfoBase is a generic interface +// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase +// accumulates test information provided by TEST_P macro invocations +// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations +// and uses that information to register all resulting test instances +// in RegisterTests method. The ParameterizeTestCaseRegistry class holds +// a collection of pointers to the ParameterizedTestCaseInfo objects +// and calls RegisterTests() on each of them when asked. +class ParameterizedTestCaseInfoBase { + public: + virtual ~ParameterizedTestCaseInfoBase() {} + + // Base part of test case name for display purposes. + virtual const string& GetTestCaseName() const = 0; + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const = 0; + // UnitTest class invokes this method to register tests in this + // test case right before running them in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + virtual void RegisterTests() = 0; + + protected: + ParameterizedTestCaseInfoBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P +// macro invocations for a particular test case and generators +// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that +// test case. It registers tests with all values generated by all +// generators when asked. +template +class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { + public: + // ParamType and GeneratorCreationFunc are private types but are required + // for declarations of public methods AddTestPattern() and + // AddTestCaseInstantiation(). + typedef typename TestCase::ParamType ParamType; + // A function that returns an instance of appropriate generator type. + typedef ParamGenerator(GeneratorCreationFunc)(); + + explicit ParameterizedTestCaseInfo(const char* name) + : test_case_name_(name) {} + + // Test case base name for display purposes. + virtual const string& GetTestCaseName() const { return test_case_name_; } + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } + // TEST_P macro uses AddTestPattern() to record information + // about a single test in a LocalTestInfo structure. + // test_case_name is the base name of the test case (without invocation + // prefix). test_base_name is the name of an individual test without + // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is + // test case base name and DoBar is test base name. + void AddTestPattern(const char* test_case_name, + const char* test_base_name, + TestMetaFactoryBase* meta_factory) { + tests_.push_back(linked_ptr(new TestInfo(test_case_name, + test_base_name, + meta_factory))); + } + // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information + // about a generator. + int AddTestCaseInstantiation(const string& instantiation_name, + GeneratorCreationFunc* func, + const char* /* file */, + int /* line */) { + instantiations_.push_back(::std::make_pair(instantiation_name, func)); + return 0; // Return value used only to run this method in namespace scope. + } + // UnitTest class invokes this method to register tests in this test case + // test cases right before running tests in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + // UnitTest has a guard to prevent from calling this method more then once. + virtual void RegisterTests() { + for (typename TestInfoContainer::iterator test_it = tests_.begin(); + test_it != tests_.end(); ++test_it) { + linked_ptr test_info = *test_it; + for (typename InstantiationContainer::iterator gen_it = + instantiations_.begin(); gen_it != instantiations_.end(); + ++gen_it) { + const string& instantiation_name = gen_it->first; + ParamGenerator generator((*gen_it->second)()); + + Message test_case_name_stream; + if ( !instantiation_name.empty() ) + test_case_name_stream << instantiation_name << "/"; + test_case_name_stream << test_info->test_case_base_name; + + int i = 0; + for (typename ParamGenerator::iterator param_it = + generator.begin(); + param_it != generator.end(); ++param_it, ++i) { + Message test_name_stream; + test_name_stream << test_info->test_base_name << "/" << i; + MakeAndRegisterTestInfo( + test_case_name_stream.GetString().c_str(), + test_name_stream.GetString().c_str(), + NULL, // No type parameter. + PrintToString(*param_it).c_str(), + GetTestCaseTypeId(), + TestCase::SetUpTestCase, + TestCase::TearDownTestCase, + test_info->test_meta_factory->CreateTestFactory(*param_it)); + } // for param_it + } // for gen_it + } // for test_it + } // RegisterTests + + private: + // LocalTestInfo structure keeps information about a single test registered + // with TEST_P macro. + struct TestInfo { + TestInfo(const char* a_test_case_base_name, + const char* a_test_base_name, + TestMetaFactoryBase* a_test_meta_factory) : + test_case_base_name(a_test_case_base_name), + test_base_name(a_test_base_name), + test_meta_factory(a_test_meta_factory) {} + + const string test_case_base_name; + const string test_base_name; + const scoped_ptr > test_meta_factory; + }; + typedef ::std::vector > TestInfoContainer; + // Keeps pairs of + // received from INSTANTIATE_TEST_CASE_P macros. + typedef ::std::vector > + InstantiationContainer; + + const string test_case_name_; + TestInfoContainer tests_; + InstantiationContainer instantiations_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); +}; // class ParameterizedTestCaseInfo + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase +// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P +// macros use it to locate their corresponding ParameterizedTestCaseInfo +// descriptors. +class ParameterizedTestCaseRegistry { + public: + ParameterizedTestCaseRegistry() {} + ~ParameterizedTestCaseRegistry() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + delete *it; + } + } + + // Looks up or creates and returns a structure containing information about + // tests and instantiations of a particular test case. + template + ParameterizedTestCaseInfo* GetTestCasePatternHolder( + const char* test_case_name, + const char* file, + int line) { + ParameterizedTestCaseInfo* typed_test_info = NULL; + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + if ((*it)->GetTestCaseName() == test_case_name) { + if ((*it)->GetTestCaseTypeId() != GetTypeId()) { + // Complain about incorrect usage of Google Test facilities + // and terminate the program since we cannot guaranty correct + // test case setup and tear-down in this case. + ReportInvalidTestCaseType(test_case_name, file, line); + posix::Abort(); + } else { + // At this point we are sure that the object we found is of the same + // type we are looking for, so we downcast it to that type + // without further checks. + typed_test_info = CheckedDowncastToActualType< + ParameterizedTestCaseInfo >(*it); + } + break; + } + } + if (typed_test_info == NULL) { + typed_test_info = new ParameterizedTestCaseInfo(test_case_name); + test_case_infos_.push_back(typed_test_info); + } + return typed_test_info; + } + void RegisterTests() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + (*it)->RegisterTests(); + } + } + + private: + typedef ::std::vector TestCaseInfoContainer; + + TestCaseInfoContainer test_case_infos_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +// This file was GENERATED by command: +// pump.py gtest-param-util-generated.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently Google Test supports at most 50 arguments in Values, +// and at most 10 arguments in Combine. Please contact +// googletestframework@googlegroups.com if you need more. +// Please note that the number of arguments to Combine is limited +// by the maximum arity of the implementation of tr1::tuple which is +// currently set at 10. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end); + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]); + +template +internal::ParamGenerator ValuesIn( + const Container& container); + +namespace internal { + +// Used in the Values() function to provide polymorphic capabilities. +template +class ValueArray1 { + public: + explicit ValueArray1(T1 v1) : v1_(v1) {} + + template + operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray1& other); + + const T1 v1_; +}; + +template +class ValueArray2 { + public: + ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray2& other); + + const T1 v1_; + const T2 v2_; +}; + +template +class ValueArray3 { + public: + ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray3& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; +}; + +template +class ValueArray4 { + public: + ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray4& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; +}; + +template +class ValueArray5 { + public: + ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray5& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; +}; + +template +class ValueArray6 { + public: + ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray6& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; +}; + +template +class ValueArray7 { + public: + ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray7& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; +}; + +template +class ValueArray8 { + public: + ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray8& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; +}; + +template +class ValueArray9 { + public: + ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray9& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; +}; + +template +class ValueArray10 { + public: + ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray10& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; +}; + +template +class ValueArray11 { + public: + ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray11& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; +}; + +template +class ValueArray12 { + public: + ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray12& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; +}; + +template +class ValueArray13 { + public: + ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray13& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; +}; + +template +class ValueArray14 { + public: + ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray14& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; +}; + +template +class ValueArray15 { + public: + ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray15& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; +}; + +template +class ValueArray16 { + public: + ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray16& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; +}; + +template +class ValueArray17 { + public: + ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray17& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; +}; + +template +class ValueArray18 { + public: + ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray18& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; +}; + +template +class ValueArray19 { + public: + ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray19& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; +}; + +template +class ValueArray20 { + public: + ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray20& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; +}; + +template +class ValueArray21 { + public: + ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray21& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; +}; + +template +class ValueArray22 { + public: + ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray22& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; +}; + +template +class ValueArray23 { + public: + ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, + v23_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray23& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; +}; + +template +class ValueArray24 { + public: + ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray24& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; +}; + +template +class ValueArray25 { + public: + ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray25& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; +}; + +template +class ValueArray26 { + public: + ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray26& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; +}; + +template +class ValueArray27 { + public: + ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray27& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; +}; + +template +class ValueArray28 { + public: + ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray28& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; +}; + +template +class ValueArray29 { + public: + ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray29& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; +}; + +template +class ValueArray30 { + public: + ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray30& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; +}; + +template +class ValueArray31 { + public: + ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray31& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; +}; + +template +class ValueArray32 { + public: + ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray32& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; +}; + +template +class ValueArray33 { + public: + ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray33& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; +}; + +template +class ValueArray34 { + public: + ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray34& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; +}; + +template +class ValueArray35 { + public: + ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, + v35_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray35& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; +}; + +template +class ValueArray36 { + public: + ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray36& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; +}; + +template +class ValueArray37 { + public: + ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray37& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; +}; + +template +class ValueArray38 { + public: + ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray38& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; +}; + +template +class ValueArray39 { + public: + ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray39& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; +}; + +template +class ValueArray40 { + public: + ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray40& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; +}; + +template +class ValueArray41 { + public: + ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray41& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; +}; + +template +class ValueArray42 { + public: + ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray42& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; +}; + +template +class ValueArray43 { + public: + ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), + v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray43& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; +}; + +template +class ValueArray44 { + public: + ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), + v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), + v43_(v43), v44_(v44) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray44& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; +}; + +template +class ValueArray45 { + public: + ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), + v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray45& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; +}; + +template +class ValueArray46 { + public: + ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray46& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; +}; + +template +class ValueArray47 { + public: + ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), + v47_(v47) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, + v47_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray47& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; +}; + +template +class ValueArray48 { + public: + ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), + v46_(v46), v47_(v47), v48_(v48) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray48& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; +}; + +template +class ValueArray49 { + public: + ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, + T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_, v49_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray49& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; +}; + +template +class ValueArray50 { + public: + ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, + T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} + + template + operator ParamGenerator() const { + const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_, + v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_, + v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_, + v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_, + v48_, v49_, v50_}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray50& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; + const T50 v50_; +}; + +# if GTEST_HAS_COMBINE +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Generates values from the Cartesian product of values produced +// by the argument generators. +// +template +class CartesianProductGenerator2 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator2(const ParamGenerator& g1, + const ParamGenerator& g2) + : g1_(g1), g2_(g2) {} + virtual ~CartesianProductGenerator2() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current2_; + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + ParamType current_value_; + }; // class CartesianProductGenerator2::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator2& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; +}; // class CartesianProductGenerator2 + + +template +class CartesianProductGenerator3 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator3(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + virtual ~CartesianProductGenerator3() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current3_; + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + ParamType current_value_; + }; // class CartesianProductGenerator3::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator3& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; +}; // class CartesianProductGenerator3 + + +template +class CartesianProductGenerator4 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator4(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + virtual ~CartesianProductGenerator4() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current4_; + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + ParamType current_value_; + }; // class CartesianProductGenerator4::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator4& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; +}; // class CartesianProductGenerator4 + + +template +class CartesianProductGenerator5 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator5(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + virtual ~CartesianProductGenerator5() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current5_; + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + ParamType current_value_; + }; // class CartesianProductGenerator5::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator5& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; +}; // class CartesianProductGenerator5 + + +template +class CartesianProductGenerator6 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator6(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + virtual ~CartesianProductGenerator6() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current6_; + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + ParamType current_value_; + }; // class CartesianProductGenerator6::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator6& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; +}; // class CartesianProductGenerator6 + + +template +class CartesianProductGenerator7 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator7(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + virtual ~CartesianProductGenerator7() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current7_; + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + ParamType current_value_; + }; // class CartesianProductGenerator7::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator7& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; +}; // class CartesianProductGenerator7 + + +template +class CartesianProductGenerator8 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator8(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + virtual ~CartesianProductGenerator8() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current8_; + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + ParamType current_value_; + }; // class CartesianProductGenerator8::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator8& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; +}; // class CartesianProductGenerator8 + + +template +class CartesianProductGenerator9 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator9(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + virtual ~CartesianProductGenerator9() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current9_; + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + ParamType current_value_; + }; // class CartesianProductGenerator9::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator9& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; +}; // class CartesianProductGenerator9 + + +template +class CartesianProductGenerator10 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator10(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9, + const ParamGenerator& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + virtual ~CartesianProductGenerator10() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end(), g10_, g10_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9, + const ParamGenerator& g10, + const typename ParamGenerator::iterator& current10) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9), + begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current10_; + if (current10_ == end10_) { + current10_ = begin10_; + ++current9_; + } + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_ && + current10_ == typed_other->current10_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_), + begin10_(other.begin10_), + end10_(other.end10_), + current10_(other.current10_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_, *current10_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_ || + current10_ == end10_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + const typename ParamGenerator::iterator begin10_; + const typename ParamGenerator::iterator end10_; + typename ParamGenerator::iterator current10_; + ParamType current_value_; + }; // class CartesianProductGenerator10::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator10& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; + const ParamGenerator g10_; +}; // class CartesianProductGenerator10 + + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Helper classes providing Combine() with polymorphic features. They allow +// casting CartesianProductGeneratorN to ParamGenerator if T is +// convertible to U. +// +template +class CartesianProductHolder2 { + public: +CartesianProductHolder2(const Generator1& g1, const Generator2& g2) + : g1_(g1), g2_(g2) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator2( + static_cast >(g1_), + static_cast >(g2_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder2& other); + + const Generator1 g1_; + const Generator2 g2_; +}; // class CartesianProductHolder2 + +template +class CartesianProductHolder3 { + public: +CartesianProductHolder3(const Generator1& g1, const Generator2& g2, + const Generator3& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator3( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder3& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; +}; // class CartesianProductHolder3 + +template +class CartesianProductHolder4 { + public: +CartesianProductHolder4(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator4( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder4& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; +}; // class CartesianProductHolder4 + +template +class CartesianProductHolder5 { + public: +CartesianProductHolder5(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator5( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder5& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; +}; // class CartesianProductHolder5 + +template +class CartesianProductHolder6 { + public: +CartesianProductHolder6(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator6( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder6& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; +}; // class CartesianProductHolder6 + +template +class CartesianProductHolder7 { + public: +CartesianProductHolder7(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator7( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder7& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; +}; // class CartesianProductHolder7 + +template +class CartesianProductHolder8 { + public: +CartesianProductHolder8(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator8( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder8& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; +}; // class CartesianProductHolder8 + +template +class CartesianProductHolder9 { + public: +CartesianProductHolder9(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator9( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder9& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; +}; // class CartesianProductHolder9 + +template +class CartesianProductHolder10 { + public: +CartesianProductHolder10(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9, const Generator10& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator10( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_), + static_cast >(g10_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder10& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; + const Generator10 g10_; +}; // class CartesianProductHolder10 + +# endif // GTEST_HAS_COMBINE + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Functions producing parameter generators. +// +// Google Test uses these generators to produce parameters for value- +// parameterized tests. When a parameterized test case is instantiated +// with a particular generator, Google Test creates and runs tests +// for each element in the sequence produced by the generator. +// +// In the following sample, tests from test case FooTest are instantiated +// each three times with parameter values 3, 5, and 8: +// +// class FooTest : public TestWithParam { ... }; +// +// TEST_P(FooTest, TestThis) { +// } +// TEST_P(FooTest, TestThat) { +// } +// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); +// + +// Range() returns generators providing sequences of values in a range. +// +// Synopsis: +// Range(start, end) +// - returns a generator producing a sequence of values {start, start+1, +// start+2, ..., }. +// Range(start, end, step) +// - returns a generator producing a sequence of values {start, start+step, +// start+step+step, ..., }. +// Notes: +// * The generated sequences never include end. For example, Range(1, 5) +// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) +// returns a generator producing {1, 3, 5, 7}. +// * start and end must have the same type. That type may be any integral or +// floating-point type or a user defined type satisfying these conditions: +// * It must be assignable (have operator=() defined). +// * It must have operator+() (operator+(int-compatible type) for +// two-operand version). +// * It must have operator<() defined. +// Elements in the resulting sequences will also have that type. +// * Condition start < end must be satisfied in order for resulting sequences +// to contain any elements. +// +template +internal::ParamGenerator Range(T start, T end, IncrementT step) { + return internal::ParamGenerator( + new internal::RangeGenerator(start, end, step)); +} + +template +internal::ParamGenerator Range(T start, T end) { + return Range(start, end, 1); +} + +// ValuesIn() function allows generation of tests with parameters coming from +// a container. +// +// Synopsis: +// ValuesIn(const T (&array)[N]) +// - returns a generator producing sequences with elements from +// a C-style array. +// ValuesIn(const Container& container) +// - returns a generator producing sequences with elements from +// an STL-style container. +// ValuesIn(Iterator begin, Iterator end) +// - returns a generator producing sequences with elements from +// a range [begin, end) defined by a pair of STL-style iterators. These +// iterators can also be plain C pointers. +// +// Please note that ValuesIn copies the values from the containers +// passed in and keeps them to generate tests in RUN_ALL_TESTS(). +// +// Examples: +// +// This instantiates tests from test case StringTest +// each with C-string values of "foo", "bar", and "baz": +// +// const char* strings[] = {"foo", "bar", "baz"}; +// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// +// This instantiates tests from test case StlStringTest +// each with STL strings with values "a" and "b": +// +// ::std::vector< ::std::string> GetParameterStrings() { +// ::std::vector< ::std::string> v; +// v.push_back("a"); +// v.push_back("b"); +// return v; +// } +// +// INSTANTIATE_TEST_CASE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); +// +// +// This will also instantiate tests from CharTest +// each with parameter values 'a' and 'b': +// +// ::std::list GetParameterChars() { +// ::std::list list; +// list.push_back('a'); +// list.push_back('b'); +// return list; +// } +// ::std::list l = GetParameterChars(); +// INSTANTIATE_TEST_CASE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); +// +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end) { + typedef typename ::testing::internal::IteratorTraits + ::value_type ParamType; + return internal::ParamGenerator( + new internal::ValuesInIteratorRangeGenerator(begin, end)); +} + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]) { + return ValuesIn(array, array + N); +} + +template +internal::ParamGenerator ValuesIn( + const Container& container) { + return ValuesIn(container.begin(), container.end()); +} + +// Values() allows generating tests from explicitly specified list of +// parameters. +// +// Synopsis: +// Values(T v1, T v2, ..., T vN) +// - returns a generator producing sequences with elements v1, v2, ..., vN. +// +// For example, this instantiates tests from test case BarTest each +// with values "one", "two", and "three": +// +// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); +// +// This instantiates tests from test case BazTest each with values 1, 2, 3.5. +// The exact type of values will depend on the type of parameter in BazTest. +// +// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// +// Currently, Values() supports from 1 to 50 parameters. +// +template +internal::ValueArray1 Values(T1 v1) { + return internal::ValueArray1(v1); +} + +template +internal::ValueArray2 Values(T1 v1, T2 v2) { + return internal::ValueArray2(v1, v2); +} + +template +internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { + return internal::ValueArray3(v1, v2, v3); +} + +template +internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { + return internal::ValueArray4(v1, v2, v3, v4); +} + +template +internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5) { + return internal::ValueArray5(v1, v2, v3, v4, v5); +} + +template +internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6) { + return internal::ValueArray6(v1, v2, v3, v4, v5, v6); +} + +template +internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7) { + return internal::ValueArray7(v1, v2, v3, v4, v5, + v6, v7); +} + +template +internal::ValueArray8 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { + return internal::ValueArray8(v1, v2, v3, v4, + v5, v6, v7, v8); +} + +template +internal::ValueArray9 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { + return internal::ValueArray9(v1, v2, v3, + v4, v5, v6, v7, v8, v9); +} + +template +internal::ValueArray10 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { + return internal::ValueArray10(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10); +} + +template +internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) { + return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); +} + +template +internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) { + return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); +} + +template +internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) { + return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); +} + +template +internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { + return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14); +} + +template +internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { + return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15); +} + +template +internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16) { + return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16); +} + +template +internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17) { + return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17); +} + +template +internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18) { + return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18); +} + +template +internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { + return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); +} + +template +internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { + return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); +} + +template +internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { + return internal::ValueArray21(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); +} + +template +internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22) { + return internal::ValueArray22(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22); +} + +template +internal::ValueArray23 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23) { + return internal::ValueArray23(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23); +} + +template +internal::ValueArray24 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24) { + return internal::ValueArray24(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24); +} + +template +internal::ValueArray25 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { + return internal::ValueArray25(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25); +} + +template +internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) { + return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); +} + +template +internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) { + return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); +} + +template +internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) { + return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28); +} + +template +internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) { + return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29); +} + +template +internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { + return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30); +} + +template +internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { + return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31); +} + +template +internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32) { + return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32); +} + +template +internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33) { + return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); +} + +template +internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34) { + return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); +} + +template +internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { + return internal::ValueArray35(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); +} + +template +internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { + return internal::ValueArray36(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36); +} + +template +internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37) { + return internal::ValueArray37(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37); +} + +template +internal::ValueArray38 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38) { + return internal::ValueArray38(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, + v33, v34, v35, v36, v37, v38); +} + +template +internal::ValueArray39 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38, T39 v39) { + return internal::ValueArray39(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, + v32, v33, v34, v35, v36, v37, v38, v39); +} + +template +internal::ValueArray40 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, + T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, + T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { + return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, + v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); +} + +template +internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { + return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, + v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); +} + +template +internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) { + return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, + v42); +} + +template +internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) { + return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, + v41, v42, v43); +} + +template +internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) { + return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, + v40, v41, v42, v43, v44); +} + +template +internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { + return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, + v39, v40, v41, v42, v43, v44, v45); +} + +template +internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { + return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46); +} + +template +internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { + return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); +} + +template +internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, + T48 v48) { + return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, + v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); +} + +template +internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, + T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, + T47 v47, T48 v48, T49 v49) { + return internal::ValueArray49(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, + v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); +} + +template +internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, + T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, + T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { + return internal::ValueArray50(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, + v48, v49, v50); +} + +// Bool() allows generating tests with parameters in a set of (false, true). +// +// Synopsis: +// Bool() +// - returns a generator producing sequences with elements {false, true}. +// +// It is useful when testing code that depends on Boolean flags. Combinations +// of multiple flags can be tested when several Bool()'s are combined using +// Combine() function. +// +// In the following example all tests in the test case FlagDependentTest +// will be instantiated twice with parameters false and true. +// +// class FlagDependentTest : public testing::TestWithParam { +// virtual void SetUp() { +// external_flag = GetParam(); +// } +// } +// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); +// +inline internal::ParamGenerator Bool() { + return Values(false, true); +} + +# if GTEST_HAS_COMBINE +// Combine() allows the user to combine two or more sequences to produce +// values of a Cartesian product of those sequences' elements. +// +// Synopsis: +// Combine(gen1, gen2, ..., genN) +// - returns a generator producing sequences with elements coming from +// the Cartesian product of elements from the sequences generated by +// gen1, gen2, ..., genN. The sequence elements will have a type of +// tuple where T1, T2, ..., TN are the types +// of elements from sequences produces by gen1, gen2, ..., genN. +// +// Combine can have up to 10 arguments. This number is currently limited +// by the maximum number of elements in the tuple implementation used by Google +// Test. +// +// Example: +// +// This will instantiate tests in test case AnimalTest each one with +// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), +// tuple("dog", BLACK), and tuple("dog", WHITE): +// +// enum Color { BLACK, GRAY, WHITE }; +// class AnimalTest +// : public testing::TestWithParam > {...}; +// +// TEST_P(AnimalTest, AnimalLooksNice) {...} +// +// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); +// +// This will instantiate tests in FlagDependentTest with all variations of two +// Boolean flags: +// +// class FlagDependentTest +// : public testing::TestWithParam > { +// virtual void SetUp() { +// // Assigns external_flag_1 and external_flag_2 values from the tuple. +// tie(external_flag_1, external_flag_2) = GetParam(); +// } +// }; +// +// TEST_P(FlagDependentTest, TestFeature1) { +// // Test your code using external_flag_1 and external_flag_2 here. +// } +// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +template +internal::CartesianProductHolder2 Combine( + const Generator1& g1, const Generator2& g2) { + return internal::CartesianProductHolder2( + g1, g2); +} + +template +internal::CartesianProductHolder3 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3) { + return internal::CartesianProductHolder3( + g1, g2, g3); +} + +template +internal::CartesianProductHolder4 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4) { + return internal::CartesianProductHolder4( + g1, g2, g3, g4); +} + +template +internal::CartesianProductHolder5 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5) { + return internal::CartesianProductHolder5( + g1, g2, g3, g4, g5); +} + +template +internal::CartesianProductHolder6 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6) { + return internal::CartesianProductHolder6( + g1, g2, g3, g4, g5, g6); +} + +template +internal::CartesianProductHolder7 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7) { + return internal::CartesianProductHolder7( + g1, g2, g3, g4, g5, g6, g7); +} + +template +internal::CartesianProductHolder8 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8) { + return internal::CartesianProductHolder8( + g1, g2, g3, g4, g5, g6, g7, g8); +} + +template +internal::CartesianProductHolder9 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9) { + return internal::CartesianProductHolder9( + g1, g2, g3, g4, g5, g6, g7, g8, g9); +} + +template +internal::CartesianProductHolder10 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9, + const Generator10& g10) { + return internal::CartesianProductHolder10( + g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); +} +# endif // GTEST_HAS_COMBINE + + + +# define TEST_P(test_case_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + : public test_case_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ + virtual void TestBody(); \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ + #test_case_name, \ + #test_name, \ + new ::testing::internal::TestMetaFactory< \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ + return 0; \ + } \ + static int gtest_registering_dummy_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_case_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ + ::testing::internal::ParamGenerator \ + gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ + int gtest_##prefix##test_case_name##_dummy_ = \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ + #prefix, \ + >est_##prefix##test_case_name##_EvalGenerator_, \ + __FILE__, __LINE__) + +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Google C++ Testing Framework definitions useful in production code. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ + +// When you need to test the private or protected members of a class, +// use the FRIEND_TEST macro to declare your tests as friends of the +// class. For example: +// +// class MyClass { +// private: +// void MyMethod(); +// FRIEND_TEST(MyClassTest, MyMethod); +// }; +// +// class MyClassTest : public testing::Test { +// // ... +// }; +// +// TEST_F(MyClassTest, MyMethod) { +// // Can call MyClass::MyMethod() here. +// } + +#define FRIEND_TEST(test_case_name, test_name)\ +friend class test_case_name##_##test_name##_Test + +#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: mheule@google.com (Markus Heule) +// + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ + +#include +#include + +namespace testing { + +// A copyable object representing the result of a test part (i.e. an +// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). +// +// Don't inherit from TestPartResult as its destructor is not virtual. +class GTEST_API_ TestPartResult { + public: + // The possible outcomes of a test part (i.e. an assertion or an + // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). + enum Type { + kSuccess, // Succeeded. + kNonFatalFailure, // Failed but the test can continue. + kFatalFailure // Failed and the test should be terminated. + }; + + // C'tor. TestPartResult does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestPartResult object. + TestPartResult(Type a_type, + const char* a_file_name, + int a_line_number, + const char* a_message) + : type_(a_type), + file_name_(a_file_name), + line_number_(a_line_number), + summary_(ExtractSummary(a_message)), + message_(a_message) { + } + + // Gets the outcome of the test part. + Type type() const { return type_; } + + // Gets the name of the source file where the test part took place, or + // NULL if it's unknown. + const char* file_name() const { return file_name_.c_str(); } + + // Gets the line in the source file where the test part took place, + // or -1 if it's unknown. + int line_number() const { return line_number_; } + + // Gets the summary of the failure message. + const char* summary() const { return summary_.c_str(); } + + // Gets the message associated with the test part. + const char* message() const { return message_.c_str(); } + + // Returns true iff the test part passed. + bool passed() const { return type_ == kSuccess; } + + // Returns true iff the test part failed. + bool failed() const { return type_ != kSuccess; } + + // Returns true iff the test part non-fatally failed. + bool nonfatally_failed() const { return type_ == kNonFatalFailure; } + + // Returns true iff the test part fatally failed. + bool fatally_failed() const { return type_ == kFatalFailure; } + private: + Type type_; + + // Gets the summary of the failure message by omitting the stack + // trace in it. + static internal::String ExtractSummary(const char* message); + + // The name of the source file where the test part took place, or + // NULL if the source file is unknown. + internal::String file_name_; + // The line in the source file where the test part took place, or -1 + // if the line number is unknown. + int line_number_; + internal::String summary_; // The test failure summary. + internal::String message_; // The test failure message. +}; + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result); + +// An array of TestPartResult objects. +// +// Don't inherit from TestPartResultArray as its destructor is not +// virtual. +class GTEST_API_ TestPartResultArray { + public: + TestPartResultArray() {} + + // Appends the given TestPartResult to the array. + void Append(const TestPartResult& result); + + // Returns the TestPartResult at the given index (0-based). + const TestPartResult& GetTestPartResult(int index) const; + + // Returns the number of TestPartResult objects in the array. + int size() const; + + private: + std::vector array_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); +}; + +// This interface knows how to report a test part result. +class TestPartResultReporterInterface { + public: + virtual ~TestPartResultReporterInterface() {} + + virtual void ReportTestPartResult(const TestPartResult& result) = 0; +}; + +namespace internal { + +// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a +// statement generates new fatal failures. To do so it registers itself as the +// current test part result reporter. Besides checking if fatal failures were +// reported, it only delegates the reporting to the former result reporter. +// The original result reporter is restored in the destructor. +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +class GTEST_API_ HasNewFatalFailureHelper + : public TestPartResultReporterInterface { + public: + HasNewFatalFailureHelper(); + virtual ~HasNewFatalFailureHelper(); + virtual void ReportTestPartResult(const TestPartResult& result); + bool has_new_fatal_failure() const { return has_new_fatal_failure_; } + private: + bool has_new_fatal_failure_; + TestPartResultReporterInterface* original_reporter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); +}; + +} // namespace internal + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: wan@google.com (Zhanyong Wan) + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// This header implements typed tests and type-parameterized tests. + +// Typed (aka type-driven) tests repeat the same test for types in a +// list. You must know which types you want to test with when writing +// typed tests. Here's how you do it: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + public: + ... + typedef std::list List; + static T shared_; + T value_; +}; + +// Next, associate a list of types with the test case, which will be +// repeated for each type in the list. The typedef is necessary for +// the macro to parse correctly. +typedef testing::Types MyTypes; +TYPED_TEST_CASE(FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// TYPED_TEST_CASE(FooTest, int); + +// Then, use TYPED_TEST() instead of TEST_F() to define as many typed +// tests for this test case as you want. +TYPED_TEST(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + // Since we are inside a derived class template, C++ requires use to + // visit the members of FooTest via 'this'. + TypeParam n = this->value_; + + // To visit static members of the fixture, add the TestFixture:: + // prefix. + n += TestFixture::shared_; + + // To refer to typedefs in the fixture, add the "typename + // TestFixture::" prefix. + typename TestFixture::List values; + values.push_back(n); + ... +} + +TYPED_TEST(FooTest, HasPropertyA) { ... } + +#endif // 0 + +// Type-parameterized tests are abstract test patterns parameterized +// by a type. Compared with typed tests, type-parameterized tests +// allow you to define the test pattern without knowing what the type +// parameters are. The defined pattern can be instantiated with +// different types any number of times, in any number of translation +// units. +// +// If you are designing an interface or concept, you can define a +// suite of type-parameterized tests to verify properties that any +// valid implementation of the interface/concept should have. Then, +// each implementation can easily instantiate the test suite to verify +// that it conforms to the requirements, without having to write +// similar tests repeatedly. Here's an example: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + ... +}; + +// Next, declare that you will define a type-parameterized test case +// (the _P suffix is for "parameterized" or "pattern", whichever you +// prefer): +TYPED_TEST_CASE_P(FooTest); + +// Then, use TYPED_TEST_P() to define as many type-parameterized tests +// for this type-parameterized test case as you want. +TYPED_TEST_P(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + TypeParam n = 0; + ... +} + +TYPED_TEST_P(FooTest, HasPropertyA) { ... } + +// Now the tricky part: you need to register all test patterns before +// you can instantiate them. The first argument of the macro is the +// test case name; the rest are the names of the tests in this test +// case. +REGISTER_TYPED_TEST_CASE_P(FooTest, + DoesBlah, HasPropertyA); + +// Finally, you are free to instantiate the pattern with the types you +// want. If you put the above code in a header file, you can #include +// it in multiple C++ source files and instantiate it multiple times. +// +// To distinguish different instances of the pattern, the first +// argument to the INSTANTIATE_* macro is a prefix that will be added +// to the actual test case name. Remember to pick unique prefixes for +// different instances. +typedef testing::Types MyTypes; +INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); + +#endif // 0 + + +// Implements typed tests. + +#if GTEST_HAS_TYPED_TEST + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the typedef for the type parameters of the +// given test case. +# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +# define TYPED_TEST_CASE(CaseName, Types) \ + typedef ::testing::internal::TypeList< Types >::type \ + GTEST_TYPE_PARAMS_(CaseName) + +# define TYPED_TEST(CaseName, TestName) \ + template \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel< \ + GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ + GTEST_TYPE_PARAMS_(CaseName)>::Register(\ + "", #CaseName, #TestName, 0); \ + template \ + void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() + +#endif // GTEST_HAS_TYPED_TEST + +// Implements type-parameterized tests. + +#if GTEST_HAS_TYPED_TEST_P + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the namespace name that the type-parameterized tests for +// the given type-parameterized test case are defined in. The exact +// name of the namespace is subject to change without notice. +# define GTEST_CASE_NAMESPACE_(TestCaseName) \ + gtest_case_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the variable used to remember the names of +// the defined tests in the given test case. +# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ + gtest_typed_test_case_p_state_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. +// +// Expands to the name of the variable used to remember the names of +// the registered tests in the given test case. +# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ + gtest_registered_test_names_##TestCaseName##_ + +// The variables defined in the type-parameterized test macros are +// static as typically these macros are used in a .h file that can be +// #included in multiple translation units linked together. +# define TYPED_TEST_CASE_P(CaseName) \ + static ::testing::internal::TypedTestCasePState \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) + +# define TYPED_TEST_P(CaseName, TestName) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + template \ + class TestName : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ + __FILE__, __LINE__, #CaseName, #TestName); \ + } \ + template \ + void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() + +# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ + } \ + static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ + __FILE__, __LINE__, #__VA_ARGS__) + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ + bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestCase::type>::Register(\ + #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) + +#endif // GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// Depending on the platform, different string classes are available. +// On Linux, in addition to ::std::string, Google also makes use of +// class ::string, which has the same interface as ::std::string, but +// has a different implementation. +// +// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that +// ::string is available AND is a distinct type to ::std::string, or +// define it to 0 to indicate otherwise. +// +// If the user's ::std::string and ::string are the same class due to +// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. +// +// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined +// heuristically. + +namespace testing { + +// Declares the flags. + +// This flag temporary enables the disabled tests. +GTEST_DECLARE_bool_(also_run_disabled_tests); + +// This flag brings the debugger on an assertion failure. +GTEST_DECLARE_bool_(break_on_failure); + +// This flag controls whether Google Test catches all test-thrown exceptions +// and logs them as failures. +GTEST_DECLARE_bool_(catch_exceptions); + +// This flag enables using colors in terminal output. Available values are +// "yes" to enable colors, "no" (disable colors), or "auto" (the default) +// to let Google Test decide. +GTEST_DECLARE_string_(color); + +// This flag sets up the filter to select by name using a glob pattern +// the tests to run. If the filter is not given all tests are executed. +GTEST_DECLARE_string_(filter); + +// This flag causes the Google Test to list tests. None of the tests listed +// are actually run if the flag is provided. +GTEST_DECLARE_bool_(list_tests); + +// This flag controls whether Google Test emits a detailed XML report to a file +// in addition to its normal textual output. +GTEST_DECLARE_string_(output); + +// This flags control whether Google Test prints the elapsed time for each +// test. +GTEST_DECLARE_bool_(print_time); + +// This flag specifies the random number seed. +GTEST_DECLARE_int32_(random_seed); + +// This flag sets how many times the tests are repeated. The default value +// is 1. If the value is -1 the tests are repeating forever. +GTEST_DECLARE_int32_(repeat); + +// This flag controls whether Google Test includes Google Test internal +// stack frames in failure stack traces. +GTEST_DECLARE_bool_(show_internal_stack_frames); + +// When this flag is specified, tests' order is randomized on every iteration. +GTEST_DECLARE_bool_(shuffle); + +// This flag specifies the maximum number of stack frames to be +// printed in a failure message. +GTEST_DECLARE_int32_(stack_trace_depth); + +// When this flag is specified, a failed assertion will throw an +// exception if exceptions are enabled, or exit the program with a +// non-zero code otherwise. +GTEST_DECLARE_bool_(throw_on_failure); + +// When this flag is set with a "host:port" string, on supported +// platforms test results are streamed to the specified port on +// the specified host machine. +GTEST_DECLARE_string_(stream_result_to); + +// The upper limit for valid stack trace depths. +const int kMaxStackTraceDepth = 100; + +namespace internal { + +class AssertHelper; +class DefaultGlobalTestPartResultReporter; +class ExecDeathTest; +class NoExecDeathTest; +class FinalSuccessChecker; +class GTestFlagSaver; +class TestResultAccessor; +class TestEventListenersAccessor; +class TestEventRepeater; +class WindowsDeathTest; +class UnitTestImpl* GetUnitTestImpl(); +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const String& message); + +// Converts a streamable value to a String. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +// Declared in gtest-internal.h but defined here, so that it has access +// to the definition of the Message class, required by the ARM +// compiler. +template +String StreamableToString(const T& streamable) { + return (Message() << streamable).GetString(); +} + +} // namespace internal + +// The friend relationship of some of these classes is cyclic. +// If we don't forward declare them the compiler might confuse the classes +// in friendship clauses with same named classes on the scope. +class Test; +class TestCase; +class TestInfo; +class UnitTest; + +// A class for indicating whether an assertion was successful. When +// the assertion wasn't successful, the AssertionResult object +// remembers a non-empty message that describes how it failed. +// +// To create an instance of this class, use one of the factory functions +// (AssertionSuccess() and AssertionFailure()). +// +// This class is useful for two purposes: +// 1. Defining predicate functions to be used with Boolean test assertions +// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts +// 2. Defining predicate-format functions to be +// used with predicate assertions (ASSERT_PRED_FORMAT*, etc). +// +// For example, if you define IsEven predicate: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) +// will print the message +// +// Value of: IsEven(Fib(5)) +// Actual: false (5 is odd) +// Expected: true +// +// instead of a more opaque +// +// Value of: IsEven(Fib(5)) +// Actual: false +// Expected: true +// +// in case IsEven is a simple Boolean predicate. +// +// If you expect your predicate to be reused and want to support informative +// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up +// about half as often as positive ones in our tests), supply messages for +// both success and failure cases: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess() << n << " is even"; +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print +// +// Value of: IsEven(Fib(6)) +// Actual: true (8 is even) +// Expected: false +// +// NB: Predicates that support negative Boolean assertions have reduced +// performance in positive ones so be careful not to use them in tests +// that have lots (tens of thousands) of positive Boolean assertions. +// +// To use this class with EXPECT_PRED_FORMAT assertions such as: +// +// // Verifies that Foo() returns an even number. +// EXPECT_PRED_FORMAT1(IsEven, Foo()); +// +// you need to define: +// +// testing::AssertionResult IsEven(const char* expr, int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() +// << "Expected: " << expr << " is even\n Actual: it's " << n; +// } +// +// If Foo() returns 5, you will see the following message: +// +// Expected: Foo() is even +// Actual: it's 5 +// +class GTEST_API_ AssertionResult { + public: + // Copy constructor. + // Used in EXPECT_TRUE/FALSE(assertion_result). + AssertionResult(const AssertionResult& other); + // Used in the EXPECT_TRUE/FALSE(bool_expression). + explicit AssertionResult(bool success) : success_(success) {} + + // Returns true iff the assertion succeeded. + operator bool() const { return success_; } // NOLINT + + // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. + AssertionResult operator!() const; + + // Returns the text streamed into this AssertionResult. Test assertions + // use it when they fail (i.e., the predicate's outcome doesn't match the + // assertion's expectation). When nothing has been streamed into the + // object, returns an empty string. + const char* message() const { + return message_.get() != NULL ? message_->c_str() : ""; + } + // TODO(vladl@google.com): Remove this after making sure no clients use it. + // Deprecated; please use message() instead. + const char* failure_message() const { return message(); } + + // Streams a custom failure message into this object. + template AssertionResult& operator<<(const T& value) { + AppendMessage(Message() << value); + return *this; + } + + // Allows streaming basic output manipulators such as endl or flush into + // this object. + AssertionResult& operator<<( + ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { + AppendMessage(Message() << basic_manipulator); + return *this; + } + + private: + // Appends the contents of message to message_. + void AppendMessage(const Message& a_message) { + if (message_.get() == NULL) + message_.reset(new ::std::string); + message_->append(a_message.GetString().c_str()); + } + + // Stores result of the assertion predicate. + bool success_; + // Stores the message describing the condition in case the expectation + // construct is not satisfied with the predicate's outcome. + // Referenced via a pointer to avoid taking too much stack frame space + // with test assertions. + internal::scoped_ptr< ::std::string> message_; + + GTEST_DISALLOW_ASSIGN_(AssertionResult); +}; + +// Makes a successful assertion result. +GTEST_API_ AssertionResult AssertionSuccess(); + +// Makes a failed assertion result. +GTEST_API_ AssertionResult AssertionFailure(); + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << msg. +GTEST_API_ AssertionResult AssertionFailure(const Message& msg); + +// The abstract class that all tests inherit from. +// +// In Google Test, a unit test program contains one or many TestCases, and +// each TestCase contains one or many Tests. +// +// When you define a test using the TEST macro, you don't need to +// explicitly derive from Test - the TEST macro automatically does +// this for you. +// +// The only time you derive from Test is when defining a test fixture +// to be used a TEST_F. For example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { ... } +// virtual void TearDown() { ... } +// ... +// }; +// +// TEST_F(FooTest, Bar) { ... } +// TEST_F(FooTest, Baz) { ... } +// +// Test is not copyable. +class GTEST_API_ Test { + public: + friend class TestInfo; + + // Defines types for pointers to functions that set up and tear down + // a test case. + typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; + typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; + + // The d'tor is virtual as we intend to inherit from Test. + virtual ~Test(); + + // Sets up the stuff shared by all tests in this test case. + // + // Google Test will call Foo::SetUpTestCase() before running the first + // test in test case Foo. Hence a sub-class can define its own + // SetUpTestCase() method to shadow the one defined in the super + // class. + static void SetUpTestCase() {} + + // Tears down the stuff shared by all tests in this test case. + // + // Google Test will call Foo::TearDownTestCase() after running the last + // test in test case Foo. Hence a sub-class can define its own + // TearDownTestCase() method to shadow the one defined in the super + // class. + static void TearDownTestCase() {} + + // Returns true iff the current test has a fatal failure. + static bool HasFatalFailure(); + + // Returns true iff the current test has a non-fatal failure. + static bool HasNonfatalFailure(); + + // Returns true iff the current test has a (either fatal or + // non-fatal) failure. + static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } + + // Logs a property for the current test. Only the last value for a given + // key is remembered. + // These are public static so they can be called from utility functions + // that are not members of the test fixture. + // The arguments are const char* instead strings, as Google Test is used + // on platforms where string doesn't compile. + // + // Note that a driving consideration for these RecordProperty methods + // was to produce xml output suited to the Greenspan charting utility, + // which at present will only chart values that fit in a 32-bit int. It + // is the user's responsibility to restrict their values to 32-bit ints + // if they intend them to be used with Greenspan. + static void RecordProperty(const char* key, const char* value); + static void RecordProperty(const char* key, int value); + + protected: + // Creates a Test object. + Test(); + + // Sets up the test fixture. + virtual void SetUp(); + + // Tears down the test fixture. + virtual void TearDown(); + + private: + // Returns true iff the current test has the same fixture class as + // the first test in the current test case. + static bool HasSameFixtureClass(); + + // Runs the test after the test fixture has been set up. + // + // A sub-class must implement this to define the test logic. + // + // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. + // Instead, use the TEST or TEST_F macro. + virtual void TestBody() = 0; + + // Sets up, executes, and tears down the test. + void Run(); + + // Deletes self. We deliberately pick an unusual name for this + // internal method to avoid clashing with names used in user TESTs. + void DeleteSelf_() { delete this; } + + // Uses a GTestFlagSaver to save and restore all Google Test flags. + const internal::GTestFlagSaver* const gtest_flag_saver_; + + // Often a user mis-spells SetUp() as Setup() and spends a long time + // wondering why it is never called by Google Test. The declaration of + // the following method is solely for catching such an error at + // compile time: + // + // - The return type is deliberately chosen to be not void, so it + // will be a conflict if a user declares void Setup() in his test + // fixture. + // + // - This method is private, so it will be another compiler error + // if a user calls it from his test fixture. + // + // DO NOT OVERRIDE THIS FUNCTION. + // + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + + // We disallow copying Tests. + GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); +}; + +typedef internal::TimeInMillis TimeInMillis; + +// A copyable object representing a user specified test property which can be +// output as a key/value string pair. +// +// Don't inherit from TestProperty as its destructor is not virtual. +class TestProperty { + public: + // C'tor. TestProperty does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestProperty object. + TestProperty(const char* a_key, const char* a_value) : + key_(a_key), value_(a_value) { + } + + // Gets the user supplied key. + const char* key() const { + return key_.c_str(); + } + + // Gets the user supplied value. + const char* value() const { + return value_.c_str(); + } + + // Sets a new value, overriding the one supplied in the constructor. + void SetValue(const char* new_value) { + value_ = new_value; + } + + private: + // The key supplied by the user. + internal::String key_; + // The value supplied by the user. + internal::String value_; +}; + +// The result of a single Test. This includes a list of +// TestPartResults, a list of TestProperties, a count of how many +// death tests there are in the Test, and how much time it took to run +// the Test. +// +// TestResult is not copyable. +class GTEST_API_ TestResult { + public: + // Creates an empty TestResult. + TestResult(); + + // D'tor. Do not inherit from TestResult. + ~TestResult(); + + // Gets the number of all test parts. This is the sum of the number + // of successful test parts and the number of failed test parts. + int total_part_count() const; + + // Returns the number of the test properties. + int test_property_count() const; + + // Returns true iff the test passed (i.e. no test part failed). + bool Passed() const { return !Failed(); } + + // Returns true iff the test failed. + bool Failed() const; + + // Returns true iff the test fatally failed. + bool HasFatalFailure() const; + + // Returns true iff the test has a non-fatal failure. + bool HasNonfatalFailure() const; + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test part result among all the results. i can range + // from 0 to test_property_count() - 1. If i is not in that range, aborts + // the program. + const TestPartResult& GetTestPartResult(int i) const; + + // Returns the i-th test property. i can range from 0 to + // test_property_count() - 1. If i is not in that range, aborts the + // program. + const TestProperty& GetTestProperty(int i) const; + + private: + friend class TestInfo; + friend class UnitTest; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::ExecDeathTest; + friend class internal::TestResultAccessor; + friend class internal::UnitTestImpl; + friend class internal::WindowsDeathTest; + + // Gets the vector of TestPartResults. + const std::vector& test_part_results() const { + return test_part_results_; + } + + // Gets the vector of TestProperties. + const std::vector& test_properties() const { + return test_properties_; + } + + // Sets the elapsed time. + void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } + + // Adds a test property to the list. The property is validated and may add + // a non-fatal failure if invalid (e.g., if it conflicts with reserved + // key names). If a property is already recorded for the same key, the + // value will be updated, rather than storing multiple values for the same + // key. + void RecordProperty(const TestProperty& test_property); + + // Adds a failure if the key is a reserved attribute of Google Test + // testcase tags. Returns true if the property is valid. + // TODO(russr): Validate attribute names are legal and human readable. + static bool ValidateTestProperty(const TestProperty& test_property); + + // Adds a test part result to the list. + void AddTestPartResult(const TestPartResult& test_part_result); + + // Returns the death test count. + int death_test_count() const { return death_test_count_; } + + // Increments the death test count, returning the new count. + int increment_death_test_count() { return ++death_test_count_; } + + // Clears the test part results. + void ClearTestPartResults(); + + // Clears the object. + void Clear(); + + // Protects mutable state of the property vector and of owned + // properties, whose values may be updated. + internal::Mutex test_properites_mutex_; + + // The vector of TestPartResults + std::vector test_part_results_; + // The vector of TestProperties + std::vector test_properties_; + // Running count of death tests. + int death_test_count_; + // The elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestResult. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); +}; // class TestResult + +// A TestInfo object stores the following information about a test: +// +// Test case name +// Test name +// Whether the test should be run +// A function pointer that creates the test object when invoked +// Test result +// +// The constructor of TestInfo registers itself with the UnitTest +// singleton such that the RUN_ALL_TESTS() macro knows which tests to +// run. +class GTEST_API_ TestInfo { + public: + // Destructs a TestInfo object. This function is not virtual, so + // don't inherit from TestInfo. + ~TestInfo(); + + // Returns the test case name. + const char* test_case_name() const { return test_case_name_.c_str(); } + + // Returns the test name. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a typed + // or a type-parameterized test. + const char* type_param() const { + if (type_param_.get() != NULL) + return type_param_->c_str(); + return NULL; + } + + // Returns the text representation of the value parameter, or NULL if this + // is not a value-parameterized test. + const char* value_param() const { + if (value_param_.get() != NULL) + return value_param_->c_str(); + return NULL; + } + + // Returns true if this test should run, that is if the test is not disabled + // (or it is disabled but the also_run_disabled_tests flag has been specified) + // and its full name matches the user-specified filter. + // + // Google Test allows the user to filter the tests by their full names. + // The full name of a test Bar in test case Foo is defined as + // "Foo.Bar". Only the tests that match the filter will run. + // + // A filter is a colon-separated list of glob (not regex) patterns, + // optionally followed by a '-' and a colon-separated list of + // negative patterns (tests to exclude). A test is run if it + // matches one of the positive patterns and does not match any of + // the negative patterns. + // + // For example, *A*:Foo.* is a filter that matches any string that + // contains the character 'A' or starts with "Foo.". + bool should_run() const { return should_run_; } + + // Returns the result of the test. + const TestResult* result() const { return &result_; } + + private: + +#if GTEST_HAS_DEATH_TEST + friend class internal::DefaultDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + friend class Test; + friend class TestCase; + friend class internal::UnitTestImpl; + friend TestInfo* internal::MakeAndRegisterTestInfo( + const char* test_case_name, const char* name, + const char* type_param, + const char* value_param, + internal::TypeId fixture_class_id, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + internal::TestFactoryBase* factory); + + // Constructs a TestInfo object. The newly constructed instance assumes + // ownership of the factory object. + TestInfo(const char* test_case_name, const char* name, + const char* a_type_param, + const char* a_value_param, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory); + + // Increments the number of death tests encountered in this test so + // far. + int increment_death_test_count() { + return result_.increment_death_test_count(); + } + + // Creates the test object, runs it, records its result, and then + // deletes it. + void Run(); + + static void ClearTestResult(TestInfo* test_info) { + test_info->result_.Clear(); + } + + // These fields are immutable properties of the test. + const std::string test_case_name_; // Test case name + const std::string name_; // Test name + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const internal::scoped_ptr type_param_; + // Text representation of the value parameter, or NULL if this is not a + // value-parameterized test. + const internal::scoped_ptr value_param_; + const internal::TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True iff this test should run + bool is_disabled_; // True iff this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + internal::TestFactoryBase* const factory_; // The factory that creates + // the test object + + // This field is mutable and needs to be reset before running the + // test for the second time. + TestResult result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); +}; + +// A test case, which consists of a vector of TestInfos. +// +// TestCase is not copyable. +class GTEST_API_ TestCase { + public: + // Creates a TestCase with the given name. + // + // TestCase does NOT have a default constructor. Always use this + // constructor to create a TestCase object. + // + // Arguments: + // + // name: name of the test case + // a_type_param: the name of the test's type parameter, or NULL if + // this is not a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase(const char* name, const char* a_type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Destructor of TestCase. + virtual ~TestCase(); + + // Gets the name of the TestCase. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a + // type-parameterized test case. + const char* type_param() const { + if (type_param_.get() != NULL) + return type_param_->c_str(); + return NULL; + } + + // Returns true if any test in this test case should run. + bool should_run() const { return should_run_; } + + // Gets the number of successful tests in this test case. + int successful_test_count() const; + + // Gets the number of failed tests in this test case. + int failed_test_count() const; + + // Gets the number of disabled tests in this test case. + int disabled_test_count() const; + + // Get the number of tests in this test case that should run. + int test_to_run_count() const; + + // Gets the number of all tests in this test case. + int total_test_count() const; + + // Returns true iff the test case passed. + bool Passed() const { return !Failed(); } + + // Returns true iff the test case failed. + bool Failed() const { return failed_test_count() > 0; } + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + const TestInfo* GetTestInfo(int i) const; + + private: + friend class Test; + friend class internal::UnitTestImpl; + + // Gets the (mutable) vector of TestInfos in this TestCase. + std::vector& test_info_list() { return test_info_list_; } + + // Gets the (immutable) vector of TestInfos in this TestCase. + const std::vector& test_info_list() const { + return test_info_list_; + } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + TestInfo* GetMutableTestInfo(int i); + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Adds a TestInfo to this test case. Will delete the TestInfo upon + // destruction of the TestCase object. + void AddTestInfo(TestInfo * test_info); + + // Clears the results of all tests in this test case. + void ClearResult(); + + // Clears the results of all tests in the given test case. + static void ClearTestCaseResult(TestCase* test_case) { + test_case->ClearResult(); + } + + // Runs every test in this TestCase. + void Run(); + + // Runs SetUpTestCase() for this TestCase. This wrapper is needed + // for catching exceptions thrown from SetUpTestCase(). + void RunSetUpTestCase() { (*set_up_tc_)(); } + + // Runs TearDownTestCase() for this TestCase. This wrapper is + // needed for catching exceptions thrown from TearDownTestCase(). + void RunTearDownTestCase() { (*tear_down_tc_)(); } + + // Returns true iff test passed. + static bool TestPassed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Passed(); + } + + // Returns true iff test failed. + static bool TestFailed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Failed(); + } + + // Returns true iff test is disabled. + static bool TestDisabled(const TestInfo* test_info) { + return test_info->is_disabled_; + } + + // Returns true if the given test should run. + static bool ShouldRunTest(const TestInfo* test_info) { + return test_info->should_run(); + } + + // Shuffles the tests in this test case. + void ShuffleTests(internal::Random* random); + + // Restores the test order to before the first shuffle. + void UnshuffleTests(); + + // Name of the test case. + internal::String name_; + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const internal::scoped_ptr type_param_; + // The vector of TestInfos in their original order. It owns the + // elements in the vector. + std::vector test_info_list_; + // Provides a level of indirection for the test list to allow easy + // shuffling and restoring the test order. The i-th element in this + // vector is the index of the i-th test in the shuffled test list. + std::vector test_indices_; + // Pointer to the function that sets up the test case. + Test::SetUpTestCaseFunc set_up_tc_; + // Pointer to the function that tears down the test case. + Test::TearDownTestCaseFunc tear_down_tc_; + // True iff any test in this test case should run. + bool should_run_; + // Elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestCases. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); +}; + +// An Environment object is capable of setting up and tearing down an +// environment. The user should subclass this to define his own +// environment(s). +// +// An Environment object does the set-up and tear-down in virtual +// methods SetUp() and TearDown() instead of the constructor and the +// destructor, as: +// +// 1. You cannot safely throw from a destructor. This is a problem +// as in some cases Google Test is used where exceptions are enabled, and +// we may want to implement ASSERT_* using exceptions where they are +// available. +// 2. You cannot use ASSERT_* directly in a constructor or +// destructor. +class Environment { + public: + // The d'tor is virtual as we need to subclass Environment. + virtual ~Environment() {} + + // Override this to define how to set up the environment. + virtual void SetUp() {} + + // Override this to define how to tear down the environment. + virtual void TearDown() {} + private: + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } +}; + +// The interface for tracing execution of tests. The methods are organized in +// the order the corresponding events are fired. +class TestEventListener { + public: + virtual ~TestEventListener() {} + + // Fired before any test activity starts. + virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; + + // Fired before each iteration of tests starts. There may be more than + // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration + // index, starting from 0. + virtual void OnTestIterationStart(const UnitTest& unit_test, + int iteration) = 0; + + // Fired before environment set-up for each iteration of tests starts. + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; + + // Fired after environment set-up for each iteration of tests ends. + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; + + // Fired before the test case starts. + virtual void OnTestCaseStart(const TestCase& test_case) = 0; + + // Fired before the test starts. + virtual void OnTestStart(const TestInfo& test_info) = 0; + + // Fired after a failed assertion or a SUCCEED() invocation. + virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; + + // Fired after the test ends. + virtual void OnTestEnd(const TestInfo& test_info) = 0; + + // Fired after the test case ends. + virtual void OnTestCaseEnd(const TestCase& test_case) = 0; + + // Fired before environment tear-down for each iteration of tests starts. + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; + + // Fired after environment tear-down for each iteration of tests ends. + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; + + // Fired after each iteration of tests finishes. + virtual void OnTestIterationEnd(const UnitTest& unit_test, + int iteration) = 0; + + // Fired after all test activities have ended. + virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; +}; + +// The convenience class for users who need to override just one or two +// methods and are not concerned that a possible change to a signature of +// the methods they override will not be caught during the build. For +// comments about each method please see the definition of TestEventListener +// above. +class EmptyTestEventListener : public TestEventListener { + public: + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} + virtual void OnTestStart(const TestInfo& /*test_info*/) {} + virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} + virtual void OnTestEnd(const TestInfo& /*test_info*/) {} + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} + virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} +}; + +// TestEventListeners lets users add listeners to track events in Google Test. +class GTEST_API_ TestEventListeners { + public: + TestEventListeners(); + ~TestEventListeners(); + + // Appends an event listener to the end of the list. Google Test assumes + // the ownership of the listener (i.e. it will delete the listener when + // the test program finishes). + void Append(TestEventListener* listener); + + // Removes the given event listener from the list and returns it. It then + // becomes the caller's responsibility to delete the listener. Returns + // NULL if the listener is not found in the list. + TestEventListener* Release(TestEventListener* listener); + + // Returns the standard listener responsible for the default console + // output. Can be removed from the listeners list to shut down default + // console output. Note that removing this object from the listener list + // with Release transfers its ownership to the caller and makes this + // function return NULL the next time. + TestEventListener* default_result_printer() const { + return default_result_printer_; + } + + // Returns the standard listener responsible for the default XML output + // controlled by the --gtest_output=xml flag. Can be removed from the + // listeners list by users who want to shut down the default XML output + // controlled by this flag and substitute it with custom one. Note that + // removing this object from the listener list with Release transfers its + // ownership to the caller and makes this function return NULL the next + // time. + TestEventListener* default_xml_generator() const { + return default_xml_generator_; + } + + private: + friend class TestCase; + friend class TestInfo; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::NoExecDeathTest; + friend class internal::TestEventListenersAccessor; + friend class internal::UnitTestImpl; + + // Returns repeater that broadcasts the TestEventListener events to all + // subscribers. + TestEventListener* repeater(); + + // Sets the default_result_printer attribute to the provided listener. + // The listener is also added to the listener list and previous + // default_result_printer is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultResultPrinter(TestEventListener* listener); + + // Sets the default_xml_generator attribute to the provided listener. The + // listener is also added to the listener list and previous + // default_xml_generator is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultXmlGenerator(TestEventListener* listener); + + // Controls whether events will be forwarded by the repeater to the + // listeners in the list. + bool EventForwardingEnabled() const; + void SuppressEventForwarding(); + + // The actual list of listeners. + internal::TestEventRepeater* repeater_; + // Listener responsible for the standard result output. + TestEventListener* default_result_printer_; + // Listener responsible for the creation of the XML output file. + TestEventListener* default_xml_generator_; + + // We disallow copying TestEventListeners. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); +}; + +// A UnitTest consists of a vector of TestCases. +// +// This is a singleton class. The only instance of UnitTest is +// created when UnitTest::GetInstance() is first called. This +// instance is never deleted. +// +// UnitTest is not copyable. +// +// This class is thread-safe as long as the methods are called +// according to their specification. +class GTEST_API_ UnitTest { + public: + // Gets the singleton UnitTest object. The first time this method + // is called, a UnitTest object is constructed and returned. + // Consecutive calls will return the same object. + static UnitTest* GetInstance(); + + // Runs all tests in this UnitTest object and prints the result. + // Returns 0 if successful, or 1 otherwise. + // + // This method can only be called from the main thread. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + int Run() GTEST_MUST_USE_RESULT_; + + // Returns the working directory when the first TEST() or TEST_F() + // was executed. The UnitTest object owns the string. + const char* original_working_dir() const; + + // Returns the TestCase object for the test that's currently running, + // or NULL if no test is running. + const TestCase* current_test_case() const; + + // Returns the TestInfo object for the test that's currently running, + // or NULL if no test is running. + const TestInfo* current_test_info() const; + + // Returns the random seed used at the start of the current test run. + int random_seed() const; + +#if GTEST_HAS_PARAM_TEST + // Returns the ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry(); +#endif // GTEST_HAS_PARAM_TEST + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const; + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const; + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const; + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const; + + // Returns the list of event listeners that can be used to track events + // inside Google Test. + TestEventListeners& listeners(); + + private: + // Registers and returns a global test environment. When a test + // program is run, all global test environments will be set-up in + // the order they were registered. After all tests in the program + // have finished, all global test environments will be torn-down in + // the *reverse* order they were registered. + // + // The UnitTest object takes ownership of the given environment. + // + // This method can only be called from the main thread. + Environment* AddEnvironment(Environment* env); + + // Adds a TestPartResult to the current TestResult object. All + // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) + // eventually call this to report their results. The user code + // should use the assertion macros instead of calling this directly. + void AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const internal::String& message, + const internal::String& os_stack_trace); + + // Adds a TestProperty to the current TestResult object. If the result already + // contains a property with the same key, the value will be updated. + void RecordPropertyForCurrentTest(const char* key, const char* value); + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i); + + // Accessors for the implementation object. + internal::UnitTestImpl* impl() { return impl_; } + const internal::UnitTestImpl* impl() const { return impl_; } + + // These classes and funcions are friends as they need to access private + // members of UnitTest. + friend class Test; + friend class internal::AssertHelper; + friend class internal::ScopedTrace; + friend Environment* AddGlobalTestEnvironment(Environment* env); + friend internal::UnitTestImpl* internal::GetUnitTestImpl(); + friend void internal::ReportFailureInUnknownLocation( + TestPartResult::Type result_type, + const internal::String& message); + + // Creates an empty UnitTest. + UnitTest(); + + // D'tor + virtual ~UnitTest(); + + // Pushes a trace defined by SCOPED_TRACE() on to the per-thread + // Google Test trace stack. + void PushGTestTrace(const internal::TraceInfo& trace); + + // Pops a trace from the per-thread Google Test trace stack. + void PopGTestTrace(); + + // Protects mutable state in *impl_. This is mutable as some const + // methods need to lock it too. + mutable internal::Mutex mutex_; + + // Opaque implementation object. This field is never changed once + // the object is constructed. We don't mark it as const here, as + // doing so will cause a warning in the constructor of UnitTest. + // Mutable state in *impl_ is protected by mutex_. + internal::UnitTestImpl* impl_; + + // We disallow copying UnitTest. + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); +}; + +// A convenient wrapper for adding an environment for the test +// program. +// +// You should call this before RUN_ALL_TESTS() is called, probably in +// main(). If you use gtest_main, you need to call this before main() +// starts for it to take effect. For example, you can define a global +// variable like this: +// +// testing::Environment* const foo_env = +// testing::AddGlobalTestEnvironment(new FooEnvironment); +// +// However, we strongly recommend you to write your own main() and +// call AddGlobalTestEnvironment() there, as relying on initialization +// of global variables makes the code harder to read and may cause +// problems when you register multiple environments from different +// translation units and the environments have dependencies among them +// (remember that the compiler doesn't guarantee the order in which +// global variables from different translation units are initialized). +inline Environment* AddGlobalTestEnvironment(Environment* env) { + return UnitTest::GetInstance()->AddEnvironment(env); +} + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +GTEST_API_ void InitGoogleTest(int* argc, char** argv); + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); + +namespace internal { + +// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) +// operand to be used in a failure message. The type (but not value) +// of the other operand may affect the format. This allows us to +// print a char* as a raw pointer when it is compared against another +// char*, and print it as a C string when it is compared against an +// std::string object, for example. +// +// The default implementation ignores the type of the other operand. +// Some specialized versions are used to handle formatting wide or +// narrow C strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +String FormatForComparisonFailureMessage(const T1& value, + const T2& /* other_operand */) { + // C++Builder compiles this incorrectly if the namespace isn't explicitly + // given. + return ::testing::PrintToString(value); +} + +// The helper function for {ASSERT|EXPECT}_EQ. +template +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4389) // Temporarily disables warning on + // signed/unsigned mismatch. +#endif + + if (expected == actual) { + return AssertionSuccess(); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// With this overloaded version, we allow anonymous enums to be used +// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums +// can be implicitly cast to BiggestInt. +GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual); + +// The helper class for {ASSERT|EXPECT}_EQ. The template argument +// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() +// is a null pointer literal. The following default implementation is +// for lhs_is_null_literal being false. +template +class EqHelper { + public: + // This templatized version is for the general case. + template + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // With this overloaded version, we allow anonymous enums to be used + // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous + // enums can be implicitly cast to BiggestInt. + // + // Even though its body looks the same as the above version, we + // cannot merge the two, as it will make anonymous enums unhappy. + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } +}; + +// This specialization is used when the first argument to ASSERT_EQ() +// is a null pointer literal, like NULL, false, or 0. +template <> +class EqHelper { + public: + // We define two overloaded versions of Compare(). The first + // version will be picked when the second argument to ASSERT_EQ() is + // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or + // EXPECT_EQ(false, a_bool). + template + static AssertionResult Compare( + const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual, + // The following line prevents this overload from being considered if T2 + // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) + // expands to Compare("", "", NULL, my_ptr), which requires a conversion + // to match the Secret* in the other overload, which would otherwise make + // this template match better. + typename EnableIf::value>::type* = 0) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // This version will be picked when the second argument to ASSERT_EQ() is a + // pointer, e.g. ASSERT_EQ(NULL, a_pointer). + template + static AssertionResult Compare( + const char* expected_expression, + const char* actual_expression, + // We used to have a second template parameter instead of Secret*. That + // template parameter would deduce to 'long', making this a better match + // than the first overload even without the first overload's EnableIf. + // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to + // non-pointer argument" (even a deduced integral argument), so the old + // implementation caused warnings in user code. + Secret* /* expected (NULL) */, + T* actual) { + // We already know that 'expected' is a null pointer. + return CmpHelperEQ(expected_expression, actual_expression, + static_cast(NULL), actual); + } +}; + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste +// of similar code. +// +// For each templatized helper function, we also define an overloaded +// version for BiggestInt in order to reduce code bloat and allow +// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled +// with gcc 4. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +template \ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + const T1& val1, const T2& val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + }\ +}\ +GTEST_API_ AssertionResult CmpHelper##op_name(\ + const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) + +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// Implements the helper function for {ASSERT|EXPECT}_NE +GTEST_IMPL_CMP_HELPER_(NE, !=); +// Implements the helper function for {ASSERT|EXPECT}_LE +GTEST_IMPL_CMP_HELPER_(LE, <=); +// Implements the helper function for {ASSERT|EXPECT}_LT +GTEST_IMPL_CMP_HELPER_(LT, < ); +// Implements the helper function for {ASSERT|EXPECT}_GE +GTEST_IMPL_CMP_HELPER_(GE, >=); +// Implements the helper function for {ASSERT|EXPECT}_GT +GTEST_IMPL_CMP_HELPER_(GT, > ); + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRNE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + + +// Helper function for *_STREQ on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual); + +// Helper function for *_STRNE on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); + +} // namespace internal + +// IsSubstring() and IsNotSubstring() are intended to be used as the +// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by +// themselves. They check whether needle is a substring of haystack +// (NULL is considered a substring of itself only), and return an +// appropriate error message when they fail. +// +// The {needle,haystack}_expr arguments are the stringified +// expressions that generated the two real arguments. +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +// Helper template function for comparing floating-points. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, + const char* actual_expression, + RawType expected, + RawType actual) { + const FloatingPoint lhs(expected), rhs(actual); + + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + ::std::stringstream expected_ss; + expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << expected; + + ::std::stringstream actual_ss; + actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << actual; + + return EqFailure(expected_expression, + actual_expression, + StringStreamToString(&expected_ss), + StringStreamToString(&actual_ss), + false); +} + +// Helper function for implementing ASSERT_NEAR. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error); + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// A class that enables one to stream messages to assertion macros +class GTEST_API_ AssertHelper { + public: + // Constructor. + AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message); + ~AssertHelper(); + + // Message assignment is a semantic trick to enable assertion + // streaming; see the GTEST_MESSAGE_ macro below. + void operator=(const Message& message) const; + + private: + // We put our data in a struct so that the size of the AssertHelper class can + // be as small as possible. This is important because gcc is incapable of + // re-using stack space even for temporary variables, so every EXPECT_EQ + // reserves stack space for another AssertHelper. + struct AssertHelperData { + AssertHelperData(TestPartResult::Type t, + const char* srcfile, + int line_num, + const char* msg) + : type(t), file(srcfile), line(line_num), message(msg) { } + + TestPartResult::Type const type; + const char* const file; + int const line; + String const message; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); + }; + + AssertHelperData* const data_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); +}; + +} // namespace internal + +#if GTEST_HAS_PARAM_TEST +// The pure interface class that all value-parameterized tests inherit from. +// A value-parameterized class must inherit from both ::testing::Test and +// ::testing::WithParamInterface. In most cases that just means inheriting +// from ::testing::TestWithParam, but more complicated test hierarchies +// may need to inherit from Test and WithParamInterface at different levels. +// +// This interface has support for accessing the test parameter value via +// the GetParam() method. +// +// Use it with one of the parameter generator defining functions, like Range(), +// Values(), ValuesIn(), Bool(), and Combine(). +// +// class FooTest : public ::testing::TestWithParam { +// protected: +// FooTest() { +// // Can use GetParam() here. +// } +// virtual ~FooTest() { +// // Can use GetParam() here. +// } +// virtual void SetUp() { +// // Can use GetParam() here. +// } +// virtual void TearDown { +// // Can use GetParam() here. +// } +// }; +// TEST_P(FooTest, DoesBar) { +// // Can use GetParam() method here. +// Foo foo; +// ASSERT_TRUE(foo.DoesBar(GetParam())); +// } +// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); + +template +class WithParamInterface { + public: + typedef T ParamType; + virtual ~WithParamInterface() {} + + // The current parameter value. Is also available in the test fixture's + // constructor. This member function is non-static, even though it only + // references static data, to reduce the opportunity for incorrect uses + // like writing 'WithParamInterface::GetParam()' for a test that + // uses a fixture whose parameter type is int. + const ParamType& GetParam() const { return *parameter_; } + + private: + // Sets parameter value. The caller is responsible for making sure the value + // remains alive and unchanged throughout the current test. + static void SetParam(const ParamType* parameter) { + parameter_ = parameter; + } + + // Static value used for accessing parameter during a test lifetime. + static const ParamType* parameter_; + + // TestClass must be a subclass of WithParamInterface and Test. + template friend class internal::ParameterizedTestFactory; +}; + +template +const T* WithParamInterface::parameter_ = NULL; + +// Most value-parameterized classes can ignore the existence of +// WithParamInterface, and can just inherit from ::testing::TestWithParam. + +template +class TestWithParam : public Test, public WithParamInterface { +}; + +#endif // GTEST_HAS_PARAM_TEST + +// Macros for indicating success/failure in test code. + +// ADD_FAILURE unconditionally adds a failure to the current test. +// SUCCEED generates a success - it doesn't automatically make the +// current test successful, as a test is only successful when it has +// no failure. +// +// EXPECT_* verifies that a certain condition is satisfied. If not, +// it behaves like ADD_FAILURE. In particular: +// +// EXPECT_TRUE verifies that a Boolean condition is true. +// EXPECT_FALSE verifies that a Boolean condition is false. +// +// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except +// that they will also abort the current function on failure. People +// usually want the fail-fast behavior of FAIL and ASSERT_*, but those +// writing data-driven tests often find themselves using ADD_FAILURE +// and EXPECT_* more. +// +// Examples: +// +// EXPECT_TRUE(server.StatusIsOK()); +// ASSERT_FALSE(server.HasPendingRequest(port)) +// << "There are still pending requests " << "on port " << port; + +// Generates a nonfatal failure with a generic message. +#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") + +// Generates a nonfatal failure at the given source file location with +// a generic message. +#define ADD_FAILURE_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kNonFatalFailure) + +// Generates a fatal failure with a generic message. +#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") + +// Define this macro to 1 to omit the definition of FAIL(), which is a +// generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_FAIL +# define FAIL() GTEST_FAIL() +#endif + +// Generates a success with a generic message. +#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") + +// Define this macro to 1 to omit the definition of SUCCEED(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_SUCCEED +# define SUCCEED() GTEST_SUCCEED() +#endif + +// Macros for testing exceptions. +// +// * {ASSERT|EXPECT}_THROW(statement, expected_exception): +// Tests that the statement throws the expected exception. +// * {ASSERT|EXPECT}_NO_THROW(statement): +// Tests that the statement doesn't throw any exception. +// * {ASSERT|EXPECT}_ANY_THROW(statement): +// Tests that the statement throws an exception. + +#define EXPECT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) +#define EXPECT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define EXPECT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define ASSERT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) +#define ASSERT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) +#define ASSERT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) + +// Boolean assertions. Condition can be either a Boolean expression or an +// AssertionResult. For more information on how to use AssertionResult with +// these macros see comments on that class. +#define EXPECT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_NONFATAL_FAILURE_) +#define EXPECT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_NONFATAL_FAILURE_) +#define ASSERT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_FATAL_FAILURE_) +#define ASSERT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_FATAL_FAILURE_) + +// Includes the auto-generated header that implements a family of +// generic predicate assertion macros. +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// This file is AUTOMATICALLY GENERATED on 09/24/2010 by command +// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! +// +// Implements a family of generic predicate assertion macros. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +// Makes sure this header is not included before gtest.h. +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +# error Do not include gtest_pred_impl.h directly. Include gtest.h instead. +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ + +// This header implements a family of generic predicate assertion +// macros: +// +// ASSERT_PRED_FORMAT1(pred_format, v1) +// ASSERT_PRED_FORMAT2(pred_format, v1, v2) +// ... +// +// where pred_format is a function or functor that takes n (in the +// case of ASSERT_PRED_FORMATn) values and their source expression +// text, and returns a testing::AssertionResult. See the definition +// of ASSERT_EQ in gtest.h for an example. +// +// If you don't care about formatting, you can use the more +// restrictive version: +// +// ASSERT_PRED1(pred, v1) +// ASSERT_PRED2(pred, v1, v2) +// ... +// +// where pred is an n-ary function or functor that returns bool, +// and the values v1, v2, ..., must support the << operator for +// streaming to std::ostream. +// +// We also define the EXPECT_* variations. +// +// For now we only support predicates whose arity is at most 5. +// Please email googletestframework@googlegroups.com if you need +// support for higher arities. + +// GTEST_ASSERT_ is the basic statement to which all of the assertions +// in this file reduce. Don't use this in your code. + +#define GTEST_ASSERT_(expression, on_failure) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar = (expression)) \ + ; \ + else \ + on_failure(gtest_ar.failure_message()) + + +// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +template +AssertionResult AssertPred1Helper(const char* pred_text, + const char* e1, + Pred pred, + const T1& v1) { + if (pred(v1)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. +// Don't use this in your code. +#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, v1),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +#define GTEST_PRED1_(pred, v1, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ + #v1, \ + pred, \ + v1), on_failure) + +// Unary predicate assertion macros. +#define EXPECT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +template +AssertionResult AssertPred2Helper(const char* pred_text, + const char* e1, + const char* e2, + Pred pred, + const T1& v1, + const T2& v2) { + if (pred(v1, v2)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. +// Don't use this in your code. +#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +#define GTEST_PRED2_(pred, v1, v2, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ + #v1, \ + #v2, \ + pred, \ + v1, \ + v2), on_failure) + +// Binary predicate assertion macros. +#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +template +AssertionResult AssertPred3Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3) { + if (pred(v1, v2, v3)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. +// Don't use this in your code. +#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + pred, \ + v1, \ + v2, \ + v3), on_failure) + +// Ternary predicate assertion macros. +#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +template +AssertionResult AssertPred4Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + if (pred(v1, v2, v3, v4)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. +// Don't use this in your code. +#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4), on_failure) + +// 4-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +template +AssertionResult AssertPred5Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ", " + << e5 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4 + << "\n" << e5 << " evaluates to " << v5; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. +// Don't use this in your code. +#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + #v5, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4, \ + v5), on_failure) + +// 5-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) + + + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +// Macros for testing equalities and inequalities. +// +// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual +// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 +// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 +// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 +// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 +// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 +// +// When they are not, Google Test prints both the tested expressions and +// their actual values. The values must be compatible built-in types, +// or you will get a compiler error. By "compatible" we mean that the +// values can be compared by the respective operator. +// +// Note: +// +// 1. It is possible to make a user-defined type work with +// {ASSERT|EXPECT}_??(), but that requires overloading the +// comparison operators and is thus discouraged by the Google C++ +// Usage Guide. Therefore, you are advised to use the +// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are +// equal. +// +// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on +// pointers (in particular, C strings). Therefore, if you use it +// with two C strings, you are testing how their locations in memory +// are related, not how their content is related. To compare two C +// strings by content, use {ASSERT|EXPECT}_STR*(). +// +// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to +// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you +// what the actual value is when it fails, and similarly for the +// other comparisons. +// +// 4. Do not depend on the order in which {ASSERT|EXPECT}_??() +// evaluate their arguments, which is undefined. +// +// 5. These macros evaluate their arguments exactly once. +// +// Examples: +// +// EXPECT_NE(5, Foo()); +// EXPECT_EQ(NULL, a_pointer); +// ASSERT_LT(i, array_size); +// ASSERT_GT(records.size(), 0) << "There is no record left."; + +#define EXPECT_EQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define EXPECT_NE(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) +#define EXPECT_LE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define EXPECT_LT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define EXPECT_GE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define EXPECT_GT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +#define GTEST_ASSERT_EQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define GTEST_ASSERT_NE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) +#define GTEST_ASSERT_LE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define GTEST_ASSERT_LT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define GTEST_ASSERT_GE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define GTEST_ASSERT_GT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of +// ASSERT_XY(), which clashes with some users' own code. + +#if !GTEST_DONT_DEFINE_ASSERT_EQ +# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_NE +# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LE +# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LT +# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GE +# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GT +# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) +#endif + +// C String Comparisons. All tests treat NULL and any non-NULL string +// as different. Two NULLs are equal. +// +// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 +// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 +// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case +// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case +// +// For wide or narrow string objects, you can use the +// {ASSERT|EXPECT}_??() macros. +// +// Don't depend on the order in which the arguments are evaluated, +// which is undefined. +// +// These macros evaluate their arguments exactly once. + +#define EXPECT_STREQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define EXPECT_STRNE(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define EXPECT_STRCASEEQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define EXPECT_STRCASENE(s1, s2)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +#define ASSERT_STREQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define ASSERT_STRNE(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define ASSERT_STRCASEEQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define ASSERT_STRCASENE(s1, s2)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +// Macros for comparing floating-point numbers. +// +// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): +// Tests that two float values are almost equal. +// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): +// Tests that two double values are almost equal. +// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): +// Tests that v1 and v2 are within the given distance to each other. +// +// Google Test uses ULP-based comparison to automatically pick a default +// error bound that is appropriate for the operands. See the +// FloatingPoint template class in gtest-internal.h if you are +// interested in the implementation details. + +#define EXPECT_FLOAT_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_DOUBLE_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_FLOAT_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_DOUBLE_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_NEAR(val1, val2, abs_error)\ + EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +#define ASSERT_NEAR(val1, val2, abs_error)\ + ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +// These predicate format functions work on floating-point values, and +// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. +// +// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2); +GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2); + + +#if GTEST_OS_WINDOWS + +// Macros that test for HRESULT failure and success, these are only useful +// on Windows, and rely on Windows SDK macros and APIs to compile. +// +// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) +// +// When expr unexpectedly fails or succeeds, Google Test prints the +// expected result and the actual result with both a human-readable +// string representation of the error, if available, as well as the +// hex result code. +# define EXPECT_HRESULT_SUCCEEDED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define ASSERT_HRESULT_SUCCEEDED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define EXPECT_HRESULT_FAILED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +# define ASSERT_HRESULT_FAILED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +#endif // GTEST_OS_WINDOWS + +// Macros that execute statement and check that it doesn't generate new fatal +// failures in the current thread. +// +// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); +// +// Examples: +// +// EXPECT_NO_FATAL_FAILURE(Process()); +// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; +// +#define ASSERT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) +#define EXPECT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) + +// Causes a trace (including the source file path, the current line +// number, and the given message) to be included in every test failure +// message generated by code in the current scope. The effect is +// undone when the control leaves the current scope. +// +// The message argument can be anything streamable to std::ostream. +// +// In the implementation, we include the current line number as part +// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s +// to appear in the same block - as long as they are on different +// lines. +#define SCOPED_TRACE(message) \ + ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, ::testing::Message() << (message)) + +// Compile-time assertion for type equality. +// StaticAssertTypeEq() compiles iff type1 and type2 are +// the same type. The value it returns is not interesting. +// +// Instead of making StaticAssertTypeEq a class template, we make it a +// function template that invokes a helper class template. This +// prevents a user from misusing StaticAssertTypeEq by +// defining objects of that type. +// +// CAVEAT: +// +// When used inside a method of a class template, +// StaticAssertTypeEq() is effective ONLY IF the method is +// instantiated. For example, given: +// +// template class Foo { +// public: +// void Bar() { testing::StaticAssertTypeEq(); } +// }; +// +// the code: +// +// void Test1() { Foo foo; } +// +// will NOT generate a compiler error, as Foo::Bar() is never +// actually instantiated. Instead, you need: +// +// void Test2() { Foo foo; foo.Bar(); } +// +// to cause a compiler error. +template +bool StaticAssertTypeEq() { + (void)internal::StaticAssertTypeEqHelper(); + return true; +} + +// Defines a test. +// +// The first parameter is the name of the test case, and the second +// parameter is the name of the test within the test case. +// +// The convention is to end the test case name with "Test". For +// example, a test case for the Foo class can be named FooTest. +// +// The user should put his test code between braces after using this +// macro. Example: +// +// TEST(FooTest, InitializesCorrectly) { +// Foo foo; +// EXPECT_TRUE(foo.StatusIsOK()); +// } + +// Note that we call GetTestTypeId() instead of GetTypeId< +// ::testing::Test>() here to get the type ID of testing::Test. This +// is to work around a suspected linker bug when using Google Test as +// a framework on Mac OS X. The bug causes GetTypeId< +// ::testing::Test>() to return different values depending on whether +// the call is from the Google Test framework itself or from user test +// code. GetTestTypeId() is guaranteed to always return the same +// value, as it always calls GetTypeId<>() from the Google Test +// framework. +#define GTEST_TEST(test_case_name, test_name)\ + GTEST_TEST_(test_case_name, test_name, \ + ::testing::Test, ::testing::internal::GetTestTypeId()) + +// Define this macro to 1 to omit the definition of TEST(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_TEST +# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) +#endif + +// Defines a test that uses a test fixture. +// +// The first parameter is the name of the test fixture class, which +// also doubles as the test case name. The second parameter is the +// name of the test within the test case. +// +// A test fixture class must be declared earlier. The user should put +// his test code between braces after using this macro. Example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { b_.AddElement(3); } +// +// Foo a_; +// Foo b_; +// }; +// +// TEST_F(FooTest, InitializesCorrectly) { +// EXPECT_TRUE(a_.StatusIsOK()); +// } +// +// TEST_F(FooTest, ReturnsElementCountCorrectly) { +// EXPECT_EQ(0, a_.size()); +// EXPECT_EQ(1, b_.size()); +// } + +#define TEST_F(test_fixture, test_name)\ + GTEST_TEST_(test_fixture, test_name, test_fixture, \ + ::testing::internal::GetTypeId()) + +// Use this macro in main() to run all tests. It returns 0 if all +// tests are successful, or 1 otherwise. +// +// RUN_ALL_TESTS() should be invoked after the command line has been +// parsed by InitGoogleTest(). + +#define RUN_ALL_TESTS()\ + (::testing::UnitTest::GetInstance()->Run()) + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/NativeTask.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/NativeTask.h new file mode 100644 index 00000000000..ba026f5f4fe --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/NativeTask.h @@ -0,0 +1,507 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NATIVETASK_H_ +#define NATIVETASK_H_ + +#include "lib/jniutils.h" +#include +#include +#include +#include + +namespace NativeTask { + +using std::string; +using std::vector; +using std::map; +using std::pair; + +/** + * NativeObjectType + */ +enum NativeObjectType { + UnknownObjectType = 0, + BatchHandlerType = 1, +}; + +/** + * Enduim setting + * + */ +enum Endium { + LITTLE_ENDIUM = 0, + LARGE_ENDIUM = 1 +}; + +#define NATIVE_COMBINER "native.combiner.class" +#define NATIVE_PARTITIONER "native.partitioner.class" +#define NATIVE_MAPPER "native.mapper.class" +#define NATIVE_RECORDREADER "native.recordreader.class" +#define NATIVE_RECORDWRITER "native.recordwriter.class" + +#define NATIVE_REDUCER "native.reducer.class" +#define NATIVE_HADOOP_VERSION "native.hadoop.version" + +#define NATIVE_INPUT_SPLIT "native.input.split" +#define INPUT_LINE_KV_SEPERATOR "mapreduce.input.keyvaluelinerecordreader.key.value.separator" +#define MAPRED_TEXTOUTPUT_FORMAT_SEPERATOR "mapreduce.output.textoutputformat.separator" +#define MAPRED_WORK_OUT_DIR "mapreduce.task.output.dir" +#define MAPRED_COMPRESS_OUTPUT "mapreduce.output.fileoutputformat.compress" +#define MAPRED_OUTPUT_COMPRESSION_CODEC "mapreduce.output.fileoutputformat.compress.codec" +#define TOTAL_ORDER_PARTITIONER_PATH "total.order.partitioner.path" +#define TOTAL_ORDER_PARTITIONER_MAX_TRIE_DEPTH "total.order.partitioner.max.trie.depth" +#define FS_DEFAULT_NAME "fs.default.name" +#define FS_DEFAULT_FS "fs.defaultFS" + +#define NATIVE_SORT_TYPE "native.sort.type" +#define MAPRED_SORT_AVOID "mapreduce.sort.avoidance" +#define NATIVE_SORT_MAX_BLOCK_SIZE "native.sort.blocksize.max" +#define MAPRED_COMPRESS_MAP_OUTPUT "mapreduce.map.output.compress" +#define MAPRED_MAP_OUTPUT_COMPRESSION_CODEC "mapreduce.map.output.compress.codec" +#define MAPRED_MAPOUTPUT_KEY_CLASS "mapreduce.map.output.key.class" +#define MAPRED_OUTPUT_KEY_CLASS "mapreduce.job.output.key.class" +#define MAPRED_MAPOUTPUT_VALUE_CLASS "mapreduce.map.output.value.class" +#define MAPRED_OUTPUT_VALUE_CLASS "mapreduce.job.output.value.class" +#define MAPRED_IO_SORT_MB "mapreduce.task.io.sort.mb" +#define MAPRED_NUM_REDUCES "mapreduce.job.reduces" +#define MAPRED_COMBINE_CLASS_OLD "mapred.combiner.class" +#define MAPRED_COMBINE_CLASS_NEW "mapreduce.job.combine.class" + +#define NATIVE_LOG_DEVICE "native.log.device" + +//format: name=path,name=path,name=path +#define NATIVE_CLASS_LIBRARY_BUILDIN "native.class.library.buildin" + +#define NATIVE_MAPOUT_KEY_COMPARATOR "native.map.output.key.comparator" + +extern const std::string NativeObjectTypeToString(NativeObjectType type); +extern NativeObjectType NativeObjectTypeFromString(const std::string type); + +/** + * Objects that can be loaded dynamically from shared library, + * and managed by NativeObjectFactory + */ +class NativeObject { +public: + virtual NativeObjectType type() { + return UnknownObjectType; + } + + virtual ~NativeObject() { + } + ; +}; + +template +NativeObject * ObjectCreator() { + return new T(); +} + +typedef NativeObject * (*ObjectCreatorFunc)(); + +typedef ObjectCreatorFunc (*GetObjectCreatorFunc)(const std::string & name); + +typedef void * (*FunctionGetter)(const std::string & name); + +typedef int32_t (*InitLibraryFunc)(); + +/** + * Exceptions + */ +class HadoopException : public std::exception { +private: + std::string _reason; +public: + HadoopException(const string & what); + virtual ~HadoopException() throw () { + } + + virtual const char* what() const throw () { + return _reason.c_str(); + } +}; + +class OutOfMemoryException : public HadoopException { +public: + OutOfMemoryException(const string & what) + : HadoopException(what) { + } +}; + +class IOException : public HadoopException { +public: + IOException(const string & what) + : HadoopException(what) { + } +}; + +class UnsupportException : public HadoopException { +public: + UnsupportException(const string & what) + : HadoopException(what) { + } +}; + +/** + * Exception when call java methods using JNI + */ +class JavaException : public HadoopException { +public: + JavaException(const string & what) + : HadoopException(what) { + } +}; + +#define STRINGIFY(x) #x +#define TOSTRING(x) STRINGIFY(x) +#define AT __FILE__ ":" TOSTRING(__LINE__) +#define THROW_EXCEPTION(type, what) throw type((std::string(AT":") + what)) +#define THROW_EXCEPTION_EX(type, fmt, args...) \ + throw type(StringUtil::Format("%s:" fmt, AT, ##args)) + +class Config { +protected: + map _configs; +public: + Config() { + } + ~Config() { + } + + const char * get(const string & name); + + string get(const string & name, const string & defaultValue); + + bool getBool(const string & name, bool defaultValue); + + int64_t getInt(const string & name, int64_t defaultValue = -1); + + float getFloat(const string & name, float defaultValue = -1); + + void getStrings(const string & name, vector & dest); + + void getInts(const string & name, vector & dest); + + void getFloats(const string & name, vector & dest); + + void set(const string & key, const string & value); + + void setInt(const string & name, int64_t value); + + void setBool(const string & name, bool value); + + /** + * Load configs from a config file with the following format: + * # comment + * key1=value1 + * key2=value2 + * ... + */ + void load(const string & path); + + /** + * Load configs form command line args + * key1=value1 key2=value2,value2 + */ + void parse(int32_t argc, const char ** argv); +}; + +class Command { +private: + int _id; + const char * _description; + +public: + Command(int id, const char * description) + : _id(id), _description(description) { + } + + Command(int id) + : _id(id), _description(NULL) { + } + + int id() const { + return _id; + } + + const char * description() const { + return _description; + } + + bool equals(const Command & other) const { + if (_id == other._id) { + return true; + } + return false; + } +}; + +class Buffer { +protected: + const char * _data; + uint32_t _length; + +public: + Buffer() + : _data(NULL), _length(0) { + } + + Buffer(const char * data, uint32_t length) + : _data(data), _length(length) { + } + + ~Buffer() { + } + + void reset(const char * data, uint32_t length) { + this->_data = data; + this->_length = length; + } + + const char * data() const { + return _data; + } + + uint32_t length() const { + return _length; + } + + void data(const char * data) { + this->_data = data; + } + + void length(uint32_t length) { + this->_length = length; + } + + string toString() const { + return string(_data, _length); + } +}; + +class InputSplit { +public: + virtual uint64_t getLength() = 0; + virtual vector & getLocations() = 0; + virtual void readFields(const string & data) = 0; + virtual void writeFields(string & dest) = 0; + virtual string toString() = 0; + + virtual ~InputSplit() { + + } +}; + +class Configurable : public NativeObject { +public: + Configurable() { + } + + virtual void configure(Config * config) { + } +}; + +class Collector { +public: + virtual ~Collector() { + } + + virtual void collect(const void * key, uint32_t keyLen, const void * value, uint32_t valueLen) { + } + + virtual void collect(const void * key, uint32_t keyLen, const void * value, uint32_t valueLen, + int32_t partition) { + collect(key, keyLen, value, valueLen); + } +}; + +class Progress { +public: + virtual ~Progress() { + } + virtual float getProgress() = 0; +}; + +class Counter { +private: + // not thread safe + // TODO: use atomic + volatile uint64_t _count; + + string _group; + string _name; +public: + Counter(const string & group, const string & name) + : _count(0), _group(group), _name(name) { + } + + const string & group() const { + return _group; + } + const string & name() const { + return _name; + } + + uint64_t get() const { + return _count; + } + + void increase() { + _count++; + } + + void increase(uint64_t cnt) { + _count += cnt; + } +}; + +class KVIterator { +public: + virtual ~KVIterator() { + } + virtual bool next(Buffer & key, Buffer & value) = 0; +}; + + +class ProcessorBase : public Configurable { +protected: + Collector * _collector; +public: + ProcessorBase() + : _collector(NULL) { + } + + void setCollector(Collector * collector) { + _collector = collector; + } + + Collector * getCollector() { + return _collector; + } + + void collect(const void * key, uint32_t keyLen, const void * value, uint32_t valueLen) { + _collector->collect(key, keyLen, value, valueLen); + } + + void collect(const void * key, uint32_t keyLen, const void * value, uint32_t valueLen, + int32_t partition) { + _collector->collect(key, keyLen, value, valueLen, partition); + } + + Counter * getCounter(const string & group, const string & name); + + virtual void close() { + } +}; + +enum KeyGroupIterState { + SAME_KEY, + NEW_KEY, + NEW_KEY_VALUE, + NO_MORE, +}; + +class KeyGroupIterator { +public: + virtual ~KeyGroupIterator() { + } + /** + * Move to nextKey, or begin this iterator + */ + virtual bool nextKey() = 0; + + /** + * Get key of this input group + */ + virtual const char * getKey(uint32_t & len) = 0; + + /** + * Get next value of this input group + * @return NULL if no more + */ + virtual const char * nextValue(uint32_t & len) = 0; +}; + + + +enum KeyValueType { + TextType = 0, + BytesType = 1, + ByteType = 2, + BoolType = 3, + IntType = 4, + LongType = 5, + FloatType = 6, + DoubleType = 7, + MD5HashType = 8, + VIntType = 9, + VLongType = 10, + UnknownType = -1 +}; + +typedef int (*ComparatorPtr)(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength); + +ComparatorPtr get_comparator(const KeyValueType keyType, const char * comparatorName); + +typedef void (*ANY_FUNC_PTR)(); + +} // namespace NativeTask; + +/** + * Use these two predefined macro to define a class library: + * DEFINE_NATIVE_LIBRARY(Library) + * REGISTER_CLASS(Type, Library) + * For example, suppose we have a demo application, which has + * defined class MyDemoMapper and MyDemoReducer, to register + * this module & these two classes, you need to add following + * code to you source code. + * DEFINE_NATIVE_LIBRARY(MyDemo) { + * REGISTER_CLASS(MyDemoMapper, MyDemo); + * REGISTER_CLASS(MyDemoReducer, MyDemo); + * } + * The class name for MyDemoMapper will be MyDemo.MyDemoMapper, + * and similar for MyDemoReducer. + * Then you can set native.mapper.class to MyDemo.MyDemoMapper + * in JobConf. + */ + +#define DEFINE_NATIVE_LIBRARY(Library) \ + static std::map Library##ClassMap__; \ + extern "C" void * Library##GetFunctionGetter(const std::string & name) { \ + std::map::iterator itr = Library##ClassMap__.find(name); \ + if (itr != Library##ClassMap__.end()) { \ + return (void *)(itr->second); \ + } \ + return NULL; \ + } \ + extern "C" NativeTask::ObjectCreatorFunc Library##GetObjectCreator(const std::string & name) { \ + std::map::iterator itr = Library##ClassMap__.find(name); \ + if (itr != Library##ClassMap__.end()) { \ + return itr->second; \ + } \ + return NULL; \ + } \ + extern "C" void Library##Init() + +#define REGISTER_CLASS(Type, Library) Library##ClassMap__[#Library"."#Type] = NativeTask::ObjectCreator + +#define REGISTER_FUNCTION(Type, Library) Library##ClassMap__[#Library"."#Type] = (ObjectCreatorFunc)Type + +#endif /* NATIVETASK_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/BlockCodec.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/BlockCodec.cc new file mode 100644 index 00000000000..ce36239ff7b --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/BlockCodec.cc @@ -0,0 +1,179 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "NativeTask.h" +#include "BlockCodec.h" + +namespace NativeTask { + +BlockCompressStream::BlockCompressStream(OutputStream * stream, uint32_t bufferSizeHint) + : CompressStream(stream), _tempBuffer(NULL), _tempBufferSize(0), _compressedBytesWritten(0) { + _hint = bufferSizeHint; + _blockMax = bufferSizeHint / 2 * 3; +} + +void BlockCompressStream::init() { + _tempBufferSize = maxCompressedLength(_blockMax) + 8; + _tempBuffer = new char[_tempBufferSize]; +} + +BlockCompressStream::~BlockCompressStream() { + delete[] _tempBuffer; + _tempBuffer = NULL; + _tempBufferSize = 0; +} + +void BlockCompressStream::write(const void * buff, uint32_t length) { + while (length > 0) { + uint32_t take = length < _blockMax ? length : _hint; + compressOneBlock(buff, take); + buff = ((const char *)buff) + take; + length -= take; + } +} + +void BlockCompressStream::flush() { + _stream->flush(); +} + +void BlockCompressStream::close() { + flush(); +} + +void BlockCompressStream::writeDirect(const void * buff, uint32_t length) { + _stream->write(buff, length); + _compressedBytesWritten += length; +} + +uint64_t BlockCompressStream::compressedBytesWritten() { + return _compressedBytesWritten; +} + +////////////////////////////////////////////////////////////// + +BlockDecompressStream::BlockDecompressStream(InputStream * stream, uint32_t bufferSizeHint) + : DecompressStream(stream), _tempBuffer(NULL), _tempBufferSize(0) { + _hint = bufferSizeHint; + _blockMax = bufferSizeHint / 2 * 3; + _tempDecompressBuffer = NULL; + _tempDecompressBufferSize = 0; + _tempDecompressBufferUsed = 0; + _tempDecompressBufferCapacity = 0; + _compressedBytesRead = 0; +} + +void BlockDecompressStream::init() { + _tempBufferSize = maxCompressedLength(_blockMax) + 8; + _tempBuffer = (char*)malloc(_tempBufferSize); +} + +BlockDecompressStream::~BlockDecompressStream() { + close(); + if (NULL != _tempBuffer) { + free(_tempBuffer); + _tempBuffer = NULL; + } + _tempBufferSize = 0; +} + +int32_t BlockDecompressStream::read(void * buff, uint32_t length) { + if (_tempDecompressBufferSize == 0) { + uint32_t sizes[2]; + int32_t rd = _stream->readFully(&sizes, sizeof(uint32_t) * 2); + if (rd <= 0) { + // EOF + return -1; + } + if (rd != sizeof(uint32_t) * 2) { + THROW_EXCEPTION(IOException, "readFully get incomplete data"); + } + _compressedBytesRead += rd; + sizes[0] = bswap(sizes[0]); + sizes[1] = bswap(sizes[1]); + if (sizes[0] <= length) { + uint32_t len = decompressOneBlock(sizes[1], buff, sizes[0]); + if (len != sizes[0]) { + THROW_EXCEPTION(IOException, "Block decompress data error, length not match"); + } + return len; + } else { + if (sizes[0] > _tempDecompressBufferCapacity) { + char * newBuffer = (char *)realloc(_tempDecompressBuffer, sizes[0]); + if (newBuffer == NULL) { + THROW_EXCEPTION(OutOfMemoryException, "realloc failed"); + } + _tempDecompressBuffer = newBuffer; + _tempDecompressBufferCapacity = sizes[0]; + } + uint32_t len = decompressOneBlock(sizes[1], _tempDecompressBuffer, sizes[0]); + if (len != sizes[0]) { + THROW_EXCEPTION(IOException, "Block decompress data error, length not match"); + } + _tempDecompressBufferSize = sizes[0]; + _tempDecompressBufferUsed = 0; + } + } + if (_tempDecompressBufferSize > 0) { + uint32_t left = _tempDecompressBufferSize - _tempDecompressBufferUsed; + if (length < left) { + memcpy(buff, _tempDecompressBuffer + _tempDecompressBufferUsed, length); + _tempDecompressBufferUsed += length; + return length; + } else { + memcpy(buff, _tempDecompressBuffer + _tempDecompressBufferUsed, left); + _tempDecompressBufferSize = 0; + _tempDecompressBufferUsed = 0; + return left; + } + } + // should not get here + THROW_EXCEPTION(IOException, "Decompress logic error"); + return -1; +} + +void BlockDecompressStream::close() { + if (_tempDecompressBufferSize > 0) { + LOG("[BlockDecompressStream] Some data left in the _tempDecompressBuffer when close()"); + } + if (NULL != _tempDecompressBuffer) { + free(_tempDecompressBuffer); + _tempDecompressBuffer = NULL; + _tempDecompressBufferCapacity = 0; + } + _tempDecompressBufferSize = 0; + _tempDecompressBufferUsed = 0; +} + +int32_t BlockDecompressStream::readDirect(void * buff, uint32_t length) { + if (_tempDecompressBufferSize > 0) { + THROW_EXCEPTION(IOException, "temp decompress data exists when call readDirect()"); + } + int32_t ret = _stream->readFully(buff, length); + if (ret > 0) { + _compressedBytesRead += ret; + } + return ret; +} + +uint64_t BlockDecompressStream::compressedBytesRead() { + return _compressedBytesRead; +} + +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/BlockCodec.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/BlockCodec.h new file mode 100644 index 00000000000..ffa4417c064 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/BlockCodec.h @@ -0,0 +1,98 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BLOCKCODEC_H_ +#define BLOCKCODEC_H_ + +#include "lib/Compressions.h" + +namespace NativeTask { + +class BlockCompressStream : public CompressStream { +protected: + uint32_t _hint; + uint32_t _blockMax; + char * _tempBuffer; + uint32_t _tempBufferSize; + uint64_t _compressedBytesWritten; +public: + BlockCompressStream(OutputStream * stream, uint32_t bufferSizeHint); + + virtual ~BlockCompressStream(); + + virtual void write(const void * buff, uint32_t length); + + virtual void flush(); + + virtual void close(); + + virtual void writeDirect(const void * buff, uint32_t length); + + virtual uint64_t compressedBytesWritten(); + + void init(); + +protected: + virtual uint64_t maxCompressedLength(uint64_t origLength) { + return origLength; + } + + virtual void compressOneBlock(const void * buff, uint32_t length) { + } +}; + +class BlockDecompressStream : public DecompressStream { +protected: + uint32_t _hint; + uint32_t _blockMax; + char * _tempBuffer; + uint32_t _tempBufferSize; + char * _tempDecompressBuffer; + uint32_t _tempDecompressBufferSize; + uint32_t _tempDecompressBufferUsed; + uint32_t _tempDecompressBufferCapacity; + uint64_t _compressedBytesRead; +public: + BlockDecompressStream(InputStream * stream, uint32_t bufferSizeHint); + + virtual ~BlockDecompressStream(); + + virtual int32_t read(void * buff, uint32_t length); + + virtual void close(); + + virtual int32_t readDirect(void * buff, uint32_t length); + + virtual uint64_t compressedBytesRead(); + + void init(); + +protected: + virtual uint64_t maxCompressedLength(uint64_t origLength) { + return origLength; + } + + virtual uint32_t decompressOneBlock(uint32_t compressedSize, void * buff, uint32_t length) { + //TODO: add implementation + return 0; + } +}; + +} // namespace NativeTask + +#endif /* BLOCKCODEC_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/GzipCodec.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/GzipCodec.cc new file mode 100644 index 00000000000..b0b985296c8 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/GzipCodec.cc @@ -0,0 +1,192 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "lib/commons.h" +#include "GzipCodec.h" +#include + +namespace NativeTask { + +GzipCompressStream::GzipCompressStream(OutputStream * stream, uint32_t bufferSizeHint) + : CompressStream(stream), _compressedBytesWritten(0), _zstream(NULL), _finished(false) { + _buffer = new char[bufferSizeHint]; + _capacity = bufferSizeHint; + _zstream = malloc(sizeof(z_stream)); + z_stream * zstream = (z_stream*)_zstream; + memset(zstream, 0, sizeof(z_stream)); + if (Z_OK != deflateInit2(zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, + Z_DEFAULT_STRATEGY)) { + free(_zstream); + _zstream = NULL; + THROW_EXCEPTION(IOException, "deflateInit2 failed"); + } + zstream->next_out = (Bytef *)_buffer; + zstream->avail_out = _capacity; +} + +GzipCompressStream::~GzipCompressStream() { + if (_zstream != NULL) { + deflateEnd((z_stream*)_zstream); + free(_zstream); + _zstream = NULL; + } + delete[] _buffer; + _buffer = NULL; +} + +void GzipCompressStream::write(const void * buff, uint32_t length) { + z_stream * zstream = (z_stream*)_zstream; + zstream->next_in = (Bytef*)buff; + zstream->avail_in = length; + while (true) { + int ret = deflate(zstream, Z_NO_FLUSH); + if (ret == Z_OK) { + if (zstream->avail_out == 0) { + _stream->write(_buffer, _capacity); + _compressedBytesWritten += _capacity; + zstream->next_out = (Bytef *)_buffer; + zstream->avail_out = _capacity; + } + if (zstream->avail_in == 0) { + break; + } + } else { + THROW_EXCEPTION(IOException, "deflate return error"); + } + } + _finished = false; +} + +void GzipCompressStream::flush() { + z_stream * zstream = (z_stream*)_zstream; + while (true) { + int ret = deflate(zstream, Z_FINISH); + if (ret == Z_OK) { + if (zstream->avail_out == 0) { + _stream->write(_buffer, _capacity); + _compressedBytesWritten += _capacity; + zstream->next_out = (Bytef *)_buffer; + zstream->avail_out = _capacity; + } else { + THROW_EXCEPTION(IOException, "flush state error"); + } + } else if (ret == Z_STREAM_END) { + size_t wt = zstream->next_out - (Bytef*)_buffer; + _stream->write(_buffer, wt); + _compressedBytesWritten += wt; + zstream->next_out = (Bytef *)_buffer; + zstream->avail_out = _capacity; + break; + } + } + _finished = true; + _stream->flush(); +} + +void GzipCompressStream::resetState() { + z_stream * zstream = (z_stream*)_zstream; + deflateReset(zstream); +} + +void GzipCompressStream::close() { + if (!_finished) { + flush(); + } +} + +void GzipCompressStream::writeDirect(const void * buff, uint32_t length) { + if (!_finished) { + flush(); + } + _stream->write(buff, length); + _compressedBytesWritten += length; +} + +////////////////////////////////////////////////////////////// + +GzipDecompressStream::GzipDecompressStream(InputStream * stream, uint32_t bufferSizeHint) + : DecompressStream(stream), _compressedBytesRead(0), _zstream(NULL) { + _buffer = new char[bufferSizeHint]; + _capacity = bufferSizeHint; + _zstream = malloc(sizeof(z_stream)); + z_stream * zstream = (z_stream*)_zstream; + memset(zstream, 0, sizeof(z_stream)); + if (Z_OK != inflateInit2(zstream, 31)) { + free(_zstream); + _zstream = NULL; + THROW_EXCEPTION(IOException, "inflateInit2 failed"); + } + zstream->next_in = NULL; + zstream->avail_in = 0; + _eof = false; +} + +GzipDecompressStream::~GzipDecompressStream() { + if (_zstream != NULL) { + inflateEnd((z_stream*)_zstream); + free(_zstream); + _zstream = NULL; + } + delete[] _buffer; + _buffer = NULL; +} + +int32_t GzipDecompressStream::read(void * buff, uint32_t length) { + z_stream * zstream = (z_stream*)_zstream; + zstream->next_out = (Bytef*)buff; + zstream->avail_out = length; + while (true) { + if (zstream->avail_in == 0) { + int32_t rd = _stream->read(_buffer, _capacity); + if (rd <= 0) { + _eof = true; + size_t wt = zstream->next_out - (Bytef*)buff; + return wt > 0 ? wt : -1; + } else { + _compressedBytesRead += rd; + zstream->next_in = (Bytef*)_buffer; + zstream->avail_in = rd; + } + } + int ret = inflate(zstream, Z_NO_FLUSH); + if (ret == Z_OK || ret == Z_STREAM_END) { + if (zstream->avail_out == 0) { + return length; + } + } else { + return -1; + } + } + return -1; +} + +void GzipDecompressStream::close() { +} + +int32_t GzipDecompressStream::readDirect(void * buff, uint32_t length) { + int32_t ret = _stream->readFully(buff, length); + if (ret > 0) { + _compressedBytesRead += ret; + } + return ret; +} + +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/GzipCodec.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/GzipCodec.h new file mode 100644 index 00000000000..a5f986ef967 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/GzipCodec.h @@ -0,0 +1,82 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GZIPCODEC_H_ +#define GZIPCODEC_H_ + +#include "lib/Compressions.h" + +namespace NativeTask { + +class GzipCompressStream : public CompressStream { +protected: + uint64_t _compressedBytesWritten; + char * _buffer; + uint32_t _capacity; + void * _zstream; + bool _finished; +public: + GzipCompressStream(OutputStream * stream, uint32_t bufferSizeHint); + + virtual ~GzipCompressStream(); + + virtual void write(const void * buff, uint32_t length); + + virtual void flush(); + + virtual void close(); + + virtual void finish() { + flush(); + } + + virtual void resetState(); + + virtual void writeDirect(const void * buff, uint32_t length); + + virtual uint64_t compressedBytesWritten() { + return _compressedBytesWritten; + } +}; + +class GzipDecompressStream : public DecompressStream { +protected: + uint64_t _compressedBytesRead; + char * _buffer; + uint32_t _capacity; + void * _zstream; + bool _eof; +public: + GzipDecompressStream(InputStream * stream, uint32_t bufferSizeHint); + + virtual ~GzipDecompressStream(); + + virtual int32_t read(void * buff, uint32_t length); + + virtual void close(); + + virtual int32_t readDirect(void * buff, uint32_t length); + + virtual uint64_t compressedBytesRead() { + return _compressedBytesRead; + } +}; + +} // namespace NativeTask + +#endif /* GZIPCODEC_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/Lz4Codec.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/Lz4Codec.cc new file mode 100644 index 00000000000..75bfad17def --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/Lz4Codec.cc @@ -0,0 +1,88 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lz4.h" +#include "NativeTask.h" +#include "Lz4Codec.h" + + +namespace NativeTask { + +static int32_t LZ4_MaxCompressedSize(int32_t orig) { + return LZ4_compressBound(orig); +} + +Lz4CompressStream::Lz4CompressStream(OutputStream * stream, uint32_t bufferSizeHint) + : BlockCompressStream(stream, bufferSizeHint) { + init(); +} + +void Lz4CompressStream::compressOneBlock(const void * buff, uint32_t length) { + size_t compressedLength = _tempBufferSize - 8; + int ret = LZ4_compress((char*)buff, _tempBuffer + 8, length); + if (ret > 0) { + compressedLength = ret; + ((uint32_t*)_tempBuffer)[0] = bswap(length); + ((uint32_t*)_tempBuffer)[1] = bswap((uint32_t)compressedLength); + _stream->write(_tempBuffer, compressedLength + 8); + _compressedBytesWritten += (compressedLength + 8); + } else { + THROW_EXCEPTION(IOException, "compress LZ4 failed"); + } +} + +uint64_t Lz4CompressStream::maxCompressedLength(uint64_t origLength) { + return LZ4_MaxCompressedSize(origLength); +} + +////////////////////////////////////////////////////////////// + +Lz4DecompressStream::Lz4DecompressStream(InputStream * stream, uint32_t bufferSizeHint) + : BlockDecompressStream(stream, bufferSizeHint) { + init(); +} + +uint32_t Lz4DecompressStream::decompressOneBlock(uint32_t compressedSize, void * buff, + uint32_t length) { + if (compressedSize > _tempBufferSize) { + char * newBuffer = (char *)realloc(_tempBuffer, compressedSize); + if (newBuffer == NULL) { + THROW_EXCEPTION(OutOfMemoryException, "realloc failed"); + } + _tempBuffer = newBuffer; + _tempBufferSize = compressedSize; + } + uint32_t rd = _stream->readFully(_tempBuffer, compressedSize); + if (rd != compressedSize) { + THROW_EXCEPTION(IOException, "readFully reach EOF"); + } + _compressedBytesRead += rd; + uint32_t ret = LZ4_uncompress(_tempBuffer, (char*)buff, length); + if (ret == compressedSize) { + return length; + } else { + THROW_EXCEPTION(IOException, "decompress LZ4 failed"); + } +} + +uint64_t Lz4DecompressStream::maxCompressedLength(uint64_t origLength) { + return LZ4_MaxCompressedSize(origLength); +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/Lz4Codec.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/Lz4Codec.h new file mode 100644 index 00000000000..f3dd1682149 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/Lz4Codec.h @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LZ4CODEC_H_ +#define LZ4CODEC_H_ + +#include "lib/Compressions.h" +#include "BlockCodec.h" + +namespace NativeTask { + +class Lz4CompressStream : public BlockCompressStream { +public: + Lz4CompressStream(OutputStream * stream, uint32_t bufferSizeHint); +protected: + virtual uint64_t maxCompressedLength(uint64_t origLength); + virtual void compressOneBlock(const void * buff, uint32_t length); +}; + +class Lz4DecompressStream : public BlockDecompressStream { +public: + Lz4DecompressStream(InputStream * stream, uint32_t bufferSizeHint); +protected: + virtual uint64_t maxCompressedLength(uint64_t origLength); + virtual uint32_t decompressOneBlock(uint32_t compressedSize, void * buff, uint32_t length); +}; + +} // namespace NativeTask + +#endif /* LZ4CODEC_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/SnappyCodec.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/SnappyCodec.cc new file mode 100644 index 00000000000..a0417e06f45 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/SnappyCodec.cc @@ -0,0 +1,98 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config.h" + +#if defined HADOOP_SNAPPY_LIBRARY +#include "lib/commons.h" +#include "NativeTask.h" +#include "SnappyCodec.h" + +#include + +namespace NativeTask { + +SnappyCompressStream::SnappyCompressStream(OutputStream * stream, uint32_t bufferSizeHint) + : BlockCompressStream(stream, bufferSizeHint) { + init(); +} + +void SnappyCompressStream::compressOneBlock(const void * buff, uint32_t length) { + size_t compressedLength = _tempBufferSize - 8; + snappy_status ret = snappy_compress((const char*)buff, length, _tempBuffer + 8, + &compressedLength); + if (ret == SNAPPY_OK) { + ((uint32_t*)_tempBuffer)[0] = bswap(length); + ((uint32_t*)_tempBuffer)[1] = bswap((uint32_t)compressedLength); + _stream->write(_tempBuffer, compressedLength + 8); + _compressedBytesWritten += (compressedLength + 8); + } else if (ret == SNAPPY_INVALID_INPUT) { + THROW_EXCEPTION(IOException, "compress SNAPPY_INVALID_INPUT"); + } else if (ret == SNAPPY_BUFFER_TOO_SMALL) { + THROW_EXCEPTION(IOException, "compress SNAPPY_BUFFER_TOO_SMALL"); + } else { + THROW_EXCEPTION(IOException, "compress snappy failed"); + } +} + +uint64_t SnappyCompressStream::maxCompressedLength(uint64_t origLength) { + return snappy_max_compressed_length(origLength); +} + +////////////////////////////////////////////////////////////// + +SnappyDecompressStream::SnappyDecompressStream(InputStream * stream, uint32_t bufferSizeHint) + : BlockDecompressStream(stream, bufferSizeHint) { + init(); +} + +uint32_t SnappyDecompressStream::decompressOneBlock(uint32_t compressedSize, void * buff, + uint32_t length) { + if (compressedSize > _tempBufferSize) { + char * newBuffer = (char *)realloc(_tempBuffer, compressedSize); + if (newBuffer == NULL) { + THROW_EXCEPTION(OutOfMemoryException, "realloc failed"); + } + _tempBuffer = newBuffer; + _tempBufferSize = compressedSize; + } + uint32_t rd = _stream->readFully(_tempBuffer, compressedSize); + if (rd != compressedSize) { + THROW_EXCEPTION(IOException, "readFully reach EOF"); + } + _compressedBytesRead += rd; + size_t uncompressedLength = length; + snappy_status ret = snappy_uncompress(_tempBuffer, compressedSize, (char *)buff, + &uncompressedLength); + if (ret == SNAPPY_OK) { + return uncompressedLength; + } else if (ret == SNAPPY_INVALID_INPUT) { + THROW_EXCEPTION(IOException, "decompress SNAPPY_INVALID_INPUT"); + } else if (ret == SNAPPY_BUFFER_TOO_SMALL) { + THROW_EXCEPTION(IOException, "decompress SNAPPY_BUFFER_TOO_SMALL"); + } else { + THROW_EXCEPTION(IOException, "decompress snappy failed"); + } +} + +uint64_t SnappyDecompressStream::maxCompressedLength(uint64_t origLength) { + return snappy_max_compressed_length(origLength); +} +} // namespace NativeTask + +#endif // define HADOOP_SNAPPY_LIBRARY diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/SnappyCodec.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/SnappyCodec.h new file mode 100644 index 00000000000..0673cf34d3f --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/codec/SnappyCodec.h @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SNAPPYCODEC_H_ +#define SNAPPYCODEC_H_ + +#include "lib/Compressions.h" +#include "BlockCodec.h" + +namespace NativeTask { + +class SnappyCompressStream : public BlockCompressStream { +public: + SnappyCompressStream(OutputStream * stream, uint32_t bufferSizeHint); +protected: + virtual uint64_t maxCompressedLength(uint64_t origLength); + virtual void compressOneBlock(const void * buff, uint32_t length); +}; + +class SnappyDecompressStream : public BlockDecompressStream { +public: + SnappyDecompressStream(InputStream * stream, uint32_t bufferSizeHint); + +protected: + virtual uint64_t maxCompressedLength(uint64_t origLength); + virtual uint32_t decompressOneBlock(uint32_t compressedSize, void * buff, uint32_t length); +}; + +} // namespace NativeTask + +#endif /* SNAPPYCODEC_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/AbstractMapHandler.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/AbstractMapHandler.cc new file mode 100644 index 00000000000..37e0d42e424 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/AbstractMapHandler.cc @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "util/StringUtil.h" +#include "MCollectorOutputHandler.h" +#include "lib/NativeObjectFactory.h" +#include "lib/MapOutputCollector.h" +#include "CombineHandler.h" + +using std::string; +using std::vector; + +namespace NativeTask { +const Command AbstractMapHandler::GET_OUTPUT_PATH(100, "GET_OUTPUT_PATH"); +const Command AbstractMapHandler::GET_OUTPUT_INDEX_PATH(101, "GET_OUTPUT_INDEX_PATH"); +const Command AbstractMapHandler::GET_SPILL_PATH(102, "GET_SPILL_PATH"); +const Command AbstractMapHandler::GET_COMBINE_HANDLER(103, "GET_COMBINE_HANDLER"); +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/AbstractMapHandler.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/AbstractMapHandler.h new file mode 100644 index 00000000000..d46cea25d5d --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/AbstractMapHandler.h @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ABSTRACT_MAP_HANDLER_H +#define ABSTRACT_MAP_HANDLER_H + +#include "NativeTask.h" +#include "BatchHandler.h" +#include "lib/SpillOutputService.h" +#include "lib/Combiner.h" +#include "CombineHandler.h" + +namespace NativeTask { + +class AbstractMapHandler : public BatchHandler, public SpillOutputService { +public: + static const Command GET_OUTPUT_PATH; + static const Command GET_OUTPUT_INDEX_PATH; + static const Command GET_SPILL_PATH; + static const Command GET_COMBINE_HANDLER; + +public: + AbstractMapHandler() {} + + virtual ~AbstractMapHandler() {} + + virtual void configure(Config * config) { + _config = config; + } + + virtual string * getOutputPath() { + ResultBuffer * outputPathResult = call(GET_OUTPUT_PATH, NULL); + if (NULL == outputPathResult) { + return NULL; + } + string * outputPath = outputPathResult->readString(); + + delete outputPathResult; + return outputPath; + } + + virtual string * getOutputIndexPath() { + + ResultBuffer * outputIndexPath = call(GET_OUTPUT_INDEX_PATH, NULL); + if (NULL == outputIndexPath) { + return NULL; + } + string * indexpath = outputIndexPath->readString(); + delete outputIndexPath; + return indexpath; + } + + + virtual string * getSpillPath() { + ResultBuffer * spillPathBuffer = call(GET_SPILL_PATH, NULL); + if (NULL == spillPathBuffer) { + return NULL; + } + string * spillpath = spillPathBuffer->readString(); + delete spillPathBuffer; + return spillpath; + } + + virtual CombineHandler * getJavaCombineHandler() { + + LOG("[MapOutputCollector::configure] java combiner is configured"); + + ResultBuffer * getCombineHandlerResult = call(GET_COMBINE_HANDLER, NULL); + if (NULL != getCombineHandlerResult) { + + getCombineHandlerResult->setReadPoint(0); + + CombineHandler * javaCombiner = (CombineHandler *)((BatchHandler * )(getCombineHandlerResult->readPointer())); + delete getCombineHandlerResult; + return javaCombiner; + } + + + + return NULL; + } + +}; + +} // namespace NativeTask + +#endif /* MMAPPERHANDLER_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/BatchHandler.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/BatchHandler.cc new file mode 100644 index 00000000000..ecb217cfccf --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/BatchHandler.cc @@ -0,0 +1,355 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef QUICK_BUILD +#include "org_apache_hadoop_mapred_nativetask_NativeBatchProcessor.h" +#endif +#include "lib/commons.h" +#include "jni_md.h" +#include "lib/jniutils.h" +#include "BatchHandler.h" +#include "lib/NativeObjectFactory.h" + +/////////////////////////////////////////////////////////////// +// NativeBatchProcessor jni util methods +/////////////////////////////////////////////////////////////// + +static jfieldID InputBufferFieldID = NULL; +static jfieldID OutputBufferFieldID = NULL; +static jmethodID FlushOutputMethodID = NULL; +static jmethodID FinishOutputMethodID = NULL; +static jmethodID SendCommandToJavaMethodID = NULL; + +/////////////////////////////////////////////////////////////// +// BatchHandler methods +/////////////////////////////////////////////////////////////// + +namespace NativeTask { + +ReadWriteBuffer * JNU_ByteArraytoReadWriteBuffer(JNIEnv * jenv, jbyteArray src) { + if (NULL == src) { + return NULL; + } + jsize len = jenv->GetArrayLength(src); + + ReadWriteBuffer * ret = new ReadWriteBuffer(len); + jenv->GetByteArrayRegion(src, 0, len, (jbyte*)ret->getBuff()); + ret->setWritePoint(len); + return ret; +} + +jbyteArray JNU_ReadWriteBufferToByteArray(JNIEnv * jenv, ReadWriteBuffer * result) { + if (NULL == result || result->getWritePoint() == 0) { + return NULL; + } + + jbyteArray ret = jenv->NewByteArray(result->getWritePoint()); + jenv->SetByteArrayRegion(ret, 0, result->getWritePoint(), (jbyte*)result->getBuff()); + return ret; +} + +BatchHandler::BatchHandler() + : _processor(NULL), _config(NULL) { +} + +BatchHandler::~BatchHandler() { + releaseProcessor(); + if (NULL != _config) { + delete _config; + _config = NULL; + } +} + +void BatchHandler::releaseProcessor() { + if (_processor != NULL) { + JNIEnv * env = JNU_GetJNIEnv(); + env->DeleteGlobalRef((jobject)_processor); + _processor = NULL; + } +} + +void BatchHandler::onInputData(uint32_t length) { + _in.rewind(0, length); + handleInput(_in); +} + +void BatchHandler::flushOutput() { + + if (NULL == _out.base()) { + return; + } + + uint32_t length = _out.position(); + _out.position(0); + + if (length == 0) { + return; + } + + JNIEnv * env = JNU_GetJNIEnv(); + env->CallVoidMethod((jobject)_processor, FlushOutputMethodID, (jint)length); + if (env->ExceptionCheck()) { + THROW_EXCEPTION(JavaException, "FlushOutput throw exception"); + } +} + +void BatchHandler::finishOutput() { + if (NULL == _out.base()) { + return; + } + JNIEnv * env = JNU_GetJNIEnv(); + env->CallVoidMethod((jobject)_processor, FinishOutputMethodID); + if (env->ExceptionCheck()) { + THROW_EXCEPTION(JavaException, "FinishOutput throw exception"); + } +} + +void BatchHandler::onSetup(Config * config, char * inputBuffer, uint32_t inputBufferCapacity, + char * outputBuffer, uint32_t outputBufferCapacity) { + this->_config = config; + _in.reset(inputBuffer, inputBufferCapacity); + if (NULL != outputBuffer) { + if (outputBufferCapacity <= 1024) { + THROW_EXCEPTION(IOException, "Output buffer size too small for BatchHandler"); + } + _out.reset(outputBuffer, outputBufferCapacity); + _out.rewind(0, outputBufferCapacity); + + LOG("[BatchHandler::onSetup] input Capacity %d, output capacity %d", + inputBufferCapacity, _out.limit()); + } + configure(_config); +} + +ResultBuffer * BatchHandler::call(const Command& cmd, ParameterBuffer * param) { + JNIEnv * env = JNU_GetJNIEnv(); + jbyteArray jcmdData = JNU_ReadWriteBufferToByteArray(env, param); + jbyteArray ret = (jbyteArray)env->CallObjectMethod((jobject)_processor, SendCommandToJavaMethodID, + cmd.id(), jcmdData); + + + if (env->ExceptionCheck()) { + THROW_EXCEPTION(JavaException, "SendCommandToJava throw exception"); + } + return JNU_ByteArraytoReadWriteBuffer(env, ret); +} + +} // namespace NativeTask + +/////////////////////////////////////////////////////////////// +// NativeBatchProcessor jni methods +/////////////////////////////////////////////////////////////// +using namespace NativeTask; + +/* + * Class: org_apache_hadoop_mapred_nativetask_NativeBatchProcessor + * Method: setupHandler + * Signature: (J)V + */ +void JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeBatchProcessor_setupHandler( + JNIEnv * jenv, jobject processor, jlong handler, jobjectArray configs) { + try { + + NativeTask::Config * config = new NativeTask::Config(); + jsize len = jenv->GetArrayLength(configs); + for (jsize i = 0; i + 1 < len; i += 2) { + jbyteArray key_obj = (jbyteArray)jenv->GetObjectArrayElement(configs, i); + jbyteArray val_obj = (jbyteArray)jenv->GetObjectArrayElement(configs, i + 1); + config->set(JNU_ByteArrayToString(jenv, key_obj), JNU_ByteArrayToString(jenv, val_obj)); + } + + NativeTask::BatchHandler * batchHandler = (NativeTask::BatchHandler *)((void*)handler); + if (NULL == batchHandler) { + JNU_ThrowByName(jenv, "java/lang/IllegalArgumentException", "BatchHandler is null"); + return; + } + jobject jinputBuffer = jenv->GetObjectField(processor, InputBufferFieldID); + char * inputBufferAddr = NULL; + uint32_t inputBufferCapacity = 0; + if (NULL != jinputBuffer) { + inputBufferAddr = (char*)(jenv->GetDirectBufferAddress(jinputBuffer)); + inputBufferCapacity = jenv->GetDirectBufferCapacity(jinputBuffer); + } + jobject joutputBuffer = jenv->GetObjectField(processor, OutputBufferFieldID); + char * outputBufferAddr = NULL; + uint32_t outputBufferCapacity = 0; + if (NULL != joutputBuffer) { + outputBufferAddr = (char*)(jenv->GetDirectBufferAddress(joutputBuffer)); + outputBufferCapacity = jenv->GetDirectBufferCapacity(joutputBuffer); + } + batchHandler->setProcessor(jenv->NewGlobalRef(processor)); + batchHandler->onSetup(config, inputBufferAddr, inputBufferCapacity, outputBufferAddr, + outputBufferCapacity); + } catch (NativeTask::UnsupportException & e) { + JNU_ThrowByName(jenv, "java/lang/UnsupportedOperationException", e.what()); + } catch (NativeTask::OutOfMemoryException & e) { + JNU_ThrowByName(jenv, "java/lang/OutOfMemoryError", e.what()); + } catch (NativeTask::IOException & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (NativeTask::JavaException & e) { + LOG("JavaException: %s", e.what()); + // Do nothing, let java side handle + } catch (std::exception & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (...) { + JNU_ThrowByName(jenv, "java/io/IOException", "Unknown exception"); + } +} + +/* + * Class: org_apache_hadoop_mapred_nativetask_NativeBatchProcessor + * Method: nativeProcessInput + * Signature: (JI)V + */ +void JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeBatchProcessor_nativeProcessInput( + JNIEnv * jenv, jobject processor, jlong handler, jint length) { + + try { + NativeTask::BatchHandler * batchHandler = (NativeTask::BatchHandler *)((void*)handler); + if (NULL == batchHandler) { + JNU_ThrowByName(jenv, "java/lang/IllegalArgumentException", + "handler not instance of BatchHandler"); + return; + } + batchHandler->onInputData(length); + } catch (NativeTask::UnsupportException & e) { + JNU_ThrowByName(jenv, "java/lang/UnsupportedOperationException", e.what()); + } catch (NativeTask::OutOfMemoryException & e) { + JNU_ThrowByName(jenv, "java/lang/OutOfMemoryError", e.what()); + } catch (NativeTask::IOException & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (NativeTask::JavaException & e) { + LOG("JavaException: %s", e.what()); + // Do nothing, let java side handle + } catch (std::exception & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (...) { + JNU_ThrowByName(jenv, "java/io/IOException", "Unknown exception"); + } +} + +/* + * Class: org_apache_hadoop_mapred_nativetask_NativeBatchProcessor + * Method: nativeFinish + * Signature: (J)V + */ +void JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeBatchProcessor_nativeFinish( + JNIEnv * jenv, jobject processor, jlong handler) { + try { + NativeTask::BatchHandler * batchHandler = (NativeTask::BatchHandler *)((void*)handler); + if (NULL == batchHandler) { + JNU_ThrowByName(jenv, "java/lang/IllegalArgumentException", + "handler not instance of BatchHandler"); + return; + } + batchHandler->onFinish(); + } catch (NativeTask::UnsupportException & e) { + JNU_ThrowByName(jenv, "java/lang/UnsupportedOperationException", e.what()); + } catch (NativeTask::OutOfMemoryException & e) { + JNU_ThrowByName(jenv, "java/lang/OutOfMemoryError", e.what()); + } catch (NativeTask::IOException & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (NativeTask::JavaException & e) { + LOG("JavaException: %s", e.what()); + // Do nothing, let java side handle + } catch (std::exception & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (...) { + JNU_ThrowByName(jenv, "java/io/IOException", "Unknown exception"); + } +} + +void JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeBatchProcessor_nativeLoadData( + JNIEnv * jenv, jobject processor, jlong handler) { + try { + NativeTask::BatchHandler * batchHandler = (NativeTask::BatchHandler *)((void*)handler); + if (NULL == batchHandler) { + JNU_ThrowByName(jenv, "java/lang/IllegalArgumentException", + "handler not instance of BatchHandler"); + return; + } + batchHandler->onLoadData(); + } catch (NativeTask::UnsupportException & e) { + JNU_ThrowByName(jenv, "java/lang/UnsupportedOperationException", e.what()); + } catch (NativeTask::OutOfMemoryException & e) { + JNU_ThrowByName(jenv, "java/lang/OutOfMemoryError", e.what()); + } catch (NativeTask::IOException & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (NativeTask::JavaException & e) { + LOG("JavaException: %s", e.what()); + // Do nothing, let java side handle + } catch (std::exception & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (...) { + JNU_ThrowByName(jenv, "java/io/IOException", "Unknown exception"); + } +} + +/* + * Class: org_apache_hadoop_mapred_nativetask_NativeBatchProcessor + * Method: nativeCommand + * Signature: (J[B)[B + */ +jbyteArray JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeBatchProcessor_nativeCommand( + JNIEnv * jenv, jobject processor, jlong handler, jint command, jbyteArray cmdData) { + try { + NativeTask::BatchHandler * batchHandler = (NativeTask::BatchHandler *)((void*)handler); + if (NULL == batchHandler) { + JNU_ThrowByName(jenv, "java/lang/IllegalArgumentException", + "handler not instance of BatchHandler"); + return NULL; + } + Command cmd(command); + ParameterBuffer * param = JNU_ByteArraytoReadWriteBuffer(jenv, cmdData); + ResultBuffer * result = batchHandler->onCall(cmd, param); + jbyteArray ret = JNU_ReadWriteBufferToByteArray(jenv, result); + + delete result; + delete param; + return ret; + } catch (NativeTask::UnsupportException & e) { + JNU_ThrowByName(jenv, "java/lang/UnsupportedOperationException", e.what()); + } catch (NativeTask::OutOfMemoryException & e) { + JNU_ThrowByName(jenv, "java/lang/OutOfMemoryError", e.what()); + } catch (NativeTask::IOException & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (const NativeTask::JavaException & e) { + LOG("JavaException: %s", e.what()); + // Do nothing, let java side handle + } catch (std::exception & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (...) { + JNU_ThrowByName(jenv, "java/io/IOException", "Unknown exception"); + } + return NULL; +} + +/* + * Class: org_apace_hadoop_mapred_nativetask_NativeBatchProcessor + * Method: InitIDs + * Signature: ()V + */ +void JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeBatchProcessor_InitIDs(JNIEnv * jenv, + jclass processorClass) { + InputBufferFieldID = jenv->GetFieldID(processorClass, "rawOutputBuffer", "Ljava/nio/ByteBuffer;"); + OutputBufferFieldID = jenv->GetFieldID(processorClass, "rawInputBuffer", "Ljava/nio/ByteBuffer;"); + FlushOutputMethodID = jenv->GetMethodID(processorClass, "flushOutput", "(I)V"); + FinishOutputMethodID = jenv->GetMethodID(processorClass, "finishOutput", "()V"); + SendCommandToJavaMethodID = jenv->GetMethodID(processorClass, "sendCommandToJava", "(I[B)[B"); +} + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/BatchHandler.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/BatchHandler.h new file mode 100644 index 00000000000..15ce2eaf823 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/BatchHandler.h @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BATCHHANDLER_H_ +#define BATCHHANDLER_H_ + +#include "NativeTask.h" +#include "lib/Buffers.h" + +namespace NativeTask { + +/** + * Native side counterpart of java side NativeBatchProcessor + */ +class BatchHandler : public Configurable { +protected: + ByteBuffer _in; + ByteBuffer _out; + void * _processor; + Config * _config; +public: + BatchHandler(); + virtual ~BatchHandler(); + + virtual NativeObjectType type() { + return BatchHandlerType; + } + + /** + * Called by native jni functions to set global jni reference + */ + void setProcessor(void * processor) { + _processor = processor; + } + + void releaseProcessor(); + + /** + * Called by java side to setup native side BatchHandler + * initialize buffers by default + */ + void onSetup(Config * config, char * inputBuffer, uint32_t inputBufferCapacity, + char * outputBuffer, uint32_t outputBufferCapacity); + + /** + * Called by java side to notice that input data available to handle + * @param length input buffer's available data length + */ + void onInputData(uint32_t length); + + virtual void onLoadData() { + } + + /** + * Called by java side to notice that input has finished + */ + void onFinish() { + finish(); + } + + /** + * Called by java side to send command to this handler + * BatchHandler ignore all command by default + * @param cmd command data + * @return command return value + */ + virtual ResultBuffer * onCall(const Command& command, ReadWriteBuffer * param) { + return NULL; + } + +protected: + virtual ResultBuffer * call(const Command& cmd, ParameterBuffer * param); + + /** + * Used by subclass, call java side flushOutput(int length) + * @param length output buffer's available data length + */ + virtual void flushOutput(); + + /** + * Used by subclass, call java side finishOutput() + */ + void finishOutput(); + + /** + * Write output buffer and use flushOutput manually, + * or use this helper method + */ + inline void output(const char * buff, uint32_t length) { + while (length > 0) { + uint32_t remain = _out.remain(); + if (length > remain) { + flushOutput(); + } + uint32_t cp = length < remain ? length : remain; + simple_memcpy(_out.current(), buff, cp); + buff += cp; + length -= cp; + _out.advance(cp); + } + } + + inline void outputInt(uint32_t v) { + if (4 > _out.remain()) { + flushOutput(); + } + *(uint32_t*)(_out.current()) = v; + _out.advance(4); + } + + ///////////////////////////////////////////////////////////// + // Subclass should implement these if needed + ///////////////////////////////////////////////////////////// + + /** + * Called by onSetup, do nothing by default + * Subclass should override this if needed + */ + virtual void configure(Config * config) { + } + + /** + * Called by onFinish, flush & close output by default + * Subclass should override this if needed + */ + virtual void finish() { + flushOutput(); + finishOutput(); + } + ; + + /** + * Called by onInputData, internal input data processor, + * Subclass should override this if needed + */ + virtual void handleInput(ByteBuffer & byteBuffer) { + } +}; + +} // namespace NativeTask + +#endif /* BATCHHANDLER_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/CombineHandler.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/CombineHandler.cc new file mode 100644 index 00000000000..5f3863eb629 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/CombineHandler.cc @@ -0,0 +1,254 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "CombineHandler.h" + +namespace NativeTask { +const char * REFILL = "refill"; +const int LENGTH_OF_REFILL_STRING = 6; + +const Command CombineHandler::COMBINE(4, "Combine"); + +CombineHandler::CombineHandler() + : _combineContext(NULL), _kvIterator(NULL), _writer(NULL), _kType(UnknownType), + _vType(UnknownType), _config(NULL), _kvCached(false), _combineInputRecordCount(0), + _combineInputBytes(0), _combineOutputRecordCount(0), _combineOutputBytes(0) { +} + +CombineHandler::~CombineHandler() { +} + +void CombineHandler::configure(Config * config) { + + _config = config; + MapOutputSpec::getSpecFromConfig(_config, _mapOutputSpec); + _kType = _mapOutputSpec.keyType; + _vType = _mapOutputSpec.valueType; +} + +uint32_t CombineHandler::feedDataToJavaInWritableSerialization() { + + uint32_t written = 0; + bool firstKV = true; + _out.position(0); + + if (_kvCached) { + uint32_t kvLength = _key.outerLength + _value.outerLength + KVBuffer::headerLength(); + outputInt(bswap(_key.outerLength)); + outputInt(bswap(_value.outerLength)); + outputKeyOrValue(_key, _kType); + outputKeyOrValue(_value, _vType); + + written += kvLength; + _kvCached = false; + firstKV = false; + } + + uint32_t recordCount = 0; + while (nextKeyValue(_key, _value)) { + + //::sleep(5); + _kvCached = false; + recordCount++; + + uint32_t kvLength = _key.outerLength + _value.outerLength + KVBuffer::headerLength(); + + if (!firstKV && kvLength > _out.remain()) { + _kvCached = true; + break; + } else { + firstKV = false; + //write final key length and final value length + outputInt(bswap(_key.outerLength)); + outputInt(bswap(_value.outerLength)); + outputKeyOrValue(_key, _kType); + outputKeyOrValue(_value, _vType); + + written += kvLength; + } + } + + if (_out.position() > 0) { + flushOutput(); + } + + _combineInputRecordCount += recordCount; + _combineInputBytes += written; + return written; +} + +/** + * KV: key or value + */ +void CombineHandler::outputKeyOrValue(SerializeInfo & KV, KeyValueType type) { + switch (type) { + case TextType: + output(KV.varBytes, KV.outerLength - KV.buffer.length()); + output(KV.buffer.data(), KV.buffer.length()); + break; + case BytesType: + outputInt(bswap(KV.buffer.length())); + output(KV.buffer.data(), KV.buffer.length()); + break; + default: + output(KV.buffer.data(), KV.buffer.length()); + break; + } +} + +bool CombineHandler::nextKeyValue(SerializeInfo & key, SerializeInfo & value) { + + if (!_kvIterator->next(key.buffer, value.buffer)) { + return false; + } + + uint32_t varLength = 0; + switch (_kType) { + case TextType: + WritableUtils::WriteVInt(key.buffer.length(), key.varBytes, varLength); + key.outerLength = key.buffer.length() + varLength; + break; + case BytesType: + key.outerLength = key.buffer.length() + 4; + break; + default: + key.outerLength = key.buffer.length(); + break; + } + + //prepare final value length + uint32_t varValueLength = 0; + switch (_vType) { + case TextType: + WritableUtils::WriteVInt(value.buffer.length(), value.varBytes, varValueLength); + value.outerLength = value.buffer.length() + varValueLength; + break; + case BytesType: + value.outerLength = value.buffer.length() + 4; + break; + default: + value.outerLength = value.buffer.length(); + break; + } + + return true; +} + +uint32_t CombineHandler::feedDataToJava(SerializationFramework serializationType) { + if (serializationType == WRITABLE_SERIALIZATION) { + return feedDataToJavaInWritableSerialization(); + } + THROW_EXCEPTION(IOException, "Native Serialization not supported"); +} + +void CombineHandler::handleInput(ByteBuffer & in) { + char * buff = in.current(); + uint32_t length = in.remain(); + uint32_t remain = length; + char * pos = buff; + if (_asideBuffer.remain() > 0) { + uint32_t filledLength = _asideBuffer.fill(pos, length); + pos += filledLength; + remain -= filledLength; + } + + if (_asideBuffer.size() > 0 && _asideBuffer.remain() == 0) { + _asideBuffer.position(0); + write(_asideBuffer.current(), _asideBuffer.size()); + _asideBuffer.wrap(NULL, 0); + } + + if (remain == 0) { + return; + } + KVBuffer * kvBuffer = (KVBuffer *)pos; + + if (unlikely(remain < kvBuffer->headerLength())) { + THROW_EXCEPTION(IOException, "k/v meta information incomplete"); + } + + uint32_t kvLength = kvBuffer->lengthConvertEndium(); + + if (kvLength > remain) { + _asideBytes.resize(kvLength); + _asideBuffer.wrap(_asideBytes.buff(), _asideBytes.size()); + _asideBuffer.fill(pos, remain); + pos += remain; + remain = 0; + } else { + write(pos, remain); + } +} + +void CombineHandler::write(char * buf, uint32_t length) { + KVBuffer * kv = NULL; + char * pos = buf; + uint32_t remain = length; + + uint32_t outputRecordCount = 0; + while (remain > 0) { + kv = (KVBuffer *)pos; + kv->keyLength = bswap(kv->keyLength); + kv->valueLength = bswap(kv->valueLength); + _writer->write(kv->getKey(), kv->keyLength, kv->getValue(), kv->valueLength); + outputRecordCount++; + remain -= kv->length(); + pos += kv->length(); + } + + _combineOutputRecordCount += outputRecordCount; + _combineOutputBytes += length; +} + +string toString(uint32_t length) { + string result; + result.reserve(4); + result.assign((char *)(&length), 4); + return result; +} + +void CombineHandler::onLoadData() { + feedDataToJava(WRITABLE_SERIALIZATION); +} + +ResultBuffer * CombineHandler::onCall(const Command& command, ParameterBuffer * param) { + THROW_EXCEPTION(UnsupportException, "Command not supported by RReducerHandler"); +} + +void CombineHandler::combine(CombineContext type, KVIterator * kvIterator, IFileWriter * writer) { + + _combineInputRecordCount = 0; + _combineOutputRecordCount = 0; + _combineInputBytes = 0; + _combineOutputBytes = 0; + + this->_combineContext = &type; + this->_kvIterator = kvIterator; + this->_writer = writer; + call(COMBINE, NULL); + + LOG("[CombineHandler] input Record Count: %d, input Bytes: %d, " + "output Record Count: %d, output Bytes: %d", + _combineInputRecordCount, _combineInputBytes, + _combineOutputRecordCount, _combineOutputBytes); + return; +} + +void CombineHandler::finish() { +} + +} /* namespace NativeTask */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/CombineHandler.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/CombineHandler.h new file mode 100644 index 00000000000..eb43bd4045b --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/CombineHandler.h @@ -0,0 +1,90 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _COMBINEHANDLER_H_ +#define _COMBINEHANDLER_H_ + +#include "lib/Combiner.h" +#include "BatchHandler.h" + +namespace NativeTask { + +enum SerializationFramework { + WRITABLE_SERIALIZATION = 0, + NATIVE_SERIALIZATION = 1 +}; + +struct SerializeInfo { + Buffer buffer; + uint32_t outerLength; + char varBytes[8]; +}; + +class CombineHandler : public NativeTask::ICombineRunner, public NativeTask::BatchHandler { +public: + static const Command COMBINE; + +private: + + CombineContext * _combineContext; + KVIterator * _kvIterator; + IFileWriter * _writer; + SerializeInfo _key; + SerializeInfo _value; + + KeyValueType _kType; + KeyValueType _vType; + MapOutputSpec _mapOutputSpec; + Config * _config; + bool _kvCached; + + uint32_t _combineInputRecordCount; + uint32_t _combineInputBytes; + + uint32_t _combineOutputRecordCount; + uint32_t _combineOutputBytes; + + FixSizeContainer _asideBuffer; + ByteArray _asideBytes; + +public: + CombineHandler(); + virtual ~CombineHandler(); + + virtual void handleInput(ByteBuffer & byteBuffer); + void finish(); + + ResultBuffer * onCall(const Command& command, ParameterBuffer * param); + + void configure(Config * config); + + void combine(CombineContext type, KVIterator * kvIterator, IFileWriter * writer); + + virtual void onLoadData(); + +private: + void flushDataToWriter(); + void outputKeyOrValue(SerializeInfo & info, KeyValueType type); + bool nextKeyValue(SerializeInfo & key, SerializeInfo & value); + uint32_t feedDataToJava(SerializationFramework serializationType); + uint32_t feedDataToJavaInWritableSerialization(); + void write(char * buf, uint32_t length); + +}; + +} /* namespace NativeTask */ +#endif /* _JAVACOMBINEHANDLER_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/MCollectorOutputHandler.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/MCollectorOutputHandler.cc new file mode 100644 index 00000000000..7e4ae448277 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/MCollectorOutputHandler.cc @@ -0,0 +1,98 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "util/StringUtil.h" +#include "lib/TaskCounters.h" +#include "MCollectorOutputHandler.h" +#include "lib/NativeObjectFactory.h" +#include "lib/MapOutputCollector.h" +#include "CombineHandler.h" + +using std::string; +using std::vector; + +namespace NativeTask { + +MCollectorOutputHandler::MCollectorOutputHandler() + : _collector(NULL), _dest(NULL), _endium(LARGE_ENDIUM) { +} + +MCollectorOutputHandler::~MCollectorOutputHandler() { + _dest = NULL; + delete _collector; + _collector = NULL; +} + +void MCollectorOutputHandler::configure(Config * config) { + if (NULL == config) { + return; + } + + uint32_t partition = config->getInt(MAPRED_NUM_REDUCES, 1); + + _collector = new MapOutputCollector(partition, this); + _collector->configure(config); +} + +void MCollectorOutputHandler::finish() { + _collector->close(); + BatchHandler::finish(); +} + +void MCollectorOutputHandler::handleInput(ByteBuffer & in) { + char * buff = in.current(); + uint32_t length = in.remain(); + + const char * end = buff + length; + char * pos = buff; + if (_kvContainer.remain() > 0) { + uint32_t filledLength = _kvContainer.fill(pos, length); + pos += filledLength; + } + + while (end - pos > 0) { + KVBufferWithParititionId * kvBuffer = (KVBufferWithParititionId *)pos; + + if (unlikely(end - pos < KVBuffer::headerLength())) { + THROW_EXCEPTION(IOException, "k/v meta information incomplete"); + } + + if (_endium == LARGE_ENDIUM) { + kvBuffer->partitionId = bswap(kvBuffer->partitionId); + kvBuffer->buffer.keyLength = bswap(kvBuffer->buffer.keyLength); + kvBuffer->buffer.valueLength = bswap(kvBuffer->buffer.valueLength); + } + + uint32_t kvLength = kvBuffer->buffer.length(); + + KVBuffer * dest = allocateKVBuffer(kvBuffer->partitionId, kvLength); + _kvContainer.wrap((char *)dest, kvLength); + + pos += 4; //skip the partition length + uint32_t filledLength = _kvContainer.fill(pos, end - pos); + pos += filledLength; + } +} + +KVBuffer * MCollectorOutputHandler::allocateKVBuffer(uint32_t partitionId, uint32_t kvlength) { + KVBuffer * dest = _collector->allocateKVBuffer(partitionId, kvlength); + return dest; +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/MCollectorOutputHandler.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/MCollectorOutputHandler.h new file mode 100644 index 00000000000..fe4635ff4a6 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/handler/MCollectorOutputHandler.h @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MCOLLECTOROUTPUTHANDLER_H_ +#define MCOLLECTOROUTPUTHANDLER_H_ + +#include "BatchHandler.h" +#include "lib/SpillOutputService.h" +#include "AbstractMapHandler.h" + +namespace NativeTask { +class MapOutputCollector; + +class MCollectorOutputHandler : public AbstractMapHandler { +private: + + FixSizeContainer _kvContainer; + + MapOutputCollector * _collector; + // state info for large KV pairs + char * _dest; + + Endium _endium; + +public: + MCollectorOutputHandler(); + virtual ~MCollectorOutputHandler(); + + virtual void configure(Config * config); + virtual void finish(); + virtual void handleInput(ByteBuffer & byteBuffer); +private: + KVBuffer * allocateKVBuffer(uint32_t partition, uint32_t kvlength); +}; + +} + +#endif /* MCOLLECTOROUTPUTHANDLER_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/BufferStream.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/BufferStream.cc new file mode 100644 index 00000000000..e459b46695b --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/BufferStream.cc @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/BufferStream.h" + +namespace NativeTask { + +int32_t InputBuffer::read(void * buff, uint32_t length) { + uint32_t rd = _capacity - _position < length ? _capacity - _position : length; + if (rd > 0) { + memcpy(buff, _buff + _position, rd); + _position += rd; + return rd; + } + return length == 0 ? 0 : -1; +} + +void OutputBuffer::write(const void * buff, uint32_t length) { + if (_position + length <= _capacity) { + memcpy(_buff + _position, buff, length); + _position += length; + } else { + THROW_EXCEPTION(IOException, "OutputBuffer too small to write"); + } +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/BufferStream.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/BufferStream.h new file mode 100644 index 00000000000..e945b95badf --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/BufferStream.h @@ -0,0 +1,156 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BUFFERSTREAM_H_ +#define BUFFERSTREAM_H_ + +#include +#include "lib/Streams.h" + +namespace NativeTask { + +using std::string; + +class InputBuffer : public InputStream { +protected: + const char * _buff; + uint32_t _position; + uint32_t _capacity; +public: + InputBuffer() + : _buff(NULL), _position(0), _capacity(0) { + } + + InputBuffer(const char * buff, uint32_t capacity) + : _buff(buff), _position(0), _capacity(capacity) { + } + + InputBuffer(const string & src) + : _buff(src.data()), _position(0), _capacity(src.length()) { + } + + virtual ~InputBuffer() { + } + + virtual void seek(uint64_t position) { + if (position <= _capacity) { + _position = position; + } else { + _position = _capacity; + } + } + + virtual uint64_t tell() { + return _position; + } + + virtual int32_t read(void * buff, uint32_t length); + + void reset(const char * buff, uint32_t capacity) { + _buff = buff; + _position = 0; + _capacity = capacity; + } + + void reset(const string & src) { + _buff = src.data(); + _position = 0; + _capacity = src.length(); + } + + void rewind() { + _position = 0; + } +}; + +class OutputBuffer : public OutputStream { +protected: + char * _buff; + uint32_t _position; + uint32_t _capacity; +public: + OutputBuffer() + : _buff(NULL), _position(0), _capacity(0) { + } + + OutputBuffer(char * buff, uint32_t capacity) + : _buff(buff), _position(0), _capacity(capacity) { + } + + virtual ~OutputBuffer() { + } + + virtual uint64_t tell() { + return _position; + } + + virtual void write(const void * buff, uint32_t length); + + void clear() { + _position = 0; + } + + void reset(char * buff, uint32_t capacity) { + _buff = buff; + _position = 0; + _capacity = capacity; + } + + string getString() { + return string(_buff, _position); + } +}; + +class OutputStringStream : public OutputStream { +protected: + string * _dest; +public: + OutputStringStream() + : _dest(NULL) { + } + + OutputStringStream(string & dest) + : _dest(&dest) { + } + virtual ~OutputStringStream() { + } + + virtual uint64_t tell() { + return _dest->length(); + } + + virtual void write(const void * buff, uint32_t length) { + _dest->append((const char *)buff, length); + } + + void reset(string * dest) { + _dest = dest; + } + + void clear() { + _dest->clear(); + } + + string getString() { + return *_dest; + } +}; + +} // namespace NativeTask + +#endif /* BUFFERSTREAM_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Buffers.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Buffers.cc new file mode 100644 index 00000000000..d40abb97b70 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Buffers.cc @@ -0,0 +1,235 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "lib/commons.h" +#include "util/StringUtil.h" +#include "util/WritableUtils.h" +#include "lib/Buffers.h" + +namespace NativeTask { + + +ReadBuffer::ReadBuffer() + : _buff(NULL), _remain(0), _size(0), _capacity(0), _stream(NULL), _source(NULL) { +} + +void ReadBuffer::init(uint32_t size, InputStream * stream, const string & codec) { + if (size < 1024) { + THROW_EXCEPTION_EX(UnsupportException, "ReadBuffer size %u not support.", size); + } + _buff = (char *)malloc(size); + if (NULL == _buff) { + THROW_EXCEPTION(OutOfMemoryException, "create append buffer"); + } + _capacity = size; + _remain = 0; + _size = 0; + _stream = stream; + _source = _stream; + if (codec.length() > 0) { + if (!Compressions::support(codec)) { + THROW_EXCEPTION(UnsupportException, "compression codec not support"); + } + _source = Compressions::getDecompressionStream(codec, _stream, size); + } +} + +ReadBuffer::~ReadBuffer() { + if (_source != _stream) { + delete _source; + _source = NULL; + } + if (NULL != _buff) { + free(_buff); + _buff = NULL; + _capacity = 0; + _remain = 0; + _size = 0; + } +} + +char * ReadBuffer::fillGet(uint32_t count) { + + if (unlikely(count > _capacity)) { + uint32_t newcap = _capacity * 2 > count ? _capacity * 2 : count; + char * newbuff = (char*)malloc(newcap); + + + if (newbuff == NULL) { + THROW_EXCEPTION(OutOfMemoryException, + StringUtil::Format("buff realloc failed, size=%u", newcap)); + } + + if (_remain > 0) { + memcpy(newbuff, current(), _remain); + } + if (NULL != _buff) { + free(_buff); + } + + _buff = newbuff; + _capacity = newcap; + } else { + if (_remain > 0) { + memmove(_buff, current(), _remain); + } + } + _size = _remain; + while (_remain < count) { + int32_t rd = _source->read(_buff + _size, _capacity - _size); + if (rd <= 0) { + THROW_EXCEPTION(IOException, "read reach EOF"); + } + _remain += rd; + _size += rd; + } + char * ret = current(); + _remain -= count; + return ret; +} + +int32_t ReadBuffer::fillRead(char * buff, uint32_t len) { + uint32_t cp = _remain; + if (cp > 0) { + memcpy(buff, current(), cp); + _remain = 0; + } + // TODO: read to buffer first + int32_t ret = _source->readFully(buff + cp, len - cp); + if (ret < 0 && cp == 0) { + return ret; + } else { + return ret < 0 ? cp : ret + cp; + } +} + +int64_t ReadBuffer::fillReadVLong() { + if (_remain == 0) { + int32_t rd = _source->read(_buff, _capacity); + if (rd <= 0) { + THROW_EXCEPTION(IOException, "fillReadVLong reach EOF"); + } + _remain = rd; + _size = rd; + } + int8_t * pos = (int8_t*)current(); + if (*pos >= -112) { + _remain--; + return (int64_t)*pos; + } + bool neg = *pos < -120; + uint32_t len = neg ? (-119 - *pos) : (-111 - *pos); + pos = (int8_t*)get(len); + const int8_t * end = pos + len; + uint64_t value = 0; + while (++pos < end) { + value = (value << 8) | *(uint8_t*)pos; + } + return neg ? (value ^ -1LL) : value; +} + +/////////////////////////////////////////////////////////// + +AppendBuffer::AppendBuffer() + : _buff(NULL), _remain(0), _capacity(0), _counter(0), _stream(NULL), _dest(NULL), + _compression(false) { +} + +void AppendBuffer::init(uint32_t size, OutputStream * stream, const string & codec) { + if (size < 1024) { + THROW_EXCEPTION_EX(UnsupportException, "AppendBuffer size %u not support.", size); + } + _buff = (char *)malloc(size + 8); + if (NULL == _buff) { + THROW_EXCEPTION(OutOfMemoryException, "create append buffer"); + } + _capacity = size; + _remain = _capacity; + _stream = stream; + _dest = _stream; + if (codec.length() > 0) { + if (!Compressions::support(codec)) { + THROW_EXCEPTION(UnsupportException, "compression codec not support"); + } + _dest = Compressions::getCompressionStream(codec, _stream, size); + _compression = true; + } +} + +CompressStream * AppendBuffer::getCompressionStream() { + if (_compression) { + return (CompressStream *)_dest; + } else { + return NULL; + } +} + +AppendBuffer::~AppendBuffer() { + if (_dest != _stream) { + delete _dest; + _dest = NULL; + } + if (NULL != _buff) { + free(_buff); + _buff = NULL; + _remain = 0; + _capacity = 0; + } +} + +void AppendBuffer::flushd() { + _dest->write(_buff, _capacity - _remain); + _counter += _capacity - _remain; + _remain = _capacity; +} + +void AppendBuffer::write_inner(const void * data, uint32_t len) { + flushd(); + if (len >= _capacity / 2) { + _dest->write(data, len); + _counter += len; + } else { + simple_memcpy(_buff, data, len); + _remain -= len; + } +} + +void AppendBuffer::write_vlong_inner(int64_t v) { + if (_remain < 9) { + flushd(); + } + uint32_t len; + WritableUtils::WriteVLong(v, current(), len); + _remain -= len; +} + +void AppendBuffer::write_vuint2_inner(uint32_t v1, uint32_t v2) { + if (_remain < 10) { + flushd(); + } + uint32_t len; + WritableUtils::WriteVLong(v1, current(), len); + _remain -= len; + WritableUtils::WriteVLong(v2, current(), len); + _remain -= len; +} + +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Buffers.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Buffers.h new file mode 100644 index 00000000000..13cd545a24f --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Buffers.h @@ -0,0 +1,637 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BUFFERS_H_ +#define BUFFERS_H_ + +#include "lib/Streams.h" +#include "lib/Compressions.h" +#include "lib/Constants.h" + +namespace NativeTask { + + +/** + * A lightweight read buffer, act as buffered input stream + */ +class ReadBuffer { +protected: + char * _buff; + uint32_t _remain; + uint32_t _size; + uint32_t _capacity; + + InputStream * _stream; + InputStream * _source; + +protected: + inline char * current() { + return _buff + _size - _remain; + } + + char * fillGet(uint32_t count); + int32_t fillRead(char * buff, uint32_t len); + int64_t fillReadVLong(); +public: + ReadBuffer(); + + void init(uint32_t size, InputStream * stream, const string & codec); + + ~ReadBuffer(); + + /** + * use get() to get inplace continuous memory of small object + */ + inline char * get(uint32_t count) { + if (likely(count <= _remain)) { + char * ret = current(); + _remain -= count; + return ret; + } + return fillGet(count); + } + + /** + * read to outside buffer + */ + inline int32_t read(char * buff, uint32_t len) { + if (likely(len <= _remain)) { + memcpy(buff, current(), len); + _remain -= len; + return len; + } + return fillRead(buff, len); + } + + /** + * read to outside buffer, use simple_memcpy + */ + inline void readUnsafe(char * buff, uint32_t len) { + if (likely(len <= _remain)) { + simple_memcpy(buff, current(), len); + _remain -= len; + return; + } + fillRead(buff, len); + } + + /** + * read VUInt + */ + inline int64_t readVLong() { + if (likely(_remain > 0)) { + char * mark = current(); + if (*(int8_t*)mark >= (int8_t)-112) { + _remain--; + return (int64_t)*mark; + } + } + return fillReadVLong(); + } + + /** + * read uint32_t little endian + */ + inline uint32_t read_uint32_le() { + return *(uint32_t*)get(4); + } + + /** + * read uint32_t big endian + */ + inline uint32_t read_uint32_be() { + return bswap(read_uint32_le()); + } +}; + +/** + * A light weighted append buffer, used as buffered output streams + */ +class AppendBuffer { +protected: + char * _buff; + uint32_t _remain; + uint32_t _capacity; + uint64_t _counter; + + OutputStream * _stream; + OutputStream * _dest; + bool _compression; + +protected: + void flushd(); + + inline char * current() { + return _buff + _capacity - _remain; + } + + void write_inner(const void * data, uint32_t len); + void write_vlong_inner(int64_t v); + void write_vuint2_inner(uint32_t v1, uint32_t v2); +public: + AppendBuffer(); + + ~AppendBuffer(); + + void init(uint32_t size, OutputStream * stream, const string & codec); + + CompressStream * getCompressionStream(); + + uint64_t getCounter() { + return _counter; + } + + inline char * borrowUnsafe(uint32_t len) { + if (likely(_remain >= len)) { + return current(); + } + if (likely(_capacity >= len)) { + flushd(); + return _buff; + } + return NULL; + } + + inline void useUnsafe(uint32_t count) { + _remain -= count; + } + + inline void write(char c) { + if (unlikely(_remain == 0)) { + flushd(); + } + *current() = c; + _remain--; + } + + inline void write(const void * data, uint32_t len) { + if (likely(len <= _remain)) { // append directly + simple_memcpy(current(), data, len); + _remain -= len; + return; + } + write_inner(data, len); + } + + inline void write_uint32_le(uint32_t v) { + if (unlikely(4 > _remain)) { + flushd(); + } + *(uint32_t*)current() = v; + _remain -= 4; + return; + } + + inline void write_uint32_be(uint32_t v) { + write_uint32_le(bswap(v)); + } + + inline void write_uint64_le(uint64_t v) { + if (unlikely(8 > _remain)) { + flushd(); + } + *(uint64_t*)current() = v; + _remain -= 8; + return; + } + + inline void write_uint64_be(uint64_t v) { + write_uint64_le(bswap64(v)); + } + + inline void write_vlong(int64_t v) { + if (likely(_remain > 0 && v <= 127 && v >= -112)) { + *(char*)current() = (char)v; + _remain--; + return; + } + write_vlong_inner(v); + } + + inline void write_vuint(uint32_t v) { + if (likely(_remain > 0 && v <= 127)) { + *(char*)current() = (char)v; + _remain--; + return; + } + write_vlong_inner(v); + } + + inline void write_vuint2(uint32_t v1, uint32_t v2) { + if (likely(_remain >= 2 && v1 <= 127 && v2 <= 127)) { + *(char*)current() = (char)v1; + *(char*)(current() + 1) = (char)v2; + _remain -= 2; + return; + } + write_vuint2_inner(v1, v2); + } + + /** + * flush current buffer, clear content + */ + inline void flush() { + if (_remain < _capacity) { + flushd(); + } + } +}; + +/** + * Memory Key-Value buffer pair with direct address content, so can be + * easily copied or dumped to file + */ +struct KVBuffer { + uint32_t keyLength; + uint32_t valueLength; + char content[1]; + + char * getKey() { + return content; + } + + char * getValue() { + return content + keyLength; + } + + KVBuffer * next() { + return ((KVBuffer*)(content + keyLength + valueLength)); + } + + std::string str() { + return std::string(content, keyLength) + "\t" + std::string(getValue(), valueLength); + } + + uint32_t length() { + return keyLength + valueLength + SIZE_OF_KEY_LENGTH + SIZE_OF_VALUE_LENGTH; + } + + uint32_t lengthConvertEndium() { + long value = bswap64(*((long *)this)); + return (value >> 32) + value + SIZE_OF_KEY_LENGTH + SIZE_OF_VALUE_LENGTH; + } + + void fill(const void * key, uint32_t keylen, const void * value, uint32_t vallen) { + keyLength = keylen; + valueLength = vallen; + + if (keylen > 0) { + simple_memcpy(getKey(), key, keylen); + } + if (vallen > 0) { + simple_memcpy(getValue(), value, vallen); + } + } + + static uint32_t headerLength() { + return SIZE_OF_KEY_LENGTH + SIZE_OF_VALUE_LENGTH; + } +}; + +struct KVBufferWithParititionId { + uint32_t partitionId; + KVBuffer buffer; + + inline static uint32_t minLength() { + return SIZE_OF_PARTITION_LENGTH + SIZE_OF_KV_LENGTH; + } + + int length() { + return 4 + buffer.length(); + } + + int lengthConvertEndium() { + return 4 + buffer.lengthConvertEndium(); + } +}; + +/** + * Native side abstraction of java ByteBuffer + */ +class ByteBuffer { +private: + char * _buff; + uint32_t _limit; + uint32_t _position; + uint32_t _capacity; + +public: + ByteBuffer() + : _buff(NULL), _limit(0), _position(0), _capacity(0) { + } + + ~ByteBuffer() { + } + + void reset(char * buff, uint32_t inputCapacity) { + this->_buff = buff; + this->_capacity = inputCapacity; + this->_position = 0; + this->_limit = 0; + } + + int capacity() { + return this->_capacity; + } + + int remain() { + return _limit - _position; + } + + int limit() { + return _limit; + } + + int advance(int positionOffset) { + _position += positionOffset; + return _position; + } + + int position() { + return this->_position; + } + + void position(int newPos) { + this->_position = newPos; + } + + void rewind(int newPos, int newLimit) { + this->_position = newPos; + if (newLimit < 0 || newLimit > this->_capacity) { + THROW_EXCEPTION(IOException, "length smaller than zero or larger than input buffer capacity"); + } + this->_limit = newLimit; + } + + char * current() { + return _buff + _position; + } + + char * base() { + return _buff; + } +}; + +class ByteArray { +private: + char * _buff; + uint32_t _length; + uint32_t _capacity; + +public: + ByteArray() + : _buff(NULL), _length(0), _capacity(0) { + } + + ~ByteArray() { + if (NULL != _buff) { + delete[] _buff; + _buff = NULL; + } + _length = 0; + _capacity = 0; + } + + void resize(uint32_t newSize) { + if (newSize <= _capacity) { + _length = newSize; + } else { + if (NULL != _buff) { + delete[] _buff; + _buff = NULL; + } + _capacity = 2 * newSize; + _buff = new char[_capacity]; + _length = newSize; + } + } + + char * buff() { + return _buff; + } + + uint32_t size() { + return _length; + } +}; + +class FixSizeContainer { +private: + char * _buff; + uint32_t _pos; + uint32_t _size; + +public: + FixSizeContainer() + : _buff(NULL), _pos(0), _size(0) { + } + + ~FixSizeContainer() { + } + + void wrap(char * buff, uint32_t size) { + _size = size; + _buff = buff; + _pos = 0; + } + + void rewind() { + _pos = 0; + } + + uint32_t remain() { + return _size - _pos; + } + + char * current() { + return _buff + _pos; + } + + char * base() { + return _buff; + } + + uint32_t size() { + return _size; + } + + /** + * return the length of actually filled data. + */ + uint32_t fill(const char * source, uint32_t maxSize) { + int remain = _size - _pos; + if (remain <= 0) { + return 0; + } + + uint32_t length = (maxSize < remain) ? maxSize : remain; + simple_memcpy(_buff + _pos, source, length); + _pos += length; + return length; + } + + uint32_t position() { + return _pos; + } + + void position(int pos) { + _pos = pos; + } +}; + +class ReadWriteBuffer { +private: + + static const uint32_t INITIAL_LENGTH = 16; + + uint32_t _readPoint; + uint32_t _writePoint; + char * _buff; + uint32_t _buffLength; + bool _newCreatedBuff; + +public: + + ReadWriteBuffer(uint32_t length) + : _readPoint(0), _writePoint(0), _buff(NULL), _buffLength(0), _newCreatedBuff(false) { + _buffLength = length; + if (_buffLength > 0) { + _buff = new char[_buffLength]; + _newCreatedBuff = true; + } + } + + ReadWriteBuffer() + : _readPoint(0), _writePoint(0), _buff(NULL), _buffLength(0), _newCreatedBuff(false) { + } + + ~ReadWriteBuffer() { + if (_newCreatedBuff) { + delete[] _buff; + _buff = NULL; + } + } + + void setReadPoint(uint32_t pos) { + _readPoint = pos; + } + + void setWritePoint(uint32_t pos) { + _writePoint = pos; + } + + char * getBuff() { + return _buff; + } + + uint32_t getWritePoint() { + return _writePoint; + } + + uint32_t getReadPoint() { + return _readPoint; + } + + void writeInt(uint32_t param) { + uint32_t written = param; + + checkWriteSpaceAndResizeIfNecessary(4); + *((uint32_t *)(_buff + _writePoint)) = written; + _writePoint += 4; + } + + void writeLong(uint64_t param) { + uint64_t written = param; + + checkWriteSpaceAndResizeIfNecessary(8); + *((uint64_t *)(_buff + _writePoint)) = written; + _writePoint += 8; + } + + void writeString(const char * param, uint32_t length) { + writeInt(length); + checkWriteSpaceAndResizeIfNecessary(length); + + memcpy(_buff + _writePoint, param, length); + _writePoint += length; + } + + void writeString(std::string * param) { + const char * str = param->c_str(); + int length = param->size(); + writeString(str, length); + } + + void writePointer(void * param) { + uint64_t written = (uint64_t)(param); + writeLong(written); + } + + uint32_t readInt() { + char * readPos = _buff + _readPoint; + uint32_t result = *((uint32_t *)(readPos)); + _readPoint += 4; + return result; + } + + uint64_t readLong() { + char * readPos = _buff + _readPoint; + uint64_t result = *((uint64_t *)(readPos)); + _readPoint += 8; + return result; + } + + std::string * readString() { + uint32_t len = readInt(); + char * strBegin = _buff + _readPoint; + _readPoint += len; + return new std::string(strBegin, len); + } + + void * readPointer() { + uint64_t result = readLong(); + return (void *)(result); + } + +private: + void checkWriteSpaceAndResizeIfNecessary(uint32_t toBeWritten) { + if (_buffLength == 0) { + _newCreatedBuff = true; + _buffLength = INITIAL_LENGTH > toBeWritten ? INITIAL_LENGTH : toBeWritten; + _buff = new char[_buffLength]; + } + + if (_buffLength - _writePoint >= toBeWritten) { + return; + } + + _buffLength = _buffLength + toBeWritten; + _newCreatedBuff = true; + char * newBuff = new char[_buffLength]; + memcpy(newBuff, _buff, _writePoint); + delete[] _buff; + _buff = newBuff; + } +}; + +typedef ReadWriteBuffer ParameterBuffer; +typedef ReadWriteBuffer ResultBuffer; + +} // namespace NativeTask + +#endif /* BUFFERS_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Combiner.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Combiner.h new file mode 100644 index 00000000000..a7309ffa205 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Combiner.h @@ -0,0 +1,70 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef COMBINER_H_ +#define COMBINER_H_ +#include "commons.h" +#include "lib/IFile.h" + +namespace NativeTask { + +class MemoryBufferKVIterator : public KVIterator { +public: + virtual const char * getBase() = 0; + virtual std::vector * getKVOffsets() = 0; +}; + +enum CombineContextType { + UNKNOWN = 0, + CONTINUOUS_MEMORY_BUFFER = 1, +}; + +class CombineContext { + +private: + CombineContextType _type; + +public: + CombineContext(CombineContextType type) + : _type(type) { + } + +public: + CombineContextType getType() { + return _type; + } +}; + +class CombineInMemory : public CombineContext { + CombineInMemory() + : CombineContext(CONTINUOUS_MEMORY_BUFFER) { + } +}; + +class ICombineRunner { +public: + ICombineRunner() { + } + + virtual void combine(CombineContext type, KVIterator * kvIterator, IFileWriter * writer) = 0; + + virtual ~ICombineRunner() { + } +}; + +} /* namespace NativeTask */ +#endif /* COMBINER_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Compressions.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Compressions.cc new file mode 100644 index 00000000000..879c0160a57 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Compressions.cc @@ -0,0 +1,145 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "config.h" +#include "lib/Compressions.h" +#include "util/SyncUtils.h" +#include "codec/GzipCodec.h" +#include "codec/SnappyCodec.h" +#include "codec/Lz4Codec.h" + +namespace NativeTask { + +CompressStream::~CompressStream() { +} + +void CompressStream::writeDirect(const void * buff, uint32_t length) { + THROW_EXCEPTION(UnsupportException, "writeDirect not support"); +} + +/////////////////////////////////////////////////////////// + +DecompressStream::~DecompressStream() { +} + +int32_t DecompressStream::readDirect(void * buff, uint32_t length) { + THROW_EXCEPTION(UnsupportException, "readDirect not support"); +} + +/////////////////////////////////////////////////////////// + +const Compressions::Codec Compressions::GzipCodec = Compressions::Codec( + "org.apache.hadoop.io.compress.GzipCodec", ".gz"); +const Compressions::Codec Compressions::SnappyCodec = Compressions::Codec( + "org.apache.hadoop.io.compress.SnappyCodec", ".snappy"); +const Compressions::Codec Compressions::Lz4Codec = Compressions::Codec( + "org.apache.hadoop.io.compress.Lz4Codec", ".lz4"); + +vector Compressions::SupportedCodecs = vector(); + +void Compressions::initCodecs() { + static Lock lock; + ScopeLock autolock(lock); + if (SupportedCodecs.size() == 0) { + SupportedCodecs.push_back(GzipCodec); + SupportedCodecs.push_back(SnappyCodec); + SupportedCodecs.push_back(Lz4Codec); + } +} + +bool Compressions::support(const string & codec) { + initCodecs(); + for (size_t i = 0; i < SupportedCodecs.size(); i++) { + if (codec == SupportedCodecs[i].name) { + return true; + } + } + return false; +} + +const string Compressions::getExtension(const string & codec) { + initCodecs(); + for (size_t i = 0; i < SupportedCodecs.size(); i++) { + if (codec == SupportedCodecs[i].name) { + return SupportedCodecs[i].extension; + } + } + return string(); +} + +const string Compressions::getCodec(const string & extension) { + initCodecs(); + for (size_t i = 0; i < SupportedCodecs.size(); i++) { + if (extension == SupportedCodecs[i].extension) { + return SupportedCodecs[i].name; + } + } + return string(); +} + +const string Compressions::getCodecByFile(const string & file) { + initCodecs(); + for (size_t i = 0; i < SupportedCodecs.size(); i++) { + const string & extension = SupportedCodecs[i].extension; + if ((file.length() > extension.length()) + && (file.substr(file.length() - extension.length()) == extension)) { + return SupportedCodecs[i].name; + } + } + return string(); +} + +CompressStream * Compressions::getCompressionStream(const string & codec, OutputStream * stream, + uint32_t bufferSizeHint) { + if (codec == GzipCodec.name) { + return new GzipCompressStream(stream, bufferSizeHint); + } + if (codec == SnappyCodec.name) { +#if defined HADOOP_SNAPPY_LIBRARY + return new SnappyCompressStream(stream, bufferSizeHint); +#else + THROW_EXCEPTION(UnsupportException, "Snappy library is not loaded"); +#endif + } + if (codec == Lz4Codec.name) { + return new Lz4CompressStream(stream, bufferSizeHint); + } + return NULL; +} + +DecompressStream * Compressions::getDecompressionStream(const string & codec, InputStream * stream, + uint32_t bufferSizeHint) { + if (codec == GzipCodec.name) { + return new GzipDecompressStream(stream, bufferSizeHint); + } + if (codec == SnappyCodec.name) { +#if defined HADOOP_SNAPPY_LIBRARY + return new SnappyDecompressStream(stream, bufferSizeHint); +#else + THROW_EXCEPTION(UnsupportException, "Snappy library is not loaded"); +#endif + } + if (codec == Lz4Codec.name) { + return new Lz4DecompressStream(stream, bufferSizeHint); + } + return NULL; +} + +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Compressions.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Compressions.h new file mode 100644 index 00000000000..96c5084c6c9 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Compressions.h @@ -0,0 +1,108 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COMPRESSIONS_H_ +#define COMPRESSIONS_H_ + +#include +#include +#include "lib/Streams.h" + +namespace NativeTask { + +using std::vector; +using std::string; + +class CompressStream : public FilterOutputStream { +public: + CompressStream(OutputStream * stream) + : FilterOutputStream(stream) { + } + + virtual ~CompressStream(); + + virtual void writeDirect(const void * buff, uint32_t length); + + virtual void finish() { + flush(); + } + + virtual void resetState() { + + } + + virtual uint64_t compressedBytesWritten() { + return 0; + } +}; + +class DecompressStream : public FilterInputStream { +public: + DecompressStream(InputStream * stream) + : FilterInputStream(stream) { + } + + virtual ~DecompressStream(); + + virtual int32_t readDirect(void * buff, uint32_t length); + + virtual uint64_t compressedBytesRead() { + return 0; + } +}; + +class Compressions { +protected: + class Codec { + public: + string name; + string extension; + + Codec(const string & name, const string & extension) + : name(name), extension(extension) { + } + }; + + static vector SupportedCodecs; + + static void initCodecs(); + +public: + static const Codec GzipCodec; + static const Codec SnappyCodec; + static const Codec Lz4Codec; + +public: + static bool support(const string & codec); + + static const string getExtension(const string & codec); + + static const string getCodec(const string & extension); + + static const string getCodecByFile(const string & file); + + static CompressStream * getCompressionStream(const string & codec, OutputStream * stream, + uint32_t bufferSizeHint); + + static DecompressStream * getDecompressionStream(const string & codec, InputStream * stream, + uint32_t bufferSizeHint); +}; + +} // namespace NativeTask + +#endif /* COMPRESSIONS_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Constants.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Constants.h new file mode 100644 index 00000000000..5a5707b2c32 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Constants.h @@ -0,0 +1,26 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef CONSTANTS_H_ +#define CONSTANTS_H_ + +const uint32_t SIZE_OF_PARTITION_LENGTH = sizeof(uint32_t); +const uint32_t SIZE_OF_KEY_LENGTH = sizeof(uint32_t); +const uint32_t SIZE_OF_VALUE_LENGTH = sizeof(uint32_t); +const uint32_t SIZE_OF_KV_LENGTH = SIZE_OF_KEY_LENGTH + SIZE_OF_VALUE_LENGTH; + +#endif //CONSTANTS_H_ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/FileSystem.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/FileSystem.cc new file mode 100644 index 00000000000..e0a698cf81b --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/FileSystem.cc @@ -0,0 +1,263 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include "lib/commons.h" +#include "util/StringUtil.h" +#include "lib/jniutils.h" +#include "NativeTask.h" +#include "lib/TaskCounters.h" +#include "lib/NativeObjectFactory.h" +#include "lib/Path.h" +#include "lib/FileSystem.h" + +namespace NativeTask { + +///////////////////////////////////////////////////////////// + +FileInputStream::FileInputStream(const string & path) { + _fd = ::open(path.c_str(), O_RDONLY); + if (_fd >= 0) { + _path = path; + } else { + _fd = -1; + THROW_EXCEPTION_EX(IOException, "Can't open file for read: [%s]", path.c_str()); + } + _bytesRead = NativeObjectFactory::GetCounter(TaskCounters::FILESYSTEM_COUNTER_GROUP, + TaskCounters::FILE_BYTES_READ); +} + +FileInputStream::~FileInputStream() { + close(); +} + +void FileInputStream::seek(uint64_t position) { + ::lseek(_fd, position, SEEK_SET); +} + +uint64_t FileInputStream::tell() { + return ::lseek(_fd, 0, SEEK_CUR); +} + +int32_t FileInputStream::read(void * buff, uint32_t length) { + int32_t ret = ::read(_fd, buff, length); + if (ret > 0) { + _bytesRead->increase(ret); + } + return ret; +} + +void FileInputStream::close() { + if (_fd >= 0) { + ::close(_fd); + _fd = -1; + } +} + +///////////////////////////////////////////////////////////// + +FileOutputStream::FileOutputStream(const string & path, bool overwite) { + int flags = 0; + if (overwite) { + flags = O_WRONLY | O_CREAT | O_TRUNC; + } else { + flags = O_WRONLY | O_CREAT | O_EXCL; + } + mode_t mask = umask(0); + umask(mask); + _fd = ::open(path.c_str(), flags, (0666 & ~mask)); + if (_fd >= 0) { + _path = path; + } else { + _fd = -1; + THROW_EXCEPTION_EX(IOException, "Can't open file for write: [%s]", path.c_str()); + } + _bytesWrite = NativeObjectFactory::GetCounter(TaskCounters::FILESYSTEM_COUNTER_GROUP, + TaskCounters::FILE_BYTES_WRITTEN); +} + +FileOutputStream::~FileOutputStream() { + close(); +} + +uint64_t FileOutputStream::tell() { + return ::lseek(_fd, 0, SEEK_CUR); +} + +void FileOutputStream::write(const void * buff, uint32_t length) { + if (::write(_fd, buff, length) < length) { + THROW_EXCEPTION(IOException, "::write error"); + } + _bytesWrite->increase(length); +} + +void FileOutputStream::flush() { +} + +void FileOutputStream::close() { + if (_fd >= 0) { + ::close(_fd); + _fd = -1; + } +} + +///////////////////////////////////////////////////////////// + +class RawFileSystem : public FileSystem { + protected: + string getRealPath(const string & path) { + if (StringUtil::StartsWith(path, "file:")) { + return path.substr(5); + } + return path; + } + + public: + InputStream * open(const string & path) { + return new FileInputStream(getRealPath(path)); + } + + OutputStream * create(const string & path, bool overwrite) { + string np = getRealPath(path); + string parent = Path::GetParent(np); + if (parent.length() > 0) { + if (!exists(parent)) { + mkdirs(parent); + } + } + return new FileOutputStream(np, overwrite); + } + + uint64_t getLength(const string & path) { + struct stat st; + if (::stat(getRealPath(path).c_str(), &st) != 0) { + char buff[256]; + strerror_r(errno, buff, 256); + THROW_EXCEPTION(IOException, + StringUtil::Format("stat path %s failed, %s", path.c_str(), buff)); + } + return st.st_size; + } + + bool list(const string & path, vector & status) { + DIR * dp; + struct dirent * dirp; + if ((dp = opendir(path.c_str())) == NULL) { + return false; + } + + FileEntry temp; + while ((dirp = readdir(dp)) != NULL) { + temp.name = dirp->d_name; + temp.isDirectory = dirp->d_type & DT_DIR; + if (temp.name == "." || temp.name == "..") { + continue; + } + status.push_back(temp); + } + closedir(dp); + return true; + } + + void remove(const string & path) { + if (!exists(path)) { + LOG("[FileSystem] remove file %s not exists, ignore", path.c_str()); + return; + } + if (::remove(getRealPath(path).c_str()) != 0) { + int err = errno; + if (::system(StringUtil::Format("rm -rf %s", path.c_str()).c_str()) == 0) { + return; + } + char buff[256]; + strerror_r(err, buff, 256); + THROW_EXCEPTION(IOException, + StringUtil::Format("FileSystem: remove path %s failed, %s", path.c_str(), buff)); + } + } + + bool exists(const string & path) { + struct stat st; + if (::stat(getRealPath(path).c_str(), &st) != 0) { + return false; + } + return true; + } + + int mkdirs(const string & path, mode_t nmode) { + string np = getRealPath(path); + struct stat sb; + + if (stat(np.c_str(), &sb) == 0) { + if (S_ISDIR(sb.st_mode) == 0) { + return 1; + } + return 0; + } + + string npathstr = np; + char * npath = const_cast(npathstr.c_str()); + + /* Skip leading slashes. */ + char * p = npath; + while (*p == '/') + p++; + + while (NULL != (p = strchr(p, '/'))) { + *p = '\0'; + if (stat(npath, &sb) != 0) { + if (mkdir(npath, nmode)) { + return 1; + } + } else if (S_ISDIR(sb.st_mode) == 0) { + return 1; + } + *p++ = '/'; /* restore slash */ + while (*p == '/') + p++; + } + + /* Create the final directory component. */ + if (stat(npath, &sb) && mkdir(npath, nmode)) { + return 1; + } + return 0; + } + + void mkdirs(const string & path) { + int ret = mkdirs(path, 0755); + if (ret != 0) { + THROW_EXCEPTION_EX(IOException, "mkdirs [%s] failed", path.c_str()); + } + } +}; + +/////////////////////////////////////////////////////////// + +extern RawFileSystem RawFileSystemInstance; + +RawFileSystem RawFileSystemInstance = RawFileSystem(); + +FileSystem & FileSystem::getLocal() { + return RawFileSystemInstance; +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/FileSystem.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/FileSystem.h new file mode 100644 index 00000000000..8eaf32d45cd --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/FileSystem.h @@ -0,0 +1,123 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FILESYSTEM_H_ +#define FILESYSTEM_H_ + +#include +#include "NativeTask.h" +#include "lib/Streams.h" + +namespace NativeTask { + +class FileSystem; + +/** + * Local raw filesystem file input stream + * with blocking semantics + */ +class FileInputStream : public InputStream { +private: + string _path; + int _fd; + Counter * _bytesRead; +public: + FileInputStream(const string & path); + virtual ~FileInputStream(); + + virtual void seek(uint64_t position); + + virtual uint64_t tell(); + + virtual int32_t read(void * buff, uint32_t length); + + virtual void close(); +}; + +/** + * Local raw filesystem file output stream + * with blocking semantics + */ +class FileOutputStream : public OutputStream { +private: + string _path; + int _fd; + Counter * _bytesWrite; +public: + FileOutputStream(const string & path, bool overwite = true); + virtual ~FileOutputStream(); + + virtual uint64_t tell(); + + virtual void write(const void * buff, uint32_t length); + + virtual void flush(); + + virtual void close(); +}; + + +class FileEntry { +public: + string name; + bool isDirectory; +}; + +/** + * FileSystem interface + */ +class FileSystem { +protected: + FileSystem() { + } +public: + virtual ~FileSystem() { + } + + virtual InputStream * open(const string & path) { + return NULL; + } + + virtual OutputStream * create(const string & path, bool overwrite = true) { + return NULL; + } + + virtual uint64_t getLength(const string & path) { + return 0; + } + + virtual bool list(const string & path, vector & status) { + return false; + } + + virtual void remove(const string & path) { + } + + virtual bool exists(const string & path) { + return false; + } + + virtual void mkdirs(const string & path) { + } + + static FileSystem & getLocal(); +}; + +} // namespace NativeTask + +#endif /* FILESYSTEM_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/IFile.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/IFile.cc new file mode 100644 index 00000000000..2d3e0b5da0f --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/IFile.cc @@ -0,0 +1,230 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "util/StringUtil.h" +#include "lib/IFile.h" +#include "lib/Compressions.h" +#include "lib/FileSystem.h" + +namespace NativeTask { + +/////////////////////////////////////////////////////////// + +IFileReader::IFileReader(InputStream * stream, SingleSpillInfo * spill, bool deleteInputStream) + : _stream(stream), _source(NULL), _checksumType(spill->checkSumType), _kType(spill->keyType), + _vType(spill->valueType), _codec(spill->codec), _segmentIndex(-1), _spillInfo(spill), + _valuePos(NULL), _valueLen(0), _deleteSourceStream(deleteInputStream) { + _source = new ChecksumInputStream(_stream, _checksumType); + _source->setLimit(0); + _reader.init(128 * 1024, _source, _codec); +} + +IFileReader::~IFileReader() { + + delete _source; + _source = NULL; + + if (_deleteSourceStream) { + delete _stream; + _stream = NULL; + } +} + +/** + * 0 if success + * 1 if end + */ +bool IFileReader::nextPartition() { + if (0 != _source->getLimit()) { + THROW_EXCEPTION(IOException, "bad ifile segment length"); + } + if (_segmentIndex >= 0) { + // verify checksum + uint32_t chsum = 0; + if (4 != _stream->readFully(&chsum, 4)) { + THROW_EXCEPTION(IOException, "read ifile checksum failed"); + } + uint32_t actual = bswap(chsum); + uint32_t expect = _source->getChecksum(); + if (actual != expect) { + THROW_EXCEPTION_EX(IOException, "read ifile checksum not match, actual %x expect %x", actual, + expect); + } + } + _segmentIndex++; + if (_segmentIndex < (int)(_spillInfo->length)) { + int64_t end_pos = (int64_t)_spillInfo->segments[_segmentIndex].realEndOffset; + if (_segmentIndex > 0) { + end_pos -= (int64_t)_spillInfo->segments[_segmentIndex - 1].realEndOffset; + } + if (end_pos < 0) { + THROW_EXCEPTION(IOException, "bad ifile format"); + } + // exclude checksum + _source->setLimit(end_pos - 4); + _source->resetChecksum(); + return true; + } else { + return false; + } +} + +/////////////////////////////////////////////////////////// + +IFileWriter * IFileWriter::create(const std::string & filepath, const MapOutputSpec & spec, + Counter * spilledRecords) { + OutputStream * fout = FileSystem::getLocal().create(filepath, true); + IFileWriter * writer = new IFileWriter(fout, spec.checksumType, spec.keyType, spec.valueType, + spec.codec, spilledRecords, true); + return writer; +} + +IFileWriter::IFileWriter(OutputStream * stream, ChecksumType checksumType, KeyValueType ktype, + KeyValueType vtype, const string & codec, Counter * counter, bool deleteTargetStream) + : _stream(stream), _dest(NULL), _checksumType(checksumType), _kType(ktype), _vType(vtype), + _codec(codec), _recordCounter(counter), _recordCount(0), _deleteTargetStream(deleteTargetStream) { + _dest = new ChecksumOutputStream(_stream, _checksumType); + _appendBuffer.init(128 * 1024, _dest, _codec); +} + +IFileWriter::~IFileWriter() { + delete _dest; + _dest = NULL; + + if (_deleteTargetStream) { + delete _stream; + _stream = NULL; + } +} + +void IFileWriter::startPartition() { + _spillFileSegments.push_back(IFileSegment()); + _dest->resetChecksum(); +} + +void IFileWriter::endPartition() { + char EOFMarker[2] = {-1, -1}; + _appendBuffer.write(EOFMarker, 2); + _appendBuffer.flush(); + + CompressStream * compressionStream = _appendBuffer.getCompressionStream(); + if (NULL != compressionStream) { + compressionStream->finish(); + compressionStream->resetState(); + } + + uint32_t chsum = _dest->getChecksum(); + chsum = bswap(chsum); + _stream->write(&chsum, sizeof(chsum)); + _stream->flush(); + IFileSegment * info = &(_spillFileSegments[_spillFileSegments.size() - 1]); + info->uncompressedEndOffset = _appendBuffer.getCounter(); + info->realEndOffset = _stream->tell(); +} + +void IFileWriter::write(const char * key, uint32_t keyLen, const char * value, uint32_t valueLen) { + // append KeyLength ValueLength KeyBytesLength + uint32_t keyBuffLen = keyLen; + uint32_t valBuffLen = valueLen; + switch (_kType) { + case TextType: + keyBuffLen += WritableUtils::GetVLongSize(keyLen); + break; + case BytesType: + keyBuffLen += 4; + break; + default: + break; + } + + switch (_vType) { + case TextType: + valBuffLen += WritableUtils::GetVLongSize(valueLen); + break; + case BytesType: + valBuffLen += 4; + break; + default: + break; + } + + _appendBuffer.write_vuint2(keyBuffLen, valBuffLen); + + switch (_kType) { + case TextType: + _appendBuffer.write_vuint(keyLen); + break; + case BytesType: + _appendBuffer.write_uint32_be(keyLen); + break; + default: + break; + } + + if (keyLen > 0) { + _appendBuffer.write(key, keyLen); + } + + if (NULL != _recordCounter) { + _recordCounter->increase(); + } + _recordCount++; + + switch (_vType) { + case TextType: + _appendBuffer.write_vuint(valueLen); + break; + case BytesType: + _appendBuffer.write_uint32_be(valueLen); + break; + default: + break; + } + if (valueLen > 0) { + _appendBuffer.write(value, valueLen); + } +} + +IFileSegment * IFileWriter::toArray(std::vector *segments) { + IFileSegment * segs = new IFileSegment[segments->size()]; + for (size_t i = 0; i < segments->size(); i++) { + segs[i] = segments->at(i); + } + return segs; +} + +SingleSpillInfo * IFileWriter::getSpillInfo() { + const uint32_t size = _spillFileSegments.size(); + return new SingleSpillInfo(toArray(&_spillFileSegments), size, "", _checksumType, _kType, _vType, + _codec); +} + +void IFileWriter::getStatistics(uint64_t & offset, uint64_t & realOffset, uint64_t & recordCount) { + if (_spillFileSegments.size() > 0) { + offset = _spillFileSegments[_spillFileSegments.size() - 1].uncompressedEndOffset; + realOffset = _spillFileSegments[_spillFileSegments.size() - 1].realEndOffset; + } else { + offset = 0; + realOffset = 0; + } + recordCount = _recordCount; +} + +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/IFile.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/IFile.h new file mode 100644 index 00000000000..e397f90545c --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/IFile.h @@ -0,0 +1,166 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IFILE_H_ +#define IFILE_H_ + +#include "util/Checksum.h" +#include "lib/Buffers.h" +#include "util/WritableUtils.h" +#include "lib/SpillInfo.h" +#include "lib/MapOutputSpec.h" + +namespace NativeTask { + +/** + * IFileReader + */ +class IFileReader { +private: + InputStream * _stream; + ChecksumInputStream * _source; + ReadBuffer _reader; + ChecksumType _checksumType; + KeyValueType _kType; + KeyValueType _vType; + string _codec; + int32_t _segmentIndex; + SingleSpillInfo * _spillInfo; + const char * _valuePos; + uint32_t _valueLen; + bool _deleteSourceStream; + +public: + IFileReader(InputStream * stream, SingleSpillInfo * spill, bool deleteSourceStream = false); + + virtual ~IFileReader(); + + /** + * @return 0 if have next partition, none 0 if no more partition + */ + bool nextPartition(); + + /** + * get next key + * NULL if no more, then next_partition() need to be called + * NOTICE: before value() is called, the return pointer value is + * guaranteed to be valid + */ + const char * nextKey(uint32_t & keyLen) { + int64_t t1 = _reader.readVLong(); + int64_t t2 = _reader.readVLong(); + if (t1 == -1) { + return NULL; + } + const char * kvbuff = _reader.get((uint32_t)(t1 + t2)); + uint32_t len; + switch (_kType) { + case TextType: + keyLen = WritableUtils::ReadVInt(kvbuff, len); + break; + case BytesType: + keyLen = bswap(*(uint32_t*)kvbuff); + len = 4; + break; + default: + keyLen = t1; + len = 0; + } + const char * kbuff = kvbuff + len; + const char * vbuff = kvbuff + (uint32_t)t1; + switch (_vType) { + case TextType: + _valueLen = WritableUtils::ReadVInt(vbuff, len); + _valuePos = vbuff + len; + break; + case BytesType: + _valueLen = bswap(*(uint32_t*)vbuff); + _valuePos = vbuff + 4; + break; + default: + _valueLen = t2; + _valuePos = vbuff; + } + return kbuff; + } + + /** + * length of current value part of IFile entry + */ + uint32_t valueLen() { + return _valueLen; + } + + /** + * get current value + */ + const char * value(uint32_t & valueLen) { + valueLen = _valueLen; + return _valuePos; + } +}; + +/** + * IFile Writer + */ +class IFileWriter : public Collector { +protected: + OutputStream * _stream; + ChecksumOutputStream * _dest; + ChecksumType _checksumType; + KeyValueType _kType; + KeyValueType _vType; + string _codec; + AppendBuffer _appendBuffer; + vector _spillFileSegments; + Counter * _recordCounter; + uint64_t _recordCount; + + bool _deleteTargetStream; + +private: + IFileSegment * toArray(std::vector *segments); + +public: + static IFileWriter * create(const std::string & filepath, const MapOutputSpec & spec, + Counter * spilledRecords); + + IFileWriter(OutputStream * stream, ChecksumType checksumType, KeyValueType ktype, + KeyValueType vtype, const string & codec, Counter * recordCounter, + bool deleteTargetStream = false); + + virtual ~IFileWriter(); + + void startPartition(); + + void endPartition(); + + virtual void write(const char * key, uint32_t keyLen, const char * value, uint32_t valueLen); + + SingleSpillInfo * getSpillInfo(); + + void getStatistics(uint64_t & offset, uint64_t & realOffset, uint64_t & recordCount); + + virtual void collect(const void * key, uint32_t keyLen, const void * value, uint32_t valueLen) { + write((const char*)key, keyLen, (const char*)value, valueLen); + } +}; + +} // namespace NativeTask + +#endif /* IFILE_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Iterator.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Iterator.cc new file mode 100644 index 00000000000..3d0516ab21c --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Iterator.cc @@ -0,0 +1,91 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "lib/Iterator.h" +#include "lib/commons.h" + +namespace NativeTask { + +KeyGroupIteratorImpl::KeyGroupIteratorImpl(KVIterator * iterator) + : _keyGroupIterState(NEW_KEY), _iterator(iterator), _first(true) { +} + +bool KeyGroupIteratorImpl::nextKey() { + if (_keyGroupIterState == NO_MORE) { + return false; + } + + uint32_t temp; + while (_keyGroupIterState == SAME_KEY || _keyGroupIterState == NEW_KEY_VALUE) { + nextValue(temp); + } + if (_keyGroupIterState == NEW_KEY) { + if (_first == true) { + _first = false; + if (!next()) { + _keyGroupIterState = NO_MORE; + return false; + } + } + _keyGroupIterState = NEW_KEY_VALUE; + _currentGroupKey.assign(_key.data(), _key.length()); + return true; + } + return false; +} + +const char * KeyGroupIteratorImpl::getKey(uint32_t & len) { + len = (uint32_t)_key.length(); + return _key.data(); +} + +const char * KeyGroupIteratorImpl::nextValue(uint32_t & len) { + switch (_keyGroupIterState) { + case NEW_KEY: { + return NULL; + } + case SAME_KEY: { + if (next()) { + if (_key.length() == _currentGroupKey.length()) { + if (fmemeq(_key.data(), _currentGroupKey.c_str(), _key.length())) { + len = _value.length(); + return _value.data(); + } + } + _keyGroupIterState = NEW_KEY; + return NULL; + } + _keyGroupIterState = NO_MORE; + return NULL; + } + case NEW_KEY_VALUE: { + _keyGroupIterState = SAME_KEY; + len = _value.length(); + return _value.data(); + } + case NO_MORE: + return NULL; + } + return NULL; +} + +bool KeyGroupIteratorImpl::next() { + bool result = _iterator->next(_key, _value); + return result; +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Iterator.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Iterator.h new file mode 100644 index 00000000000..b1b5f03ee8c --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Iterator.h @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ITERATOR_H_ +#define ITERATOR_H_ + +#include "NativeTask.h" + +namespace NativeTask { + +class KeyGroupIteratorImpl : public KeyGroupIterator { +protected: + // for KeyGroupIterator + KeyGroupIterState _keyGroupIterState; + KVIterator * _iterator; + string _currentGroupKey; + Buffer _key; + Buffer _value; + bool _first; + +public: + KeyGroupIteratorImpl(KVIterator * iterator); + bool nextKey(); + const char * getKey(uint32_t & len); + const char * nextValue(uint32_t & len); + +protected: + bool next(); +}; + +} //namespace NativeTask +#endif diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Log.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Log.cc new file mode 100644 index 00000000000..1e36e186c37 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Log.cc @@ -0,0 +1,30 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/Log.h" + +namespace NativeTask { + +#ifdef PRINT_LOG + +FILE * LOG_DEVICE = stderr; + +#endif + +} //namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Log.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Log.h new file mode 100644 index 00000000000..a0c17f359a1 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Log.h @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LOG_H_ +#define LOG_H_ + +#include +#include + +namespace NativeTask { + +#define PRINT_LOG + +#ifdef PRINT_LOG + +extern FILE * LOG_DEVICE; +#define LOG(_fmt_, args...) if (LOG_DEVICE) { \ + time_t log_timer; struct tm log_tm; \ + time(&log_timer); localtime_r(&log_timer, &log_tm); \ + fprintf(LOG_DEVICE, "%02d/%02d/%02d %02d:%02d:%02d INFO "_fmt_"\n", \ + log_tm.tm_year%100, log_tm.tm_mon+1, log_tm.tm_mday, \ + log_tm.tm_hour, log_tm.tm_min, log_tm.tm_sec, \ + ##args);} + +#else + +#define LOG(_fmt_, args...) + +#endif + +} // namespace NativeTask + +#endif /* LOG_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MapOutputCollector.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MapOutputCollector.cc new file mode 100644 index 00000000000..1175b2345d0 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MapOutputCollector.cc @@ -0,0 +1,413 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "lib/commons.h" +#include "util/Timer.h" +#include "util/StringUtil.h" +#include "lib/FileSystem.h" +#include "lib/NativeObjectFactory.h" +#include "lib/MapOutputCollector.h" +#include "lib/Merge.h" +#include "NativeTask.h" +#include "util/WritableUtils.h" +#include "util/DualPivotQuickSort.h" +#include "lib/Combiner.h" +#include "lib/TaskCounters.h" +#include "lib/MinHeap.h" + +namespace NativeTask { + +ICombineRunner * CombineRunnerWrapper::createCombiner() { + + ICombineRunner * combineRunner = NULL; + if (NULL != _config->get(NATIVE_COMBINER)) { + // Earlier versions of this code supported user-defined + // native Combiner implementations. This simplified version + // no longer supports it. + THROW_EXCEPTION_EX(UnsupportException, "Native Combiners not supported"); + } + + CombineHandler * javaCombiner = _spillOutput->getJavaCombineHandler(); + if (NULL != javaCombiner) { + _isJavaCombiner = true; + combineRunner = (ICombineRunner *)javaCombiner; + } else { + LOG("[MapOutputCollector::getCombiner] cannot get combine handler from java"); + } + return combineRunner; +} + +void CombineRunnerWrapper::combine(CombineContext type, KVIterator * kvIterator, + IFileWriter * writer) { + + if (!_combinerInited) { + _combineRunner = createCombiner(); + _combinerInited = true; + } + + if (NULL != _combineRunner) { + _combineRunner->combine(type, kvIterator, writer); + } else { + LOG("[CombineRunnerWrapper::combine] no valid combiner"); + } +} + +///////////////////////////////////////////////////////////////// +// MapOutputCollector +///////////////////////////////////////////////////////////////// + +MapOutputCollector::MapOutputCollector(uint32_t numberPartitions, SpillOutputService * spillService) + : _config(NULL), _numPartitions(numberPartitions), _buckets(NULL), + _keyComparator(NULL), _combineRunner(NULL), + _mapOutputRecords(NULL), _mapOutputBytes(NULL), + _mapOutputMaterializedBytes(NULL), _spilledRecords(NULL), + _spillOutput(spillService), _defaultBlockSize(0), _pool(NULL) { + _pool = new MemoryPool(); +} + +MapOutputCollector::~MapOutputCollector() { + + if (NULL != _buckets) { + for (uint32_t i = 0; i < _numPartitions; i++) { + if (NULL != _buckets[i]) { + delete _buckets[i]; + _buckets[i] = NULL; + } + } + } + + delete[] _buckets; + _buckets = NULL; + + if (NULL != _pool) { + delete _pool; + _pool = NULL; + } + + if (NULL != _combineRunner) { + delete _combineRunner; + _combineRunner = NULL; + } +} + +void MapOutputCollector::init(uint32_t defaultBlockSize, uint32_t memoryCapacity, + ComparatorPtr keyComparator, ICombineRunner * combiner) { + + this->_combineRunner = combiner; + + this->_defaultBlockSize = defaultBlockSize; + + _pool->init(memoryCapacity); + + // TODO: add support for customized comparator + this->_keyComparator = keyComparator; + + _buckets = new PartitionBucket*[_numPartitions]; + + for (uint32_t partitionId = 0; partitionId < _numPartitions; partitionId++) { + PartitionBucket * pb = new PartitionBucket(_pool, partitionId, keyComparator, _combineRunner, + defaultBlockSize); + + _buckets[partitionId] = pb; + } + + _mapOutputRecords = NativeObjectFactory::GetCounter( + TaskCounters::TASK_COUNTER_GROUP, TaskCounters::MAP_OUTPUT_RECORDS); + _mapOutputBytes = NativeObjectFactory::GetCounter( + TaskCounters::TASK_COUNTER_GROUP, TaskCounters::MAP_OUTPUT_BYTES); + _mapOutputMaterializedBytes = NativeObjectFactory::GetCounter( + TaskCounters::TASK_COUNTER_GROUP, + TaskCounters::MAP_OUTPUT_MATERIALIZED_BYTES); + _spilledRecords = NativeObjectFactory::GetCounter( + TaskCounters::TASK_COUNTER_GROUP, TaskCounters::SPILLED_RECORDS); + + _collectTimer.reset(); +} + +void MapOutputCollector::reset() { + for (uint32_t i = 0; i < _numPartitions; i++) { + if (NULL != _buckets[i]) { + _buckets[i]->reset(); + } + } + _pool->reset(); +} + +void MapOutputCollector::configure(Config * config) { + _config = config; + MapOutputSpec::getSpecFromConfig(config, _spec); + + uint32_t maxBlockSize = config->getInt(NATIVE_SORT_MAX_BLOCK_SIZE, DEFAULT_MAX_BLOCK_SIZE); + uint32_t capacity = config->getInt(MAPRED_IO_SORT_MB, 300) * 1024 * 1024; + + uint32_t defaultBlockSize = getDefaultBlockSize(capacity, _numPartitions, maxBlockSize); + LOG("Native Total MemoryBlockPool: num_partitions %u, min_block_size %uK, " + "max_block_size %uK, capacity %uM", _numPartitions, defaultBlockSize / 1024, + maxBlockSize / 1024, capacity / 1024 / 1024); + + ComparatorPtr comparator = getComparator(config, _spec); + + ICombineRunner * combiner = NULL; + if (NULL != config->get(NATIVE_COMBINER) + // config name for old api and new api + || NULL != config->get(MAPRED_COMBINE_CLASS_OLD) + || NULL != config->get(MAPRED_COMBINE_CLASS_NEW)) { + combiner = new CombineRunnerWrapper(config, _spillOutput); + } + + init(defaultBlockSize, capacity, comparator, combiner); +} + +KVBuffer * MapOutputCollector::allocateKVBuffer(uint32_t partitionId, uint32_t kvlength) { + PartitionBucket * partition = getPartition(partitionId); + if (NULL == partition) { + THROW_EXCEPTION_EX(IOException, "Partition is NULL, partition_id: %d, num_partitions: %d", + partitionId, _numPartitions); + } + + KVBuffer * dest = partition->allocateKVBuffer(kvlength); + + if (NULL == dest) { + string * spillpath = _spillOutput->getSpillPath(); + if (NULL == spillpath || spillpath->length() == 0) { + THROW_EXCEPTION(IOException, "Illegal(empty) spill files path"); + } else { + middleSpill(*spillpath, "", false); + delete spillpath; + } + + dest = partition->allocateKVBuffer(kvlength); + if (NULL == dest) { + // io.sort.mb too small, cann't proceed + // should not get here, cause get_buffer_to_put can throw OOM exception + THROW_EXCEPTION(OutOfMemoryException, "key/value pair larger than io.sort.mb"); + } + } + _mapOutputRecords->increase(); + _mapOutputBytes->increase(kvlength - KVBuffer::headerLength()); + return dest; +} + +/** + * collect one k/v pair + * @return true success; false buffer full, need spill + */ +bool MapOutputCollector::collect(const void * key, uint32_t keylen, const void * value, + uint32_t vallen, uint32_t partitionId) { + uint32_t total_length = keylen + vallen + KVBuffer::headerLength(); + KVBuffer * buff = allocateKVBuffer(partitionId, total_length); + + if (NULL == buff) { + return false; + } + buff->fill(key, keylen, value, vallen); + return true; +} + +ComparatorPtr MapOutputCollector::getComparator(Config * config, MapOutputSpec & spec) { + string nativeComparator = NATIVE_MAPOUT_KEY_COMPARATOR; + const char * key_class = config->get(MAPRED_MAPOUTPUT_KEY_CLASS); + if (NULL == key_class) { + key_class = config->get(MAPRED_OUTPUT_KEY_CLASS); + } + nativeComparator.append(".").append(key_class); + const char * comparatorName = config->get(nativeComparator); + return NativeTask::get_comparator(spec.keyType, comparatorName); +} + +PartitionBucket * MapOutputCollector::getPartition(uint32_t partition) { + if (partition >= _numPartitions) { + return NULL; + } + return _buckets[partition]; +} + +/** + * Spill buffer to file + * @return Array of spill segments information + */ +void MapOutputCollector::sortPartitions(SortOrder orderType, SortAlgorithm sortType, + IFileWriter * writer, SortMetrics & metric) { + + uint32_t start_partition = 0; + uint32_t num_partition = _numPartitions; + if (orderType == GROUPBY) { + THROW_EXCEPTION(UnsupportException, "GROUPBY not supported"); + } + + uint64_t sortingTime = 0; + Timer timer; + uint64_t recordNum = 0; + + for (uint32_t i = 0; i < num_partition; i++) { + if (NULL != writer) { + writer->startPartition(); + } + PartitionBucket * pb = _buckets[start_partition + i]; + if (pb != NULL) { + recordNum += pb->getKVCount(); + if (orderType == FULLORDER) { + timer.reset(); + pb->sort(sortType); + sortingTime += timer.now() - timer.last(); + } + if (NULL != writer) { + pb->spill(writer); + } + } + if (NULL != writer) { + writer->endPartition(); + } + } + metric.sortTime = sortingTime; + metric.recordCount = recordNum; +} + +void MapOutputCollector::middleSpill(const std::string & spillOutput, + const std::string & indexFilePath, bool final) { + + uint64_t collecttime = _collectTimer.now() - _collectTimer.last(); + + if (spillOutput.empty()) { + THROW_EXCEPTION(IOException, "MapOutputCollector: Spill file path empty"); + } else { + OutputStream * fout = FileSystem::getLocal().create(spillOutput, true); + + IFileWriter * writer = new IFileWriter(fout, _spec.checksumType, _spec.keyType, _spec.valueType, + _spec.codec, _spilledRecords); + + Timer timer; + SortMetrics metrics; + sortPartitions(_spec.sortOrder, _spec.sortAlgorithm, writer, metrics); + + SingleSpillInfo * info = writer->getSpillInfo(); + info->path = spillOutput; + uint64_t spillTime = timer.now() - timer.last() - metrics.sortTime; + + const uint64_t M = 1000000; // million + LOG("%s-spill: { id: %d, collect: %"PRIu64" ms, " + "in-memory sort: %"PRIu64" ms, in-memory records: %"PRIu64", " + "merge&spill: %"PRIu64" ms, uncompressed size: %"PRIu64", " + "real size: %"PRIu64" path: %s }", + final ? "Final" : "Mid", + _spillInfos.getSpillCount(), + collecttime / M, + metrics.sortTime / M, + metrics.recordCount, + spillTime / M, + info->getEndPosition(), + info->getRealEndPosition(), + spillOutput.c_str()); + + if (final) { + _mapOutputMaterializedBytes->increase(info->getRealEndPosition()); + } + + if (indexFilePath.length() > 0) { + info->writeSpillInfo(indexFilePath); + delete info; + } else { + _spillInfos.add(info); + } + + delete writer; + delete fout; + + reset(); + _collectTimer.reset(); + } +} + +/** + * final merge and/or spill, use previous spilled + * file & in-memory data + */ +void MapOutputCollector::finalSpill(const std::string & filepath, + const std::string & idx_file_path) { + + if (_spillInfos.getSpillCount() == 0) { + middleSpill(filepath, idx_file_path, true); + return; + } + + IFileWriter * writer = IFileWriter::create(filepath, _spec, _spilledRecords); + Merger * merger = new Merger(writer, _config, _keyComparator, _combineRunner); + + for (size_t i = 0; i < _spillInfos.getSpillCount(); i++) { + SingleSpillInfo * spill = _spillInfos.getSingleSpillInfo(i); + MergeEntryPtr pme = IFileMergeEntry::create(spill); + merger->addMergeEntry(pme); + } + + SortMetrics metrics; + sortPartitions(_spec.sortOrder, _spec.sortAlgorithm, NULL, metrics); + + merger->addMergeEntry(new MemoryMergeEntry(_buckets, _numPartitions)); + + Timer timer; + merger->merge(); + + uint64_t outputSize; + uint64_t realOutputSize; + uint64_t recordCount; + writer->getStatistics(outputSize, realOutputSize, recordCount); + + const uint64_t M = 1000000; // million + LOG("Final-merge-spill: { id: %d, in-memory sort: %"PRIu64" ms, " + "in-memory records: %"PRIu64", merge&spill: %"PRIu64" ms, " + "records: %"PRIu64", uncompressed size: %"PRIu64", " + "real size: %"PRIu64" path: %s }", + _spillInfos.getSpillCount(), + metrics.sortTime / M, + metrics.recordCount, + (timer.now() - timer.last()) / M, + recordCount, + outputSize, + realOutputSize, + filepath.c_str()); + + _mapOutputMaterializedBytes->increase(realOutputSize); + + delete merger; + + // write index + SingleSpillInfo * spill_range = writer->getSpillInfo(); + spill_range->writeSpillInfo(idx_file_path); + delete spill_range; + _spillInfos.deleteAllSpillFiles(); + delete writer; + reset(); +} + +void MapOutputCollector::close() { + string * outputpath = _spillOutput->getOutputPath(); + string * indexpath = _spillOutput->getOutputIndexPath(); + + if ((outputpath->length() == 0) || (indexpath->length() == 0)) { + THROW_EXCEPTION(IOException, "Illegal(empty) map output file/index path"); + } + + finalSpill(*outputpath, *indexpath); + + delete outputpath; + delete indexpath; +} +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MapOutputCollector.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MapOutputCollector.h new file mode 100644 index 00000000000..ee447ed2e45 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MapOutputCollector.h @@ -0,0 +1,167 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MAP_OUTPUT_COLLECTOR_H_ +#define MAP_OUTPUT_COLLECTOR_H_ + +#include "NativeTask.h" +#include "lib/MemoryPool.h" +#include "util/Timer.h" +#include "lib/Buffers.h" +#include "lib/MapOutputSpec.h" +#include "lib/IFile.h" +#include "lib/SpillInfo.h" +#include "lib/Combiner.h" +#include "lib/PartitionBucket.h" +#include "lib/SpillOutputService.h" + +namespace NativeTask { +/** + * MapOutputCollector + */ + +struct SortMetrics { + uint64_t recordCount; + uint64_t sortTime; + +public: + SortMetrics() + : recordCount(0), sortTime(0) { + } +}; + +class CombineRunnerWrapper : public ICombineRunner { +private: + Config * _config; + ICombineRunner * _combineRunner; + bool _isJavaCombiner; + bool _combinerInited; + SpillOutputService * _spillOutput; + +public: + CombineRunnerWrapper(Config * config, SpillOutputService * service) + : _config(config), _combineRunner(NULL), _isJavaCombiner(false), + _combinerInited(false), _spillOutput(service) { + } + + ~CombineRunnerWrapper() { + if (!_isJavaCombiner) { + delete _combineRunner; + } + } + + virtual void combine(CombineContext type, KVIterator * kvIterator, IFileWriter * writer); + +private: + ICombineRunner * createCombiner(); +}; + +class MapOutputCollector { + static const uint32_t DEFAULT_MIN_BLOCK_SIZE = 16 * 1024; + static const uint32_t DEFAULT_MAX_BLOCK_SIZE = 4 * 1024 * 1024; + +private: + Config * _config; + + uint32_t _numPartitions; + PartitionBucket ** _buckets; + + ComparatorPtr _keyComparator; + + ICombineRunner * _combineRunner; + + Counter * _mapOutputRecords; + Counter * _mapOutputBytes; + Counter * _mapOutputMaterializedBytes; + Counter * _spilledRecords; + + SpillOutputService * _spillOutput; + + uint32_t _defaultBlockSize; + + SpillInfos _spillInfos; + + MapOutputSpec _spec; + + Timer _collectTimer; + + MemoryPool * _pool; + +public: + MapOutputCollector(uint32_t num_partition, SpillOutputService * spillService); + + ~MapOutputCollector(); + + void configure(Config * config); + + /** + * collect one k/v pair + * @return true success; false buffer full, need spill + */ + bool collect(const void * key, uint32_t keylen, const void * value, uint32_t vallen, + uint32_t partitionId); + + KVBuffer * allocateKVBuffer(uint32_t partitionId, uint32_t kvlength); + + void close(); + +private: + void init(uint32_t maxBlockSize, uint32_t memory_capacity, ComparatorPtr keyComparator, + ICombineRunner * combiner); + + void reset(); + + /** + * spill a range of partition buckets, prepare for future + * Parallel sort & spill, TODO: parallel sort & spill + */ + void sortPartitions(SortOrder orderType, SortAlgorithm sortType, IFileWriter * writer, + SortMetrics & metrics); + + ComparatorPtr getComparator(Config * config, MapOutputSpec & spec); + + inline uint32_t GetCeil(uint32_t v, uint32_t unit) { + return ((v + unit - 1) / unit) * unit; + } + + uint32_t getDefaultBlockSize(uint32_t memoryCapacity, uint32_t partitionNum, + uint32_t maxBlockSize) { + uint32_t defaultBlockSize = memoryCapacity / _numPartitions / 4; + defaultBlockSize = GetCeil(defaultBlockSize, DEFAULT_MIN_BLOCK_SIZE); + defaultBlockSize = std::min(defaultBlockSize, maxBlockSize); + return defaultBlockSize; + } + + PartitionBucket * getPartition(uint32_t partition); + + /** + * normal spill use options in _config + * @param filepaths: spill file path + */ + void middleSpill(const std::string & spillOutput, const std::string & indexFilePath, bool final); + + /** + * final merge and/or spill use options in _config, and + * previous spilled file & in-memory data + */ + void finalSpill(const std::string & filepath, const std::string & indexpath); +}; + +} //namespace NativeTask + +#endif /* MAP_OUTPUT_COLLECTOR_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MapOutputSpec.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MapOutputSpec.cc new file mode 100644 index 00000000000..8874d0299c5 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MapOutputSpec.cc @@ -0,0 +1,64 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/MapOutputSpec.h" +#include "NativeTask.h" + +namespace NativeTask { + +void MapOutputSpec::getSpecFromConfig(Config * config, MapOutputSpec & spec) { + if (NULL == config) { + return; + } + spec.checksumType = CHECKSUM_CRC32; + string sortType = config->get(NATIVE_SORT_TYPE, "DUALPIVOTSORT"); + if (sortType == "DUALPIVOTSORT") { + spec.sortAlgorithm = DUALPIVOTSORT; + } else { + spec.sortAlgorithm = CPPSORT; + } + if (config->get(MAPRED_COMPRESS_MAP_OUTPUT, "false") == "true") { + spec.codec = config->get(MAPRED_MAP_OUTPUT_COMPRESSION_CODEC); + } else { + spec.codec = ""; + } + if (config->getBool(MAPRED_SORT_AVOID, false)) { + spec.sortOrder = NOSORT; + } else { + spec.sortOrder = FULLORDER; + } + const char * key_class = config->get(MAPRED_MAPOUTPUT_KEY_CLASS); + if (NULL == key_class) { + key_class = config->get(MAPRED_OUTPUT_KEY_CLASS); + } + if (NULL == key_class) { + THROW_EXCEPTION(IOException, "mapred.mapoutput.key.class not set"); + } + spec.keyType = JavaClassToKeyValueType(key_class); + const char * value_class = config->get(MAPRED_MAPOUTPUT_VALUE_CLASS); + if (NULL == value_class) { + value_class = config->get(MAPRED_OUTPUT_VALUE_CLASS); + } + if (NULL == value_class) { + THROW_EXCEPTION(IOException, "mapred.mapoutput.value.class not set"); + } + spec.valueType = JavaClassToKeyValueType(value_class); +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MapOutputSpec.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MapOutputSpec.h new file mode 100644 index 00000000000..ce43997c5b3 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MapOutputSpec.h @@ -0,0 +1,81 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MAPOUTPUTSPEC_H_ +#define MAPOUTPUTSPEC_H_ + +#include +#include "util/Checksum.h" +#include "util/WritableUtils.h" +#include "NativeTask.h" + +namespace NativeTask { + +using std::string; + +/** + * internal sort method + */ +enum SortAlgorithm { + CQSORT = 0, + CPPSORT = 1, + DUALPIVOTSORT = 2, +}; + +/** + * spill file type + * INTERMEDIATE: a simple key/value sequence file + * IFILE: classic hadoop IFile + */ +enum OutputFileType { + INTERMEDIATE = 0, + IFILE = 1, +}; + +/** + * key/value recored order requirements + * FULLSORT: hadoop standard + * GROUPBY: same key are grouped together, but not in order + * NOSORT: no order at all + */ +enum SortOrder { + FULLORDER = 0, + GROUPBY = 1, + NOSORT = 2, +}; + +enum CompressionType { + PLAIN = 0, + SNAPPY = 1, +}; + +class MapOutputSpec { +public: + KeyValueType keyType; + KeyValueType valueType; + SortOrder sortOrder; + SortAlgorithm sortAlgorithm; + string codec; + ChecksumType checksumType; + + static void getSpecFromConfig(Config * config, MapOutputSpec & spec); +}; + +} // namespace NativeTask + +#endif /* MAPOUTPUTSPEC_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MemoryBlock.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MemoryBlock.cc new file mode 100644 index 00000000000..b3734a170b7 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MemoryBlock.cc @@ -0,0 +1,67 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "NativeTask.h" +#include "lib/commons.h" +#include "util/Timer.h" +#include "lib/Buffers.h" +#include "lib/MapOutputSpec.h" +#include "lib/IFile.h" +#include "lib/SpillInfo.h" +#include "lib/Combiner.h" + +#include "lib/MemoryBlock.h" +#include "lib/MemoryPool.h" +#include "util/DualPivotQuickSort.h" + +namespace NativeTask { + +class MemoryPool; + +MemoryBlock::MemoryBlock(char * pos, uint32_t size) + : _base(pos), _size(size), _position(0), _sorted(false) { +} + +KVBuffer * MemoryBlock::getKVBuffer(int index) { + if (index < 0 || index >= _kvOffsets.size()) { + return NULL; + } + uint32_t offset = _kvOffsets.at(index); + KVBuffer * kvbuffer = (KVBuffer*)(_base + offset); + return kvbuffer; +} + +void MemoryBlock::sort(SortAlgorithm type, ComparatorPtr comparator) { + if ((!_sorted) && (_kvOffsets.size() > 1)) { + switch (type) { + case CPPSORT: + std::sort(_kvOffsets.begin(), _kvOffsets.end(), ComparatorForStdSort(_base, comparator)); + break; + case DUALPIVOTSORT: { + DualPivotQuicksort(_kvOffsets, ComparatorForDualPivotSort(_base, comparator)); + } + break; + default: + THROW_EXCEPTION(UnsupportException, "Sort Algorithm not support"); + } + } + _sorted = true; +} +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MemoryBlock.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MemoryBlock.h new file mode 100644 index 00000000000..f85c3b61f1f --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MemoryBlock.h @@ -0,0 +1,172 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "commons.h" + +#ifndef MEMORYBLOCK_H_ +#define MEMORYBLOCK_H_ + +namespace NativeTask { + +class MemoryPool; + +class ComparatorForDualPivotSort { +private: + const char * _base; + ComparatorPtr _keyComparator; +public: + ComparatorForDualPivotSort(const char * base, ComparatorPtr comparator) + : _base(base), _keyComparator(comparator) { + } + + inline int operator()(uint32_t lhs, uint32_t rhs) { + KVBuffer * left = (KVBuffer *)(_base + lhs); + KVBuffer * right = (KVBuffer *)(_base + rhs); + return (*_keyComparator)(left->content, left->keyLength, right->content, right->keyLength); + } +}; + +class ComparatorForStdSort { +private: + const char * _base; + ComparatorPtr _keyComparator; +public: + ComparatorForStdSort(const char * base, ComparatorPtr comparator) + : _base(base), _keyComparator(comparator) { + } + +public: + inline bool operator()(uint32_t lhs, uint32_t rhs) { + KVBuffer * left = (KVBuffer *)(_base + lhs); + KVBuffer * right = (KVBuffer *)(_base + rhs); + int ret = (*_keyComparator)(left->getKey(), left->keyLength, right->getKey(), right->keyLength); + return ret < 0; + } +}; + +class MemoryBlock { +private: + char * _base; + uint32_t _size; + uint32_t _position; + std::vector _kvOffsets; + bool _sorted; + +public: + MemoryBlock(char * pos, uint32_t size); + + char * base() { + return _base; + } + + bool sorted() { + return _sorted; + } + + KVBuffer * allocateKVBuffer(uint32_t length) { + if (length > remainSpace()) { + LOG("Unable to allocate kv from memory buffer, length: %d, remain: %d", length, remainSpace()); + return NULL; + } + _sorted = false; + _kvOffsets.push_back(_position); + char * space = _base + _position; + _position += length; + return (KVBuffer *)space; + } + + uint32_t remainSpace() const { + return _size - _position; + } + + uint32_t getKVCount() { + return _kvOffsets.size(); + } + + KVBuffer * getKVBuffer(int index); + + void sort(SortAlgorithm type, ComparatorPtr comparator); +}; +//class MemoryBlock + +class MemBlockIterator { +private: + MemoryBlock * _memBlock; + uint32_t _end; + uint32_t _current; + KVBuffer * _kvBuffer; + +public: + + MemBlockIterator(MemoryBlock * memBlock) + : _memBlock(memBlock), _end(0), _current(0), _kvBuffer(NULL) { + _end = memBlock->getKVCount(); + } + + KVBuffer * getKVBuffer() { + return _kvBuffer; + } + + /** + * move to next key/value + * 0 on success + * 1 on no more + */ + bool next() { + if (_current >= _end) { + return false; + } + this->_kvBuffer = _memBlock->getKVBuffer(_current); + ++_current; + return true; + } +}; +//class MemoryBlockIterator + +typedef MemBlockIterator * MemBlockIteratorPtr; + +class MemBlockComparator { +private: + ComparatorPtr _keyComparator; + +public: + MemBlockComparator(ComparatorPtr comparator) + : _keyComparator(comparator) { + } + +public: + bool operator()(const MemBlockIteratorPtr lhs, const MemBlockIteratorPtr rhs) { + + KVBuffer * left = lhs->getKVBuffer(); + KVBuffer * right = rhs->getKVBuffer(); + + //Treat NULL as infinite MAX, so that we can pop out next value + if (NULL == left) { + return false; + } + + if (NULL == right) { + return true; + } + + return (*_keyComparator)(left->content, left->keyLength, right->content, right->keyLength) < 0; + } +}; + +} //namespace NativeTask + +#endif /* MEMORYBLOCK_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MemoryPool.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MemoryPool.h new file mode 100644 index 00000000000..1aa9cc2f2ac --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MemoryPool.h @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MEMORYPOOL_H_ +#define MEMORYPOOL_H_ + +#include "lib/Buffers.h" +#include "lib/MapOutputSpec.h" +#include "NativeTask.h" +#include "util/StringUtil.h" + +namespace NativeTask { + +/** + * Class for allocating memory buffer + */ + +class MemoryPool { +private: + char * _base; + uint32_t _capacity; + uint32_t _used; + +public: + + MemoryPool() + : _base(NULL), _capacity(0), _used(0) { + } + + ~MemoryPool() { + if (NULL != _base) { + free(_base); + _base = NULL; + } + } + + void init(uint32_t capacity) throw (OutOfMemoryException) { + if (capacity > _capacity) { + if (NULL != _base) { + free(_base); + _base = NULL; + } + _base = (char*)malloc(capacity); + if (NULL == _base) { + THROW_EXCEPTION(OutOfMemoryException, "Not enough memory to init MemoryBlockPool"); + } + _capacity = capacity; + } + reset(); + } + + void reset() { + _used = 0; + } + + char * allocate(uint32_t min, uint32_t expect, uint32_t & allocated) { + if (_used + min > _capacity) { + return NULL; + } else if (_used + expect > _capacity) { + char * buff = _base + _used; + allocated = min; + _used += min; + return buff; + } else { + char * buff = _base + _used; + allocated = expect; + _used += expect; + return buff; + } + } +}; + +} // namespace NativeTask + +#endif /* MEMORYPOOL_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Merge.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Merge.cc new file mode 100644 index 00000000000..0d18db8b008 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Merge.cc @@ -0,0 +1,156 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "util/Timer.h" +#include "util/StringUtil.h" +#include "lib/Merge.h" +#include "lib/FileSystem.h" + +namespace NativeTask { + +IFileMergeEntry * IFileMergeEntry::create(SingleSpillInfo * spill) { + InputStream * fileOut = FileSystem::getLocal().open(spill->path); + IFileReader * reader = new IFileReader(fileOut, spill, true); + return new IFileMergeEntry(reader); +} + +Merger::Merger(IFileWriter * writer, Config * config, ComparatorPtr comparator, + ICombineRunner * combineRunner) + : _writer(writer), _config(config), _combineRunner(combineRunner), _first(true), + _comparator(comparator) { +} + +Merger::~Merger() { + _heap.clear(); + for (size_t i = 0; i < _entries.size(); i++) { + delete _entries[i]; + } + _entries.clear(); +} + +void Merger::addMergeEntry(MergeEntryPtr pme) { + _entries.push_back(pme); +} + +/** + * 0 if success, have next partition + * 1 if failed, no more + */ +bool Merger::startPartition() { + bool firstPartitionState = false; + for (size_t i = 0; i < _entries.size(); i++) { + bool partitionState = _entries[i]->nextPartition(); + if (i == 0) { + firstPartitionState = partitionState; + } + if (firstPartitionState != partitionState) { + THROW_EXCEPTION(IOException, "MergeEntry partition number not equal"); + } + } + if (firstPartitionState) { // do have new partition + _writer->startPartition(); + } + return firstPartitionState; +} + +/** + * finish one partition + */ +void Merger::endPartition() { + _writer->endPartition(); +} + +void Merger::initHeap() { + _heap.clear(); + for (size_t i = 0; i < _entries.size(); i++) { + MergeEntryPtr pme = _entries[i]; + if (pme->next()) { + _heap.push_back(pme); + } + } + makeHeap(&(_heap[0]), &(_heap[0]) + _heap.size(), _comparator); +} + +bool Merger::next() { + size_t cur_heap_size = _heap.size(); + if (cur_heap_size > 0) { + if (!_first) { + if (_heap[0]->next()) { // have more, adjust heap + if (cur_heap_size == 1) { + return true; + } else if (cur_heap_size == 2) { + MergeEntryPtr * base = &(_heap[0]); + + if (_comparator(base[1], base[0])) { + std::swap(base[0], base[1]); + } + } else { + MergeEntryPtr * base = &(_heap[0]); + heapify(base, 1, cur_heap_size, _comparator); + } + } else { // no more, pop heap + MergeEntryPtr * base = &(_heap[0]); + popHeap(base, base + cur_heap_size, _comparator); + _heap.pop_back(); + } + } else { + _first = false; + } + return _heap.size() > 0; + } + return false; +} + +bool Merger::next(Buffer & key, Buffer & value) { + bool result = next(); + if (result) { + MergeEntryPtr * base = &(_heap[0]); + key.reset(base[0]->getKey(), base[0]->getKeyLength()); + value.reset(base[0]->getValue(), base[0]->getValueLength()); + return true; + } else { + return false; + } +} + +void Merger::merge() { + uint64_t total_record = 0; + _heap.reserve(_entries.size()); + MergeEntryPtr * base = &(_heap[0]); + while (startPartition()) { + initHeap(); + if (_heap.size() == 0) { + endPartition(); + continue; + } + _first = true; + if (_combineRunner == NULL) { + while (next()) { + _writer->write(base[0]->getKey(), base[0]->getKeyLength(), base[0]->getValue(), + base[0]->getValueLength()); + total_record++; + } + } else { + _combineRunner->combine(CombineContext(UNKNOWN), this, _writer); + } + endPartition(); + } +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Merge.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Merge.h new file mode 100644 index 00000000000..cf1f2be9560 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Merge.h @@ -0,0 +1,254 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MERGE_H_ +#define MERGE_H_ + +#include "NativeTask.h" +#include "lib/Buffers.h" +#include "lib/MapOutputCollector.h" +#include "lib/IFile.h" +#include "lib/MinHeap.h" + +namespace NativeTask { + +/** + * merger + */ +class MergeEntry { + +protected: + // these 3 fields should be filled after next() is called + const char * _key; + const char * _value; + uint32_t _keyLength; + uint32_t _valueLength; + +public: + MergeEntry() + : _key(NULL), _value(NULL), _keyLength(0), _valueLength(0) { + } + + const char * getKey() const { + return _key; + } + + const char * getValue() const { + return _value; + } + + uint32_t getKeyLength() const { + return _keyLength; + } + + uint32_t getValueLength() const { + return _valueLength; + } + + virtual ~MergeEntry() { + } + + /** + * move to next partition + * 0 on success + * 1 on no more + */ + virtual bool nextPartition() = 0; + + /** + * move to next key/value + * 0 on success + * 1 on no more + */ + virtual bool next() = 0; +}; + +/** + * Merger + */ +typedef MergeEntry * MergeEntryPtr; + +class MergeEntryComparator { +private: + ComparatorPtr _keyComparator; + +public: + MergeEntryComparator(ComparatorPtr comparator) + : _keyComparator(comparator) { + } + +public: + bool operator()(const MergeEntryPtr lhs, const MergeEntryPtr rhs) { + return (*_keyComparator)(lhs->getKey(), lhs->getKeyLength(), rhs->getKey(), rhs->getKeyLength()) + < 0; + } +}; + +/** + * Merge entry for in-memory partition bucket + */ +class MemoryMergeEntry : public MergeEntry { +protected: + + PartitionBucket ** _partitions; + uint32_t _number; + int64_t _index; + + KVIterator * _iterator; + Buffer keyBuffer; + Buffer valueBuffer; + +public: + MemoryMergeEntry(PartitionBucket ** partitions, uint32_t numberOfPartitions) + : _partitions(partitions), _number(numberOfPartitions), _index(-1), _iterator(NULL) { + } + + virtual ~MemoryMergeEntry() { + if (NULL != _iterator) { + delete _iterator; + _iterator = NULL; + } + } + + virtual bool nextPartition() { + ++_index; + if (_index < _number) { + PartitionBucket * current = _partitions[_index]; + if (NULL != _iterator) { + delete _iterator; + _iterator = NULL; + } + if (NULL != current) { + _iterator = current->getIterator(); + } + return true; + } + return false; + } + + /** + * move to next key/value + * 0 on success + * 1 on no more + */ + virtual bool next() { + if (NULL == _iterator) { + return false; + } + bool hasNext = _iterator->next(keyBuffer, valueBuffer); + + if (hasNext) { + _keyLength = keyBuffer.length(); + _key = keyBuffer.data(); + _valueLength = valueBuffer.length(); + _value = valueBuffer.data(); + assert(_value != NULL); + return true; + } + // detect error early + _keyLength = 0xffffffff; + _valueLength = 0xffffffff; + _key = NULL; + _value = NULL; + return false; + } +}; + +/** + * Merge entry for intermediate file + */ +class IFileMergeEntry : public MergeEntry { +protected: + IFileReader * _reader; + bool new_partition; +public: + /** + * @param reader: managed by InterFileMergeEntry + */ + + static IFileMergeEntry * create(SingleSpillInfo * spill); + + IFileMergeEntry(IFileReader * reader) + : _reader(reader) { + new_partition = false; + } + + virtual ~IFileMergeEntry() { + delete _reader; + _reader = NULL; + } + + /** + * move to next partition + * 0 on success + * 1 on no more + */ + virtual bool nextPartition() { + return _reader->nextPartition(); + } + + /** + * move to next key/value + * 0 on success + * 1 on no more + */ + virtual bool next() { + _key = _reader->nextKey(_keyLength); + if (unlikely(NULL == _key)) { + // detect error early + _keyLength = 0xffffffffU; + _valueLength = 0xffffffffU; + return false; + } + _value = _reader->value(_valueLength); + return true; + } +}; + +class Merger : public KVIterator { + +private: + vector _entries; + vector _heap; + IFileWriter * _writer; + Config * _config; + ICombineRunner * _combineRunner; + bool _first; + MergeEntryComparator _comparator; + +public: + Merger(IFileWriter * writer, Config * config, ComparatorPtr comparator, + ICombineRunner * combineRunner = NULL); + + ~Merger(); + + void addMergeEntry(MergeEntryPtr pme); + + void merge(); + + virtual bool next(Buffer & key, Buffer & value); +protected: + bool startPartition(); + void endPartition(); + void initHeap(); + bool next(); +}; + +} // namespace NativeTask + +#endif /* MERGE_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MinHeap.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MinHeap.h new file mode 100644 index 00000000000..5885f34ff8c --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/MinHeap.h @@ -0,0 +1,64 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MIN_HEAP_H_ +#define MIN_HEAP_H_ + +#include "NativeTask.h" +#include "lib/Buffers.h" + +template +void heapify(T* first, int rt, int heap_len, Compare & Comp) { + while (rt * 2 <= heap_len) // not leaf + { + int left = (rt << 1); // left child + int right = (rt << 1) + 1; // right child + int smallest = rt; + if (Comp(*(first + left - 1), *(first + smallest - 1))) { + smallest = left; + } + if (right <= heap_len && Comp(*(first + right - 1), *(first + smallest - 1))) { + smallest = right; + } + if (smallest != rt) { + std::swap(*(first + smallest - 1), *(first + rt - 1)); + rt = smallest; + } else { + break; + } + } +} + +template +void makeHeap(T* begin, T* end, Compare & Comp) { + int heap_len = end - begin; + if (heap_len >= 0) { + for (uint32_t i = heap_len / 2; i >= 1; i--) { + heapify(begin, i, heap_len, Comp); + } + } +} + +template +void popHeap(T* begin, T* end, Compare & Comp) { + *begin = *(end - 1); + // adjust [begin, end - 1) to heap + heapify(begin, 1, end - begin - 1, Comp); +} + +#endif /* HEAP_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeLibrary.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeLibrary.cc new file mode 100644 index 00000000000..5d69b26cb59 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeLibrary.cc @@ -0,0 +1,89 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "lib/commons.h" +#include "lib/NativeObjectFactory.h" +#include "lib/NativeLibrary.h" + +namespace NativeTask { + +////////////////////////////////////////////////////////////////// +// NativeLibrary methods +////////////////////////////////////////////////////////////////// + +NativeLibrary::NativeLibrary(const string & path, const string & name) + : _path(path), _name(name), _getObjectCreatorFunc(NULL), _functionGetter(NULL) { +} + +bool NativeLibrary::init() { + void *library = dlopen(_path.c_str(), RTLD_LAZY | RTLD_GLOBAL); + if (NULL == library) { + LOG("[NativeLibrary] Load object library %s failed.", _path.c_str()); + return false; + } + // clean error status + dlerror(); + + string create_object_func_name = _name + "GetObjectCreator"; + _getObjectCreatorFunc = (GetObjectCreatorFunc)dlsym(library, create_object_func_name.c_str()); + if (NULL == _getObjectCreatorFunc) { + LOG("[NativeLibrary] ObjectCreator function [%s] not found", create_object_func_name.c_str()); + } + + string functionGetter = _name + "GetFunctionGetter"; + _functionGetter = (FunctionGetter)dlsym(library, functionGetter.c_str()); + if (NULL == _functionGetter) { + LOG("[NativeLibrary] function getter [%s] not found", functionGetter.c_str()); + } + + string init_library_func_name = _name + "Init"; + InitLibraryFunc init_library_func = (InitLibraryFunc)dlsym(library, + init_library_func_name.c_str()); + if (NULL == init_library_func) { + LOG("[NativeLibrary] Library init function [%s] not found", init_library_func_name.c_str()); + } else { + init_library_func(); + } + return true; +} + +NativeObject * NativeLibrary::createObject(const string & clz) { + if (NULL == _getObjectCreatorFunc) { + return NULL; + } + return (NativeObject*)((_getObjectCreatorFunc(clz))()); +} + +void * NativeLibrary::getFunction(const string & functionName) { + if (NULL == _functionGetter) { + return NULL; + } + return (*_functionGetter)(functionName); +} + +ObjectCreatorFunc NativeLibrary::getObjectCreator(const string & clz) { + if (NULL == _getObjectCreatorFunc) { + return NULL; + } + return _getObjectCreatorFunc(clz); +} + +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeLibrary.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeLibrary.h new file mode 100644 index 00000000000..4eda2158197 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeLibrary.h @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NATIVELIBRARY_H_ +#define NATIVELIBRARY_H_ + +#include + +namespace NativeTask { + +using std::string; +class NativeObject; +class NativeObjectFactory; + +/** + * User level object library abstraction + */ +class NativeLibrary { + friend class NativeObjectFactory; +private: + string _path; + string _name; + GetObjectCreatorFunc _getObjectCreatorFunc; + FunctionGetter _functionGetter; +public: + NativeLibrary(const string & path, const string & name); + + bool init(); + + NativeObject * createObject(const string & clz); + + void * getFunction(const string & functionName); + + ObjectCreatorFunc getObjectCreator(const string & clz); + + ~NativeLibrary() { + } +}; + +} // namespace NativeTask + +#endif /* NATIVELIBRARY_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeObjectFactory.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeObjectFactory.cc new file mode 100644 index 00000000000..21857980f3a --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeObjectFactory.cc @@ -0,0 +1,444 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#ifndef __CYGWIN__ +#include +#endif +#include "lib/commons.h" +#include "NativeTask.h" +#include "lib/NativeObjectFactory.h" +#include "lib/NativeLibrary.h" +#include "lib/BufferStream.h" +#include "util/StringUtil.h" +#include "util/SyncUtils.h" +#include "util/WritableUtils.h" +#include "handler/BatchHandler.h" +#include "handler/MCollectorOutputHandler.h" +#include "handler/CombineHandler.h" + +using namespace NativeTask; + +// TODO: just for debug, should be removed +extern "C" void handler(int sig) { + void *array[10]; + size_t size; + + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + +#ifndef __CYGWIN__ + // get void*'s for all entries on the stack + size = backtrace(array, 10); + + backtrace_symbols_fd(array, size, 2); +#endif + + exit(1); +} + +DEFINE_NATIVE_LIBRARY(NativeTask) { + REGISTER_CLASS(BatchHandler, NativeTask); + REGISTER_CLASS(CombineHandler, NativeTask); + REGISTER_CLASS(MCollectorOutputHandler, NativeTask); + NativeObjectFactory::SetDefaultClass(BatchHandlerType, "NativeTask.BatchHandler"); +} + +namespace NativeTask { + +static Config G_CONFIG; + +vector NativeObjectFactory::Libraries; +map NativeObjectFactory::DefaultClasses; +Config * NativeObjectFactory::GlobalConfig = &G_CONFIG; +float NativeObjectFactory::LastProgress = 0; +Progress * NativeObjectFactory::TaskProgress = NULL; +string NativeObjectFactory::LastStatus; +set NativeObjectFactory::CounterSet; +vector NativeObjectFactory::Counters; +vector NativeObjectFactory::CounterLastUpdateValues; +bool NativeObjectFactory::Inited = false; + +static Lock FactoryLock; + +bool NativeObjectFactory::Init() { + ScopeLock autolocak(FactoryLock); + if (Inited == false) { + // setup log device + string device = GetConfig().get(NATIVE_LOG_DEVICE, "stderr"); + if (device == "stdout") { + LOG_DEVICE = stdout; + } else if (device == "stderr") { + LOG_DEVICE = stderr; + } else { + LOG_DEVICE = fopen(device.c_str(), "w"); + } + NativeTaskInit(); + NativeLibrary * library = new NativeLibrary("libnativetask.so", "NativeTask"); + library->_getObjectCreatorFunc = NativeTaskGetObjectCreator; + Libraries.push_back(library); + Inited = true; + // load extra user provided libraries + string libraryConf = GetConfig().get(NATIVE_CLASS_LIBRARY_BUILDIN, ""); + if (libraryConf.length() > 0) { + vector libraries; + vector pair; + StringUtil::Split(libraryConf, ",", libraries, true); + for (size_t i = 0; i < libraries.size(); i++) { + pair.clear(); + StringUtil::Split(libraries[i], "=", pair, true); + if (pair.size() == 2) { + string & name = pair[0]; + string & path = pair[1]; + LOG("[NativeObjectLibrary] Try to load library [%s] with file [%s]", name.c_str(), + path.c_str()); + if (false == RegisterLibrary(path, name)) { + LOG("[NativeObjectLibrary] RegisterLibrary failed: name=%s path=%s", name.c_str(), + path.c_str()); + return false; + } else { + LOG("[NativeObjectLibrary] RegisterLibrary success: name=%s path=%s", name.c_str(), + path.c_str()); + } + } else { + LOG("[NativeObjectLibrary] Illegal native.class.libray: [%s] in [%s]", + libraries[i].c_str(), libraryConf.c_str()); + } + } + } + const char * version = GetConfig().get(NATIVE_HADOOP_VERSION); + LOG("[NativeObjectLibrary] NativeTask library initialized with hadoop %s", + version == NULL ? "unkown" : version); + } + return true; +} + +void NativeObjectFactory::Release() { + ScopeLock autolocak(FactoryLock); + for (ssize_t i = Libraries.size() - 1; i >= 0; i--) { + delete Libraries[i]; + Libraries[i] = NULL; + } + Libraries.clear(); + for (size_t i = 0; i < Counters.size(); i++) { + delete Counters[i]; + } + Counters.clear(); + if (LOG_DEVICE != stdout && LOG_DEVICE != stderr) { + fclose(LOG_DEVICE); + LOG_DEVICE = stderr; + } + Inited = false; +} + +void NativeObjectFactory::CheckInit() { + if (Inited == false) { + if (!Init()) { + throw new IOException("Init NativeTask library failed."); + } + } +} + +Config & NativeObjectFactory::GetConfig() { + return *GlobalConfig; +} + +Config * NativeObjectFactory::GetConfigPtr() { + return GlobalConfig; +} + +void NativeObjectFactory::SetTaskProgressSource(Progress * progress) { + TaskProgress = progress; +} + +float NativeObjectFactory::GetTaskProgress() { + if (TaskProgress != NULL) { + LastProgress = TaskProgress->getProgress(); + } + return LastProgress; +} + +void NativeObjectFactory::SetTaskStatus(const string & status) { + LastStatus = status; +} + +static Lock CountersLock; + +void NativeObjectFactory::GetTaskStatusUpdate(string & statusData) { + // Encoding: + // progress:float + // status:Text + // Counter number + // Counters[group:Text, name:Text, incrCount:Long] + OutputStringStream os(statusData); + float progress = GetTaskProgress(); + WritableUtils::WriteFloat(&os, progress); + WritableUtils::WriteText(&os, LastStatus); + LastStatus.clear(); + { + ScopeLock AutoLock(CountersLock); + uint32_t numCounter = (uint32_t)Counters.size(); + WritableUtils::WriteInt(&os, numCounter); + for (size_t i = 0; i < numCounter; i++) { + Counter * counter = Counters[i]; + uint64_t newCount = counter->get(); + uint64_t incr = newCount - CounterLastUpdateValues[i]; + CounterLastUpdateValues[i] = newCount; + WritableUtils::WriteText(&os, counter->group()); + WritableUtils::WriteText(&os, counter->name()); + WritableUtils::WriteLong(&os, incr); + } + } +} + +Counter * NativeObjectFactory::GetCounter(const string & group, const string & name) { + ScopeLock AutoLock(CountersLock); + Counter tmpCounter(group, name); + set::iterator itr = CounterSet.find(&tmpCounter); + if (itr != CounterSet.end()) { + return *itr; + } + Counter * ret = new Counter(group, name); + Counters.push_back(ret); + CounterLastUpdateValues.push_back(0); + CounterSet.insert(ret); + return ret; +} + +void NativeObjectFactory::RegisterClass(const string & clz, ObjectCreatorFunc func) { + NativeTaskClassMap__[clz] = func; +} + +NativeObject * NativeObjectFactory::CreateObject(const string & clz) { + ObjectCreatorFunc creator = GetObjectCreator(clz); + return creator ? creator() : NULL; +} + +void * NativeObjectFactory::GetFunction(const string & funcName) { + CheckInit(); + { + for (vector::reverse_iterator ritr = Libraries.rbegin(); + ritr != Libraries.rend(); ritr++) { + void * ret = (*ritr)->getFunction(funcName); + if (NULL != ret) { + return ret; + } + } + return NULL; + } +} + +ObjectCreatorFunc NativeObjectFactory::GetObjectCreator(const string & clz) { + CheckInit(); + { + for (vector::reverse_iterator ritr = Libraries.rbegin(); + ritr != Libraries.rend(); ritr++) { + ObjectCreatorFunc ret = (*ritr)->getObjectCreator(clz); + if (NULL != ret) { + return ret; + } + } + return NULL; + } +} + +void NativeObjectFactory::ReleaseObject(NativeObject * obj) { + delete obj; +} + +bool NativeObjectFactory::RegisterLibrary(const string & path, const string & name) { + CheckInit(); + { + NativeLibrary * library = new NativeLibrary(path, name); + bool ret = library->init(); + if (!ret) { + delete library; + return false; + } + Libraries.push_back(library); + return true; + } +} + +static Lock DefaultClassesLock; + +void NativeObjectFactory::SetDefaultClass(NativeObjectType type, const string & clz) { + ScopeLock autolocak(DefaultClassesLock); + DefaultClasses[type] = clz; +} + +NativeObject * NativeObjectFactory::CreateDefaultObject(NativeObjectType type) { + CheckInit(); + { + if (DefaultClasses.find(type) != DefaultClasses.end()) { + string clz = DefaultClasses[type]; + return CreateObject(clz); + } + LOG("[NativeObjectLibrary] Default class for NativeObjectType %s not found", + NativeObjectTypeToString(type).c_str()); + return NULL; + } +} + +int NativeObjectFactory::BytesComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength) { + + uint32_t minlen = std::min(srcLength, destLength); + int64_t ret = fmemcmp(src, dest, minlen); + if (ret > 0) { + return 1; + } else if (ret < 0) { + return -1; + } + return srcLength - destLength; +} + +int NativeObjectFactory::ByteComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength) { + return (*src) - (*dest); +} + +int NativeObjectFactory::IntComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength) { + int result = (*src) - (*dest); + if (result == 0) { + uint32_t from = bswap(*(uint32_t*)src); + uint32_t to = bswap(*(uint32_t*)dest); + if (from > to) { + return 1; + } else if (from == to) { + return 0; + } else { + return -1; + } + } + return result; +} + +int NativeObjectFactory::LongComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength) { + int result = (int)(*src) - (int)(*dest); + if (result == 0) { + + uint64_t from = bswap64(*(uint64_t*)src); + uint64_t to = bswap64(*(uint64_t*)dest); + if (from > to) { + return 1; + } else if (from == to) { + return 0; + } else { + return -1; + } + } + return result; +} + +int NativeObjectFactory::VIntComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength) { + int32_t from = WritableUtils::ReadVInt(src, srcLength); + int32_t to = WritableUtils::ReadVInt(dest, destLength); + if (from > to) { + return 1; + } else if (from == to) { + return 0; + } else { + return -1; + } +} + +int NativeObjectFactory::VLongComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength) { + int64_t from = WritableUtils::ReadVLong(src, srcLength); + int64_t to = WritableUtils::ReadVLong(dest, destLength); + if (from > to) { + return 1; + } else if (from == to) { + return 0; + } else { + return -1; + } +} + +int NativeObjectFactory::FloatComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength) { + if (srcLength != 4 || destLength != 4) { + THROW_EXCEPTION_EX(IOException, "float comparator, while src/dest lengt is not 4"); + } + + uint32_t from = bswap(*(uint32_t*)src); + uint32_t to = bswap(*(uint32_t*)dest); + + float * srcValue = (float *)(&from); + float * destValue = (float *)(&to); + + if ((*srcValue) < (*destValue)) { + return -1; + } else if ((*srcValue) == (*destValue)) { + return 0; + } else { + return 1; + } +} + +int NativeObjectFactory::DoubleComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength) { + if (srcLength != 8 || destLength != 8) { + THROW_EXCEPTION_EX(IOException, "double comparator, while src/dest lengt is not 4"); + } + + uint64_t from = bswap64(*(uint64_t*)src); + uint64_t to = bswap64(*(uint64_t*)dest); + + double * srcValue = (double *)(&from); + double * destValue = (double *)(&to); + if ((*srcValue) < (*destValue)) { + return -1; + } else if ((*srcValue) == (*destValue)) { + return 0; + } else { + return 1; + } +} + +ComparatorPtr get_comparator(const KeyValueType keyType, const char * comparatorName) { + if (NULL == comparatorName) { + if (keyType == BytesType || keyType == TextType) { + return &NativeObjectFactory::BytesComparator; + } else if (keyType == ByteType || keyType == BoolType) { + return &NativeObjectFactory::ByteComparator; + } else if (keyType == IntType) { + return &NativeObjectFactory::IntComparator; + } else if (keyType == LongType) { + return &NativeObjectFactory::LongComparator; + } else if (keyType == FloatType) { + return &NativeObjectFactory::FloatComparator; + } else if (keyType == DoubleType) { + return &NativeObjectFactory::DoubleComparator; + } else if (keyType == VIntType) { + return &NativeObjectFactory::VIntComparator; + } else if (keyType == VLongType) { + return &NativeObjectFactory::VLongComparator; + } + } else { + void * func = NativeObjectFactory::GetFunction(string(comparatorName)); + return (ComparatorPtr)func; + } + return NULL; +} +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeObjectFactory.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeObjectFactory.h new file mode 100644 index 00000000000..9a9d41a25b5 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeObjectFactory.h @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NATIVEOBJECTFACTORY_H_ +#define NATIVEOBJECTFACTORY_H_ + +#include +#include +#include +#include + +#include "NativeTask.h" + +namespace NativeTask { + +using std::string; +using std::vector; +using std::map; +using std::set; +using std::pair; + +class NativeLibrary; + +class CounterPtrCompare { +public: + bool operator()(const Counter * lhs, const Counter * rhs) const { + if (lhs->group() < rhs->group()) { + return true; + } else if (lhs->group() == rhs->group()) { + return lhs->name() < rhs->name(); + } else { + return false; + } + } +}; + +/** + * Native object factory + */ +class NativeObjectFactory { +private: + static vector Libraries; + static map DefaultClasses; + static Config * GlobalConfig; + static float LastProgress; + static Progress * TaskProgress; + static string LastStatus; + static set CounterSet; + static vector Counters; + static vector CounterLastUpdateValues; + static bool Inited; +public: + static bool Init(); + static void Release(); + static void CheckInit(); + static Config & GetConfig(); + static Config * GetConfigPtr(); + static void SetTaskProgressSource(Progress * progress); + static float GetTaskProgress(); + static void SetTaskStatus(const string & status); + static void GetTaskStatusUpdate(string & statusData); + static Counter * GetCounter(const string & group, const string & name); + static void RegisterClass(const string & clz, ObjectCreatorFunc func); + static NativeObject * CreateObject(const string & clz); + static void * GetFunction(const string & clz); + static ObjectCreatorFunc GetObjectCreator(const string & clz); + static void ReleaseObject(NativeObject * obj); + static bool RegisterLibrary(const string & path, const string & name); + static void SetDefaultClass(NativeObjectType type, const string & clz); + static NativeObject * CreateDefaultObject(NativeObjectType type); + static int BytesComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength); + static int ByteComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength); + static int IntComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength); + static int LongComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength); + static int VIntComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength); + static int VLongComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength); + static int FloatComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength); + static int DoubleComparator(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength); +}; + +} // namespace NativeTask + +#endif /* NATIVEOBJECTFACTORY_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeRuntimeJniImpl.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeRuntimeJniImpl.cc new file mode 100644 index 00000000000..be682e827d7 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeRuntimeJniImpl.cc @@ -0,0 +1,256 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef QUICK_BUILD +#include "org_apache_hadoop_mapred_nativetask_NativeRuntime.h" +#endif +#include "config.h" +#include "lib/commons.h" +#include "lib/jniutils.h" +#include "lib/NativeObjectFactory.h" + +using namespace NativeTask; + +/////////////////////////////////////////////////////////////// +// NativeRuntime JNI methods +/////////////////////////////////////////////////////////////// + +/* + * Class: org_apache_hadoop_mapred_nativetask_NativeRuntime + * Method: supportCompressionCodec + * Signature: ([B)Z + */ +JNIEXPORT jboolean JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeRuntime_supportsCompressionCodec + (JNIEnv *jenv, jclass clazz, jbyteArray codec) { + const std::string codecString = JNU_ByteArrayToString(jenv, codec); + if ("org.apache.hadoop.io.compress.GzipCodec" == codecString) { + return JNI_TRUE; + } else if ("org.apache.hadoop.io.compress.Lz4Codec" == codecString) { + return JNI_TRUE; + } else if ("org.apache.hadoop.io.compress.SnappyCodec" == codecString) { +#if defined HADOOP_SNAPPY_LIBRARY + return JNI_TRUE; +#else + return JNI_FALSE; +#endif + } else { + return JNI_FALSE; + } +} + +/* + * Class: org_apache_hadoop_mapred_nativetask_NativeRuntime + * Method: JNIRelease + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeRuntime_JNIRelease( + JNIEnv * jenv, jclass nativeRuntimeClass) { + try { + NativeTask::NativeObjectFactory::Release(); + } catch (NativeTask::UnsupportException & e) { + JNU_ThrowByName(jenv, "java/lang/UnsupportedOperationException", e.what()); + } catch (NativeTask::OutOfMemoryException & e) { + JNU_ThrowByName(jenv, "java/lang/OutOfMemoryError", e.what()); + } catch (NativeTask::IOException & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (NativeTask::JavaException & e) { + LOG("[NativeRuntimeJniImpl] JavaException: %s", e.what()); + // Do nothing, let java side handle + } catch (std::exception & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (...) { + JNU_ThrowByName(jenv, "java/io/IOException", "[NativeRuntimeJniImpl] Unkown std::exception"); + } +} + +/* + * Class: org_apache_hadoop_mapred_nativetask_NativeRuntime + * Method: JNIConfigure + * Signature: ([[B)V + */ +JNIEXPORT void JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeRuntime_JNIConfigure( + JNIEnv * jenv, jclass nativeRuntimeClass, jobjectArray configs) { + try { + NativeTask::Config & config = NativeTask::NativeObjectFactory::GetConfig(); + jsize len = jenv->GetArrayLength(configs); + for (jsize i = 0; i + 1 < len; i += 2) { + jbyteArray key_obj = (jbyteArray)jenv->GetObjectArrayElement(configs, i); + jbyteArray val_obj = (jbyteArray)jenv->GetObjectArrayElement(configs, i + 1); + config.set(JNU_ByteArrayToString(jenv, key_obj), JNU_ByteArrayToString(jenv, val_obj)); + } + } catch (NativeTask::UnsupportException & e) { + JNU_ThrowByName(jenv, "java/lang/UnsupportedOperationException", e.what()); + } catch (NativeTask::OutOfMemoryException & e) { + JNU_ThrowByName(jenv, "java/lang/OutOfMemoryError", e.what()); + } catch (NativeTask::IOException & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (NativeTask::JavaException & e) { + LOG("JavaException: %s", e.what()); + // Do nothing, let java side handle + } catch (std::exception & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (...) { + JNU_ThrowByName(jenv, "java/io/IOException", "Unkown std::exception"); + } +} + +/* + * Class: org_apache_hadoop_mapred_nativetask_NativeRuntime + * Method: JNICreateNativeObject + * Signature: ([B[B)J + */ +jlong JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeRuntime_JNICreateNativeObject( + JNIEnv * jenv, jclass nativeRuntimeClass, jbyteArray clazz) { + try { + std::string typeString = JNU_ByteArrayToString(jenv, clazz); + return (jlong)(NativeTask::NativeObjectFactory::CreateObject(typeString)); + } catch (NativeTask::UnsupportException & e) { + JNU_ThrowByName(jenv, "java/lang/UnsupportedOperationException", e.what()); + } catch (NativeTask::OutOfMemoryException & e) { + JNU_ThrowByName(jenv, "java/lang/OutOfMemoryError", e.what()); + } catch (NativeTask::IOException & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (NativeTask::JavaException & e) { + LOG("JavaException: %s", e.what()); + // Do nothing, let java side handle + } catch (std::exception & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (...) { + JNU_ThrowByName(jenv, "java/io/IOException", "Unknown exception"); + } + return 0; +} + +/* + * Class: org_apache_hadoop_mapred_nativetask_NativeRuntime + * Method: JNICreateDefaultNativeObject + * Signature: ([B)J + */ +JNIEXPORT jlong JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeRuntime_JNICreateDefaultNativeObject( + JNIEnv * jenv, jclass nativeRuntimeClass, jbyteArray type) { + try { + std::string typeString = JNU_ByteArrayToString(jenv, type); + NativeTask::NativeObjectType type = NativeTask::NativeObjectTypeFromString(typeString.c_str()); + return (jlong)(NativeTask::NativeObjectFactory::CreateDefaultObject(type)); + } catch (NativeTask::UnsupportException & e) { + JNU_ThrowByName(jenv, "java/lang/UnsupportedOperationException", e.what()); + } catch (NativeTask::OutOfMemoryException & e) { + JNU_ThrowByName(jenv, "java/lang/OutOfMemoryError", e.what()); + } catch (NativeTask::IOException & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (NativeTask::JavaException & e) { + LOG("[NativeRuntimeJniImpl] JavaException: %s", e.what()); + // Do nothing, let java side handle + } catch (std::exception & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (...) { + JNU_ThrowByName(jenv, "java/io/IOException", "[NativeRuntimeJniImpl] Unknown exception"); + } + return 0; +} + +/* + * Class: org_apache_hadoop_mapred_nativetask_NativeRuntime + * Method: JNIReleaseNativeObject + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeRuntime_JNIReleaseNativeObject( + JNIEnv * jenv, jclass nativeRuntimeClass, jlong objectAddr) { + try { + NativeTask::NativeObject * nobj = ((NativeTask::NativeObject *)objectAddr); + if (NULL == nobj) { + JNU_ThrowByName(jenv, "java/lang/IllegalArgumentException", + "Object addr not instance of NativeObject"); + return; + } + NativeTask::NativeObjectFactory::ReleaseObject(nobj); + } catch (NativeTask::UnsupportException & e) { + JNU_ThrowByName(jenv, "java/lang/UnsupportedOperationException", e.what()); + } catch (NativeTask::OutOfMemoryException & e) { + JNU_ThrowByName(jenv, "java/lang/OutOfMemoryError", e.what()); + } catch (NativeTask::IOException & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (NativeTask::JavaException & e) { + LOG("JavaException: %s", e.what()); + // Do nothing, let java side handle + } catch (std::exception & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (...) { + JNU_ThrowByName(jenv, "java/io/IOException", "Unknown exception"); + } +} + +/* + * Class: org_apache_hadoop_mapred_nativetask_NativeRuntime + * Method: JNIRegisterModule + * Signature: ([B[B)I + */ +JNIEXPORT jint JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeRuntime_JNIRegisterModule( + JNIEnv * jenv, jclass nativeRuntimeClass, jbyteArray modulePath, jbyteArray moduleName) { + try { + std::string pathString = JNU_ByteArrayToString(jenv, modulePath); + std::string nameString = JNU_ByteArrayToString(jenv, moduleName); + if (NativeTask::NativeObjectFactory::RegisterLibrary(pathString, nameString)) { + return 0; + } + } catch (NativeTask::UnsupportException & e) { + JNU_ThrowByName(jenv, "java/lang/UnsupportedOperationException", e.what()); + } catch (NativeTask::OutOfMemoryException & e) { + JNU_ThrowByName(jenv, "java/lang/OutOfMemoryError", e.what()); + } catch (NativeTask::IOException & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (NativeTask::JavaException & e) { + LOG("JavaException: %s", e.what()); + // Do nothing, let java side handle + } catch (std::exception & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (...) { + JNU_ThrowByName(jenv, "java/io/IOException", "Unknown exception"); + } + return 1; +} + +/* + * Class: org_apache_hadoop_mapred_nativetask_NativeRuntime + * Method: JNIUpdateStatus + * Signature: ()[B + */ +JNIEXPORT jbyteArray JNICALL Java_org_apache_hadoop_mapred_nativetask_NativeRuntime_JNIUpdateStatus( + JNIEnv * jenv, jclass nativeRuntimeClass) { + try { + std::string statusData; + NativeTask::NativeObjectFactory::GetTaskStatusUpdate(statusData); + jbyteArray ret = jenv->NewByteArray(statusData.length()); + jenv->SetByteArrayRegion(ret, 0, statusData.length(), (jbyte*)statusData.c_str()); + return ret; + } catch (NativeTask::UnsupportException & e) { + JNU_ThrowByName(jenv, "java/lang/UnsupportedOperationException", e.what()); + } catch (NativeTask::OutOfMemoryException & e) { + JNU_ThrowByName(jenv, "java/lang/OutOfMemoryError", e.what()); + } catch (NativeTask::IOException & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (NativeTask::JavaException & e) { + LOG("JavaException: %s", e.what()); + // Do nothing, let java side handle + } catch (std::exception & e) { + JNU_ThrowByName(jenv, "java/io/IOException", e.what()); + } catch (...) { + JNU_ThrowByName(jenv, "java/io/IOException", "Unknown exception"); + } + return NULL; +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeTask.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeTask.cc new file mode 100644 index 00000000000..5dc880c296a --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/NativeTask.cc @@ -0,0 +1,211 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __CYGWIN__ +#include +#endif +#include "lib/commons.h" +#include "util/StringUtil.h" +#include "NativeTask.h" +#include "lib/NativeObjectFactory.h" + +namespace NativeTask { + +////////////////////////////////////////////////////////////////// +// NativeObjectType methods +////////////////////////////////////////////////////////////////// + +const string NativeObjectTypeToString(NativeObjectType type) { + switch (type) { + case BatchHandlerType: + return string("BatchHandlerType"); + default: + return string("UnknownObjectType"); + } +} + +NativeObjectType NativeObjectTypeFromString(const string type) { + if (type == "BatchHandlerType") { + return BatchHandlerType; + } + return UnknownObjectType; +} + +HadoopException::HadoopException(const string & what) { + // remove long path prefix + size_t n = 0; + if (what[0] == '/') { + size_t p = what.find(':'); + if (p != what.npos) { + while (true) { + size_t np = what.find('/', n + 1); + if (np == what.npos || np >= p) { + break; + } + n = np; + } + } + } + _reason.append(what.c_str() + n, what.length() - n); + void *array[64]; + size_t size; + +#ifndef __CYGWIN__ + size = backtrace(array, 64); + char ** traces = backtrace_symbols(array, size); + for (size_t i = 0; i < size; i++) { + _reason.append("\n\t"); + _reason.append(traces[i]); + } +#endif +} + +/////////////////////////////////////////////////////////// + +void Config::load(const string & path) { + FILE * fin = fopen(path.c_str(), "r"); + if (NULL == fin) { + THROW_EXCEPTION(IOException, "file not found or can not open for read"); + } + char buff[256]; + while (fgets(buff, 256, fin) != NULL) { + if (buff[0] == '#') { + continue; + } + std::string key = buff; + if (key[key.length() - 1] == '\n') { + size_t br = key.find('='); + if (br != key.npos) { + set(key.substr(0, br), StringUtil::Trim(key.substr(br + 1))); + } + } + } + fclose(fin); +} + +void Config::set(const string & key, const string & value) { + _configs[key] = value; +} + +void Config::setInt(const string & name, int64_t value) { + _configs[name] = StringUtil::ToString(value); +} + +void Config::setBool(const string & name, bool value) { + _configs[name] = StringUtil::ToString(value); +} + +void Config::parse(int32_t argc, const char ** argv) { + for (int32_t i = 0; i < argc; i++) { + const char * equ = strchr(argv[i], '='); + if (NULL == equ) { + LOG("[NativeTask] config argument not recognized: %s", argv[i]); + continue; + } + if (argv[i][0] == '-') { + LOG("[NativeTask] config argument with '-' prefix ignored: %s", argv[i]); + continue; + } + string key(argv[i], equ - argv[i]); + string value(equ + 1, strlen(equ + 1)); + map::iterator itr = _configs.find(key); + if (itr == _configs.end()) { + _configs[key] = value; + } else { + itr->second.append(","); + itr->second.append(value); + } + } +} + +const char * Config::get(const string & name) { + map::iterator itr = _configs.find(name); + if (itr == _configs.end()) { + return NULL; + } else { + return itr->second.c_str(); + } +} + +string Config::get(const string & name, const string & defaultValue) { + map::iterator itr = _configs.find(name); + if (itr == _configs.end()) { + return defaultValue; + } else { + return itr->second; + } +} + +int64_t Config::getInt(const string & name, int64_t defaultValue) { + map::iterator itr = _configs.find(name); + if (itr == _configs.end()) { + return defaultValue; + } else { + return StringUtil::toInt(itr->second); + } +} + +bool Config::getBool(const string & name, bool defaultValue) { + map::iterator itr = _configs.find(name); + if (itr == _configs.end()) { + return defaultValue; + } else { + return StringUtil::toBool(itr->second); + } +} + +float Config::getFloat(const string & name, float defaultValue) { + map::iterator itr = _configs.find(name); + if (itr == _configs.end()) { + return defaultValue; + } else { + return StringUtil::toFloat(itr->second); + } +} + +void Config::getStrings(const string & name, vector & dest) { + map::iterator itr = _configs.find(name); + if (itr != _configs.end()) { + StringUtil::Split(itr->second, ",", dest, true); + } +} + +void Config::getInts(const string & name, vector & dest) { + vector sdest; + getStrings(name, sdest); + for (size_t i = 0; i < sdest.size(); i++) { + dest.push_back(StringUtil::toInt(sdest[i])); + } +} + +void Config::getFloats(const string & name, vector & dest) { + vector sdest; + getStrings(name, sdest); + for (size_t i = 0; i < sdest.size(); i++) { + dest.push_back(StringUtil::toFloat(sdest[i])); + } +} + +/////////////////////////////////////////////////////////// + +Counter * ProcessorBase::getCounter(const string & group, const string & name) { + return NULL; +} + +/////////////////////////////////////////////////////////// + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/PartitionBucket.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/PartitionBucket.cc new file mode 100644 index 00000000000..33c24039792 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/PartitionBucket.cc @@ -0,0 +1,75 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "util/Timer.h" +#include "util/StringUtil.h" +#include "lib/NativeObjectFactory.h" +#include "lib/PartitionBucket.h" +#include "lib/Merge.h" +#include "NativeTask.h" +#include "util/WritableUtils.h" +#include "util/DualPivotQuickSort.h" +#include "lib/Combiner.h" +#include "lib/TaskCounters.h" +#include "lib/MinHeap.h" +#include "lib/PartitionBucketIterator.h" + +namespace NativeTask { + +KVIterator * PartitionBucket::getIterator() { + if (_memBlocks.size() == 0) { + return NULL; + } + return new PartitionBucketIterator(this, _keyComparator); +} + +void PartitionBucket::spill(IFileWriter * writer) + throw(IOException, UnsupportException) { + KVIterator * iterator = getIterator(); + if (NULL == iterator || NULL == writer) { + return; + } + + if (_combineRunner == NULL) { + Buffer key; + Buffer value; + + while (iterator->next(key, value)) { + writer->write(key.data(), key.length(), value.data(), value.length()); + } + } else { + _combineRunner->combine(CombineContext(UNKNOWN), iterator, writer); + } + delete iterator; +} + +void PartitionBucket::sort(SortAlgorithm type) { + if (_memBlocks.size() == 0) { + return; + } + if ((!_sorted)) { + for (uint32_t i = 0; i < _memBlocks.size(); i++) { + MemoryBlock * block = _memBlocks[i]; + block->sort(type, _keyComparator); + } + } + _sorted = true; +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/PartitionBucket.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/PartitionBucket.h new file mode 100644 index 00000000000..cd9ec979b37 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/PartitionBucket.h @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PARTITION_BUCKET_H_ +#define PARTITION_BUCKET_H_ + +#include "NativeTask.h" +#include "lib/MemoryPool.h" +#include "lib/MemoryBlock.h" +#include "util/Timer.h" +#include "lib/Buffers.h" +#include "lib/MapOutputSpec.h" +#include "lib/IFile.h" +#include "lib/SpillInfo.h" +#include "lib/Combiner.h" + +namespace NativeTask { + +/** + * Buffer for a single partition + */ +class PartitionBucket { + friend class PartitionBucketIterator; + friend class TestPartitionBucket; + +private: + std::vector _memBlocks; + MemoryPool * _pool; + uint32_t _partition; + uint32_t _blockSize; + ComparatorPtr _keyComparator; + ICombineRunner * _combineRunner; + bool _sorted; + +public: + PartitionBucket(MemoryPool * pool, uint32_t partition, ComparatorPtr comparator, + ICombineRunner * combineRunner, uint32_t blockSize) + : _pool(pool), _partition(partition), _blockSize(blockSize), + _keyComparator(comparator), _combineRunner(combineRunner), _sorted(false) { + if (NULL == _pool || NULL == comparator) { + THROW_EXCEPTION_EX(IOException, "pool is NULL, or comparator is not set"); + } + + if (NULL != combineRunner) { + LOG("[PartitionBucket] combine runner has been set"); + } + } + + ~PartitionBucket() { + reset(); + } + + uint32_t getPartitionId() { + return _partition; + } + + void reset() { + for (uint32_t i = 0; i < _memBlocks.size(); i++) { + if (NULL != _memBlocks[i]) { + delete _memBlocks[i]; + _memBlocks[i] = NULL; + } + } + _memBlocks.clear(); + } + + KVIterator * getIterator(); + + uint32_t getKVCount() const { + uint32_t size = 0; + for (uint32_t i = 0; i < _memBlocks.size(); i++) { + MemoryBlock * block = _memBlocks[i]; + if (NULL != block) { + size += block->getKVCount(); + } + } + return size; + } + + /** + * @throws OutOfMemoryException if total_length > io.sort.mb + */ + KVBuffer * allocateKVBuffer(uint32_t kvLength) { + if (kvLength == 0) { + LOG("KV Length is empty, no need to allocate buffer for it"); + return NULL; + } + _sorted = false; + MemoryBlock * memBlock = NULL; + uint32_t memBlockSize = _memBlocks.size(); + if (memBlockSize > 0) { + memBlock = _memBlocks[memBlockSize - 1]; + } + if (NULL != memBlock && memBlock->remainSpace() >= kvLength) { + return memBlock->allocateKVBuffer(kvLength); + } else { + uint32_t min = kvLength; + uint32_t expect = std::max(_blockSize, min); + uint32_t allocated = 0; + char * buff = _pool->allocate(min, expect, allocated); + if (NULL != buff) { + memBlock = new MemoryBlock(buff, allocated); + _memBlocks.push_back(memBlock); + return memBlock->allocateKVBuffer(kvLength); + } + } + return NULL; + } + + void sort(SortAlgorithm type); + + void spill(IFileWriter * writer) throw (IOException, UnsupportException); + + uint32_t getMemoryBlockCount() const { + return _memBlocks.size(); + } + + MemoryBlock * getMemoryBlock(uint32_t index) const { + return _memBlocks[index]; + } +}; + +} +; +//namespace NativeTask + +#endif /* PARTITION_BUCKET_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/PartitionBucketIterator.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/PartitionBucketIterator.cc new file mode 100644 index 00000000000..ade042e5a48 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/PartitionBucketIterator.cc @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "lib/commons.h" +#include "util/Timer.h" +#include "util/StringUtil.h" +#include "lib/NativeObjectFactory.h" +#include "lib/PartitionBucketIterator.h" +#include "lib/Merge.h" +#include "NativeTask.h" +#include "util/WritableUtils.h" +#include "util/DualPivotQuickSort.h" +#include "lib/Combiner.h" +#include "lib/TaskCounters.h" +#include "lib/MinHeap.h" + +namespace NativeTask { + +///////////////////////////////////////////////////////////////// +// PartitionBucket +///////////////////////////////////////////////////////////////// + +PartitionBucketIterator::PartitionBucketIterator(PartitionBucket * pb, ComparatorPtr comparator) + : _pb(pb), _comparator(comparator), _first(true) { + uint32_t blockCount = _pb->getMemoryBlockCount(); + for (uint32_t i = 0; i < blockCount; i++) { + MemoryBlock * block = _pb->getMemoryBlock(i); + MemBlockIteratorPtr blockIterator = new MemBlockIterator(block); + if (blockIterator->next()) { + _heap.push_back(blockIterator); + } else { + delete blockIterator; + } + } + if (_heap.size() > 1) { + makeHeap(&(_heap[0]), &(_heap[0]) + _heap.size(), _comparator); + } +} + +PartitionBucketIterator::~PartitionBucketIterator() { + for (uint32_t i = 0; i < _heap.size(); i++) { + MemBlockIteratorPtr ptr = _heap[i]; + if (NULL != ptr) { + delete ptr; + _heap[i] = NULL; + } + } +} + +bool PartitionBucketIterator::next() { + size_t cur_heap_size = _heap.size(); + if (cur_heap_size > 0) { + if (!_first) { + if (_heap[0]->next()) { // have more, adjust heap + if (cur_heap_size == 1) { + return true; + } else if (cur_heap_size == 2) { + MemBlockIteratorPtr * base = &(_heap[0]); + + if (_comparator(base[1], base[0])) { + std::swap(base[0], base[1]); + } + } else { + MemBlockIteratorPtr * base = &(_heap[0]); + heapify(base, 1, cur_heap_size, _comparator); + } + } else { // no more, pop heap + // after popHeap, the first element of heap will be removed + // and replaced by other element, so it needs to be deleted + delete _heap[0]; + MemBlockIteratorPtr * base = &(_heap[0]); + popHeap(base, base + cur_heap_size, _comparator); + _heap.pop_back(); + } + } else { + _first = false; + } + return _heap.size() > 0; + } + return false; +} + +bool PartitionBucketIterator::next(Buffer & key, Buffer & value) { + bool result = next(); + if (result) { + MemBlockIteratorPtr * base = &(_heap[0]); + KVBuffer * kvBuffer = base[0]->getKVBuffer(); + + key.reset(kvBuffer->getKey(), kvBuffer->keyLength); + value.reset(kvBuffer->getValue(), kvBuffer->valueLength); + + return true; + } + return false; +} +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/PartitionBucketIterator.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/PartitionBucketIterator.h new file mode 100644 index 00000000000..be7849791d8 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/PartitionBucketIterator.h @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PARTITION_BUCKET_ITERATOR_H_ +#define PARTITION_BUCKET_ITERATOR_H_ + +#include "NativeTask.h" +#include "lib/MemoryPool.h" +#include "util/Timer.h" +#include "lib/Buffers.h" +#include "lib/MapOutputSpec.h" +#include "lib/IFile.h" +#include "lib/SpillInfo.h" +#include "lib/Combiner.h" +#include "lib/PartitionBucket.h" + +namespace NativeTask { + +class PartitionBucketIterator : public KVIterator { +protected: + PartitionBucket * _pb; + std::vector _heap; + MemBlockComparator _comparator; + bool _first; + +public: + PartitionBucketIterator(PartitionBucket * pb, ComparatorPtr comparator); + virtual ~PartitionBucketIterator(); + virtual bool next(Buffer & key, Buffer & value); + +private: + bool next(); +}; + +} +; +//namespace NativeTask + +#endif /* PARTITION_BUCKET_ITERATOR_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Path.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Path.cc new file mode 100644 index 00000000000..78321e2d096 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Path.cc @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/Path.h" + +namespace NativeTask { + +bool Path::IsAbsolute(const string & path) { + if (path.length() > 0 && path[0] == '/') { + return true; + } + return false; +} + +string Path::GetParent(const string & path) { + size_t lastSlash = path.rfind('/'); + if (lastSlash == path.npos) { + return "."; + } + if (lastSlash == 0 && path.length() == 1) { + return ""; + } + if (lastSlash == 0) { + return path; + } + return path.substr(0, lastSlash); +} + +string Path::GetName(const string & path) { + size_t lastSlash = path.rfind('/'); + if (lastSlash == path.npos) { + return path; + } + return path.substr(lastSlash + 1); +} + +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Path.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Path.h new file mode 100644 index 00000000000..0dc82f27dbc --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Path.h @@ -0,0 +1,38 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PATH_H_ +#define PATH_H_ + +#include +#include + +namespace NativeTask { + +using std::string; + +class Path { +public: + static bool IsAbsolute(const string & path); + static string GetParent(const string & path); + static string GetName(const string & path); +}; + +} // namespace NativeTask + +#endif /* PATH_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/SpillInfo.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/SpillInfo.cc new file mode 100644 index 00000000000..9cff52975e4 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/SpillInfo.cc @@ -0,0 +1,73 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/Streams.h" +#include "lib/FileSystem.h" +#include "lib/Buffers.h" +#include "lib/SpillInfo.h" + +namespace NativeTask { + +void SingleSpillInfo::deleteSpillFile() { + if (path.length() > 0) { + struct stat st; + if (0 == stat(path.c_str(), &st)) { + remove(path.c_str()); + } + } +} + +void SingleSpillInfo::writeSpillInfo(const std::string & filepath) { + OutputStream * fout = FileSystem::getLocal().create(filepath, true); + { + ChecksumOutputStream dest = ChecksumOutputStream(fout, CHECKSUM_CRC32); + AppendBuffer appendBuffer; + appendBuffer.init(32 * 1024, &dest, ""); + uint64_t base = 0; + + for (size_t j = 0; j < this->length; j++) { + IFileSegment * segment = &(this->segments[j]); + const bool firstSegment = (j == 0); + if (firstSegment) { + appendBuffer.write_uint64_be(base); + appendBuffer.write_uint64_be(segment->uncompressedEndOffset); + appendBuffer.write_uint64_be(segment->realEndOffset); + } else { + appendBuffer.write_uint64_be(base + this->segments[j - 1].realEndOffset); + appendBuffer.write_uint64_be( + segment->uncompressedEndOffset - this->segments[j - 1].uncompressedEndOffset); + appendBuffer.write_uint64_be(segment->realEndOffset - this->segments[j - 1].realEndOffset); + } + } + appendBuffer.flush(); + uint32_t chsum = dest.getChecksum(); +#ifdef SPILLRECORD_CHECKSUM_UINT + chsum = bswap(chsum); + fout->write(&chsum, sizeof(uint32_t)); +#else + uint64_t wtchsum = bswap64((uint64_t)chsum); + fout->write(&wtchsum, sizeof(uint64_t)); +#endif + } + fout->close(); + delete fout; +} + +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/SpillInfo.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/SpillInfo.h new file mode 100644 index 00000000000..94eb16e5f36 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/SpillInfo.h @@ -0,0 +1,106 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PARTITIONINDEX_H_ +#define PARTITIONINDEX_H_ + +#include +#include + +namespace NativeTask { + +using std::string; + +/** + * Store spill file segment information + */ +struct IFileSegment { + // uncompressed stream end position + uint64_t uncompressedEndOffset; + // compressed stream end position + uint64_t realEndOffset; +}; + +class SingleSpillInfo { +public: + uint32_t length; + std::string path; + IFileSegment * segments; + ChecksumType checkSumType; + KeyValueType keyType; + KeyValueType valueType; + std::string codec; + + SingleSpillInfo(IFileSegment * segments, uint32_t len, const string & path, ChecksumType checksum, + KeyValueType ktype, KeyValueType vtype, const string & inputCodec) + : length(len), path(path), segments(segments), checkSumType(checksum), keyType(ktype), + valueType(vtype), codec(inputCodec) { + } + + ~SingleSpillInfo() { + delete[] segments; + } + + void deleteSpillFile(); + + uint64_t getEndPosition() { + return segments ? segments[length - 1].uncompressedEndOffset : 0; + } + + uint64_t getRealEndPosition() { + return segments ? segments[length - 1].realEndOffset : 0; + } + + void writeSpillInfo(const std::string & filepath); +}; + +class SpillInfos { +public: + std::vector spills; + SpillInfos() { + } + + ~SpillInfos() { + for (size_t i = 0; i < spills.size(); i++) { + delete spills[i]; + } + spills.clear(); + } + + void deleteAllSpillFiles() { + for (size_t i = 0; i < spills.size(); i++) { + spills[i]->deleteSpillFile(); + } + } + + void add(SingleSpillInfo * sri) { + spills.push_back(sri); + } + + uint32_t getSpillCount() const { + return spills.size(); + } + + SingleSpillInfo* getSingleSpillInfo(int index) { + return spills.at(index); + } +}; + +} // namespace NativeTask + +#endif /* PARTITIONINDEX_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/SpillOutputService.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/SpillOutputService.h new file mode 100644 index 00000000000..16a6685f424 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/SpillOutputService.h @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SPILL_OUTPUT_SERVICE_H_ +#define SPILL_OUTPUT_SERVICE_H_ + +#include +#include + +namespace NativeTask { + +class CombineHandler; + +using std::string; + +class SpillOutputService { +public: + virtual ~SpillOutputService() {} + + virtual string * getSpillPath() = 0; + virtual string * getOutputPath() = 0; + virtual string * getOutputIndexPath() = 0; + + virtual CombineHandler * getJavaCombineHandler() = 0; +}; + +} // namespace NativeTask + +#endif /* SPILL_OUTPUT_SERVICE_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Streams.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Streams.cc new file mode 100644 index 00000000000..9e8ffbaf697 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Streams.cc @@ -0,0 +1,122 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "util/Checksum.h" +#include "lib/Streams.h" + +namespace NativeTask { + +///////////////////////////////////////////////////////////// + +void InputStream::seek(uint64_t position) { + THROW_EXCEPTION(UnsupportException, "seek not support"); +} + +uint64_t InputStream::tell() { + THROW_EXCEPTION(UnsupportException, "tell not support"); +} + +int32_t InputStream::readFully(void * buff, uint32_t length) { + int32_t ret = 0; + while (length > 0) { + int32_t rd = read(buff, length); + if (rd <= 0) { + return ret > 0 ? ret : -1; + } + ret += rd; + buff = ((char *)buff) + rd; + length -= rd; + } + return ret; +} + +void InputStream::readAllTo(OutputStream & out, uint32_t bufferHint) { + char * buffer = new char[bufferHint]; + while (true) { + int32_t rd = read(buffer, bufferHint); + if (rd <= 0) { + break; + } + out.write(buffer, rd); + } + delete buffer; +} + +///////////////////////////////////////////////////////////// + +uint64_t OutputStream::tell() { + THROW_EXCEPTION(UnsupportException, "tell not support"); +} + +/////////////////////////////////////////////////////////// + +ChecksumInputStream::ChecksumInputStream(InputStream * stream, ChecksumType type) + : FilterInputStream(stream), _type(type), _limit(-1) { + resetChecksum(); +} + +void ChecksumInputStream::resetChecksum() { + _checksum = Checksum::init(_type); +} + +uint32_t ChecksumInputStream::getChecksum() { + return Checksum::getValue(_type, _checksum); +} + +int32_t ChecksumInputStream::read(void * buff, uint32_t length) { + if (_limit < 0) { + int32_t ret = _stream->read(buff, length); + if (ret > 0) { + Checksum::update(_type, _checksum, buff, ret); + } + return ret; + } else if (_limit == 0) { + return -1; + } else { + int64_t rd = _limit < length ? _limit : length; + int32_t ret = _stream->read(buff, rd); + if (ret > 0) { + _limit -= ret; + Checksum::update(_type, _checksum, buff, ret); + } + return ret; + } +} + +/////////////////////////////////////////////////////////// + +ChecksumOutputStream::ChecksumOutputStream(OutputStream * stream, ChecksumType type) + : FilterOutputStream(stream), _type(type) { + resetChecksum(); +} + +void ChecksumOutputStream::resetChecksum() { + _checksum = Checksum::init(_type); +} + +uint32_t ChecksumOutputStream::getChecksum() { + return Checksum::getValue(_type, _checksum); +} + +void ChecksumOutputStream::write(const void * buff, uint32_t length) { + Checksum::update(_type, _checksum, buff, length); + _stream->write(buff, length); +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Streams.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Streams.h new file mode 100644 index 00000000000..199762bdf95 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/Streams.h @@ -0,0 +1,221 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef STREAMS_H_ +#define STREAMS_H_ + +#include "util/Checksum.h" + +namespace NativeTask { + +class OutputStream; + +class InputStream { +public: + InputStream() { + } + + virtual ~InputStream() { + } + + virtual void seek(uint64_t position); + + virtual uint64_t tell(); + + virtual int32_t read(void * buff, uint32_t length) { + return -1; + } + + virtual void close() { + } + + virtual int32_t readFully(void * buff, uint32_t length); + + void readAllTo(OutputStream & out, uint32_t bufferHint = 1024 * 4); +}; + +class OutputStream { +public: + OutputStream() { + } + + virtual ~OutputStream() { + } + + virtual uint64_t tell(); + + virtual void write(const void * buff, uint32_t length) { + } + + virtual void flush() { + } + + virtual void close() { + } +}; + +class FilterInputStream : public InputStream { +protected: + InputStream * _stream; +public: + FilterInputStream(InputStream * stream) + : _stream(stream) { + } + + virtual ~FilterInputStream() { + } + + void setStream(InputStream * stream) { + _stream = stream; + } + + InputStream * getStream() { + return _stream; + } + + virtual void seek(uint64_t position) { + _stream->seek(position); + } + + virtual uint64_t tell() { + return _stream->tell(); + } + + virtual int32_t read(void * buff, uint32_t length) { + return _stream->read(buff, length); + } +}; + +class FilterOutputStream : public OutputStream { +protected: + OutputStream * _stream; +public: + FilterOutputStream(OutputStream * stream) + : _stream(stream) { + } + + virtual ~FilterOutputStream() { + } + + void setStream(OutputStream * stream) { + _stream = stream; + } + + OutputStream * getStream() { + return _stream; + } + + virtual uint64_t tell() { + return _stream->tell(); + } + + virtual void write(const void * buff, uint32_t length) { + _stream->write(buff, length); + } + + virtual void flush() { + _stream->flush(); + } + + virtual void close() { + flush(); + } +}; + +class LimitInputStream : public FilterInputStream { +protected: + int64_t _limit; +public: + LimitInputStream(InputStream * stream, int64_t limit) + : FilterInputStream(stream), _limit(limit) { + } + + virtual ~LimitInputStream() { + } + + int64_t getLimit() { + return _limit; + } + + void setLimit(int64_t limit) { + _limit = limit; + } + + virtual int32_t read(void * buff, uint32_t length) { + if (_limit < 0) { + return _stream->read(buff, length); + } else if (_limit == 0) { + return -1; + } else { + int64_t rd = _limit < length ? _limit : length; + int32_t ret = _stream->read(buff, rd); + if (ret > 0) { + _limit -= ret; + } + return ret; + } + } +}; + +class ChecksumInputStream : public FilterInputStream { +protected: + ChecksumType _type; + uint32_t _checksum; + int64_t _limit; +public: + ChecksumInputStream(InputStream * stream, ChecksumType type); + + virtual ~ChecksumInputStream() { + } + + int64_t getLimit() { + return _limit; + } + + void setLimit(int64_t limit) { + _limit = limit; + } + + void resetChecksum(); + + uint32_t getChecksum(); + + virtual int32_t read(void * buff, uint32_t length); +}; + +class ChecksumOutputStream : public FilterOutputStream { +protected: + ChecksumType _type; + uint32_t _checksum; +public: + ChecksumOutputStream(OutputStream * stream, ChecksumType type); + + virtual ~ChecksumOutputStream() { + } + + void resetChecksum(); + + uint32_t getChecksum(); + + virtual void write(const void * buff, uint32_t length); + +}; + +} // namespace NativeTask + +#endif /* STREAMS_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/TaskCounters.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/TaskCounters.cc new file mode 100644 index 00000000000..b70db4cd68e --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/TaskCounters.cc @@ -0,0 +1,40 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/TaskCounters.h" + +namespace NativeTask { + +#define DEFINE_COUNTER(name) const char * TaskCounters::name = #name; + +const char * TaskCounters::TASK_COUNTER_GROUP = "org.apache.hadoop.mapreduce.TaskCounter"; + +DEFINE_COUNTER(MAP_INPUT_RECORDS) +DEFINE_COUNTER(MAP_OUTPUT_RECORDS) +DEFINE_COUNTER(MAP_OUTPUT_BYTES) +DEFINE_COUNTER(MAP_OUTPUT_MATERIALIZED_BYTES) +DEFINE_COUNTER(COMBINE_INPUT_RECORDS) +DEFINE_COUNTER(COMBINE_OUTPUT_RECORDS) +DEFINE_COUNTER(SPILLED_RECORDS) + +const char * TaskCounters::FILESYSTEM_COUNTER_GROUP = "FileSystemCounters"; + +DEFINE_COUNTER(FILE_BYTES_READ) +DEFINE_COUNTER(FILE_BYTES_WRITTEN) + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/TaskCounters.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/TaskCounters.h new file mode 100644 index 00000000000..23cedf93faa --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/TaskCounters.h @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TASKCOUNTERS_H_ +#define TASKCOUNTERS_H_ + +namespace NativeTask { + +class TaskCounters { +public: + static const char * TASK_COUNTER_GROUP; + + static const char * MAP_INPUT_RECORDS; + static const char * MAP_OUTPUT_RECORDS; + static const char * MAP_OUTPUT_BYTES; + static const char * MAP_OUTPUT_MATERIALIZED_BYTES; + static const char * COMBINE_INPUT_RECORDS; + static const char * COMBINE_OUTPUT_RECORDS; + static const char * SPILLED_RECORDS; + + static const char * FILESYSTEM_COUNTER_GROUP; + + static const char * FILE_BYTES_READ; + static const char * FILE_BYTES_WRITTEN; +}; + +} // namespace NativeTask + +#endif /* TASKCOUNTERS_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/commons.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/commons.h new file mode 100644 index 00000000000..57500b78a15 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/commons.h @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef COMMONS_H_ +#define COMMONS_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __STDC_FORMAT_MACROS +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "lib/primitives.h" +#include "lib/Log.h" +#include "NativeTask.h" + +#include "lib/Constants.h" + +#include "lib/Iterator.h" + +#endif /* COMMONS_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/jniutils.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/jniutils.cc new file mode 100644 index 00000000000..d1c45bdaa3c --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/jniutils.cc @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "util/StringUtil.h" +#include "util/SyncUtils.h" +#include "lib/jniutils.h" + +using namespace NativeTask; + +JavaVM * JNU_GetJVM(void) { + static JavaVM * gJVM = NULL; + static Lock GJVMLock; + if (gJVM != NULL) { + return gJVM; + } + { + ScopeLock autolock(GJVMLock); + if (gJVM == NULL) { + jint rv = 0; + jint noVMs = 0; + rv = JNI_GetCreatedJavaVMs(&gJVM, 1, &noVMs); + if (rv != 0) { + THROW_EXCEPTION(NativeTask::HadoopException, "JNI_GetCreatedJavaVMs failed"); + } + if (noVMs == 0) { + char *hadoopClassPath = getenv("CLASSPATH"); + if (hadoopClassPath == NULL) { + THROW_EXCEPTION(NativeTask::HadoopException, "Environment variable CLASSPATH not set!"); + return NULL; + } + const char *hadoopClassPathVMArg = "-Djava.class.path="; + size_t optHadoopClassPathLen = strlen(hadoopClassPath) + strlen(hadoopClassPathVMArg) + 1; + char *optHadoopClassPath = (char*)malloc(sizeof(char) * optHadoopClassPathLen); + snprintf(optHadoopClassPath, optHadoopClassPathLen, "%s%s", hadoopClassPathVMArg, + hadoopClassPath); + int noArgs = 1; + JavaVMOption options[noArgs]; + options[0].optionString = optHadoopClassPath; + + // Create the VM + JavaVMInitArgs vm_args; + vm_args.version = JNI_VERSION_1_6; + vm_args.options = options; + vm_args.nOptions = noArgs; + vm_args.ignoreUnrecognized = 1; + JNIEnv * jenv; + rv = JNI_CreateJavaVM(&gJVM, (void**)&jenv, &vm_args); + if (rv != 0) { + THROW_EXCEPTION(NativeTask::HadoopException, "JNI_CreateJavaVM failed"); + return NULL; + } + free(optHadoopClassPath); + } + } + } + return gJVM; +} + +JNIEnv* JNU_GetJNIEnv(void) { + JNIEnv * env; + jint rv = JNU_GetJVM()->AttachCurrentThread((void **)&env, NULL); + if (rv != 0) { + THROW_EXCEPTION(NativeTask::HadoopException, "Call to AttachCurrentThread failed"); + } + return env; +} + +void JNU_AttachCurrentThread() { + JNU_GetJNIEnv(); +} + +void JNU_DetachCurrentThread() { + jint rv = JNU_GetJVM()->DetachCurrentThread(); + if (rv != 0) { + THROW_EXCEPTION(NativeTask::HadoopException, "Call to DetachCurrentThread failed"); + } +} + +void JNU_ThrowByName(JNIEnv *jenv, const char *name, const char *msg) { + jclass cls = jenv->FindClass(name); + if (cls != NULL) { + jenv->ThrowNew(cls, msg); + } + jenv->DeleteLocalRef(cls); +} + +std::string JNU_ByteArrayToString(JNIEnv * jenv, jbyteArray src) { + if (NULL != src) { + jsize len = jenv->GetArrayLength(src); + std::string ret(len, '\0'); + jenv->GetByteArrayRegion(src, 0, len, (jbyte*)ret.data()); + return ret; + } + return std::string(); +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/jniutils.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/jniutils.h new file mode 100644 index 00000000000..45c4fda28a0 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/jniutils.h @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef JNIUTILS_H_ +#define JNIUTILS_H_ + +#include +#include + +/** + * Get current JavaVM, if none then try to create one. + */ +JavaVM * JNU_GetJVM(void); + +/** + * Get JNIEnv for current thread. + */ +JNIEnv* JNU_GetJNIEnv(void); + +/** + * Attach currentThread, same effect as JNU_GetJNIEnv. + */ +void JNU_AttachCurrentThread(); + +/** + * Detach current thread, call it if current thread + * is created in native side and have called + * JNU_AttachCurrentThread before + */ +void JNU_DetachCurrentThread(); + +/** + * Throw a java exception. + */ +void JNU_ThrowByName(JNIEnv *jenv, const char *name, const char *msg); + +/** + * Convert a java byte array to c++ std::string + */ +std::string JNU_ByteArrayToString(JNIEnv * jenv, jbyteArray src); + +#endif /* JNIUTILS_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/primitives.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/primitives.h new file mode 100644 index 00000000000..4c0c1a72974 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/lib/primitives.h @@ -0,0 +1,287 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * High performance primitive functions + * + **/ + +#ifndef PRIMITIVES_H_ +#define PRIMITIVES_H_ + +#include +#include +#include +#include + +#ifdef __GNUC__ +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) +#else +#define likely(x) (x) +#define unlikely(x) (x) +#endif + +//#define SIMPLE_MEMCPY + +#if !defined(SIMPLE_MEMCPY) +#define simple_memcpy memcpy +#define simple_memcpy2 memcpy +#else + +/** + * This memcpy assumes src & dest are not overlapped, + * and len are normally very small(<64) + * This function is primarily optimized for x86-64 processors, + * on which unaligned 64-bit loads and stores are cheap + * + * @param dest: dest buffer + * @param src: src buffer + * @param len: src buffer size, must be >0 + */ +inline void simple_memcpy(void * dest, const void * src, size_t len) { + const uint8_t * src8 = (const uint8_t*)src; + uint8_t * dest8 = (uint8_t*)dest; + switch (len) { + case 0: + return; + case 1: + dest8[0]=src8[0]; + return; + case 2: + *(uint16_t*)dest8=*(const uint16_t*)src8; + return; + case 3: + *(uint16_t*)dest8 = *(const uint16_t*)src8; + dest8[2]=src8[2]; + return; + case 4: + *(uint32_t*)dest8 = *(const uint32_t*)src8; + return; + } + if (len<8) { + *(uint32_t*)dest8 = *(const uint32_t*)src8; + *(uint32_t*)(dest8+len-4) = *(const uint32_t*)(src8+len-4); + return; + } + if (len<128) { + int64_t cur = (int64_t)len - 8; + while (cur>0) { + *(uint64_t*)(dest8+cur) = *(const uint64_t*)(src8+cur); + cur -= 8; + } + *(uint64_t*)(dest8) = *(const uint64_t*)(src8); + return; + } + ::memcpy(dest, src, len); +} + +#endif + +/** + * little-endian to big-endian or vice versa + */ +inline uint32_t bswap(uint32_t val) { + __asm__("bswap %0" : "=r" (val) : "0" (val)); + return val; +} + +inline uint64_t bswap64(uint64_t val) { +#ifdef __X64 + __asm__("bswapq %0" : "=r" (val) : "0" (val)); +#else + + uint64_t lower = val & 0xffffffffU; + uint32_t higher = (val >> 32) & 0xffffffffU; + + lower = bswap(lower); + higher = bswap(higher); + + return (lower << 32) + higher; + +#endif + return val; +} + +/** + * Fast memcmp + */ +inline int64_t fmemcmp(const char * src, const char * dest, uint32_t len) { + +#ifdef BUILDIN_MEMCMP + return memcmp(src, dest, len); +#else + + const uint8_t * src8 = (const uint8_t*)src; + const uint8_t * dest8 = (const uint8_t*)dest; + switch (len) { + case 0: + return 0; + case 1: + return (int64_t)src8[0] - (int64_t)dest8[0]; + case 2: { + int64_t ret = ((int64_t)src8[0] - (int64_t)dest8[0]); + if (ret) + return ret; + return ((int64_t)src8[1] - (int64_t)dest8[1]); + } + case 3: { + int64_t ret = ((int64_t)src8[0] - (int64_t)dest8[0]); + if (ret) + return ret; + ret = ((int64_t)src8[1] - (int64_t)dest8[1]); + if (ret) + return ret; + return ((int64_t)src8[2] - (int64_t)dest8[2]); + } + case 4: { + return (int64_t)bswap(*(uint32_t*)src) - (int64_t)bswap(*(uint32_t*)dest); + } + } + if (len < 8) { + int64_t ret = ((int64_t)bswap(*(uint32_t*)src) - (int64_t)bswap(*(uint32_t*)dest)); + if (ret) { + return ret; + } + return ((int64_t)bswap(*(uint32_t*)(src + len - 4)) + - (int64_t)bswap(*(uint32_t*)(dest + len - 4))); + } + uint32_t cur = 0; + uint32_t end = len & (0xffffffffU << 3); + while (cur < end) { + uint64_t l = *(uint64_t*)(src8 + cur); + uint64_t r = *(uint64_t*)(dest8 + cur); + if (l != r) { + l = bswap64(l); + r = bswap64(r); + return l > r ? 1 : -1; + } + cur += 8; + } + uint64_t l = *(uint64_t*)(src8 + len - 8); + uint64_t r = *(uint64_t*)(dest8 + len - 8); + if (l != r) { + l = bswap64(l); + r = bswap64(r); + return l > r ? 1 : -1; + } + return 0; +#endif +} + +inline int64_t fmemcmp(const char * src, const char * dest, uint32_t srcLen, uint32_t destLen) { + uint32_t minlen = srcLen < destLen ? srcLen : destLen; + int64_t ret = fmemcmp(src, dest, minlen); + if (ret) { + return ret; + } + return (int64_t)srcLen - (int64_t)destLen; +} + +/** + * Fast memory equal + */ +inline bool fmemeq(const char * src, const char * dest, uint32_t len) { +#ifdef BUILDIN_MEMCMP + return 0 == memcmp(src, dest, len); +#else + + const uint8_t * src8 = (const uint8_t*)src; + const uint8_t * dest8 = (const uint8_t*)dest; + switch (len) { + case 0: + return true; + case 1: + return src8[0] == dest8[0]; + case 2: + return *(uint16_t*)src8 == *(uint16_t*)dest8; + case 3: + return (*(uint16_t*)src8 == *(uint16_t*)dest8) && (src8[2] == dest8[2]); + case 4: + return *(uint32_t*)src8 == *(uint32_t*)dest8; + } + if (len < 8) { + return (*(uint32_t*)src8 == *(uint32_t*)dest8) + && (*(uint32_t*)(src8 + len - 4) == *(uint32_t*)(dest8 + len - 4)); + } + uint32_t cur = 0; + uint32_t end = len & (0xffffffff << 3); + while (cur < end) { + uint64_t l = *(uint64_t*)(src8 + cur); + uint64_t r = *(uint64_t*)(dest8 + cur); + if (l != r) { + return false; + } + cur += 8; + } + uint64_t l = *(uint64_t*)(src8 + len - 8); + uint64_t r = *(uint64_t*)(dest8 + len - 8); + if (l != r) { + return false; + } + return true; +#endif +} + +inline bool fmemeq(const char * src, uint32_t srcLen, const char * dest, uint32_t destLen) { + if (srcLen != destLen) { + return false; + } + return fmemeq(src, dest, std::min(srcLen, destLen)); +} + +/** + * Fast memory equal, reverse order + */ +inline bool frmemeq(const char * src, const char * dest, uint32_t len) { + const uint8_t * src8 = (const uint8_t*)src; + const uint8_t * dest8 = (const uint8_t*)dest; + switch (len) { + case 0: + return true; + case 1: + return src8[0] == dest8[0]; + case 2: + return *(uint16_t*)src8 == *(uint16_t*)dest8; + case 3: + return (src8[2] == dest8[2]) && (*(uint16_t*)src8 == *(uint16_t*)dest8); + case 4: + return *(uint32_t*)src8 == *(uint32_t*)dest8; + } + if (len < 8) { + return (*(uint32_t*)(src8 + len - 4) == *(uint32_t*)(dest8 + len - 4)) + && (*(uint32_t*)src8 == *(uint32_t*)dest8); + } + int32_t cur = (int32_t)len - 8; + while (cur > 0) { + if (*(uint64_t*)(src8 + cur) != *(uint64_t*)(dest8 + cur)) { + return false; + } + cur -= 8; + } + return *(uint64_t*)(src8) == *(uint64_t*)(dest8); +} + +inline bool frmemeq(const char * src, const char * dest, uint32_t srcLen, uint32_t destLen) { + if (srcLen != destLen) { + return false; + } + return frmemeq(src, dest, std::min(srcLen, destLen)); +} + +#endif /* PRIMITIVES_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Checksum.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Checksum.cc new file mode 100644 index 00000000000..191e0938941 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Checksum.cc @@ -0,0 +1,749 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "util/Checksum.h" + +namespace NativeTask { + +const uint32_t CRC32_T8_0[] = {0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, + 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, + 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, + 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, + 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, + 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, + 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, + 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, + 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, + 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, + 0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, + 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, + 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, + 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, + 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, + 0x206F85B3, 0xB966D409, 0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, + 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, + 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, + 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, + 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, + 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, + 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, + 0xA867DF55, 0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, + 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, + 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, + 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, + 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, + 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, + 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, + 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, + 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, + 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, + 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D}; +const uint32_t CRC32_T8_1[] = {0x00000000, 0x191B3141, 0x32366282, 0x2B2D53C3, 0x646CC504, + 0x7D77F445, 0x565AA786, 0x4F4196C7, 0xC8D98A08, 0xD1C2BB49, 0xFAEFE88A, 0xE3F4D9CB, 0xACB54F0C, + 0xB5AE7E4D, 0x9E832D8E, 0x87981CCF, 0x4AC21251, 0x53D92310, 0x78F470D3, 0x61EF4192, 0x2EAED755, + 0x37B5E614, 0x1C98B5D7, 0x05838496, 0x821B9859, 0x9B00A918, 0xB02DFADB, 0xA936CB9A, 0xE6775D5D, + 0xFF6C6C1C, 0xD4413FDF, 0xCD5A0E9E, 0x958424A2, 0x8C9F15E3, 0xA7B24620, 0xBEA97761, 0xF1E8E1A6, + 0xE8F3D0E7, 0xC3DE8324, 0xDAC5B265, 0x5D5DAEAA, 0x44469FEB, 0x6F6BCC28, 0x7670FD69, 0x39316BAE, + 0x202A5AEF, 0x0B07092C, 0x121C386D, 0xDF4636F3, 0xC65D07B2, 0xED705471, 0xF46B6530, 0xBB2AF3F7, + 0xA231C2B6, 0x891C9175, 0x9007A034, 0x179FBCFB, 0x0E848DBA, 0x25A9DE79, 0x3CB2EF38, 0x73F379FF, + 0x6AE848BE, 0x41C51B7D, 0x58DE2A3C, 0xF0794F05, 0xE9627E44, 0xC24F2D87, 0xDB541CC6, 0x94158A01, + 0x8D0EBB40, 0xA623E883, 0xBF38D9C2, 0x38A0C50D, 0x21BBF44C, 0x0A96A78F, 0x138D96CE, 0x5CCC0009, + 0x45D73148, 0x6EFA628B, 0x77E153CA, 0xBABB5D54, 0xA3A06C15, 0x888D3FD6, 0x91960E97, 0xDED79850, + 0xC7CCA911, 0xECE1FAD2, 0xF5FACB93, 0x7262D75C, 0x6B79E61D, 0x4054B5DE, 0x594F849F, 0x160E1258, + 0x0F152319, 0x243870DA, 0x3D23419B, 0x65FD6BA7, 0x7CE65AE6, 0x57CB0925, 0x4ED03864, 0x0191AEA3, + 0x188A9FE2, 0x33A7CC21, 0x2ABCFD60, 0xAD24E1AF, 0xB43FD0EE, 0x9F12832D, 0x8609B26C, 0xC94824AB, + 0xD05315EA, 0xFB7E4629, 0xE2657768, 0x2F3F79F6, 0x362448B7, 0x1D091B74, 0x04122A35, 0x4B53BCF2, + 0x52488DB3, 0x7965DE70, 0x607EEF31, 0xE7E6F3FE, 0xFEFDC2BF, 0xD5D0917C, 0xCCCBA03D, 0x838A36FA, + 0x9A9107BB, 0xB1BC5478, 0xA8A76539, 0x3B83984B, 0x2298A90A, 0x09B5FAC9, 0x10AECB88, 0x5FEF5D4F, + 0x46F46C0E, 0x6DD93FCD, 0x74C20E8C, 0xF35A1243, 0xEA412302, 0xC16C70C1, 0xD8774180, 0x9736D747, + 0x8E2DE606, 0xA500B5C5, 0xBC1B8484, 0x71418A1A, 0x685ABB5B, 0x4377E898, 0x5A6CD9D9, 0x152D4F1E, + 0x0C367E5F, 0x271B2D9C, 0x3E001CDD, 0xB9980012, 0xA0833153, 0x8BAE6290, 0x92B553D1, 0xDDF4C516, + 0xC4EFF457, 0xEFC2A794, 0xF6D996D5, 0xAE07BCE9, 0xB71C8DA8, 0x9C31DE6B, 0x852AEF2A, 0xCA6B79ED, + 0xD37048AC, 0xF85D1B6F, 0xE1462A2E, 0x66DE36E1, 0x7FC507A0, 0x54E85463, 0x4DF36522, 0x02B2F3E5, + 0x1BA9C2A4, 0x30849167, 0x299FA026, 0xE4C5AEB8, 0xFDDE9FF9, 0xD6F3CC3A, 0xCFE8FD7B, 0x80A96BBC, + 0x99B25AFD, 0xB29F093E, 0xAB84387F, 0x2C1C24B0, 0x350715F1, 0x1E2A4632, 0x07317773, 0x4870E1B4, + 0x516BD0F5, 0x7A468336, 0x635DB277, 0xCBFAD74E, 0xD2E1E60F, 0xF9CCB5CC, 0xE0D7848D, 0xAF96124A, + 0xB68D230B, 0x9DA070C8, 0x84BB4189, 0x03235D46, 0x1A386C07, 0x31153FC4, 0x280E0E85, 0x674F9842, + 0x7E54A903, 0x5579FAC0, 0x4C62CB81, 0x8138C51F, 0x9823F45E, 0xB30EA79D, 0xAA1596DC, 0xE554001B, + 0xFC4F315A, 0xD7626299, 0xCE7953D8, 0x49E14F17, 0x50FA7E56, 0x7BD72D95, 0x62CC1CD4, 0x2D8D8A13, + 0x3496BB52, 0x1FBBE891, 0x06A0D9D0, 0x5E7EF3EC, 0x4765C2AD, 0x6C48916E, 0x7553A02F, 0x3A1236E8, + 0x230907A9, 0x0824546A, 0x113F652B, 0x96A779E4, 0x8FBC48A5, 0xA4911B66, 0xBD8A2A27, 0xF2CBBCE0, + 0xEBD08DA1, 0xC0FDDE62, 0xD9E6EF23, 0x14BCE1BD, 0x0DA7D0FC, 0x268A833F, 0x3F91B27E, 0x70D024B9, + 0x69CB15F8, 0x42E6463B, 0x5BFD777A, 0xDC656BB5, 0xC57E5AF4, 0xEE530937, 0xF7483876, 0xB809AEB1, + 0xA1129FF0, 0x8A3FCC33, 0x9324FD72}; +const uint32_t CRC32_T8_2[] = {0x00000000, 0x01C26A37, 0x0384D46E, 0x0246BE59, 0x0709A8DC, + 0x06CBC2EB, 0x048D7CB2, 0x054F1685, 0x0E1351B8, 0x0FD13B8F, 0x0D9785D6, 0x0C55EFE1, 0x091AF964, + 0x08D89353, 0x0A9E2D0A, 0x0B5C473D, 0x1C26A370, 0x1DE4C947, 0x1FA2771E, 0x1E601D29, 0x1B2F0BAC, + 0x1AED619B, 0x18ABDFC2, 0x1969B5F5, 0x1235F2C8, 0x13F798FF, 0x11B126A6, 0x10734C91, 0x153C5A14, + 0x14FE3023, 0x16B88E7A, 0x177AE44D, 0x384D46E0, 0x398F2CD7, 0x3BC9928E, 0x3A0BF8B9, 0x3F44EE3C, + 0x3E86840B, 0x3CC03A52, 0x3D025065, 0x365E1758, 0x379C7D6F, 0x35DAC336, 0x3418A901, 0x3157BF84, + 0x3095D5B3, 0x32D36BEA, 0x331101DD, 0x246BE590, 0x25A98FA7, 0x27EF31FE, 0x262D5BC9, 0x23624D4C, + 0x22A0277B, 0x20E69922, 0x2124F315, 0x2A78B428, 0x2BBADE1F, 0x29FC6046, 0x283E0A71, 0x2D711CF4, + 0x2CB376C3, 0x2EF5C89A, 0x2F37A2AD, 0x709A8DC0, 0x7158E7F7, 0x731E59AE, 0x72DC3399, 0x7793251C, + 0x76514F2B, 0x7417F172, 0x75D59B45, 0x7E89DC78, 0x7F4BB64F, 0x7D0D0816, 0x7CCF6221, 0x798074A4, + 0x78421E93, 0x7A04A0CA, 0x7BC6CAFD, 0x6CBC2EB0, 0x6D7E4487, 0x6F38FADE, 0x6EFA90E9, 0x6BB5866C, + 0x6A77EC5B, 0x68315202, 0x69F33835, 0x62AF7F08, 0x636D153F, 0x612BAB66, 0x60E9C151, 0x65A6D7D4, + 0x6464BDE3, 0x662203BA, 0x67E0698D, 0x48D7CB20, 0x4915A117, 0x4B531F4E, 0x4A917579, 0x4FDE63FC, + 0x4E1C09CB, 0x4C5AB792, 0x4D98DDA5, 0x46C49A98, 0x4706F0AF, 0x45404EF6, 0x448224C1, 0x41CD3244, + 0x400F5873, 0x4249E62A, 0x438B8C1D, 0x54F16850, 0x55330267, 0x5775BC3E, 0x56B7D609, 0x53F8C08C, + 0x523AAABB, 0x507C14E2, 0x51BE7ED5, 0x5AE239E8, 0x5B2053DF, 0x5966ED86, 0x58A487B1, 0x5DEB9134, + 0x5C29FB03, 0x5E6F455A, 0x5FAD2F6D, 0xE1351B80, 0xE0F771B7, 0xE2B1CFEE, 0xE373A5D9, 0xE63CB35C, + 0xE7FED96B, 0xE5B86732, 0xE47A0D05, 0xEF264A38, 0xEEE4200F, 0xECA29E56, 0xED60F461, 0xE82FE2E4, + 0xE9ED88D3, 0xEBAB368A, 0xEA695CBD, 0xFD13B8F0, 0xFCD1D2C7, 0xFE976C9E, 0xFF5506A9, 0xFA1A102C, + 0xFBD87A1B, 0xF99EC442, 0xF85CAE75, 0xF300E948, 0xF2C2837F, 0xF0843D26, 0xF1465711, 0xF4094194, + 0xF5CB2BA3, 0xF78D95FA, 0xF64FFFCD, 0xD9785D60, 0xD8BA3757, 0xDAFC890E, 0xDB3EE339, 0xDE71F5BC, + 0xDFB39F8B, 0xDDF521D2, 0xDC374BE5, 0xD76B0CD8, 0xD6A966EF, 0xD4EFD8B6, 0xD52DB281, 0xD062A404, + 0xD1A0CE33, 0xD3E6706A, 0xD2241A5D, 0xC55EFE10, 0xC49C9427, 0xC6DA2A7E, 0xC7184049, 0xC25756CC, + 0xC3953CFB, 0xC1D382A2, 0xC011E895, 0xCB4DAFA8, 0xCA8FC59F, 0xC8C97BC6, 0xC90B11F1, 0xCC440774, + 0xCD866D43, 0xCFC0D31A, 0xCE02B92D, 0x91AF9640, 0x906DFC77, 0x922B422E, 0x93E92819, 0x96A63E9C, + 0x976454AB, 0x9522EAF2, 0x94E080C5, 0x9FBCC7F8, 0x9E7EADCF, 0x9C381396, 0x9DFA79A1, 0x98B56F24, + 0x99770513, 0x9B31BB4A, 0x9AF3D17D, 0x8D893530, 0x8C4B5F07, 0x8E0DE15E, 0x8FCF8B69, 0x8A809DEC, + 0x8B42F7DB, 0x89044982, 0x88C623B5, 0x839A6488, 0x82580EBF, 0x801EB0E6, 0x81DCDAD1, 0x8493CC54, + 0x8551A663, 0x8717183A, 0x86D5720D, 0xA9E2D0A0, 0xA820BA97, 0xAA6604CE, 0xABA46EF9, 0xAEEB787C, + 0xAF29124B, 0xAD6FAC12, 0xACADC625, 0xA7F18118, 0xA633EB2F, 0xA4755576, 0xA5B73F41, 0xA0F829C4, + 0xA13A43F3, 0xA37CFDAA, 0xA2BE979D, 0xB5C473D0, 0xB40619E7, 0xB640A7BE, 0xB782CD89, 0xB2CDDB0C, + 0xB30FB13B, 0xB1490F62, 0xB08B6555, 0xBBD72268, 0xBA15485F, 0xB853F606, 0xB9919C31, 0xBCDE8AB4, + 0xBD1CE083, 0xBF5A5EDA, 0xBE9834ED}; +const uint32_t CRC32_T8_3[] = {0x00000000, 0xB8BC6765, 0xAA09C88B, 0x12B5AFEE, 0x8F629757, + 0x37DEF032, 0x256B5FDC, 0x9DD738B9, 0xC5B428EF, 0x7D084F8A, 0x6FBDE064, 0xD7018701, 0x4AD6BFB8, + 0xF26AD8DD, 0xE0DF7733, 0x58631056, 0x5019579F, 0xE8A530FA, 0xFA109F14, 0x42ACF871, 0xDF7BC0C8, + 0x67C7A7AD, 0x75720843, 0xCDCE6F26, 0x95AD7F70, 0x2D111815, 0x3FA4B7FB, 0x8718D09E, 0x1ACFE827, + 0xA2738F42, 0xB0C620AC, 0x087A47C9, 0xA032AF3E, 0x188EC85B, 0x0A3B67B5, 0xB28700D0, 0x2F503869, + 0x97EC5F0C, 0x8559F0E2, 0x3DE59787, 0x658687D1, 0xDD3AE0B4, 0xCF8F4F5A, 0x7733283F, 0xEAE41086, + 0x525877E3, 0x40EDD80D, 0xF851BF68, 0xF02BF8A1, 0x48979FC4, 0x5A22302A, 0xE29E574F, 0x7F496FF6, + 0xC7F50893, 0xD540A77D, 0x6DFCC018, 0x359FD04E, 0x8D23B72B, 0x9F9618C5, 0x272A7FA0, 0xBAFD4719, + 0x0241207C, 0x10F48F92, 0xA848E8F7, 0x9B14583D, 0x23A83F58, 0x311D90B6, 0x89A1F7D3, 0x1476CF6A, + 0xACCAA80F, 0xBE7F07E1, 0x06C36084, 0x5EA070D2, 0xE61C17B7, 0xF4A9B859, 0x4C15DF3C, 0xD1C2E785, + 0x697E80E0, 0x7BCB2F0E, 0xC377486B, 0xCB0D0FA2, 0x73B168C7, 0x6104C729, 0xD9B8A04C, 0x446F98F5, + 0xFCD3FF90, 0xEE66507E, 0x56DA371B, 0x0EB9274D, 0xB6054028, 0xA4B0EFC6, 0x1C0C88A3, 0x81DBB01A, + 0x3967D77F, 0x2BD27891, 0x936E1FF4, 0x3B26F703, 0x839A9066, 0x912F3F88, 0x299358ED, 0xB4446054, + 0x0CF80731, 0x1E4DA8DF, 0xA6F1CFBA, 0xFE92DFEC, 0x462EB889, 0x549B1767, 0xEC277002, 0x71F048BB, + 0xC94C2FDE, 0xDBF98030, 0x6345E755, 0x6B3FA09C, 0xD383C7F9, 0xC1366817, 0x798A0F72, 0xE45D37CB, + 0x5CE150AE, 0x4E54FF40, 0xF6E89825, 0xAE8B8873, 0x1637EF16, 0x048240F8, 0xBC3E279D, 0x21E91F24, + 0x99557841, 0x8BE0D7AF, 0x335CB0CA, 0xED59B63B, 0x55E5D15E, 0x47507EB0, 0xFFEC19D5, 0x623B216C, + 0xDA874609, 0xC832E9E7, 0x708E8E82, 0x28ED9ED4, 0x9051F9B1, 0x82E4565F, 0x3A58313A, 0xA78F0983, + 0x1F336EE6, 0x0D86C108, 0xB53AA66D, 0xBD40E1A4, 0x05FC86C1, 0x1749292F, 0xAFF54E4A, 0x322276F3, + 0x8A9E1196, 0x982BBE78, 0x2097D91D, 0x78F4C94B, 0xC048AE2E, 0xD2FD01C0, 0x6A4166A5, 0xF7965E1C, + 0x4F2A3979, 0x5D9F9697, 0xE523F1F2, 0x4D6B1905, 0xF5D77E60, 0xE762D18E, 0x5FDEB6EB, 0xC2098E52, + 0x7AB5E937, 0x680046D9, 0xD0BC21BC, 0x88DF31EA, 0x3063568F, 0x22D6F961, 0x9A6A9E04, 0x07BDA6BD, + 0xBF01C1D8, 0xADB46E36, 0x15080953, 0x1D724E9A, 0xA5CE29FF, 0xB77B8611, 0x0FC7E174, 0x9210D9CD, + 0x2AACBEA8, 0x38191146, 0x80A57623, 0xD8C66675, 0x607A0110, 0x72CFAEFE, 0xCA73C99B, 0x57A4F122, + 0xEF189647, 0xFDAD39A9, 0x45115ECC, 0x764DEE06, 0xCEF18963, 0xDC44268D, 0x64F841E8, 0xF92F7951, + 0x41931E34, 0x5326B1DA, 0xEB9AD6BF, 0xB3F9C6E9, 0x0B45A18C, 0x19F00E62, 0xA14C6907, 0x3C9B51BE, + 0x842736DB, 0x96929935, 0x2E2EFE50, 0x2654B999, 0x9EE8DEFC, 0x8C5D7112, 0x34E11677, 0xA9362ECE, + 0x118A49AB, 0x033FE645, 0xBB838120, 0xE3E09176, 0x5B5CF613, 0x49E959FD, 0xF1553E98, 0x6C820621, + 0xD43E6144, 0xC68BCEAA, 0x7E37A9CF, 0xD67F4138, 0x6EC3265D, 0x7C7689B3, 0xC4CAEED6, 0x591DD66F, + 0xE1A1B10A, 0xF3141EE4, 0x4BA87981, 0x13CB69D7, 0xAB770EB2, 0xB9C2A15C, 0x017EC639, 0x9CA9FE80, + 0x241599E5, 0x36A0360B, 0x8E1C516E, 0x866616A7, 0x3EDA71C2, 0x2C6FDE2C, 0x94D3B949, 0x090481F0, + 0xB1B8E695, 0xA30D497B, 0x1BB12E1E, 0x43D23E48, 0xFB6E592D, 0xE9DBF6C3, 0x516791A6, 0xCCB0A91F, + 0x740CCE7A, 0x66B96194, 0xDE0506F1}; +const uint32_t CRC32_T8_4[] = {0x00000000, 0x3D6029B0, 0x7AC05360, 0x47A07AD0, 0xF580A6C0, + 0xC8E08F70, 0x8F40F5A0, 0xB220DC10, 0x30704BC1, 0x0D106271, 0x4AB018A1, 0x77D03111, 0xC5F0ED01, + 0xF890C4B1, 0xBF30BE61, 0x825097D1, 0x60E09782, 0x5D80BE32, 0x1A20C4E2, 0x2740ED52, 0x95603142, + 0xA80018F2, 0xEFA06222, 0xD2C04B92, 0x5090DC43, 0x6DF0F5F3, 0x2A508F23, 0x1730A693, 0xA5107A83, + 0x98705333, 0xDFD029E3, 0xE2B00053, 0xC1C12F04, 0xFCA106B4, 0xBB017C64, 0x866155D4, 0x344189C4, + 0x0921A074, 0x4E81DAA4, 0x73E1F314, 0xF1B164C5, 0xCCD14D75, 0x8B7137A5, 0xB6111E15, 0x0431C205, + 0x3951EBB5, 0x7EF19165, 0x4391B8D5, 0xA121B886, 0x9C419136, 0xDBE1EBE6, 0xE681C256, 0x54A11E46, + 0x69C137F6, 0x2E614D26, 0x13016496, 0x9151F347, 0xAC31DAF7, 0xEB91A027, 0xD6F18997, 0x64D15587, + 0x59B17C37, 0x1E1106E7, 0x23712F57, 0x58F35849, 0x659371F9, 0x22330B29, 0x1F532299, 0xAD73FE89, + 0x9013D739, 0xD7B3ADE9, 0xEAD38459, 0x68831388, 0x55E33A38, 0x124340E8, 0x2F236958, 0x9D03B548, + 0xA0639CF8, 0xE7C3E628, 0xDAA3CF98, 0x3813CFCB, 0x0573E67B, 0x42D39CAB, 0x7FB3B51B, 0xCD93690B, + 0xF0F340BB, 0xB7533A6B, 0x8A3313DB, 0x0863840A, 0x3503ADBA, 0x72A3D76A, 0x4FC3FEDA, 0xFDE322CA, + 0xC0830B7A, 0x872371AA, 0xBA43581A, 0x9932774D, 0xA4525EFD, 0xE3F2242D, 0xDE920D9D, 0x6CB2D18D, + 0x51D2F83D, 0x167282ED, 0x2B12AB5D, 0xA9423C8C, 0x9422153C, 0xD3826FEC, 0xEEE2465C, 0x5CC29A4C, + 0x61A2B3FC, 0x2602C92C, 0x1B62E09C, 0xF9D2E0CF, 0xC4B2C97F, 0x8312B3AF, 0xBE729A1F, 0x0C52460F, + 0x31326FBF, 0x7692156F, 0x4BF23CDF, 0xC9A2AB0E, 0xF4C282BE, 0xB362F86E, 0x8E02D1DE, 0x3C220DCE, + 0x0142247E, 0x46E25EAE, 0x7B82771E, 0xB1E6B092, 0x8C869922, 0xCB26E3F2, 0xF646CA42, 0x44661652, + 0x79063FE2, 0x3EA64532, 0x03C66C82, 0x8196FB53, 0xBCF6D2E3, 0xFB56A833, 0xC6368183, 0x74165D93, + 0x49767423, 0x0ED60EF3, 0x33B62743, 0xD1062710, 0xEC660EA0, 0xABC67470, 0x96A65DC0, 0x248681D0, + 0x19E6A860, 0x5E46D2B0, 0x6326FB00, 0xE1766CD1, 0xDC164561, 0x9BB63FB1, 0xA6D61601, 0x14F6CA11, + 0x2996E3A1, 0x6E369971, 0x5356B0C1, 0x70279F96, 0x4D47B626, 0x0AE7CCF6, 0x3787E546, 0x85A73956, + 0xB8C710E6, 0xFF676A36, 0xC2074386, 0x4057D457, 0x7D37FDE7, 0x3A978737, 0x07F7AE87, 0xB5D77297, + 0x88B75B27, 0xCF1721F7, 0xF2770847, 0x10C70814, 0x2DA721A4, 0x6A075B74, 0x576772C4, 0xE547AED4, + 0xD8278764, 0x9F87FDB4, 0xA2E7D404, 0x20B743D5, 0x1DD76A65, 0x5A7710B5, 0x67173905, 0xD537E515, + 0xE857CCA5, 0xAFF7B675, 0x92979FC5, 0xE915E8DB, 0xD475C16B, 0x93D5BBBB, 0xAEB5920B, 0x1C954E1B, + 0x21F567AB, 0x66551D7B, 0x5B3534CB, 0xD965A31A, 0xE4058AAA, 0xA3A5F07A, 0x9EC5D9CA, 0x2CE505DA, + 0x11852C6A, 0x562556BA, 0x6B457F0A, 0x89F57F59, 0xB49556E9, 0xF3352C39, 0xCE550589, 0x7C75D999, + 0x4115F029, 0x06B58AF9, 0x3BD5A349, 0xB9853498, 0x84E51D28, 0xC34567F8, 0xFE254E48, 0x4C059258, + 0x7165BBE8, 0x36C5C138, 0x0BA5E888, 0x28D4C7DF, 0x15B4EE6F, 0x521494BF, 0x6F74BD0F, 0xDD54611F, + 0xE03448AF, 0xA794327F, 0x9AF41BCF, 0x18A48C1E, 0x25C4A5AE, 0x6264DF7E, 0x5F04F6CE, 0xED242ADE, + 0xD044036E, 0x97E479BE, 0xAA84500E, 0x4834505D, 0x755479ED, 0x32F4033D, 0x0F942A8D, 0xBDB4F69D, + 0x80D4DF2D, 0xC774A5FD, 0xFA148C4D, 0x78441B9C, 0x4524322C, 0x028448FC, 0x3FE4614C, 0x8DC4BD5C, + 0xB0A494EC, 0xF704EE3C, 0xCA64C78C}; +const uint32_t CRC32_T8_5[] = {0x00000000, 0xCB5CD3A5, 0x4DC8A10B, 0x869472AE, 0x9B914216, + 0x50CD91B3, 0xD659E31D, 0x1D0530B8, 0xEC53826D, 0x270F51C8, 0xA19B2366, 0x6AC7F0C3, 0x77C2C07B, + 0xBC9E13DE, 0x3A0A6170, 0xF156B2D5, 0x03D6029B, 0xC88AD13E, 0x4E1EA390, 0x85427035, 0x9847408D, + 0x531B9328, 0xD58FE186, 0x1ED33223, 0xEF8580F6, 0x24D95353, 0xA24D21FD, 0x6911F258, 0x7414C2E0, + 0xBF481145, 0x39DC63EB, 0xF280B04E, 0x07AC0536, 0xCCF0D693, 0x4A64A43D, 0x81387798, 0x9C3D4720, + 0x57619485, 0xD1F5E62B, 0x1AA9358E, 0xEBFF875B, 0x20A354FE, 0xA6372650, 0x6D6BF5F5, 0x706EC54D, + 0xBB3216E8, 0x3DA66446, 0xF6FAB7E3, 0x047A07AD, 0xCF26D408, 0x49B2A6A6, 0x82EE7503, 0x9FEB45BB, + 0x54B7961E, 0xD223E4B0, 0x197F3715, 0xE82985C0, 0x23755665, 0xA5E124CB, 0x6EBDF76E, 0x73B8C7D6, + 0xB8E41473, 0x3E7066DD, 0xF52CB578, 0x0F580A6C, 0xC404D9C9, 0x4290AB67, 0x89CC78C2, 0x94C9487A, + 0x5F959BDF, 0xD901E971, 0x125D3AD4, 0xE30B8801, 0x28575BA4, 0xAEC3290A, 0x659FFAAF, 0x789ACA17, + 0xB3C619B2, 0x35526B1C, 0xFE0EB8B9, 0x0C8E08F7, 0xC7D2DB52, 0x4146A9FC, 0x8A1A7A59, 0x971F4AE1, + 0x5C439944, 0xDAD7EBEA, 0x118B384F, 0xE0DD8A9A, 0x2B81593F, 0xAD152B91, 0x6649F834, 0x7B4CC88C, + 0xB0101B29, 0x36846987, 0xFDD8BA22, 0x08F40F5A, 0xC3A8DCFF, 0x453CAE51, 0x8E607DF4, 0x93654D4C, + 0x58399EE9, 0xDEADEC47, 0x15F13FE2, 0xE4A78D37, 0x2FFB5E92, 0xA96F2C3C, 0x6233FF99, 0x7F36CF21, + 0xB46A1C84, 0x32FE6E2A, 0xF9A2BD8F, 0x0B220DC1, 0xC07EDE64, 0x46EAACCA, 0x8DB67F6F, 0x90B34FD7, + 0x5BEF9C72, 0xDD7BEEDC, 0x16273D79, 0xE7718FAC, 0x2C2D5C09, 0xAAB92EA7, 0x61E5FD02, 0x7CE0CDBA, + 0xB7BC1E1F, 0x31286CB1, 0xFA74BF14, 0x1EB014D8, 0xD5ECC77D, 0x5378B5D3, 0x98246676, 0x852156CE, + 0x4E7D856B, 0xC8E9F7C5, 0x03B52460, 0xF2E396B5, 0x39BF4510, 0xBF2B37BE, 0x7477E41B, 0x6972D4A3, + 0xA22E0706, 0x24BA75A8, 0xEFE6A60D, 0x1D661643, 0xD63AC5E6, 0x50AEB748, 0x9BF264ED, 0x86F75455, + 0x4DAB87F0, 0xCB3FF55E, 0x006326FB, 0xF135942E, 0x3A69478B, 0xBCFD3525, 0x77A1E680, 0x6AA4D638, + 0xA1F8059D, 0x276C7733, 0xEC30A496, 0x191C11EE, 0xD240C24B, 0x54D4B0E5, 0x9F886340, 0x828D53F8, + 0x49D1805D, 0xCF45F2F3, 0x04192156, 0xF54F9383, 0x3E134026, 0xB8873288, 0x73DBE12D, 0x6EDED195, + 0xA5820230, 0x2316709E, 0xE84AA33B, 0x1ACA1375, 0xD196C0D0, 0x5702B27E, 0x9C5E61DB, 0x815B5163, + 0x4A0782C6, 0xCC93F068, 0x07CF23CD, 0xF6999118, 0x3DC542BD, 0xBB513013, 0x700DE3B6, 0x6D08D30E, + 0xA65400AB, 0x20C07205, 0xEB9CA1A0, 0x11E81EB4, 0xDAB4CD11, 0x5C20BFBF, 0x977C6C1A, 0x8A795CA2, + 0x41258F07, 0xC7B1FDA9, 0x0CED2E0C, 0xFDBB9CD9, 0x36E74F7C, 0xB0733DD2, 0x7B2FEE77, 0x662ADECF, + 0xAD760D6A, 0x2BE27FC4, 0xE0BEAC61, 0x123E1C2F, 0xD962CF8A, 0x5FF6BD24, 0x94AA6E81, 0x89AF5E39, + 0x42F38D9C, 0xC467FF32, 0x0F3B2C97, 0xFE6D9E42, 0x35314DE7, 0xB3A53F49, 0x78F9ECEC, 0x65FCDC54, + 0xAEA00FF1, 0x28347D5F, 0xE368AEFA, 0x16441B82, 0xDD18C827, 0x5B8CBA89, 0x90D0692C, 0x8DD55994, + 0x46898A31, 0xC01DF89F, 0x0B412B3A, 0xFA1799EF, 0x314B4A4A, 0xB7DF38E4, 0x7C83EB41, 0x6186DBF9, + 0xAADA085C, 0x2C4E7AF2, 0xE712A957, 0x15921919, 0xDECECABC, 0x585AB812, 0x93066BB7, 0x8E035B0F, + 0x455F88AA, 0xC3CBFA04, 0x089729A1, 0xF9C19B74, 0x329D48D1, 0xB4093A7F, 0x7F55E9DA, 0x6250D962, + 0xA90C0AC7, 0x2F987869, 0xE4C4ABCC}; +const uint32_t CRC32_T8_6[] = {0x00000000, 0xA6770BB4, 0x979F1129, 0x31E81A9D, 0xF44F2413, + 0x52382FA7, 0x63D0353A, 0xC5A73E8E, 0x33EF4E67, 0x959845D3, 0xA4705F4E, 0x020754FA, 0xC7A06A74, + 0x61D761C0, 0x503F7B5D, 0xF64870E9, 0x67DE9CCE, 0xC1A9977A, 0xF0418DE7, 0x56368653, 0x9391B8DD, + 0x35E6B369, 0x040EA9F4, 0xA279A240, 0x5431D2A9, 0xF246D91D, 0xC3AEC380, 0x65D9C834, 0xA07EF6BA, + 0x0609FD0E, 0x37E1E793, 0x9196EC27, 0xCFBD399C, 0x69CA3228, 0x582228B5, 0xFE552301, 0x3BF21D8F, + 0x9D85163B, 0xAC6D0CA6, 0x0A1A0712, 0xFC5277FB, 0x5A257C4F, 0x6BCD66D2, 0xCDBA6D66, 0x081D53E8, + 0xAE6A585C, 0x9F8242C1, 0x39F54975, 0xA863A552, 0x0E14AEE6, 0x3FFCB47B, 0x998BBFCF, 0x5C2C8141, + 0xFA5B8AF5, 0xCBB39068, 0x6DC49BDC, 0x9B8CEB35, 0x3DFBE081, 0x0C13FA1C, 0xAA64F1A8, 0x6FC3CF26, + 0xC9B4C492, 0xF85CDE0F, 0x5E2BD5BB, 0x440B7579, 0xE27C7ECD, 0xD3946450, 0x75E36FE4, 0xB044516A, + 0x16335ADE, 0x27DB4043, 0x81AC4BF7, 0x77E43B1E, 0xD19330AA, 0xE07B2A37, 0x460C2183, 0x83AB1F0D, + 0x25DC14B9, 0x14340E24, 0xB2430590, 0x23D5E9B7, 0x85A2E203, 0xB44AF89E, 0x123DF32A, 0xD79ACDA4, + 0x71EDC610, 0x4005DC8D, 0xE672D739, 0x103AA7D0, 0xB64DAC64, 0x87A5B6F9, 0x21D2BD4D, 0xE47583C3, + 0x42028877, 0x73EA92EA, 0xD59D995E, 0x8BB64CE5, 0x2DC14751, 0x1C295DCC, 0xBA5E5678, 0x7FF968F6, + 0xD98E6342, 0xE86679DF, 0x4E11726B, 0xB8590282, 0x1E2E0936, 0x2FC613AB, 0x89B1181F, 0x4C162691, + 0xEA612D25, 0xDB8937B8, 0x7DFE3C0C, 0xEC68D02B, 0x4A1FDB9F, 0x7BF7C102, 0xDD80CAB6, 0x1827F438, + 0xBE50FF8C, 0x8FB8E511, 0x29CFEEA5, 0xDF879E4C, 0x79F095F8, 0x48188F65, 0xEE6F84D1, 0x2BC8BA5F, + 0x8DBFB1EB, 0xBC57AB76, 0x1A20A0C2, 0x8816EAF2, 0x2E61E146, 0x1F89FBDB, 0xB9FEF06F, 0x7C59CEE1, + 0xDA2EC555, 0xEBC6DFC8, 0x4DB1D47C, 0xBBF9A495, 0x1D8EAF21, 0x2C66B5BC, 0x8A11BE08, 0x4FB68086, + 0xE9C18B32, 0xD82991AF, 0x7E5E9A1B, 0xEFC8763C, 0x49BF7D88, 0x78576715, 0xDE206CA1, 0x1B87522F, + 0xBDF0599B, 0x8C184306, 0x2A6F48B2, 0xDC27385B, 0x7A5033EF, 0x4BB82972, 0xEDCF22C6, 0x28681C48, + 0x8E1F17FC, 0xBFF70D61, 0x198006D5, 0x47ABD36E, 0xE1DCD8DA, 0xD034C247, 0x7643C9F3, 0xB3E4F77D, + 0x1593FCC9, 0x247BE654, 0x820CEDE0, 0x74449D09, 0xD23396BD, 0xE3DB8C20, 0x45AC8794, 0x800BB91A, + 0x267CB2AE, 0x1794A833, 0xB1E3A387, 0x20754FA0, 0x86024414, 0xB7EA5E89, 0x119D553D, 0xD43A6BB3, + 0x724D6007, 0x43A57A9A, 0xE5D2712E, 0x139A01C7, 0xB5ED0A73, 0x840510EE, 0x22721B5A, 0xE7D525D4, + 0x41A22E60, 0x704A34FD, 0xD63D3F49, 0xCC1D9F8B, 0x6A6A943F, 0x5B828EA2, 0xFDF58516, 0x3852BB98, + 0x9E25B02C, 0xAFCDAAB1, 0x09BAA105, 0xFFF2D1EC, 0x5985DA58, 0x686DC0C5, 0xCE1ACB71, 0x0BBDF5FF, + 0xADCAFE4B, 0x9C22E4D6, 0x3A55EF62, 0xABC30345, 0x0DB408F1, 0x3C5C126C, 0x9A2B19D8, 0x5F8C2756, + 0xF9FB2CE2, 0xC813367F, 0x6E643DCB, 0x982C4D22, 0x3E5B4696, 0x0FB35C0B, 0xA9C457BF, 0x6C636931, + 0xCA146285, 0xFBFC7818, 0x5D8B73AC, 0x03A0A617, 0xA5D7ADA3, 0x943FB73E, 0x3248BC8A, 0xF7EF8204, + 0x519889B0, 0x6070932D, 0xC6079899, 0x304FE870, 0x9638E3C4, 0xA7D0F959, 0x01A7F2ED, 0xC400CC63, + 0x6277C7D7, 0x539FDD4A, 0xF5E8D6FE, 0x647E3AD9, 0xC209316D, 0xF3E12BF0, 0x55962044, 0x90311ECA, + 0x3646157E, 0x07AE0FE3, 0xA1D90457, 0x579174BE, 0xF1E67F0A, 0xC00E6597, 0x66796E23, 0xA3DE50AD, + 0x05A95B19, 0x34414184, 0x92364A30}; +const uint32_t CRC32_T8_7[] = {0x00000000, 0xCCAA009E, 0x4225077D, 0x8E8F07E3, 0x844A0EFA, + 0x48E00E64, 0xC66F0987, 0x0AC50919, 0xD3E51BB5, 0x1F4F1B2B, 0x91C01CC8, 0x5D6A1C56, 0x57AF154F, + 0x9B0515D1, 0x158A1232, 0xD92012AC, 0x7CBB312B, 0xB01131B5, 0x3E9E3656, 0xF23436C8, 0xF8F13FD1, + 0x345B3F4F, 0xBAD438AC, 0x767E3832, 0xAF5E2A9E, 0x63F42A00, 0xED7B2DE3, 0x21D12D7D, 0x2B142464, + 0xE7BE24FA, 0x69312319, 0xA59B2387, 0xF9766256, 0x35DC62C8, 0xBB53652B, 0x77F965B5, 0x7D3C6CAC, + 0xB1966C32, 0x3F196BD1, 0xF3B36B4F, 0x2A9379E3, 0xE639797D, 0x68B67E9E, 0xA41C7E00, 0xAED97719, + 0x62737787, 0xECFC7064, 0x205670FA, 0x85CD537D, 0x496753E3, 0xC7E85400, 0x0B42549E, 0x01875D87, + 0xCD2D5D19, 0x43A25AFA, 0x8F085A64, 0x562848C8, 0x9A824856, 0x140D4FB5, 0xD8A74F2B, 0xD2624632, + 0x1EC846AC, 0x9047414F, 0x5CED41D1, 0x299DC2ED, 0xE537C273, 0x6BB8C590, 0xA712C50E, 0xADD7CC17, + 0x617DCC89, 0xEFF2CB6A, 0x2358CBF4, 0xFA78D958, 0x36D2D9C6, 0xB85DDE25, 0x74F7DEBB, 0x7E32D7A2, + 0xB298D73C, 0x3C17D0DF, 0xF0BDD041, 0x5526F3C6, 0x998CF358, 0x1703F4BB, 0xDBA9F425, 0xD16CFD3C, + 0x1DC6FDA2, 0x9349FA41, 0x5FE3FADF, 0x86C3E873, 0x4A69E8ED, 0xC4E6EF0E, 0x084CEF90, 0x0289E689, + 0xCE23E617, 0x40ACE1F4, 0x8C06E16A, 0xD0EBA0BB, 0x1C41A025, 0x92CEA7C6, 0x5E64A758, 0x54A1AE41, + 0x980BAEDF, 0x1684A93C, 0xDA2EA9A2, 0x030EBB0E, 0xCFA4BB90, 0x412BBC73, 0x8D81BCED, 0x8744B5F4, + 0x4BEEB56A, 0xC561B289, 0x09CBB217, 0xAC509190, 0x60FA910E, 0xEE7596ED, 0x22DF9673, 0x281A9F6A, + 0xE4B09FF4, 0x6A3F9817, 0xA6959889, 0x7FB58A25, 0xB31F8ABB, 0x3D908D58, 0xF13A8DC6, 0xFBFF84DF, + 0x37558441, 0xB9DA83A2, 0x7570833C, 0x533B85DA, 0x9F918544, 0x111E82A7, 0xDDB48239, 0xD7718B20, + 0x1BDB8BBE, 0x95548C5D, 0x59FE8CC3, 0x80DE9E6F, 0x4C749EF1, 0xC2FB9912, 0x0E51998C, 0x04949095, + 0xC83E900B, 0x46B197E8, 0x8A1B9776, 0x2F80B4F1, 0xE32AB46F, 0x6DA5B38C, 0xA10FB312, 0xABCABA0B, + 0x6760BA95, 0xE9EFBD76, 0x2545BDE8, 0xFC65AF44, 0x30CFAFDA, 0xBE40A839, 0x72EAA8A7, 0x782FA1BE, + 0xB485A120, 0x3A0AA6C3, 0xF6A0A65D, 0xAA4DE78C, 0x66E7E712, 0xE868E0F1, 0x24C2E06F, 0x2E07E976, + 0xE2ADE9E8, 0x6C22EE0B, 0xA088EE95, 0x79A8FC39, 0xB502FCA7, 0x3B8DFB44, 0xF727FBDA, 0xFDE2F2C3, + 0x3148F25D, 0xBFC7F5BE, 0x736DF520, 0xD6F6D6A7, 0x1A5CD639, 0x94D3D1DA, 0x5879D144, 0x52BCD85D, + 0x9E16D8C3, 0x1099DF20, 0xDC33DFBE, 0x0513CD12, 0xC9B9CD8C, 0x4736CA6F, 0x8B9CCAF1, 0x8159C3E8, + 0x4DF3C376, 0xC37CC495, 0x0FD6C40B, 0x7AA64737, 0xB60C47A9, 0x3883404A, 0xF42940D4, 0xFEEC49CD, + 0x32464953, 0xBCC94EB0, 0x70634E2E, 0xA9435C82, 0x65E95C1C, 0xEB665BFF, 0x27CC5B61, 0x2D095278, + 0xE1A352E6, 0x6F2C5505, 0xA386559B, 0x061D761C, 0xCAB77682, 0x44387161, 0x889271FF, 0x825778E6, + 0x4EFD7878, 0xC0727F9B, 0x0CD87F05, 0xD5F86DA9, 0x19526D37, 0x97DD6AD4, 0x5B776A4A, 0x51B26353, + 0x9D1863CD, 0x1397642E, 0xDF3D64B0, 0x83D02561, 0x4F7A25FF, 0xC1F5221C, 0x0D5F2282, 0x079A2B9B, + 0xCB302B05, 0x45BF2CE6, 0x89152C78, 0x50353ED4, 0x9C9F3E4A, 0x121039A9, 0xDEBA3937, 0xD47F302E, + 0x18D530B0, 0x965A3753, 0x5AF037CD, 0xFF6B144A, 0x33C114D4, 0xBD4E1337, 0x71E413A9, 0x7B211AB0, + 0xB78B1A2E, 0x39041DCD, 0xF5AE1D53, 0x2C8E0FFF, 0xE0240F61, 0x6EAB0882, 0xA201081C, 0xA8C40105, + 0x646E019B, 0xEAE10678, 0x264B06E6}; + +/** + * Update a CRC using the "zlib" polynomial -- what Hadoop calls CHECKSUM_CRC32 + * using slicing-by-8 + */ +uint32_t crc32_sb8(uint32_t value, const uint8_t *buf, size_t length) { + uint32_t running_length = ((length) / 8) * 8; + uint32_t end_bytes = length - running_length; + uint32_t li; + for (li = 0; li < running_length / 8; li++) { + value ^= *(uint32_t *)buf; + buf += 4; + uint32_t term1 = CRC32_T8_7[value & 0x000000FF] ^ CRC32_T8_6[(value >> 8) & 0x000000FF]; + uint32_t term2 = value >> 16; + value = term1 ^ CRC32_T8_5[term2 & 0x000000FF] ^ CRC32_T8_4[(term2 >> 8) & 0x000000FF]; + term1 = CRC32_T8_3[(*(uint32_t *)buf) & 0x000000FF] + ^ CRC32_T8_2[((*(uint32_t *)buf) >> 8) & 0x000000FF]; + + term2 = (*(uint32_t *)buf) >> 16; + value = value ^ term1 ^ CRC32_T8_1[term2 & 0x000000FF] ^ CRC32_T8_0[(term2 >> 8) & 0x000000FF]; + buf += 4; + } + for (li = 0; li < end_bytes; li++) { + value = CRC32_T8_0[(value ^ *buf++) & 0x000000FF] ^ (value >> 8); + } + return value; +} + +const uint32_t CRC32C_T8_0[256] = {0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, + 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, 0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, + 0xBF284CD3, 0xAC78BF27, 0x5E133C24, 0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, + 0x25AFD373, 0x36FF2087, 0xC494A384, 0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, + 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, 0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, + 0x154C9AC2, 0x061C6936, 0xF477EA35, 0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, + 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, 0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, + 0x05125DAD, 0x1642AE59, 0xE4292D5A, 0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, + 0x8FCB0562, 0x9C9BF696, 0x6EF07595, 0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, + 0x748A09A0, 0x67DAFA54, 0x95B17957, 0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, + 0xFE53516F, 0xED03A29B, 0x1F682198, 0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, + 0x64D4CECF, 0x77843D3B, 0x85EFBE38, 0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, + 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, 0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, + 0x5437877E, 0x4767748A, 0xB50CF789, 0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, + 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, 0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, + 0x44694011, 0x5739B3E5, 0xA55230E6, 0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, + 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, 0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, + 0xB7072F64, 0xA457DC90, 0x563C5F93, 0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, + 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, 0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, + 0xA759E80B, 0xB4091BFF, 0x466298FC, 0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, + 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, 0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, + 0x97BAA1BA, 0x84EA524E, 0x7681D14D, 0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, + 0x1D63F975, 0x0E330A81, 0xFC588982, 0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, + 0x87E466D5, 0x94B49521, 0x66DF1622, 0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, + 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, 0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, + 0xF67C32D8, 0xE52CC12C, 0x1747422F, 0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, + 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, 0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, + 0xE622F5B7, 0xF5720643, 0x07198540, 0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, + 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, 0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, + 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, 0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, + 0x5C18E4C9, 0x4F48173D, 0xBD23943E, 0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, + 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, 0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, + 0x4C4623A6, 0x5F16D052, 0xAD7D5351}; +const uint32_t CRC32C_T8_1[256] = {0x00000000, 0x13A29877, 0x274530EE, 0x34E7A899, 0x4E8A61DC, + 0x5D28F9AB, 0x69CF5132, 0x7A6DC945, 0x9D14C3B8, 0x8EB65BCF, 0xBA51F356, 0xA9F36B21, 0xD39EA264, + 0xC03C3A13, 0xF4DB928A, 0xE7790AFD, 0x3FC5F181, 0x2C6769F6, 0x1880C16F, 0x0B225918, 0x714F905D, + 0x62ED082A, 0x560AA0B3, 0x45A838C4, 0xA2D13239, 0xB173AA4E, 0x859402D7, 0x96369AA0, 0xEC5B53E5, + 0xFFF9CB92, 0xCB1E630B, 0xD8BCFB7C, 0x7F8BE302, 0x6C297B75, 0x58CED3EC, 0x4B6C4B9B, 0x310182DE, + 0x22A31AA9, 0x1644B230, 0x05E62A47, 0xE29F20BA, 0xF13DB8CD, 0xC5DA1054, 0xD6788823, 0xAC154166, + 0xBFB7D911, 0x8B507188, 0x98F2E9FF, 0x404E1283, 0x53EC8AF4, 0x670B226D, 0x74A9BA1A, 0x0EC4735F, + 0x1D66EB28, 0x298143B1, 0x3A23DBC6, 0xDD5AD13B, 0xCEF8494C, 0xFA1FE1D5, 0xE9BD79A2, 0x93D0B0E7, + 0x80722890, 0xB4958009, 0xA737187E, 0xFF17C604, 0xECB55E73, 0xD852F6EA, 0xCBF06E9D, 0xB19DA7D8, + 0xA23F3FAF, 0x96D89736, 0x857A0F41, 0x620305BC, 0x71A19DCB, 0x45463552, 0x56E4AD25, 0x2C896460, + 0x3F2BFC17, 0x0BCC548E, 0x186ECCF9, 0xC0D23785, 0xD370AFF2, 0xE797076B, 0xF4359F1C, 0x8E585659, + 0x9DFACE2E, 0xA91D66B7, 0xBABFFEC0, 0x5DC6F43D, 0x4E646C4A, 0x7A83C4D3, 0x69215CA4, 0x134C95E1, + 0x00EE0D96, 0x3409A50F, 0x27AB3D78, 0x809C2506, 0x933EBD71, 0xA7D915E8, 0xB47B8D9F, 0xCE1644DA, + 0xDDB4DCAD, 0xE9537434, 0xFAF1EC43, 0x1D88E6BE, 0x0E2A7EC9, 0x3ACDD650, 0x296F4E27, 0x53028762, + 0x40A01F15, 0x7447B78C, 0x67E52FFB, 0xBF59D487, 0xACFB4CF0, 0x981CE469, 0x8BBE7C1E, 0xF1D3B55B, + 0xE2712D2C, 0xD69685B5, 0xC5341DC2, 0x224D173F, 0x31EF8F48, 0x050827D1, 0x16AABFA6, 0x6CC776E3, + 0x7F65EE94, 0x4B82460D, 0x5820DE7A, 0xFBC3FAF9, 0xE861628E, 0xDC86CA17, 0xCF245260, 0xB5499B25, + 0xA6EB0352, 0x920CABCB, 0x81AE33BC, 0x66D73941, 0x7575A136, 0x419209AF, 0x523091D8, 0x285D589D, + 0x3BFFC0EA, 0x0F186873, 0x1CBAF004, 0xC4060B78, 0xD7A4930F, 0xE3433B96, 0xF0E1A3E1, 0x8A8C6AA4, + 0x992EF2D3, 0xADC95A4A, 0xBE6BC23D, 0x5912C8C0, 0x4AB050B7, 0x7E57F82E, 0x6DF56059, 0x1798A91C, + 0x043A316B, 0x30DD99F2, 0x237F0185, 0x844819FB, 0x97EA818C, 0xA30D2915, 0xB0AFB162, 0xCAC27827, + 0xD960E050, 0xED8748C9, 0xFE25D0BE, 0x195CDA43, 0x0AFE4234, 0x3E19EAAD, 0x2DBB72DA, 0x57D6BB9F, + 0x447423E8, 0x70938B71, 0x63311306, 0xBB8DE87A, 0xA82F700D, 0x9CC8D894, 0x8F6A40E3, 0xF50789A6, + 0xE6A511D1, 0xD242B948, 0xC1E0213F, 0x26992BC2, 0x353BB3B5, 0x01DC1B2C, 0x127E835B, 0x68134A1E, + 0x7BB1D269, 0x4F567AF0, 0x5CF4E287, 0x04D43CFD, 0x1776A48A, 0x23910C13, 0x30339464, 0x4A5E5D21, + 0x59FCC556, 0x6D1B6DCF, 0x7EB9F5B8, 0x99C0FF45, 0x8A626732, 0xBE85CFAB, 0xAD2757DC, 0xD74A9E99, + 0xC4E806EE, 0xF00FAE77, 0xE3AD3600, 0x3B11CD7C, 0x28B3550B, 0x1C54FD92, 0x0FF665E5, 0x759BACA0, + 0x663934D7, 0x52DE9C4E, 0x417C0439, 0xA6050EC4, 0xB5A796B3, 0x81403E2A, 0x92E2A65D, 0xE88F6F18, + 0xFB2DF76F, 0xCFCA5FF6, 0xDC68C781, 0x7B5FDFFF, 0x68FD4788, 0x5C1AEF11, 0x4FB87766, 0x35D5BE23, + 0x26772654, 0x12908ECD, 0x013216BA, 0xE64B1C47, 0xF5E98430, 0xC10E2CA9, 0xD2ACB4DE, 0xA8C17D9B, + 0xBB63E5EC, 0x8F844D75, 0x9C26D502, 0x449A2E7E, 0x5738B609, 0x63DF1E90, 0x707D86E7, 0x0A104FA2, + 0x19B2D7D5, 0x2D557F4C, 0x3EF7E73B, 0xD98EEDC6, 0xCA2C75B1, 0xFECBDD28, 0xED69455F, 0x97048C1A, + 0x84A6146D, 0xB041BCF4, 0xA3E32483}; +const uint32_t CRC32C_T8_2[256] = {0x00000000, 0xA541927E, 0x4F6F520D, 0xEA2EC073, 0x9EDEA41A, + 0x3B9F3664, 0xD1B1F617, 0x74F06469, 0x38513EC5, 0x9D10ACBB, 0x773E6CC8, 0xD27FFEB6, 0xA68F9ADF, + 0x03CE08A1, 0xE9E0C8D2, 0x4CA15AAC, 0x70A27D8A, 0xD5E3EFF4, 0x3FCD2F87, 0x9A8CBDF9, 0xEE7CD990, + 0x4B3D4BEE, 0xA1138B9D, 0x045219E3, 0x48F3434F, 0xEDB2D131, 0x079C1142, 0xA2DD833C, 0xD62DE755, + 0x736C752B, 0x9942B558, 0x3C032726, 0xE144FB14, 0x4405696A, 0xAE2BA919, 0x0B6A3B67, 0x7F9A5F0E, + 0xDADBCD70, 0x30F50D03, 0x95B49F7D, 0xD915C5D1, 0x7C5457AF, 0x967A97DC, 0x333B05A2, 0x47CB61CB, + 0xE28AF3B5, 0x08A433C6, 0xADE5A1B8, 0x91E6869E, 0x34A714E0, 0xDE89D493, 0x7BC846ED, 0x0F382284, + 0xAA79B0FA, 0x40577089, 0xE516E2F7, 0xA9B7B85B, 0x0CF62A25, 0xE6D8EA56, 0x43997828, 0x37691C41, + 0x92288E3F, 0x78064E4C, 0xDD47DC32, 0xC76580D9, 0x622412A7, 0x880AD2D4, 0x2D4B40AA, 0x59BB24C3, + 0xFCFAB6BD, 0x16D476CE, 0xB395E4B0, 0xFF34BE1C, 0x5A752C62, 0xB05BEC11, 0x151A7E6F, 0x61EA1A06, + 0xC4AB8878, 0x2E85480B, 0x8BC4DA75, 0xB7C7FD53, 0x12866F2D, 0xF8A8AF5E, 0x5DE93D20, 0x29195949, + 0x8C58CB37, 0x66760B44, 0xC337993A, 0x8F96C396, 0x2AD751E8, 0xC0F9919B, 0x65B803E5, 0x1148678C, + 0xB409F5F2, 0x5E273581, 0xFB66A7FF, 0x26217BCD, 0x8360E9B3, 0x694E29C0, 0xCC0FBBBE, 0xB8FFDFD7, + 0x1DBE4DA9, 0xF7908DDA, 0x52D11FA4, 0x1E704508, 0xBB31D776, 0x511F1705, 0xF45E857B, 0x80AEE112, + 0x25EF736C, 0xCFC1B31F, 0x6A802161, 0x56830647, 0xF3C29439, 0x19EC544A, 0xBCADC634, 0xC85DA25D, + 0x6D1C3023, 0x8732F050, 0x2273622E, 0x6ED23882, 0xCB93AAFC, 0x21BD6A8F, 0x84FCF8F1, 0xF00C9C98, + 0x554D0EE6, 0xBF63CE95, 0x1A225CEB, 0x8B277743, 0x2E66E53D, 0xC448254E, 0x6109B730, 0x15F9D359, + 0xB0B84127, 0x5A968154, 0xFFD7132A, 0xB3764986, 0x1637DBF8, 0xFC191B8B, 0x595889F5, 0x2DA8ED9C, + 0x88E97FE2, 0x62C7BF91, 0xC7862DEF, 0xFB850AC9, 0x5EC498B7, 0xB4EA58C4, 0x11ABCABA, 0x655BAED3, + 0xC01A3CAD, 0x2A34FCDE, 0x8F756EA0, 0xC3D4340C, 0x6695A672, 0x8CBB6601, 0x29FAF47F, 0x5D0A9016, + 0xF84B0268, 0x1265C21B, 0xB7245065, 0x6A638C57, 0xCF221E29, 0x250CDE5A, 0x804D4C24, 0xF4BD284D, + 0x51FCBA33, 0xBBD27A40, 0x1E93E83E, 0x5232B292, 0xF77320EC, 0x1D5DE09F, 0xB81C72E1, 0xCCEC1688, + 0x69AD84F6, 0x83834485, 0x26C2D6FB, 0x1AC1F1DD, 0xBF8063A3, 0x55AEA3D0, 0xF0EF31AE, 0x841F55C7, + 0x215EC7B9, 0xCB7007CA, 0x6E3195B4, 0x2290CF18, 0x87D15D66, 0x6DFF9D15, 0xC8BE0F6B, 0xBC4E6B02, + 0x190FF97C, 0xF321390F, 0x5660AB71, 0x4C42F79A, 0xE90365E4, 0x032DA597, 0xA66C37E9, 0xD29C5380, + 0x77DDC1FE, 0x9DF3018D, 0x38B293F3, 0x7413C95F, 0xD1525B21, 0x3B7C9B52, 0x9E3D092C, 0xEACD6D45, + 0x4F8CFF3B, 0xA5A23F48, 0x00E3AD36, 0x3CE08A10, 0x99A1186E, 0x738FD81D, 0xD6CE4A63, 0xA23E2E0A, + 0x077FBC74, 0xED517C07, 0x4810EE79, 0x04B1B4D5, 0xA1F026AB, 0x4BDEE6D8, 0xEE9F74A6, 0x9A6F10CF, + 0x3F2E82B1, 0xD50042C2, 0x7041D0BC, 0xAD060C8E, 0x08479EF0, 0xE2695E83, 0x4728CCFD, 0x33D8A894, + 0x96993AEA, 0x7CB7FA99, 0xD9F668E7, 0x9557324B, 0x3016A035, 0xDA386046, 0x7F79F238, 0x0B899651, + 0xAEC8042F, 0x44E6C45C, 0xE1A75622, 0xDDA47104, 0x78E5E37A, 0x92CB2309, 0x378AB177, 0x437AD51E, + 0xE63B4760, 0x0C158713, 0xA954156D, 0xE5F54FC1, 0x40B4DDBF, 0xAA9A1DCC, 0x0FDB8FB2, 0x7B2BEBDB, + 0xDE6A79A5, 0x3444B9D6, 0x91052BA8}; +const uint32_t CRC32C_T8_3[256] = {0x00000000, 0xDD45AAB8, 0xBF672381, 0x62228939, 0x7B2231F3, + 0xA6679B4B, 0xC4451272, 0x1900B8CA, 0xF64463E6, 0x2B01C95E, 0x49234067, 0x9466EADF, 0x8D665215, + 0x5023F8AD, 0x32017194, 0xEF44DB2C, 0xE964B13D, 0x34211B85, 0x560392BC, 0x8B463804, 0x924680CE, + 0x4F032A76, 0x2D21A34F, 0xF06409F7, 0x1F20D2DB, 0xC2657863, 0xA047F15A, 0x7D025BE2, 0x6402E328, + 0xB9474990, 0xDB65C0A9, 0x06206A11, 0xD725148B, 0x0A60BE33, 0x6842370A, 0xB5079DB2, 0xAC072578, + 0x71428FC0, 0x136006F9, 0xCE25AC41, 0x2161776D, 0xFC24DDD5, 0x9E0654EC, 0x4343FE54, 0x5A43469E, + 0x8706EC26, 0xE524651F, 0x3861CFA7, 0x3E41A5B6, 0xE3040F0E, 0x81268637, 0x5C632C8F, 0x45639445, + 0x98263EFD, 0xFA04B7C4, 0x27411D7C, 0xC805C650, 0x15406CE8, 0x7762E5D1, 0xAA274F69, 0xB327F7A3, + 0x6E625D1B, 0x0C40D422, 0xD1057E9A, 0xABA65FE7, 0x76E3F55F, 0x14C17C66, 0xC984D6DE, 0xD0846E14, + 0x0DC1C4AC, 0x6FE34D95, 0xB2A6E72D, 0x5DE23C01, 0x80A796B9, 0xE2851F80, 0x3FC0B538, 0x26C00DF2, + 0xFB85A74A, 0x99A72E73, 0x44E284CB, 0x42C2EEDA, 0x9F874462, 0xFDA5CD5B, 0x20E067E3, 0x39E0DF29, + 0xE4A57591, 0x8687FCA8, 0x5BC25610, 0xB4868D3C, 0x69C32784, 0x0BE1AEBD, 0xD6A40405, 0xCFA4BCCF, + 0x12E11677, 0x70C39F4E, 0xAD8635F6, 0x7C834B6C, 0xA1C6E1D4, 0xC3E468ED, 0x1EA1C255, 0x07A17A9F, + 0xDAE4D027, 0xB8C6591E, 0x6583F3A6, 0x8AC7288A, 0x57828232, 0x35A00B0B, 0xE8E5A1B3, 0xF1E51979, + 0x2CA0B3C1, 0x4E823AF8, 0x93C79040, 0x95E7FA51, 0x48A250E9, 0x2A80D9D0, 0xF7C57368, 0xEEC5CBA2, + 0x3380611A, 0x51A2E823, 0x8CE7429B, 0x63A399B7, 0xBEE6330F, 0xDCC4BA36, 0x0181108E, 0x1881A844, + 0xC5C402FC, 0xA7E68BC5, 0x7AA3217D, 0x52A0C93F, 0x8FE56387, 0xEDC7EABE, 0x30824006, 0x2982F8CC, + 0xF4C75274, 0x96E5DB4D, 0x4BA071F5, 0xA4E4AAD9, 0x79A10061, 0x1B838958, 0xC6C623E0, 0xDFC69B2A, + 0x02833192, 0x60A1B8AB, 0xBDE41213, 0xBBC47802, 0x6681D2BA, 0x04A35B83, 0xD9E6F13B, 0xC0E649F1, + 0x1DA3E349, 0x7F816A70, 0xA2C4C0C8, 0x4D801BE4, 0x90C5B15C, 0xF2E73865, 0x2FA292DD, 0x36A22A17, + 0xEBE780AF, 0x89C50996, 0x5480A32E, 0x8585DDB4, 0x58C0770C, 0x3AE2FE35, 0xE7A7548D, 0xFEA7EC47, + 0x23E246FF, 0x41C0CFC6, 0x9C85657E, 0x73C1BE52, 0xAE8414EA, 0xCCA69DD3, 0x11E3376B, 0x08E38FA1, + 0xD5A62519, 0xB784AC20, 0x6AC10698, 0x6CE16C89, 0xB1A4C631, 0xD3864F08, 0x0EC3E5B0, 0x17C35D7A, + 0xCA86F7C2, 0xA8A47EFB, 0x75E1D443, 0x9AA50F6F, 0x47E0A5D7, 0x25C22CEE, 0xF8878656, 0xE1873E9C, + 0x3CC29424, 0x5EE01D1D, 0x83A5B7A5, 0xF90696D8, 0x24433C60, 0x4661B559, 0x9B241FE1, 0x8224A72B, + 0x5F610D93, 0x3D4384AA, 0xE0062E12, 0x0F42F53E, 0xD2075F86, 0xB025D6BF, 0x6D607C07, 0x7460C4CD, + 0xA9256E75, 0xCB07E74C, 0x16424DF4, 0x106227E5, 0xCD278D5D, 0xAF050464, 0x7240AEDC, 0x6B401616, + 0xB605BCAE, 0xD4273597, 0x09629F2F, 0xE6264403, 0x3B63EEBB, 0x59416782, 0x8404CD3A, 0x9D0475F0, + 0x4041DF48, 0x22635671, 0xFF26FCC9, 0x2E238253, 0xF36628EB, 0x9144A1D2, 0x4C010B6A, 0x5501B3A0, + 0x88441918, 0xEA669021, 0x37233A99, 0xD867E1B5, 0x05224B0D, 0x6700C234, 0xBA45688C, 0xA345D046, + 0x7E007AFE, 0x1C22F3C7, 0xC167597F, 0xC747336E, 0x1A0299D6, 0x782010EF, 0xA565BA57, 0xBC65029D, + 0x6120A825, 0x0302211C, 0xDE478BA4, 0x31035088, 0xEC46FA30, 0x8E647309, 0x5321D9B1, 0x4A21617B, + 0x9764CBC3, 0xF54642FA, 0x2803E842}; +const uint32_t CRC32C_T8_4[256] = {0x00000000, 0x38116FAC, 0x7022DF58, 0x4833B0F4, 0xE045BEB0, + 0xD854D11C, 0x906761E8, 0xA8760E44, 0xC5670B91, 0xFD76643D, 0xB545D4C9, 0x8D54BB65, 0x2522B521, + 0x1D33DA8D, 0x55006A79, 0x6D1105D5, 0x8F2261D3, 0xB7330E7F, 0xFF00BE8B, 0xC711D127, 0x6F67DF63, + 0x5776B0CF, 0x1F45003B, 0x27546F97, 0x4A456A42, 0x725405EE, 0x3A67B51A, 0x0276DAB6, 0xAA00D4F2, + 0x9211BB5E, 0xDA220BAA, 0xE2336406, 0x1BA8B557, 0x23B9DAFB, 0x6B8A6A0F, 0x539B05A3, 0xFBED0BE7, + 0xC3FC644B, 0x8BCFD4BF, 0xB3DEBB13, 0xDECFBEC6, 0xE6DED16A, 0xAEED619E, 0x96FC0E32, 0x3E8A0076, + 0x069B6FDA, 0x4EA8DF2E, 0x76B9B082, 0x948AD484, 0xAC9BBB28, 0xE4A80BDC, 0xDCB96470, 0x74CF6A34, + 0x4CDE0598, 0x04EDB56C, 0x3CFCDAC0, 0x51EDDF15, 0x69FCB0B9, 0x21CF004D, 0x19DE6FE1, 0xB1A861A5, + 0x89B90E09, 0xC18ABEFD, 0xF99BD151, 0x37516AAE, 0x0F400502, 0x4773B5F6, 0x7F62DA5A, 0xD714D41E, + 0xEF05BBB2, 0xA7360B46, 0x9F2764EA, 0xF236613F, 0xCA270E93, 0x8214BE67, 0xBA05D1CB, 0x1273DF8F, + 0x2A62B023, 0x625100D7, 0x5A406F7B, 0xB8730B7D, 0x806264D1, 0xC851D425, 0xF040BB89, 0x5836B5CD, + 0x6027DA61, 0x28146A95, 0x10050539, 0x7D1400EC, 0x45056F40, 0x0D36DFB4, 0x3527B018, 0x9D51BE5C, + 0xA540D1F0, 0xED736104, 0xD5620EA8, 0x2CF9DFF9, 0x14E8B055, 0x5CDB00A1, 0x64CA6F0D, 0xCCBC6149, + 0xF4AD0EE5, 0xBC9EBE11, 0x848FD1BD, 0xE99ED468, 0xD18FBBC4, 0x99BC0B30, 0xA1AD649C, 0x09DB6AD8, + 0x31CA0574, 0x79F9B580, 0x41E8DA2C, 0xA3DBBE2A, 0x9BCAD186, 0xD3F96172, 0xEBE80EDE, 0x439E009A, + 0x7B8F6F36, 0x33BCDFC2, 0x0BADB06E, 0x66BCB5BB, 0x5EADDA17, 0x169E6AE3, 0x2E8F054F, 0x86F90B0B, + 0xBEE864A7, 0xF6DBD453, 0xCECABBFF, 0x6EA2D55C, 0x56B3BAF0, 0x1E800A04, 0x269165A8, 0x8EE76BEC, + 0xB6F60440, 0xFEC5B4B4, 0xC6D4DB18, 0xABC5DECD, 0x93D4B161, 0xDBE70195, 0xE3F66E39, 0x4B80607D, + 0x73910FD1, 0x3BA2BF25, 0x03B3D089, 0xE180B48F, 0xD991DB23, 0x91A26BD7, 0xA9B3047B, 0x01C50A3F, + 0x39D46593, 0x71E7D567, 0x49F6BACB, 0x24E7BF1E, 0x1CF6D0B2, 0x54C56046, 0x6CD40FEA, 0xC4A201AE, + 0xFCB36E02, 0xB480DEF6, 0x8C91B15A, 0x750A600B, 0x4D1B0FA7, 0x0528BF53, 0x3D39D0FF, 0x954FDEBB, + 0xAD5EB117, 0xE56D01E3, 0xDD7C6E4F, 0xB06D6B9A, 0x887C0436, 0xC04FB4C2, 0xF85EDB6E, 0x5028D52A, + 0x6839BA86, 0x200A0A72, 0x181B65DE, 0xFA2801D8, 0xC2396E74, 0x8A0ADE80, 0xB21BB12C, 0x1A6DBF68, + 0x227CD0C4, 0x6A4F6030, 0x525E0F9C, 0x3F4F0A49, 0x075E65E5, 0x4F6DD511, 0x777CBABD, 0xDF0AB4F9, + 0xE71BDB55, 0xAF286BA1, 0x9739040D, 0x59F3BFF2, 0x61E2D05E, 0x29D160AA, 0x11C00F06, 0xB9B60142, + 0x81A76EEE, 0xC994DE1A, 0xF185B1B6, 0x9C94B463, 0xA485DBCF, 0xECB66B3B, 0xD4A70497, 0x7CD10AD3, + 0x44C0657F, 0x0CF3D58B, 0x34E2BA27, 0xD6D1DE21, 0xEEC0B18D, 0xA6F30179, 0x9EE26ED5, 0x36946091, + 0x0E850F3D, 0x46B6BFC9, 0x7EA7D065, 0x13B6D5B0, 0x2BA7BA1C, 0x63940AE8, 0x5B856544, 0xF3F36B00, + 0xCBE204AC, 0x83D1B458, 0xBBC0DBF4, 0x425B0AA5, 0x7A4A6509, 0x3279D5FD, 0x0A68BA51, 0xA21EB415, + 0x9A0FDBB9, 0xD23C6B4D, 0xEA2D04E1, 0x873C0134, 0xBF2D6E98, 0xF71EDE6C, 0xCF0FB1C0, 0x6779BF84, + 0x5F68D028, 0x175B60DC, 0x2F4A0F70, 0xCD796B76, 0xF56804DA, 0xBD5BB42E, 0x854ADB82, 0x2D3CD5C6, + 0x152DBA6A, 0x5D1E0A9E, 0x650F6532, 0x081E60E7, 0x300F0F4B, 0x783CBFBF, 0x402DD013, 0xE85BDE57, + 0xD04AB1FB, 0x9879010F, 0xA0686EA3}; + +const uint32_t CRC32C_T8_5[256] = {0x00000000, 0xEF306B19, 0xDB8CA0C3, 0x34BCCBDA, 0xB2F53777, + 0x5DC55C6E, 0x697997B4, 0x8649FCAD, 0x6006181F, 0x8F367306, 0xBB8AB8DC, 0x54BAD3C5, 0xD2F32F68, + 0x3DC34471, 0x097F8FAB, 0xE64FE4B2, 0xC00C303E, 0x2F3C5B27, 0x1B8090FD, 0xF4B0FBE4, 0x72F90749, + 0x9DC96C50, 0xA975A78A, 0x4645CC93, 0xA00A2821, 0x4F3A4338, 0x7B8688E2, 0x94B6E3FB, 0x12FF1F56, + 0xFDCF744F, 0xC973BF95, 0x2643D48C, 0x85F4168D, 0x6AC47D94, 0x5E78B64E, 0xB148DD57, 0x370121FA, + 0xD8314AE3, 0xEC8D8139, 0x03BDEA20, 0xE5F20E92, 0x0AC2658B, 0x3E7EAE51, 0xD14EC548, 0x570739E5, + 0xB83752FC, 0x8C8B9926, 0x63BBF23F, 0x45F826B3, 0xAAC84DAA, 0x9E748670, 0x7144ED69, 0xF70D11C4, + 0x183D7ADD, 0x2C81B107, 0xC3B1DA1E, 0x25FE3EAC, 0xCACE55B5, 0xFE729E6F, 0x1142F576, 0x970B09DB, + 0x783B62C2, 0x4C87A918, 0xA3B7C201, 0x0E045BEB, 0xE13430F2, 0xD588FB28, 0x3AB89031, 0xBCF16C9C, + 0x53C10785, 0x677DCC5F, 0x884DA746, 0x6E0243F4, 0x813228ED, 0xB58EE337, 0x5ABE882E, 0xDCF77483, + 0x33C71F9A, 0x077BD440, 0xE84BBF59, 0xCE086BD5, 0x213800CC, 0x1584CB16, 0xFAB4A00F, 0x7CFD5CA2, + 0x93CD37BB, 0xA771FC61, 0x48419778, 0xAE0E73CA, 0x413E18D3, 0x7582D309, 0x9AB2B810, 0x1CFB44BD, + 0xF3CB2FA4, 0xC777E47E, 0x28478F67, 0x8BF04D66, 0x64C0267F, 0x507CEDA5, 0xBF4C86BC, 0x39057A11, + 0xD6351108, 0xE289DAD2, 0x0DB9B1CB, 0xEBF65579, 0x04C63E60, 0x307AF5BA, 0xDF4A9EA3, 0x5903620E, + 0xB6330917, 0x828FC2CD, 0x6DBFA9D4, 0x4BFC7D58, 0xA4CC1641, 0x9070DD9B, 0x7F40B682, 0xF9094A2F, + 0x16392136, 0x2285EAEC, 0xCDB581F5, 0x2BFA6547, 0xC4CA0E5E, 0xF076C584, 0x1F46AE9D, 0x990F5230, + 0x763F3929, 0x4283F2F3, 0xADB399EA, 0x1C08B7D6, 0xF338DCCF, 0xC7841715, 0x28B47C0C, 0xAEFD80A1, + 0x41CDEBB8, 0x75712062, 0x9A414B7B, 0x7C0EAFC9, 0x933EC4D0, 0xA7820F0A, 0x48B26413, 0xCEFB98BE, + 0x21CBF3A7, 0x1577387D, 0xFA475364, 0xDC0487E8, 0x3334ECF1, 0x0788272B, 0xE8B84C32, 0x6EF1B09F, + 0x81C1DB86, 0xB57D105C, 0x5A4D7B45, 0xBC029FF7, 0x5332F4EE, 0x678E3F34, 0x88BE542D, 0x0EF7A880, + 0xE1C7C399, 0xD57B0843, 0x3A4B635A, 0x99FCA15B, 0x76CCCA42, 0x42700198, 0xAD406A81, 0x2B09962C, + 0xC439FD35, 0xF08536EF, 0x1FB55DF6, 0xF9FAB944, 0x16CAD25D, 0x22761987, 0xCD46729E, 0x4B0F8E33, + 0xA43FE52A, 0x90832EF0, 0x7FB345E9, 0x59F09165, 0xB6C0FA7C, 0x827C31A6, 0x6D4C5ABF, 0xEB05A612, + 0x0435CD0B, 0x308906D1, 0xDFB96DC8, 0x39F6897A, 0xD6C6E263, 0xE27A29B9, 0x0D4A42A0, 0x8B03BE0D, + 0x6433D514, 0x508F1ECE, 0xBFBF75D7, 0x120CEC3D, 0xFD3C8724, 0xC9804CFE, 0x26B027E7, 0xA0F9DB4A, + 0x4FC9B053, 0x7B757B89, 0x94451090, 0x720AF422, 0x9D3A9F3B, 0xA98654E1, 0x46B63FF8, 0xC0FFC355, + 0x2FCFA84C, 0x1B736396, 0xF443088F, 0xD200DC03, 0x3D30B71A, 0x098C7CC0, 0xE6BC17D9, 0x60F5EB74, + 0x8FC5806D, 0xBB794BB7, 0x544920AE, 0xB206C41C, 0x5D36AF05, 0x698A64DF, 0x86BA0FC6, 0x00F3F36B, + 0xEFC39872, 0xDB7F53A8, 0x344F38B1, 0x97F8FAB0, 0x78C891A9, 0x4C745A73, 0xA344316A, 0x250DCDC7, + 0xCA3DA6DE, 0xFE816D04, 0x11B1061D, 0xF7FEE2AF, 0x18CE89B6, 0x2C72426C, 0xC3422975, 0x450BD5D8, + 0xAA3BBEC1, 0x9E87751B, 0x71B71E02, 0x57F4CA8E, 0xB8C4A197, 0x8C786A4D, 0x63480154, 0xE501FDF9, + 0x0A3196E0, 0x3E8D5D3A, 0xD1BD3623, 0x37F2D291, 0xD8C2B988, 0xEC7E7252, 0x034E194B, 0x8507E5E6, + 0x6A378EFF, 0x5E8B4525, 0xB1BB2E3C}; +const uint32_t CRC32C_T8_6[256] = {0x00000000, 0x68032CC8, 0xD0065990, 0xB8057558, 0xA5E0C5D1, + 0xCDE3E919, 0x75E69C41, 0x1DE5B089, 0x4E2DFD53, 0x262ED19B, 0x9E2BA4C3, 0xF628880B, 0xEBCD3882, + 0x83CE144A, 0x3BCB6112, 0x53C84DDA, 0x9C5BFAA6, 0xF458D66E, 0x4C5DA336, 0x245E8FFE, 0x39BB3F77, + 0x51B813BF, 0xE9BD66E7, 0x81BE4A2F, 0xD27607F5, 0xBA752B3D, 0x02705E65, 0x6A7372AD, 0x7796C224, + 0x1F95EEEC, 0xA7909BB4, 0xCF93B77C, 0x3D5B83BD, 0x5558AF75, 0xED5DDA2D, 0x855EF6E5, 0x98BB466C, + 0xF0B86AA4, 0x48BD1FFC, 0x20BE3334, 0x73767EEE, 0x1B755226, 0xA370277E, 0xCB730BB6, 0xD696BB3F, + 0xBE9597F7, 0x0690E2AF, 0x6E93CE67, 0xA100791B, 0xC90355D3, 0x7106208B, 0x19050C43, 0x04E0BCCA, + 0x6CE39002, 0xD4E6E55A, 0xBCE5C992, 0xEF2D8448, 0x872EA880, 0x3F2BDDD8, 0x5728F110, 0x4ACD4199, + 0x22CE6D51, 0x9ACB1809, 0xF2C834C1, 0x7AB7077A, 0x12B42BB2, 0xAAB15EEA, 0xC2B27222, 0xDF57C2AB, + 0xB754EE63, 0x0F519B3B, 0x6752B7F3, 0x349AFA29, 0x5C99D6E1, 0xE49CA3B9, 0x8C9F8F71, 0x917A3FF8, + 0xF9791330, 0x417C6668, 0x297F4AA0, 0xE6ECFDDC, 0x8EEFD114, 0x36EAA44C, 0x5EE98884, 0x430C380D, + 0x2B0F14C5, 0x930A619D, 0xFB094D55, 0xA8C1008F, 0xC0C22C47, 0x78C7591F, 0x10C475D7, 0x0D21C55E, + 0x6522E996, 0xDD279CCE, 0xB524B006, 0x47EC84C7, 0x2FEFA80F, 0x97EADD57, 0xFFE9F19F, 0xE20C4116, + 0x8A0F6DDE, 0x320A1886, 0x5A09344E, 0x09C17994, 0x61C2555C, 0xD9C72004, 0xB1C40CCC, 0xAC21BC45, + 0xC422908D, 0x7C27E5D5, 0x1424C91D, 0xDBB77E61, 0xB3B452A9, 0x0BB127F1, 0x63B20B39, 0x7E57BBB0, + 0x16549778, 0xAE51E220, 0xC652CEE8, 0x959A8332, 0xFD99AFFA, 0x459CDAA2, 0x2D9FF66A, 0x307A46E3, + 0x58796A2B, 0xE07C1F73, 0x887F33BB, 0xF56E0EF4, 0x9D6D223C, 0x25685764, 0x4D6B7BAC, 0x508ECB25, + 0x388DE7ED, 0x808892B5, 0xE88BBE7D, 0xBB43F3A7, 0xD340DF6F, 0x6B45AA37, 0x034686FF, 0x1EA33676, + 0x76A01ABE, 0xCEA56FE6, 0xA6A6432E, 0x6935F452, 0x0136D89A, 0xB933ADC2, 0xD130810A, 0xCCD53183, + 0xA4D61D4B, 0x1CD36813, 0x74D044DB, 0x27180901, 0x4F1B25C9, 0xF71E5091, 0x9F1D7C59, 0x82F8CCD0, + 0xEAFBE018, 0x52FE9540, 0x3AFDB988, 0xC8358D49, 0xA036A181, 0x1833D4D9, 0x7030F811, 0x6DD54898, + 0x05D66450, 0xBDD31108, 0xD5D03DC0, 0x8618701A, 0xEE1B5CD2, 0x561E298A, 0x3E1D0542, 0x23F8B5CB, + 0x4BFB9903, 0xF3FEEC5B, 0x9BFDC093, 0x546E77EF, 0x3C6D5B27, 0x84682E7F, 0xEC6B02B7, 0xF18EB23E, + 0x998D9EF6, 0x2188EBAE, 0x498BC766, 0x1A438ABC, 0x7240A674, 0xCA45D32C, 0xA246FFE4, 0xBFA34F6D, + 0xD7A063A5, 0x6FA516FD, 0x07A63A35, 0x8FD9098E, 0xE7DA2546, 0x5FDF501E, 0x37DC7CD6, 0x2A39CC5F, + 0x423AE097, 0xFA3F95CF, 0x923CB907, 0xC1F4F4DD, 0xA9F7D815, 0x11F2AD4D, 0x79F18185, 0x6414310C, + 0x0C171DC4, 0xB412689C, 0xDC114454, 0x1382F328, 0x7B81DFE0, 0xC384AAB8, 0xAB878670, 0xB66236F9, + 0xDE611A31, 0x66646F69, 0x0E6743A1, 0x5DAF0E7B, 0x35AC22B3, 0x8DA957EB, 0xE5AA7B23, 0xF84FCBAA, + 0x904CE762, 0x2849923A, 0x404ABEF2, 0xB2828A33, 0xDA81A6FB, 0x6284D3A3, 0x0A87FF6B, 0x17624FE2, + 0x7F61632A, 0xC7641672, 0xAF673ABA, 0xFCAF7760, 0x94AC5BA8, 0x2CA92EF0, 0x44AA0238, 0x594FB2B1, + 0x314C9E79, 0x8949EB21, 0xE14AC7E9, 0x2ED97095, 0x46DA5C5D, 0xFEDF2905, 0x96DC05CD, 0x8B39B544, + 0xE33A998C, 0x5B3FECD4, 0x333CC01C, 0x60F48DC6, 0x08F7A10E, 0xB0F2D456, 0xD8F1F89E, 0xC5144817, + 0xAD1764DF, 0x15121187, 0x7D113D4F}; +const uint32_t CRC32C_T8_7[256] = {0x00000000, 0x493C7D27, 0x9278FA4E, 0xDB448769, 0x211D826D, + 0x6821FF4A, 0xB3657823, 0xFA590504, 0x423B04DA, 0x0B0779FD, 0xD043FE94, 0x997F83B3, 0x632686B7, + 0x2A1AFB90, 0xF15E7CF9, 0xB86201DE, 0x847609B4, 0xCD4A7493, 0x160EF3FA, 0x5F328EDD, 0xA56B8BD9, + 0xEC57F6FE, 0x37137197, 0x7E2F0CB0, 0xC64D0D6E, 0x8F717049, 0x5435F720, 0x1D098A07, 0xE7508F03, + 0xAE6CF224, 0x7528754D, 0x3C14086A, 0x0D006599, 0x443C18BE, 0x9F789FD7, 0xD644E2F0, 0x2C1DE7F4, + 0x65219AD3, 0xBE651DBA, 0xF759609D, 0x4F3B6143, 0x06071C64, 0xDD439B0D, 0x947FE62A, 0x6E26E32E, + 0x271A9E09, 0xFC5E1960, 0xB5626447, 0x89766C2D, 0xC04A110A, 0x1B0E9663, 0x5232EB44, 0xA86BEE40, + 0xE1579367, 0x3A13140E, 0x732F6929, 0xCB4D68F7, 0x827115D0, 0x593592B9, 0x1009EF9E, 0xEA50EA9A, + 0xA36C97BD, 0x782810D4, 0x31146DF3, 0x1A00CB32, 0x533CB615, 0x8878317C, 0xC1444C5B, 0x3B1D495F, + 0x72213478, 0xA965B311, 0xE059CE36, 0x583BCFE8, 0x1107B2CF, 0xCA4335A6, 0x837F4881, 0x79264D85, + 0x301A30A2, 0xEB5EB7CB, 0xA262CAEC, 0x9E76C286, 0xD74ABFA1, 0x0C0E38C8, 0x453245EF, 0xBF6B40EB, + 0xF6573DCC, 0x2D13BAA5, 0x642FC782, 0xDC4DC65C, 0x9571BB7B, 0x4E353C12, 0x07094135, 0xFD504431, + 0xB46C3916, 0x6F28BE7F, 0x2614C358, 0x1700AEAB, 0x5E3CD38C, 0x857854E5, 0xCC4429C2, 0x361D2CC6, + 0x7F2151E1, 0xA465D688, 0xED59ABAF, 0x553BAA71, 0x1C07D756, 0xC743503F, 0x8E7F2D18, 0x7426281C, + 0x3D1A553B, 0xE65ED252, 0xAF62AF75, 0x9376A71F, 0xDA4ADA38, 0x010E5D51, 0x48322076, 0xB26B2572, + 0xFB575855, 0x2013DF3C, 0x692FA21B, 0xD14DA3C5, 0x9871DEE2, 0x4335598B, 0x0A0924AC, 0xF05021A8, + 0xB96C5C8F, 0x6228DBE6, 0x2B14A6C1, 0x34019664, 0x7D3DEB43, 0xA6796C2A, 0xEF45110D, 0x151C1409, + 0x5C20692E, 0x8764EE47, 0xCE589360, 0x763A92BE, 0x3F06EF99, 0xE44268F0, 0xAD7E15D7, 0x572710D3, + 0x1E1B6DF4, 0xC55FEA9D, 0x8C6397BA, 0xB0779FD0, 0xF94BE2F7, 0x220F659E, 0x6B3318B9, 0x916A1DBD, + 0xD856609A, 0x0312E7F3, 0x4A2E9AD4, 0xF24C9B0A, 0xBB70E62D, 0x60346144, 0x29081C63, 0xD3511967, + 0x9A6D6440, 0x4129E329, 0x08159E0E, 0x3901F3FD, 0x703D8EDA, 0xAB7909B3, 0xE2457494, 0x181C7190, + 0x51200CB7, 0x8A648BDE, 0xC358F6F9, 0x7B3AF727, 0x32068A00, 0xE9420D69, 0xA07E704E, 0x5A27754A, + 0x131B086D, 0xC85F8F04, 0x8163F223, 0xBD77FA49, 0xF44B876E, 0x2F0F0007, 0x66337D20, 0x9C6A7824, + 0xD5560503, 0x0E12826A, 0x472EFF4D, 0xFF4CFE93, 0xB67083B4, 0x6D3404DD, 0x240879FA, 0xDE517CFE, + 0x976D01D9, 0x4C2986B0, 0x0515FB97, 0x2E015D56, 0x673D2071, 0xBC79A718, 0xF545DA3F, 0x0F1CDF3B, + 0x4620A21C, 0x9D642575, 0xD4585852, 0x6C3A598C, 0x250624AB, 0xFE42A3C2, 0xB77EDEE5, 0x4D27DBE1, + 0x041BA6C6, 0xDF5F21AF, 0x96635C88, 0xAA7754E2, 0xE34B29C5, 0x380FAEAC, 0x7133D38B, 0x8B6AD68F, + 0xC256ABA8, 0x19122CC1, 0x502E51E6, 0xE84C5038, 0xA1702D1F, 0x7A34AA76, 0x3308D751, 0xC951D255, + 0x806DAF72, 0x5B29281B, 0x1215553C, 0x230138CF, 0x6A3D45E8, 0xB179C281, 0xF845BFA6, 0x021CBAA2, + 0x4B20C785, 0x906440EC, 0xD9583DCB, 0x613A3C15, 0x28064132, 0xF342C65B, 0xBA7EBB7C, 0x4027BE78, + 0x091BC35F, 0xD25F4436, 0x9B633911, 0xA777317B, 0xEE4B4C5C, 0x350FCB35, 0x7C33B612, 0x866AB316, + 0xCF56CE31, 0x14124958, 0x5D2E347F, 0xE54C35A1, 0xAC704886, 0x7734CFEF, 0x3E08B2C8, 0xC451B7CC, + 0x8D6DCAEB, 0x56294D82, 0x1F1530A5}; + +#ifndef SOFTWARE_CRC +#define USE_HARDWARE_CRC32C 1 +#endif + +#ifdef USE_HARDWARE_CRC32C + +static int cached_cpu_supports_crc32; // initialized by constructor below +static uint32_t crc32c_hardware(uint32_t crc, const uint8_t* data, size_t length); + +#define SSE42_FEATURE_BIT (1 << 20) +#define CPUID_FEATURES 1 + +/** + * Call the cpuid instruction to determine CPU feature flags. + */ +static uint32_t cpuid(uint32_t eax_in) { + uint32_t eax, ebx, ecx, edx; +# if defined(__PIC__) && !defined(__LP64__) +// 32-bit PIC code uses the ebx register for the base offset -- +// have to save and restore it on the stack + asm("pushl %%ebx\n\t" + "cpuid\n\t" + "movl %%ebx, %[ebx]\n\t" + "popl %%ebx" : "=a" (eax), [ebx] "=r"(ebx), "=c"(ecx), "=d"(edx) : "a" (eax_in) + : "cc"); +# else + asm("cpuid" : "=a" (eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(eax_in) + : "cc"); +# endif + + return ecx; +} + +// +// Definitions of the SSE4.2 crc32 operations. Using these instead of +// the GCC __builtin_* intrinsics allows this code to compile without +// -msse4.2, since we do dynamic CPU detection at runtime. +// + +inline uint64_t _mm_crc32_u64(uint64_t crc, uint64_t value) { + asm("crc32q %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value)); + return crc; +} + +inline uint32_t _mm_crc32_u32(uint32_t crc, uint32_t value) { + asm("crc32l %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value)); + return crc; +} + +inline uint32_t _mm_crc32_u16(uint32_t crc, uint16_t value) { + asm("crc32w %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value)); + return crc; +} + +inline uint32_t _mm_crc32_u8(uint32_t crc, uint8_t value) { + asm("crc32b %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value)); + return crc; +} + +/** + * Hardware-accelerated CRC32C calculation using the 64-bit instructions. + */ +static uint32_t crc32c_hardware(uint32_t crc, const uint8_t* p_buf, size_t length) { + // start directly at p_buf, even if it's an unaligned address. According + // to the original author of this code, doing a small run of single bytes + // to word-align the 64-bit instructions doesn't seem to help, but + // we haven't reconfirmed those benchmarks ourselves. + uint64_t crc64bit = crc; + size_t i; + for (i = 0; i < length / sizeof(uint64_t); i++) { + crc64bit = _mm_crc32_u64(crc64bit, *(uint64_t*) p_buf); + p_buf += sizeof(uint64_t); + } + + // This ugly switch is slightly faster for short strings than the straightforward loop + uint32_t crc32bit = (uint32_t) crc64bit; + length &= sizeof(uint64_t) - 1; + switch (length) { + case 7: + crc32bit = _mm_crc32_u8(crc32bit, *p_buf++); + case 6: + crc32bit = _mm_crc32_u16(crc32bit, *(uint16_t*) p_buf); + p_buf += 2; + // case 5 is below: 4 + 1 + case 4: + crc32bit = _mm_crc32_u32(crc32bit, *(uint32_t*) p_buf); + break; + case 3: + crc32bit = _mm_crc32_u8(crc32bit, *p_buf++); + case 2: + crc32bit = _mm_crc32_u16(crc32bit, *(uint16_t*) p_buf); + break; + case 5: + crc32bit = _mm_crc32_u32(crc32bit, *(uint32_t*) p_buf); + p_buf += 4; + case 1: + crc32bit = _mm_crc32_u8(crc32bit, *p_buf); + break; + case 0: + break; + default: + // This should never happen; enable in debug code + assert(0 && "ended up with 8 or more bytes at tail of calculation"); + } + + return crc32bit; +} + +/** + * On library load, initiailize the cached value above for + * whether the cpu supports SSE4.2's crc32 instruction. + */ +void __attribute__ ((constructor)) init_cpu_support_flag(void) { + uint32_t ecx = cpuid(CPUID_FEATURES); + cached_cpu_supports_crc32 = ecx & SSE42_FEATURE_BIT; +} + +#endif + +/** + * Computes the CRC32c checksum for the specified buffer using the slicing by 8 + * algorithm over 64 bit quantities. + */ +uint32_t crc32c_sb8_software(uint32_t crc, const uint8_t *buf, size_t length) { + uint32_t running_length = ((length) / 8) * 8; + uint32_t end_bytes = length - running_length; + uint32_t li; + for (li = 0; li < running_length / 8; li++) { + crc ^= *(uint32_t *)buf; + buf += 4; + uint32_t term1 = CRC32C_T8_7[crc & 0x000000FF] ^ CRC32C_T8_6[(crc >> 8) & 0x000000FF]; + uint32_t term2 = crc >> 16; + crc = term1 ^ CRC32C_T8_5[term2 & 0x000000FF] ^ CRC32C_T8_4[(term2 >> 8) & 0x000000FF]; + term1 = CRC32C_T8_3[(*(uint32_t *)buf) & 0x000000FF] + ^ CRC32C_T8_2[((*(uint32_t *)buf) >> 8) & 0x000000FF]; + + term2 = (*(uint32_t *)buf) >> 16; + crc = crc ^ term1 ^ CRC32C_T8_1[term2 & 0x000000FF] ^ CRC32C_T8_0[(term2 >> 8) & 0x000000FF]; + buf += 4; + } + for (li = 0; li < end_bytes; li++) { + crc = CRC32C_T8_0[(crc ^ *buf++) & 0x000000FF] ^ (crc >> 8); + } + return crc; +} + +#ifdef __GNUC__ +#define likely(x) __builtin_expect((x),1) +#define unlikely(x) __builtin_expect((x),0) +#else +#define likely(x) (x) +#define unlikely(x) (x) +#endif + +uint32_t crc32c_sb8(uint32_t crc, const uint8_t *buf, size_t length) { +#ifdef USE_HARDWARE_CRC32C + if (likely(cached_cpu_supports_crc32)) { + return crc32c_hardware(crc, buf, length); + } else { + return crc32c_sb8_software(crc, buf, length); + } +#else + return crc32c_sb8_software(crc, buf, length); +#endif +} + +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Checksum.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Checksum.h new file mode 100644 index 00000000000..2eae355f493 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Checksum.h @@ -0,0 +1,78 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef CHECKSUM_H_ +#define CHECKSUM_H_ + +#include +#include + +namespace NativeTask { + +extern uint32_t crc32_sb8(uint32_t, const uint8_t *, size_t); +extern uint32_t crc32c_sb8(uint32_t, const uint8_t *, size_t); + +enum ChecksumType { + CHECKSUM_NONE, + CHECKSUM_CRC32, + CHECKSUM_CRC32C, +}; + +class Checksum { +public: + static uint32_t init(ChecksumType type) { + switch (type) { + case CHECKSUM_NONE: + return 0; + case CHECKSUM_CRC32: + return 0xffffffff; + case CHECKSUM_CRC32C: + return 0xffffffff; + } + return 0; + } + + static void update(ChecksumType type, uint32_t & value, const void * buff, uint32_t length) { + switch (type) { + case CHECKSUM_NONE: + return; + case CHECKSUM_CRC32: + value = crc32_sb8(value, (const uint8_t *)buff, length); + return; + case CHECKSUM_CRC32C: + value = crc32c_sb8(value, (const uint8_t *)buff, length); + return; + } + return; + } + + static uint32_t getValue(ChecksumType type, uint32_t value) { + switch (type) { + case CHECKSUM_NONE: + return 0; + case CHECKSUM_CRC32: + case CHECKSUM_CRC32C: + return ~value; + } + return 0; + } +}; + +} // namespace NativeTask + +#endif /* CHECKSUM_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/DualPivotQuickSort.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/DualPivotQuickSort.h new file mode 100644 index 00000000000..0d3013bc930 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/DualPivotQuickSort.h @@ -0,0 +1,137 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef DUALPIVOTQUICKSORT_H_ +#define DUALPIVOTQUICKSORT_H_ + +#include +#include + +namespace NativeTask { + +// TODO: definitely needs refactoring.. +template +void DualPivotQuicksort(std::vector & elements, int left, int right, int div, + _Compare compare) { + + if (left >= right) { + return; + } + + uint32_t * e = &(elements[0]); + int len = right - left; + + if (len < 27) { // insertion sort for tiny array + for (int i = left + 1; i <= right; i++) { + for (int j = i; j > left && compare(e[j - 1], e[j]) > 0; --j) { + std::swap(e[j], e[j - 1]); + } + } + return; + } + + int third = len / div; + + // "medians" + int m1 = left + third; + int m2 = right - third; + + if (m1 <= left) { + m1 = left + 1; + } + if (m2 >= right) { + m2 = right - 1; + } + if (compare(e[m1], e[m2]) < 0) { + std::swap(e[m1], e[left]); + std::swap(e[m2], e[right]); + } else { + std::swap(e[m1], e[right]); + std::swap(e[m2], e[left]); + } + + // pivot idx + int pivot1 = left; + int pivot2 = right; + + // pointers + int less = left + 1; + int great = right - 1; + + // sorting + for (int k = less; k <= great; k++) { + if (compare(e[k], e[pivot1]) < 0) { + std::swap(e[k], e[less]); + less++; + } else if (compare(e[k], e[pivot2]) > 0) { + while (k < great && compare(e[great], e[pivot2]) > 0) { + --great; + } + std::swap(e[k], e[great]); + great--; + + if (compare(e[k], e[pivot1]) < 0) { + std::swap(e[k], e[less]); + less++; + } + } + } + // swaps + int dist = great - less; + + if (dist < 13) { + ++div; + } + std::swap(e[less - 1], e[left]); + std::swap(e[great + 1], e[right]); + + // subarrays + DualPivotQuicksort(elements, left, less - 2, div, compare); + DualPivotQuicksort(elements, great + 2, right, div, compare); + + // equal elements + if (dist > len - 13 && pivot1 != pivot2) { + for (int k = less; k <= great; ++k) { + if (0 == compare(e[k], e[pivot1])) { + std::swap(e[k], e[less]); + less++; + } else if (0 == compare(e[k], e[pivot2])) { + std::swap(e[k], e[great]); + great--; + if (0 == compare(e[k], e[pivot1])) { + std::swap(e[k], e[less]); + less++; + } + } + } + } + + // subarray + if (compare(e[pivot1], e[pivot2]) < 0) { + DualPivotQuicksort(elements, less, great, div, compare); + } +} + +template +void DualPivotQuicksort(std::vector & elements, _Compare compare) { + DualPivotQuicksort(elements, 0, elements.size() - 1, 3, compare); +} + +} // namespace NativeTask + +#endif /* DUALPIVOTQUICKSORT_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Random.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Random.cc new file mode 100644 index 00000000000..6266b1f0492 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Random.cc @@ -0,0 +1,285 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "lib/commons.h" +#include "util/Random.h" + +namespace NativeTask { + +static long RandomInitializeID = 8682522807148012ULL; + +// A random list of 1000 words from /usr/share/dict/words +static const +char * Words[] = {"diurnalness", "Homoiousian", "spiranthic", "tetragynian", "silverhead", + "ungreat", "lithograph", "exploiter", "physiologian", "by", "hellbender", "Filipendula", + "undeterring", "antiscolic", "pentagamist", "hypoid", "cacuminal", "sertularian", + "schoolmasterism", "nonuple", "gallybeggar", "phytonic", "swearingly", "nebular", "Confervales", + "thermochemically", "characinoid", "cocksuredom", "fallacious", "feasibleness", "debromination", + "playfellowship", "tramplike", "testa", "participatingly", "unaccessible", "bromate", + "experientialist", "roughcast", "docimastical", "choralcelo", "blightbird", "peptonate", + "sombreroed", "unschematized", "antiabolitionist", "besagne", "mastication", "bromic", + "sviatonosite", "cattimandoo", "metaphrastical", "endotheliomyoma", "hysterolysis", + "unfulminated", "Hester", "oblongly", "blurredness", "authorling", "chasmy", "Scorpaenidae", + "toxihaemia", "Dictograph", "Quakerishly", "deaf", "timbermonger", "strammel", "Thraupidae", + "seditious", "plerome", "Arneb", "eristically", "serpentinic", "glaumrie", "socioromantic", + "apocalypst", "tartrous", "Bassaris", "angiolymphoma", "horsefly", "kenno", "astronomize", + "euphemious", "arsenide", "untongued", "parabolicness", "uvanite", "helpless", "gemmeous", + "stormy", "templar", "erythrodextrin", "comism", "interfraternal", "preparative", "parastas", + "frontoorbital", "Ophiosaurus", "diopside", "serosanguineous", "ununiformly", "karyological", + "collegian", "allotropic", "depravity", "amylogenesis", "reformatory", "epidymides", + "pleurotropous", "trillium", "dastardliness", "coadvice", "embryotic", "benthonic", + "pomiferous", "figureheadship", "Megaluridae", "Harpa", "frenal", "commotion", "abthainry", + "cobeliever", "manilla", "spiciferous", "nativeness", "obispo", "monilioid", "biopsic", + "valvula", "enterostomy", "planosubulate", "pterostigma", "lifter", "triradiated", "venialness", + "tum", "archistome", "tautness", "unswanlike", "antivenin", "Lentibulariaceae", "Triphora", + "angiopathy", "anta", "Dawsonia", "becomma", "Yannigan", "winterproof", "antalgol", "harr", + "underogating", "ineunt", "cornberry", "flippantness", "scyphostoma", "approbation", "Ghent", + "Macraucheniidae", "scabbiness", "unanatomized", "photoelasticity", "eurythermal", "enation", + "prepavement", "flushgate", "subsequentially", "Edo", "antihero", "Isokontae", "unforkedness", + "porriginous", "daytime", "nonexecutive", "trisilicic", "morphiomania", "paranephros", + "botchedly", "impugnation", "Dodecatheon", "obolus", "unburnt", "provedore", "Aktistetae", + "superindifference", "Alethea", "Joachimite", "cyanophilous", "chorograph", "brooky", "figured", + "periclitation", "quintette", "hondo", "ornithodelphous", "unefficient", "pondside", "bogydom", + "laurinoxylon", "Shiah", "unharmed", "cartful", "noncrystallized", "abusiveness", "cromlech", + "japanned", "rizzomed", "underskin", "adscendent", "allectory", "gelatinousness", "volcano", + "uncompromisingly", "cubit", "idiotize", "unfurbelowed", "undinted", "magnetooptics", "Savitar", + "diwata", "ramosopalmate", "Pishquow", "tomorn", "apopenptic", "Haversian", "Hysterocarpus", + "ten", "outhue", "Bertat", "mechanist", "asparaginic", "velaric", "tonsure", "bubble", + "Pyrales", "regardful", "glyphography", "calabazilla", "shellworker", "stradametrical", "havoc", + "theologicopolitical", "sawdust", "diatomaceous", "jajman", "temporomastoid", "Serrifera", + "Ochnaceae", "aspersor", "trailmaking", "Bishareen", "digitule", "octogynous", "epididymitis", + "smokefarthings", "bacillite", "overcrown", "mangonism", "sirrah", "undecorated", "psychofugal", + "bismuthiferous", "rechar", "Lemuridae", "frameable", "thiodiazole", "Scanic", + "sportswomanship", "interruptedness", "admissory", "osteopaedion", "tingly", "tomorrowness", + "ethnocracy", "trabecular", "vitally", "fossilism", "adz", "metopon", "prefatorial", + "expiscate", "diathermacy", "chronist", "nigh", "generalizable", "hysterogen", + "aurothiosulphuric", "whitlowwort", "downthrust", "Protestantize", "monander", "Itea", + "chronographic", "silicize", "Dunlop", "eer", "componental", "spot", "pamphlet", "antineuritic", + "paradisean", "interruptor", "debellator", "overcultured", "Florissant", "hyocholic", + "pneumatotherapy", "tailoress", "rave", "unpeople", "Sebastian", "thermanesthesia", "Coniferae", + "swacking", "posterishness", "ethmopalatal", "whittle", "analgize", "scabbardless", "naught", + "symbiogenetically", "trip", "parodist", "columniform", "trunnel", "yawler", "goodwill", + "pseudohalogen", "swangy", "cervisial", "mediateness", "genii", "imprescribable", "pony", + "consumptional", "carposporangial", "poleax", "bestill", "subfebrile", "sapphiric", "arrowworm", + "qualminess", "ultraobscure", "thorite", "Fouquieria", "Bermudian", "prescriber", "elemicin", + "warlike", "semiangle", "rotular", "misthread", "returnability", "seraphism", "precostal", + "quarried", "Babylonism", "sangaree", "seelful", "placatory", "pachydermous", "bozal", + "galbulus", "spermaphyte", "cumbrousness", "pope", "signifier", "Endomycetaceae", "shallowish", + "sequacity", "periarthritis", "bathysphere", "pentosuria", "Dadaism", "spookdom", + "Consolamentum", "afterpressure", "mutter", "louse", "ovoviviparous", "corbel", "metastoma", + "biventer", "Hydrangea", "hogmace", "seizing", "nonsuppressed", "oratorize", "uncarefully", + "benzothiofuran", "penult", "balanocele", "macropterous", "dishpan", "marten", "absvolt", + "jirble", "parmelioid", "airfreighter", "acocotl", "archesporial", "hypoplastral", "preoral", + "quailberry", "cinque", "terrestrially", "stroking", "limpet", "moodishness", "canicule", + "archididascalian", "pompiloid", "overstaid", "introducer", "Italical", "Christianopaganism", + "prescriptible", "subofficer", "danseuse", "cloy", "saguran", "frictionlessly", + "deindividualization", "Bulanda", "ventricous", "subfoliar", "basto", "scapuloradial", + "suspend", "stiffish", "Sphenodontidae", "eternal", "verbid", "mammonish", "upcushion", + "barkometer", "concretion", "preagitate", "incomprehensible", "tristich", "visceral", + "hemimelus", "patroller", "stentorophonic", "pinulus", "kerykeion", "brutism", "monstership", + "merciful", "overinstruct", "defensibly", "bettermost", "splenauxe", "Mormyrus", + "unreprimanded", "taver", "ell", "proacquittal", "infestation", "overwoven", "Lincolnlike", + "chacona", "Tamil", "classificational", "lebensraum", "reeveland", "intuition", "Whilkut", + "focaloid", "Eleusinian", "micromembrane", "byroad", "nonrepetition", "bacterioblast", "brag", + "ribaldrous", "phytoma", "counteralliance", "pelvimetry", "pelf", "relaster", "thermoresistant", + "aneurism", "molossic", "euphonym", "upswell", "ladhood", "phallaceous", "inertly", "gunshop", + "stereotypography", "laryngic", "refasten", "twinling", "oflete", "hepatorrhaphy", + "electrotechnics", "cockal", "guitarist", "topsail", "Cimmerianism", "larklike", "Llandovery", + "pyrocatechol", "immatchable", "chooser", "metrocratic", "craglike", "quadrennial", + "nonpoisonous", "undercolored", "knob", "ultratense", "balladmonger", "slait", "sialadenitis", + "bucketer", "magnificently", "unstipulated", "unscourged", "unsupercilious", "packsack", + "pansophism", "soorkee", "percent", "subirrigate", "champer", "metapolitics", "spherulitic", + "involatile", "metaphonical", "stachyuraceous", "speckedness", "bespin", "proboscidiform", + "gul", "squit", "yeelaman", "peristeropode", "opacousness", "shibuichi", "retinize", "yote", + "misexposition", "devilwise", "pumpkinification", "vinny", "bonze", "glossing", "decardinalize", + "transcortical", "serphoid", "deepmost", "guanajuatite", "wemless", "arval", "lammy", "Effie", + "Saponaria", "tetrahedral", "prolificy", "excerpt", "dunkadoo", "Spencerism", "insatiately", + "Gilaki", "oratorship", "arduousness", "unbashfulness", "Pithecolobium", "unisexuality", + "veterinarian", "detractive", "liquidity", "acidophile", "proauction", "sural", "totaquina", + "Vichyite", "uninhabitedness", "allegedly", "Gothish", "manny", "Inger", "flutist", "ticktick", + "Ludgatian", "homotransplant", "orthopedical", "diminutively", "monogoneutic", "Kenipsim", + "sarcologist", "drome", "stronghearted", "Fameuse", "Swaziland", "alen", "chilblain", + "beatable", "agglomeratic", "constitutor", "tendomucoid", "porencephalous", "arteriasis", + "boser", "tantivy", "rede", "lineamental", "uncontradictableness", "homeotypical", "masa", + "folious", "dosseret", "neurodegenerative", "subtransverse", "Chiasmodontidae", + "palaeotheriodont", "unstressedly", "chalcites", "piquantness", "lampyrine", "Aplacentalia", + "projecting", "elastivity", "isopelletierin", "bladderwort", "strander", "almud", + "iniquitously", "theologal", "bugre", "chargeably", "imperceptivity", "meriquinoidal", + "mesophyte", "divinator", "perfunctory", "counterappellant", "synovial", "charioteer", + "crystallographical", "comprovincial", "infrastapedial", "pleasurehood", "inventurous", + "ultrasystematic", "subangulated", "supraoesophageal", "Vaishnavism", "transude", + "chrysochrous", "ungrave", "reconciliable", "uninterpleaded", "erlking", "wherefrom", + "aprosopia", "antiadiaphorist", "metoxazine", "incalculable", "umbellic", "predebit", + "foursquare", "unimmortal", "nonmanufacture", "slangy", "predisputant", "familist", + "preaffiliate", "friarhood", "corelysis", "zoonitic", "halloo", "paunchy", "neuromimesis", + "aconitine", "hackneyed", "unfeeble", "cubby", "autoschediastical", "naprapath", "lyrebird", + "inexistency", "leucophoenicite", "ferrogoslarite", "reperuse", "uncombable", "tambo", + "propodiale", "diplomatize", "Russifier", "clanned", "corona", "michigan", "nonutilitarian", + "transcorporeal", "bought", "Cercosporella", "stapedius", "glandularly", "pictorially", "weism", + "disilane", "rainproof", "Caphtor", "scrubbed", "oinomancy", "pseudoxanthine", "nonlustrous", + "redesertion", "Oryzorictinae", "gala", "Mycogone", "reappreciate", "cyanoguanidine", + "seeingness", "breadwinner", "noreast", "furacious", "epauliere", "omniscribent", + "Passiflorales", "uninductive", "inductivity", "Orbitolina", "Semecarpus", "migrainoid", + "steprelationship", "phlogisticate", "mesymnion", "sloped", "edificator", "beneficent", "culm", + "paleornithology", "unurban", "throbless", "amplexifoliate", "sesquiquintile", "sapience", + "astucious", "dithery", "boor", "ambitus", "scotching", "uloid", "uncompromisingness", "hoove", + "waird", "marshiness", "Jerusalem", "mericarp", "unevoked", "benzoperoxide", "outguess", + "pyxie", "hymnic", "euphemize", "mendacity", "erythremia", "rosaniline", "unchatteled", + "lienteria", "Bushongo", "dialoguer", "unrepealably", "rivethead", "antideflation", + "vinegarish", "manganosiderite", "doubtingness", "ovopyriform", "Cephalodiscus", "Muscicapa", + "Animalivora", "angina", "planispheric", "ipomoein", "cuproiodargyrite", "sandbox", "scrat", + "Munnopsidae", "shola", "pentafid", "overstudiousness", "times", "nonprofession", "appetible", + "valvulotomy", "goladar", "uniarticular", "oxyterpene", "unlapsing", "omega", "trophonema", + "seminonflammable", "circumzenithal", "starer", "depthwise", "liberatress", "unleavened", + "unrevolting", "groundneedle", "topline", "wandoo", "umangite", "ordinant", "unachievable", + "oversand", "snare", "avengeful", "unexplicit", "mustafina", "sonable", "rehabilitative", + "eulogization", "papery", "technopsychology", "impressor", "cresylite", "entame", + "transudatory", "scotale", "pachydermatoid", "imaginary", "yeat", "slipped", "stewardship", + "adatom", "cockstone", "skyshine", "heavenful", "comparability", "exprobratory", + "dermorhynchous", "parquet", "cretaceous", "vesperal", "raphis", "undangered", "Glecoma", + "engrain", "counteractively", "Zuludom", "orchiocatabasis", "Auriculariales", "warriorwise", + "extraorganismal", "overbuilt", "alveolite", "tetchy", "terrificness", "widdle", + "unpremonished", "rebilling", "sequestrum", "equiconvex", "heliocentricism", "catabaptist", + "okonite", "propheticism", "helminthagogic", "calycular", "giantly", "wingable", "golem", + "unprovided", "commandingness", "greave", "haply", "doina", "depressingly", "subdentate", + "impairment", "decidable", "neurotrophic", "unpredict", "bicorporeal", "pendulant", "flatman", + "intrabred", "toplike", "Prosobranchiata", "farrantly", "toxoplasmosis", "gorilloid", + "dipsomaniacal", "aquiline", "atlantite", "ascitic", "perculsive", "prospectiveness", + "saponaceous", "centrifugalization", "dinical", "infravaginal", "beadroll", "affaite", + "Helvidian", "tickleproof", "abstractionism", "enhedge", "outwealth", "overcontribute", + "coldfinch", "gymnastic", "Pincian", "Munychian", "codisjunct", "quad", "coracomandibular", + "phoenicochroite", "amender", "selectivity", "putative", "semantician", "lophotrichic", + "Spatangoidea", "saccharogenic", "inferent", "Triconodonta", "arrendation", "sheepskin", + "taurocolla", "bunghole", "Machiavel", "triakistetrahedral", "dehairer", "prezygapophysial", + "cylindric", "pneumonalgia", "sleigher", "emir", "Socraticism", "licitness", "massedly", + "instructiveness", "sturdied", "redecrease", "starosta", "evictor", "orgiastic", "squdge", + "meloplasty", "Tsonecan", "repealableness", "swoony", "myesthesia", "molecule", + "autobiographist", "reciprocation", "refective", "unobservantness", "tricae", "ungouged", + "floatability", "Mesua", "fetlocked", "chordacentrum", "sedentariness", "various", "laubanite", + "nectopod", "zenick", "sequentially", "analgic", "biodynamics", "posttraumatic", "nummi", + "pyroacetic", "bot", "redescend", "dispermy", "undiffusive", "circular", "trillion", + "Uraniidae", "ploration", "discipular", "potentness", "sud", "Hu", "Eryon", "plugger", + "subdrainage", "jharal", "abscission", "supermarket", "countergabion", "glacierist", + "lithotresis", "minniebush", "zanyism", "eucalypteol", "sterilely", "unrealize", "unpatched", + "hypochondriacism", "critically", "cheesecutter", }; + +static size_t WordsCount = sizeof(Words) / sizeof(char *); + +Random::Random() { + setSeed(time(NULL) + clock() + RandomInitializeID++); +} + +Random::Random(int64_t seed) { + if (seed == -1) { + setSeed(time(NULL) + clock() + RandomInitializeID++); + } else { + setSeed(seed); + } +} + +Random::~Random() { + +} + +void Random::setSeed(int64_t seed) { + _seed = (seed ^ multiplier) & mask; +} + +int32_t Random::next(int bits) { + _seed = (_seed * multiplier + addend) & mask; + return (int32_t)(_seed >> (48 - bits)); +} + +int32_t Random::next_int32() { + return next(32); +} + +uint32_t Random::next_uint32() { + return (uint32_t)next(32); +} + +uint64_t Random::next_uint64() { + return ((uint64_t)(next(32)) << 32) + next(32); +} + +int32_t Random::next_int32(int32_t n) { + if ((n & -n) == n) // i.e., n is a power of 2 + return (int32_t)((n * (int64_t)next(31)) >> 31); + + int32_t bits, val; + do { + bits = next(31); + val = bits % n; + } while (bits - val + (n - 1) < 0); + return val; +} + +float Random::nextFloat() { + return next(24) / ((float)(1 << 24)); +} + +double Random::nextDouble() { + return (((uint64_t)(next(26)) << 27) + next(27)) / (double)(1L << 53); +} + +uint64_t Random::nextLog2() { + return (uint64_t)exp2(nextDouble() * 64); +} + +uint64_t Random::nextLog2(uint64_t range) { + double range_r = log2(range); + double v = nextDouble() * range_r; + return (uint64_t)exp2(v); +} + +uint64_t Random::nextLog10(uint64_t range) { + double range_r = log10(range); + double v = nextDouble() * range_r; + return (uint64_t)pow(10, v); +} + +char Random::nextByte(const string & range) { + if (range.length() == 0) { + return (char)next(8); + } else { + return range[next_int32(range.length())]; + } +} + +string Random::nextBytes(uint32_t length, const string & range) { + string ret(length, '-'); + for (uint32_t i = 0; i < length; i++) { + ret[i] = nextByte(range); + } + return ret; +} + +const char * Random::nextWord(int64_t limit) { + if (limit < 0) { + return Words[next_int32(WordsCount)]; + } + uint32_t r = limit < WordsCount ? limit : WordsCount; + return Words[next_int32(r)]; +} + +void Random::nextWord(string & dest, int64_t limit) { + dest = nextWord(limit); +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Random.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Random.h new file mode 100644 index 00000000000..9f062e097da --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Random.h @@ -0,0 +1,140 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RANDOM_H_ +#define RANDOM_H_ + +#include +#include + +namespace NativeTask { + +using std::string; + +/** + * Copy of java.lang.Random & some random text/bytes generator + */ +class Random { +protected: + static const int64_t multiplier = 0x5DEECE66DULL; + static const int64_t addend = 0xBL; + static const int64_t mask = (1ULL << 48) - 1; +protected: + int64_t _seed; + + int32_t next(int bits); +public: + Random(); + + Random(int64_t seed); + + ~Random(); + + /** + * Set random seed + */ + void setSeed(int64_t seed); + + /** + * Returns uniformly distributed uint32_t in [INT_MIN, INT_MAX] + */ + int32_t next_int32(); + + /** + * Returns uniformly distributed uint32_t in [0,(uint32_t)-1) + */ + uint32_t next_uint32(); + + /** + * Returns uniformly distributed uint64_t in [0,(uint64_t)-1) + */ + uint64_t next_uint64(); + + /** + * Returns uniformly distributed int32_t in [0,n) + */ + int32_t next_int32(int32_t n); + + /** + * Returns the next pseudorandom, uniformly distributed + * {@code float} value between {@code 0.0} and + * {@code 1.0} from this random number generator's sequence. + */ + float nextFloat(); + + /** + * Returns the next pseudorandom, uniformly distributed + * {@code double} value between {@code 0.0} and + * {@code 1.0} from this random number generator's sequence. + */ + double nextDouble(); + + /** + * Returns the next pseudorandom, log2-normal distributed + * value between [0, MAX_UNIT64] + */ + uint64_t nextLog2(); + + /** + * Returns the next pseudorandom, log2-normal distributed + * value between [0, range] + */ + uint64_t nextLog2(uint64_t range); + + /** + * Returns the next pseudorandom, log10-normal distributed + * value between [0, range] + */ + uint64_t nextLog10(uint64_t range); + + /** + * Returns uniformly distributed byte in range + * @param range e.g. "ABCDEFG", "01234566789" + */ + char nextByte(const string & range); + + /** + * Return byte sequence of length + * each byte in the sequence is generated using + * nextByte + */ + string nextBytes(uint32_t length, const string & range); + + /** + * Generate random word from a 100 word collection(same + * as RandomTextWriter), Just a utility function to + * construct the test data. + * @param limit use first limit words in + * the word collection + */ + const char * nextWord(int64_t limit = -1); + + /** + * Generate random word from a 100 word collection(same + * as RandomTextWriter), Just a utility function to + * construct the test data. + * @param dest assign the generated word to dest + * @param limit use first limit words in + * the word collection + */ + void nextWord(string & dest, int64_t limit = -1); +}; + +} // namespace NativeTask + +#endif /* RANDOM_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/StringUtil.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/StringUtil.cc new file mode 100644 index 00000000000..3ed74356bda --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/StringUtil.cc @@ -0,0 +1,213 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "lib/commons.h" +#include "util/StringUtil.h" + +namespace NativeTask { + +string StringUtil::ToString(int32_t v) { + char tmp[32]; + snprintf(tmp, 32, "%d", v); + return tmp; +} + +string StringUtil::ToString(uint32_t v) { + char tmp[32]; + snprintf(tmp, 32, "%u", v); + return tmp; +} + +string StringUtil::ToString(int64_t v) { + char tmp[32]; + snprintf(tmp, 32, "%"PRId64, v); + return tmp; +} + +string StringUtil::ToString(int64_t v, char pad, int64_t len) { + char tmp[32]; + snprintf(tmp, 32, "%%%c%"PRId64""PRId64, pad, len); + return Format(tmp, v); +} + +string StringUtil::ToString(uint64_t v) { + char tmp[32]; + snprintf(tmp, 32, "%"PRIu64, v); + return tmp; +} + +string StringUtil::ToString(bool v) { + if (v) { + return "true"; + } else { + return "false"; + } +} + +string StringUtil::ToString(float v) { + return Format("%f", v); +} + +string StringUtil::ToString(double v) { + return Format("%lf", v); +} + +string StringUtil::ToHexString(const void * v, uint32_t len) { + string ret = string(len * 2, '0'); + for (uint32_t i = 0; i < len; i++) { + snprintf(&(ret[i*2]), 3, "%02x", ((char*)v)[i]); + } + return ret; +} + +bool StringUtil::toBool(const string & str) { + if (str == "true") { + return true; + } else { + return false; + } +} + +int64_t StringUtil::toInt(const string & str) { + return strtoll(str.c_str(), NULL, 10); +} + +float StringUtil::toFloat(const string & str) { + return strtof(str.c_str(), NULL); +} + +string StringUtil::Format(const char * fmt, ...) { + char tmp[256]; + string dest; + va_list al; + va_start(al, fmt); + int len = vsnprintf(tmp, 255, fmt, al); + va_end(al); + if (len > 255) { + char * destbuff = new char[len + 1]; + va_start(al, fmt); + len = vsnprintf(destbuff, len + 1, fmt, al); + va_end(al); + dest.append(destbuff, len); + delete [] destbuff; + } else { + dest.append(tmp, len); + } + return dest; +} + +void StringUtil::Format(string & dest, const char * fmt, ...) { + char tmp[256]; + va_list al; + va_start(al, fmt); + int len = vsnprintf(tmp, 255, fmt, al); + if (len > 255) { + char * destbuff = new char[len + 1]; + len = vsnprintf(destbuff, len + 1, fmt, al); + dest.append(destbuff, len); + } else { + dest.append(tmp, len); + } + va_end(al); +} + +string StringUtil::ToLower(const string & name) { + string ret = name; + for (size_t i = 0; i < ret.length(); i++) { + ret.at(i) = ::tolower(ret[i]); + } + return ret; +} + +string StringUtil::Trim(const string & str) { + if (str.length() == 0) { + return str; + } + size_t l = 0; + while (l < str.length() && isspace(str[l])) { + l++; + } + if (l >= str.length()) { + return string(); + } + size_t r = str.length(); + while (isspace(str[r - 1])) { + r--; + } + return str.substr(l, r - l); +} + +void StringUtil::Split(const string & src, const string & sep, vector & dest, bool clean) { + if (sep.length() == 0) { + return; + } + size_t cur = 0; + while (true) { + size_t pos; + if (sep.length() == 1) { + pos = src.find(sep[0], cur); + } else { + pos = src.find(sep, cur); + } + string add = src.substr(cur, pos - cur); + if (clean) { + string trimed = Trim(add); + if (trimed.length() > 0) { + dest.push_back(trimed); + } + } else { + dest.push_back(add); + } + if (pos == string::npos) { + break; + } + cur = pos + sep.length(); + } +} + +string StringUtil::Join(const vector & strs, const string & sep) { + string ret; + for (size_t i = 0; i < strs.size(); i++) { + if (i > 0) { + ret.append(sep); + } + ret.append(strs[i]); + } + return ret; +} + +bool StringUtil::StartsWith(const string & str, const string & prefix) { + if ((prefix.length() > str.length()) + || (memcmp(str.data(), prefix.data(), prefix.length()) != 0)) { + return false; + } + return true; +} + +bool StringUtil::EndsWith(const string & str, const string & suffix) { + if ((suffix.length() > str.length()) || + (memcmp(str.data() + str.length() - suffix.length(), + suffix.data(), suffix.length()) != 0)) { + return false; + } + return true; +} + +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/StringUtil.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/StringUtil.h new file mode 100644 index 00000000000..05904d40a37 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/StringUtil.h @@ -0,0 +1,66 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef STRINGUTIL_H_ +#define STRINGUTIL_H_ + +#include +#include +#include + +namespace NativeTask { + +using std::vector; +using std::string; + +class StringUtil { +public: + static string ToString(int32_t v); + static string ToString(uint32_t v); + static string ToString(int64_t v); + static string ToString(int64_t v, char pad, int64_t len); + static string ToString(uint64_t v); + static string ToString(bool v); + static string ToString(float v); + static string ToString(double v); + static string ToHexString(const void * v, uint32_t len); + + static int64_t toInt(const string & str); + static bool toBool(const string & str); + static float toFloat(const string & str); + + static string Format(const char * fmt, ...); + + static void Format(string & dest, const char * fmt, ...); + + static string ToLower(const string & name); + + static string Trim(const string & str); + + static void Split(const string & src, const string & sep, vector & dest, + bool clean = false); + + static string Join(const vector & strs, const string & sep); + + static bool StartsWith(const string & str, const string & prefix); + static bool EndsWith(const string & str, const string & suffix); +}; + +} // namespace NativeTask + +#endif /* STRINGUTIL_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/SyncUtils.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/SyncUtils.cc new file mode 100644 index 00000000000..357a68d0003 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/SyncUtils.cc @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/jniutils.h" +#include "util/StringUtil.h" +#include "util/SyncUtils.h" + +namespace NativeTask { + +static void PthreadCall(const char* label, int result) { + if (result != 0) { + THROW_EXCEPTION_EX(IOException, "pthread %s: %s", label, strerror(result)); + } +} + +Lock::Lock() { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + int ret = pthread_mutex_init(&_mutex, &attr); + pthread_mutexattr_destroy(&attr); + if (ret != 0) { + THROW_EXCEPTION_EX(IOException, "pthread_mutex_init: %s", strerror(ret)); + } +} + +Lock::~Lock() { + PthreadCall("destroy mutex", pthread_mutex_destroy(&_mutex)); +} + +void Lock::lock() { + PthreadCall("lock", pthread_mutex_lock(&_mutex)); +} + +void Lock::unlock() { + PthreadCall("unlock", pthread_mutex_unlock(&_mutex)); +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/SyncUtils.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/SyncUtils.h new file mode 100644 index 00000000000..270f8517fb4 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/SyncUtils.h @@ -0,0 +1,71 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SYNCUTILS_H_ +#define SYNCUTILS_H_ + +#include +#include +#ifdef __MACH__ +#include +#endif +#include + +namespace NativeTask { + +class Condition; + +class Lock { +public: + Lock(); + ~Lock(); + + void lock(); + void unlock(); + +private: + friend class Condition; + pthread_mutex_t _mutex; + + // No copying + Lock(const Lock&); + void operator=(const Lock&); +}; + +template +class ScopeLock { +public: + ScopeLock(LockT & lock) + : _lock(&lock) { + _lock->lock(); + } + ~ScopeLock() { + _lock->unlock(); + } +private: + LockT * _lock; + + // No copying + ScopeLock(const ScopeLock&); + void operator=(const ScopeLock&); +}; + + +} // namespace NativeTask + +#endif /* SYNCUTILS_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Timer.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Timer.cc new file mode 100644 index 00000000000..9f8a9ad3151 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Timer.cc @@ -0,0 +1,116 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "lib/commons.h" +#include "util/StringUtil.h" +#include "util/Timer.h" + +namespace NativeTask { + +#ifdef __MACH__ +#include +#include + +static uint64_t clock_get() { + clock_serv_t cclock; + mach_timespec_t mts; + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + return 1000000000ULL * mts.tv_sec + mts.tv_nsec; +} + +#else + +static uint64_t clock_get() { + timespec ts; + clock_gettime(_POSIX_CPUTIME, &ts); + return 1000000000 * ts.tv_sec + ts.tv_nsec; +} + +#endif + +Timer::Timer() { + _last = clock_get(); +} + +Timer::~Timer() { +} + +uint64_t Timer::last() { + return _last; +} + +uint64_t Timer::now() { + return clock_get(); +} + +void Timer::reset() { + _last = clock_get(); +} + +string Timer::getInterval(const char * msg) { + uint64_t now = clock_get(); + uint64_t interval = now - _last; + _last = now; + return StringUtil::Format("%s time: %.5lfs", msg, (double)interval / 1000000000.0); +} + +string Timer::getSpeed(const char * msg, uint64_t size) { + uint64_t now = clock_get(); + double interval = (now - _last) / 1000000000.0; + _last = now; + double speed = size / interval; + return StringUtil::Format("%s time:\t %3.5lfs size: %10llu speed: %12.0lf/s", msg, interval, size, + speed); +} + +string Timer::getSpeedM(const char * msg, uint64_t size) { + uint64_t now = clock_get(); + double interval = (now - _last) / 1000000000.0; + _last = now; + double msize = size / (1024.0 * 1024.0); + double speed = msize / interval; + return StringUtil::Format("%s time: %3.5lfs size: %.3lfM speed: %.2lfM/s", msg, interval, msize, + speed); +} + +string Timer::getSpeed2(const char * msg, uint64_t size1, uint64_t size2) { + uint64_t now = clock_get(); + double interval = (now - _last) / 1000000000.0; + _last = now; + double speed1 = size1 / interval; + double speed2 = size2 / interval; + return StringUtil::Format("%s time: %3.5lfs size: %llu/%llu speed: %.0lf/%.0lf", msg, interval, + size1, size2, speed1, speed2); +} + +string Timer::getSpeedM2(const char * msg, uint64_t size1, uint64_t size2) { + uint64_t now = clock_get(); + double interval = (now - _last) / 1000000000.0; + _last = now; + double msize1 = size1 / (1024.0 * 1024.0); + double speed1 = msize1 / interval; + double msize2 = size2 / (1024.0 * 1024.0); + double speed2 = msize2 / interval; + return StringUtil::Format("%s time: %3.5lfs size: %.3lfM/%.3lfM speed: %.2lfM/%.2lfM", msg, + interval, msize1, msize2, speed1, speed2); +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Timer.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Timer.h new file mode 100644 index 00000000000..c26e2e43d82 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/Timer.h @@ -0,0 +1,56 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TIMER_H_ +#define TIMER_H_ + +#include +#include +#include + +namespace NativeTask { + +using std::string; + +class Timer { +protected: + uint64_t _last; +public: + Timer(); + ~Timer(); + + uint64_t last(); + + uint64_t now(); + + void reset(); + + string getInterval(const char * msg); + + string getSpeed(const char * msg, uint64_t size); + + string getSpeed2(const char * msg, uint64_t size1, uint64_t size2); + + string getSpeedM(const char * msg, uint64_t size); + + string getSpeedM2(const char * msg, uint64_t size1, uint64_t size2); +}; + +} // namespace NativeTask + +#endif /* TIMER_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/WritableUtils.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/WritableUtils.cc new file mode 100644 index 00000000000..243668117b3 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/WritableUtils.cc @@ -0,0 +1,309 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "util/StringUtil.h" +#include "util/WritableUtils.h" + +namespace NativeTask { + +KeyValueType JavaClassToKeyValueType(const std::string & clazz) { + if (clazz == "org.apache.hadoop.io.Text") { + return TextType; + } + if (clazz == "org.apache.hadoop.io.BytesWritable") { + return BytesType; + } + if (clazz == "org.apache.hadoop.io.ByteWritable") { + return ByteType; + } + if (clazz == "org.apache.hadoop.io.BooleanWritable") { + return BoolType; + } + if (clazz == "org.apache.hadoop.io.IntWritable") { + return IntType; + } + if (clazz == "org.apache.hadoop.io.LongWritable") { + return LongType; + } + if (clazz == "org.apache.hadoop.io.FloatWritable") { + return FloatType; + } + if (clazz == "org.apache.hadoop.io.DoubleWritable") { + return DoubleType; + } + if (clazz == "org.apache.hadoop.io.MD5Hash") { + return MD5HashType; + } + if (clazz == "org.apache.hadoop.io.VIntWritable") { + return VIntType; + } + if (clazz == "org.apache.hadoop.io.VLongWritable") { + return VLongType; + } + return UnknownType; +} + +int64_t WritableUtils::ReadVLongInner(const char * pos, uint32_t & len) { + bool neg = *pos < -120; + len = neg ? (-119 - *pos) : (-111 - *pos); + const char * end = pos + len; + int64_t value = 0; + while (++pos < end) { + value = (value << 8) | *(uint8_t*)pos; + } + return neg ? (value ^ -1LL) : value; +} + +uint32_t WritableUtils::GetVLongSizeInner(int64_t value) { + if (value < 0) { + value ^= -1L; // take one's complement' + } + + if (value < (1LL << 8)) { + return 2; + } else if (value < (1LL << 16)) { + return 3; + } else if (value < (1LL << 24)) { + return 4; + } else if (value < (1LL << 32)) { + return 5; + } else if (value < (1LL << 40)) { + return 6; + } else if (value < (1LL << 48)) { + return 7; + } else if (value < (1LL << 56)) { + return 8; + } else { + return 9; + } +} + +void WritableUtils::WriteVLongInner(int64_t v, char * pos, uint32_t & len) { + char base; + if (v >= 0) { + base = -113; + } else { + v ^= -1L; // take one's complement + base = -121; + } + uint64_t value = v; + if (value < (1 << 8)) { + *(pos++) = base; + *(uint8_t*)(pos) = value; + len = 2; + } else if (value < (1 << 16)) { + *(pos++) = base - 1; + *(uint8_t*)(pos++) = value >> 8; + *(uint8_t*)(pos) = value; + len = 3; + } else if (value < (1 << 24)) { + *(pos++) = base - 2; + *(uint8_t*)(pos++) = value >> 16; + *(uint8_t*)(pos++) = value >> 8; + *(uint8_t*)(pos) = value; + len = 4; + } else if (value < (1ULL << 32)) { + *(pos++) = base - 3; + *(uint32_t*)(pos) = bswap((uint32_t)value); + len = 5; + } else if (value < (1ULL << 40)) { + *(pos++) = base - 4; + *(uint32_t*)(pos) = bswap((uint32_t)(value >> 8)); + *(uint8_t*)(pos + 4) = value; + len = 6; + } else if (value < (1ULL << 48)) { + *(pos++) = base - 5; + *(uint32_t*)(pos) = bswap((uint32_t)(value >> 16)); + *(uint8_t*)(pos + 4) = value >> 8; + *(uint8_t*)(pos + 5) = value; + len = 7; + } else if (value < (1ULL << 56)) { + *(pos++) = base - 6; + *(uint32_t*)(pos) = bswap((uint32_t)(value >> 24)); + *(uint8_t*)(pos + 4) = value >> 16; + *(uint8_t*)(pos + 5) = value >> 8; + *(uint8_t*)(pos + 6) = value; + len = 8; + } else { + *(pos++) = base - 7; + *(uint64_t*)pos = bswap64(value); + len = 9; + } +} + +// Stream interfaces +int64_t WritableUtils::ReadVLong(InputStream * stream) { + char buff[10]; + if (stream->read(buff, 1) != 1) { + THROW_EXCEPTION(IOException, "ReadVLong reach EOF"); + } + uint32_t len = DecodeVLongSize(buff); + if (len > 1) { + if (stream->readFully(buff + 1, len - 1) != len - 1) { + THROW_EXCEPTION(IOException, "ReadVLong reach EOF"); + } + } + return ReadVLong(buff, len); +} + +int64_t WritableUtils::ReadLong(InputStream * stream) { + int64_t ret; + if (stream->readFully(&ret, 8) != 8) { + THROW_EXCEPTION(IOException, "ReadLong reach EOF"); + } + return (int64_t)bswap64(ret); +} + +int32_t WritableUtils::ReadInt(InputStream * stream) { + int32_t ret; + if (stream->readFully(&ret, 4) != 4) { + THROW_EXCEPTION(IOException, "ReadInt reach EOF"); + } + return (int32_t)bswap(ret); +} + +int16_t WritableUtils::ReadShort(InputStream * stream) { + uint16_t ret; + if (stream->readFully(&ret, 2) != 2) { + THROW_EXCEPTION(IOException, "ReadShort reach EOF"); + } + return (int16_t)((ret >> 8) | (ret << 8)); +} + +float WritableUtils::ReadFloat(InputStream * stream) { + uint32_t ret; + if (stream->readFully(&ret, 4) != 4) { + THROW_EXCEPTION(IOException, "ReadFloat reach EOF"); + } + ret = bswap(ret); + return *(float*)&ret; +} + +string WritableUtils::ReadText(InputStream * stream) { + int64_t len = ReadVLong(stream); + string ret = string(len, '\0'); + if (stream->readFully((void *)ret.data(), len) != len) { + THROW_EXCEPTION_EX(IOException, "ReadString reach EOF, need %d", len); + } + return ret; +} + +string WritableUtils::ReadBytes(InputStream * stream) { + int32_t len = ReadInt(stream); + string ret = string(len, '\0'); + if (stream->readFully((void *)ret.data(), len) != len) { + THROW_EXCEPTION_EX(IOException, "ReadString reach EOF, need %d", len); + } + return ret; +} + +string WritableUtils::ReadUTF8(InputStream * stream) { + int16_t len = ReadShort(stream); + string ret = string(len, '\0'); + if (stream->readFully((void *)ret.data(), len) != len) { + THROW_EXCEPTION_EX(IOException, "ReadString reach EOF, need %d", len); + } + return ret; +} + + +void WritableUtils::WriteVLong(OutputStream * stream, int64_t v) { + char buff[10]; + uint32_t len; + WriteVLong(v, buff, len); + stream->write(buff, len); +} + +void WritableUtils::WriteLong(OutputStream * stream, int64_t v) { + uint64_t be = bswap64((uint64_t)v); + stream->write(&be, 8); +} + +void WritableUtils::WriteInt(OutputStream * stream, int32_t v) { + uint32_t be = bswap((uint32_t)v); + stream->write(&be, 4); +} + +void WritableUtils::WriteShort(OutputStream * stream, int16_t v) { + uint16_t be = v; + be = ((be >> 8) | (be << 8)); + stream->write(&be, 2); +} + +void WritableUtils::WriteFloat(OutputStream * stream, float v) { + uint32_t intv = *(uint32_t*)&v; + intv = bswap(intv); + stream->write(&intv, 4); +} + +void WritableUtils::WriteText(OutputStream * stream, const string & v) { + WriteVLong(stream, v.length()); + stream->write(v.c_str(), (uint32_t)v.length()); +} + +void WritableUtils::WriteBytes(OutputStream * stream, const string & v) { + WriteInt(stream, (int32_t)v.length()); + stream->write(v.c_str(), (uint32_t)v.length()); +} + +void WritableUtils::WriteUTF8(OutputStream * stream, const string & v) { + if (v.length() > 65535) { + THROW_EXCEPTION_EX(IOException, "string too long (%lu) for WriteUTF8", v.length()); + } + WriteShort(stream, (int16_t)v.length()); + stream->write(v.c_str(), (uint32_t)v.length()); +} + +void WritableUtils::toString(string & dest, KeyValueType type, const void * data, uint32_t length) { + switch (type) { + case TextType: + dest.append((const char*)data, length); + break; + case BytesType: + dest.append((const char*)data, length); + break; + case ByteType: + dest.append(1, *(char*)data); + break; + case BoolType: + dest.append(*(uint8_t*)data ? "true" : "false"); + break; + case IntType: + dest.append(StringUtil::ToString((int32_t)bswap(*(uint32_t*)data))); + break; + case LongType: + dest.append(StringUtil::ToString((int64_t)bswap64(*(uint64_t*)data))); + break; + case FloatType: + dest.append(StringUtil::ToString(*(float*)data)); + break; + case DoubleType: + dest.append(StringUtil::ToString(*(double*)data)); + break; + case MD5HashType: + dest.append(StringUtil::ToHexString(data, length)); + break; + default: + dest.append((const char*)data, length); + break; + } +} + +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/WritableUtils.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/WritableUtils.h new file mode 100644 index 00000000000..24a2b1be868 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/src/util/WritableUtils.h @@ -0,0 +1,124 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WRITABLEUTILS_H_ +#define WRITABLEUTILS_H_ + +#include +#include +#include "lib/Streams.h" +#include "NativeTask.h" + +namespace NativeTask { + +KeyValueType JavaClassToKeyValueType(const std::string & clazz); + +using std::string; + +class WritableUtils { +protected: + static int64_t ReadVLongInner(const char * pos, uint32_t & len); + static void WriteVLongInner(int64_t value, char * pos, uint32_t & len); + static uint32_t GetVLongSizeInner(int64_t value); +public: + inline static uint32_t DecodeVLongSize(int8_t ch) { + if (ch >= -112) { + return 1; + } else if (ch < -120) { + return -119 - ch; + } + return -111 - ch; + } + + inline static uint32_t DecodeVLongSize(const char * pos) { + return DecodeVLongSize(*pos); + } + + inline static uint32_t GetVLongSize(int64_t value) { + if (value >= -112 && value <= 127) { + return 1; + } + return GetVLongSizeInner(value); + } + + inline static int64_t ReadVLong(const char * pos, uint32_t & len) { + if (*pos >= (char)-112) { + len = 1; + return *pos; + } else { + return ReadVLongInner(pos, len); + } + } + + inline static int32_t ReadVInt(const char * pos, uint32_t & len) { + return (int32_t)ReadVLong(pos, len); + } + + inline static void WriteVLong(int64_t v, char * target, uint32_t & written) { + if (v <= 127 && v >= -112) { + written = 1; + *target = (char)v; + } else { + WriteVLongInner(v, target, written); + } + } + + inline static void WriteVInt(int32_t v, char * target, uint32_t & written) { + WriteVLong(v, target, written); + } + + // Stream interfaces + static int64_t ReadVLong(InputStream * stream); + + static int64_t ReadLong(InputStream * stream); + + static int32_t ReadInt(InputStream * stream); + + static int16_t ReadShort(InputStream * stream); + + static float ReadFloat(InputStream * stream); + + static string ReadText(InputStream * stream); + + static string ReadBytes(InputStream * stream); + + static string ReadUTF8(InputStream * stream); + + static void WriteVLong(OutputStream * stream, int64_t v); + + static void WriteLong(OutputStream * stream, int64_t v); + + static void WriteInt(OutputStream * stream, int32_t v); + + static void WriteShort(OutputStream * stream, int16_t v); + + static void WriteFloat(OutputStream * stream, float v); + + static void WriteText(OutputStream * stream, const string & v); + + static void WriteBytes(OutputStream * stream, const string & v); + + static void WriteUTF8(OutputStream * stream, const string & v); + + // Writable binary to string interface + static void toString(string & dest, KeyValueType type, const void * data, uint32_t length); +}; + +} // namespace NativeTask + +#endif /* WRITABLEUTILS_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test.sh b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test.sh new file mode 100644 index 00000000000..fe1ca78b627 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# only do normal tests by default +FILTER="--gtest_filter=-Perf.*" + +# do all tests +if [ "$1" = "all" ]; then + shift + FILTER="" +fi + +# do performance tests only +if [ "$1" = "perf" ]; then + shift + FILTER="--gtest_filter=Perf.*" +fi + +if [ "${SYSTEM_MAC}" = "TRUE" ]; then + # MACOSX already setup RPATH, no extra help required + ./nttest $FILTER $@ +else + JAVA_JVM_LIBRARY_DIR=`dirname ${JAVA_JVM_LIBRARY}` + LD_LIBRARY_PATH=$JAVA_JVM_LIBRARY_DIR:$LD_LIBRARY_PATH ./nttest $FILTER $@ +fi + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestCommand.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestCommand.cc new file mode 100644 index 00000000000..c09b7b00eee --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestCommand.cc @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/BufferStream.h" +#include "lib/Buffers.h" +#include "test_commons.h" +#include "NativeTask.h" + +namespace NativeTask { + +TEST(Command, equals) { + Command cmd1(100, "hello command"); + Command cmd2(100, "hello command 2"); + + ASSERT_TRUE(cmd1.equals(cmd2)); + ASSERT_TRUE(cmd2.equals(cmd1)); + ASSERT_EQ(100, cmd1.id()); + + std::string helloCommand = "hello command"; + ASSERT_EQ(helloCommand, cmd1.description()); +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestCompressions.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestCompressions.cc new file mode 100644 index 00000000000..387e262710c --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestCompressions.cc @@ -0,0 +1,286 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lz4.h" +#include "config.h" +#include "lib/commons.h" +#include "lib/Path.h" +#include "lib/BufferStream.h" +#include "lib/FileSystem.h" +#include "lib/Compressions.h" +#include "test_commons.h" + +#if defined HADOOP_SNAPPY_LIBRARY +#include +#endif + +void TestCodec(const string & codec) { + string data; + size_t length = TestConfig.getInt("compression.input.length", 100 * 1024 * 1024); + uint32_t buffhint = TestConfig.getInt("compression.buffer.hint", 128 * 1024); + string type = TestConfig.get("compression.input.type", "bytes"); + Timer timer; + GenerateKVTextLength(data, length, type); + LOG("%s", timer.getInterval("Generate data").c_str()); + + InputBuffer inputBuffer = InputBuffer(data); + size_t buffLen = data.length() / 2 * 3; + + timer.reset(); + char * buff = new char[buffLen]; + char * buff2 = new char[buffLen]; + memset(buff, 0, buffLen); + memset(buff2, 0, buffLen); + LOG("%s", timer.getInterval("memset buffer to prevent missing page").c_str()); + + OutputBuffer outputBuffer = OutputBuffer(buff, buffLen); + CompressStream * compressor = Compressions::getCompressionStream(codec, &outputBuffer, buffhint); + + LOG("%s", codec.c_str()); + timer.reset(); + for (size_t i = 0; i < data.length(); i += 128 * 1024) { + compressor->write(data.c_str() + i, std::min(data.length() - i, (size_t)(128 * 1024))); + } + compressor->flush(); + LOG("%s", + timer.getSpeedM2("compress origin/compressed", data.length(), outputBuffer.tell()).c_str()); + + InputBuffer decompInputBuffer = InputBuffer(buff, outputBuffer.tell()); + DecompressStream * decompressor = Compressions::getDecompressionStream(codec, &decompInputBuffer, + buffhint); + size_t total = 0; + timer.reset(); + while (true) { + int32_t rd = decompressor->read(buff2 + total, buffLen - total); + if (rd <= 0) { + break; + } + total += rd; + } + LOG("%s", timer.getSpeedM2("decompress origin/uncompressed", outputBuffer.tell(), total).c_str()); + LOG("ratio: %.3lf", outputBuffer.tell() / (double )total); + ASSERT_EQ(data.length(), total); + ASSERT_EQ(0, memcmp(data.c_str(), buff2, total)); + + delete[] buff; + delete[] buff2; + delete compressor; + delete decompressor; +} + +TEST(Perf, CompressionUtil) { + string inputfile = TestConfig.get("input", ""); + string outputfile = TestConfig.get("output", ""); + uint32_t buffhint = TestConfig.getInt("compression.buffer.hint", 128 * 1024); + string inputcodec = Compressions::getCodecByFile(inputfile); + string outputcodec = Compressions::getCodecByFile(outputfile); + size_t bufferSize = buffhint; + if (inputcodec.length() > 0 && outputcodec.length() == 0) { + // decompression + InputStream * fin = FileSystem::getLocal().open(inputfile); + if (fin == NULL) { + THROW_EXCEPTION(IOException, "input file not found"); + } + DecompressStream * source = Compressions::getDecompressionStream(inputcodec, fin, bufferSize); + OutputStream * fout = FileSystem::getLocal().create(outputfile, true); + char * buffer = new char[bufferSize]; + while (true) { + int rd = source->read(buffer, bufferSize); + if (rd <= 0) { + break; + } + fout->write(buffer, rd); + } + source->close(); + delete source; + fin->close(); + delete fin; + fout->flush(); + fout->close(); + delete fout; + delete buffer; + } else if (inputcodec.length() == 0 && outputcodec.length() > 0) { + // compression + InputStream * fin = FileSystem::getLocal().open(inputfile); + if (fin == NULL) { + THROW_EXCEPTION(IOException, "input file not found"); + } + OutputStream * fout = FileSystem::getLocal().create(outputfile, true); + CompressStream * dest = Compressions::getCompressionStream(outputcodec, fout, bufferSize); + char * buffer = new char[bufferSize]; + while (true) { + int rd = fin->read(buffer, bufferSize); + if (rd <= 0) { + break; + } + dest->write(buffer, rd); + } + dest->flush(); + dest->close(); + delete dest; + fout->close(); + delete fout; + fin->close(); + delete fin; + delete buffer; + } else { + LOG("Not compression or decompression, do nothing"); + } +} + +class CompressResult { + public: + uint64_t uncompressedSize; + uint64_t compressedSize; + uint64_t compressTime; + uint64_t uncompressTime; + CompressResult() + : uncompressedSize(0), compressedSize(0), compressTime(0), uncompressTime(0) { + } + CompressResult & operator+=(const CompressResult & rhs) { + uncompressedSize += rhs.uncompressedSize; + compressedSize += rhs.compressedSize; + compressTime += rhs.compressTime; + uncompressTime += rhs.uncompressTime; + return *this; + } + string toString() { + return StringUtil::Format("Compress: %4.0fM/s Decompress: %5.0fM/s(%5.0fM/s) ratio: %.1f%%", + (uncompressedSize / 1024.0 / 1024) / (compressTime / 1000000000.), + (compressedSize / 1024.0 / 1024) / (uncompressTime / 1000000000.), + (uncompressedSize / 1024.0 / 1024) / (uncompressTime / 1000000000.), + compressedSize / (float)uncompressedSize * 100); + } +}; + +TEST(Perf, GzipCodec) { + TestCodec("org.apache.hadoop.io.compress.GzipCodec"); +} + +void MeasureSingleFileLz4(const string & path, CompressResult & total, size_t blockSize, + int times) { + string data; + ReadFile(data, path); + size_t maxlength = std::max((size_t)(blockSize * 1.005), blockSize + 8); + char * outputBuffer = new char[maxlength]; + char * dest = new char[blockSize + 8]; + CompressResult result; + Timer t; + for (size_t start = 0; start < data.length(); start += blockSize) { + size_t currentblocksize = std::min(data.length() - start, blockSize); + uint64_t startTime = t.now(); + for (int i = 0; i < times; i++) { + int osize = LZ4_compress((char*)data.data() + start, outputBuffer, currentblocksize); + result.compressedSize += osize; + result.uncompressedSize += currentblocksize; + } + uint64_t endTime = t.now(); + result.compressTime += endTime - startTime; + startTime = t.now(); + for (int i = 0; i < times; i++) { + int osize = LZ4_uncompress(outputBuffer, dest, currentblocksize); + ASSERT_EQ(currentblocksize, osize); + } + endTime = t.now(); + result.uncompressTime += endTime - startTime; + } + printf("%s - %s\n", result.toString().c_str(), Path::GetName(path).c_str()); + delete[] outputBuffer; + delete[] dest; + total += result; +} + +TEST(Perf, RawCompressionLz4) { + string inputdir = TestConfig.get("compressions.input.path", ""); + int64_t times = TestConfig.getInt("compression.time", 400); + int64_t blockSize = TestConfig.getInt("compression.block.size", 1024 * 64); + vector inputfiles; + FileSystem::getLocal().list(inputdir, inputfiles); + CompressResult total; + printf("Block size: %lldK\n", (long long int)(blockSize / 1024)); + for (size_t i = 0; i < inputfiles.size(); i++) { + if (!inputfiles[i].isDirectory) { + MeasureSingleFileLz4((inputdir + "/" + inputfiles[i].name).c_str(), total, blockSize, times); + } + } + printf("%s - Total\n", total.toString().c_str()); +} + +TEST(Perf, Lz4Codec) { + TestCodec("org.apache.hadoop.io.compress.Lz4Codec"); +} + +#if defined HADOOP_SNAPPY_LIBRARY + +void MeasureSingleFileSnappy(const string & path, CompressResult & total, size_t blockSize, + int times) { + string data; + ReadFile(data, path); + size_t maxlength = snappy::MaxCompressedLength(blockSize); + char * outputBuffer = new char[maxlength]; + char * dest = new char[blockSize]; + CompressResult result; + Timer t; + int compressedSize = -1; + for (size_t start = 0; start < data.length(); start += blockSize) { + size_t currentblocksize = std::min(data.length() - start, blockSize); + uint64_t startTime = t.now(); + for (int i = 0; i < times; i++) { + size_t osize = maxlength; + snappy::RawCompress(data.data() + start, currentblocksize, outputBuffer, &osize); + compressedSize = osize; + result.compressedSize += osize; + result.uncompressedSize += currentblocksize; + } + uint64_t endTime = t.now(); + result.compressTime += endTime - startTime; + startTime = t.now(); + for (int i = 0; i < times; i++) { + snappy::RawUncompress(outputBuffer, compressedSize, dest); + } + endTime = t.now(); + result.uncompressTime += endTime - startTime; + } + printf("%s - %s\n", result.toString().c_str(), Path::GetName(path).c_str()); + delete[] outputBuffer; + delete[] dest; + total += result; +} + +TEST(Perf, RawCompressionSnappy) { + string inputdir = TestConfig.get("compressions.input.path", ""); + int64_t times = TestConfig.getInt("compression.time", 400); + int64_t blockSize = TestConfig.getInt("compression.block.size", 1024 * 64); + vector inputfiles; + FileSystem::getLocal().list(inputdir, inputfiles); + CompressResult total; + printf("Block size: %"PRId64"K\n", blockSize / 1024); + for (size_t i = 0; i < inputfiles.size(); i++) { + if (!inputfiles[i].isDirectory) { + MeasureSingleFileSnappy((inputdir + "/" + inputfiles[i].name).c_str(), total, blockSize, + times); + } + } + printf("%s - Total\n", total.toString().c_str()); +} + +TEST(Perf, SnappyCodec) { + TestCodec("org.apache.hadoop.io.compress.SnappyCodec"); +} + +#endif // define HADOOP_SNAPPY_LIBRARY diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestConfig.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestConfig.cc new file mode 100644 index 00000000000..a5c0b9ac75e --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestConfig.cc @@ -0,0 +1,67 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/BufferStream.h" +#include "lib/Buffers.h" +#include "test_commons.h" + +float absoute(float v) { + if (v > 0) { + return v; + } else { + return -v; + } +} + +TEST(Config, readAndWrite) { + Config config; + std::string STR = "CONFIG"; + std::string STRS = "CONFIG,LOG"; + int INT = 3; + bool BOOL = true; + + config.set("STR", STR.c_str()); + config.set("STRS", STRS.c_str()); + config.setInt("INT", INT); + config.setBool("BOOL", BOOL); + config.set("INTS", "3,4"); + config.set("FLOAT", "3.5"); + config.set("FLOATS", "3.5,4.6"); + + ASSERT_EQ(0, STR.compare(config.get("STR"))); + ASSERT_EQ(0, STRS.compare(config.get("STRS"))); + + ASSERT_EQ(INT, config.getInt("INT")); + ASSERT_EQ(BOOL, config.getBool("BOOL", false)); + + vector ints; + config.getInts("INTS", ints); + ASSERT_EQ(2, ints.size()); + ASSERT_EQ(3, ints[0]); + ASSERT_EQ(4, ints[1]); + + float floatValue = config.getFloat("FLOAT"); + ASSERT_TRUE(absoute(floatValue - 3.5) < 0.01); + + vector floats; + config.getFloats("FLOATS", floats); + ASSERT_EQ(2, floats.size()); + ASSERT_TRUE(absoute(floats[0] - 3.5) < 0.01); + ASSERT_TRUE(absoute(floats[1] - 4.6) < 0.01); +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestCounter.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestCounter.cc new file mode 100644 index 00000000000..028c43b37f0 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestCounter.cc @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/NativeObjectFactory.h" +#include "lib/BufferStream.h" +#include "lib/Buffers.h" +#include "test_commons.h" + +TEST(Counter, Counter) { + Counter counter1("group", "key"); + const string & group = counter1.group(); + const string & name = counter1.name(); + ASSERT_EQ(0, name.compare("key")); + ASSERT_EQ(0, group.compare("group")); + + ASSERT_EQ(0, counter1.get()); + + counter1.increase(100); + ASSERT_EQ(100, counter1.get()); +} + +TEST(Counter, CounterSet) { + Counter * counter1 = NativeObjectFactory::GetCounter("group0", "name0"); + ASSERT_EQ(string("group0"), counter1->group()); + ASSERT_EQ(string("name0"), counter1->name()); + counter1->increase(100); + ASSERT_EQ(100, counter1->get()); + Counter * counter2 = NativeObjectFactory::GetCounter("group0", "name0"); + Counter * counter3 = NativeObjectFactory::GetCounter("group0", "name1"); + ASSERT_EQ(counter1, counter2); + ASSERT_NE(counter1, counter3); +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestFileSystem.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestFileSystem.cc new file mode 100644 index 00000000000..667858b711b --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestFileSystem.cc @@ -0,0 +1,50 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/FileSystem.h" +#include "test_commons.h" + +TEST(FileSystem, RawFileSystem) { + FileSystem & fs = FileSystem::getLocal(); + fs.mkdirs("temp"); + string temppath = "temp/data"; + string content; + GenerateKVTextLength(content, 4111111, "word"); + FileOutputStream * output = (FileOutputStream*)fs.create(temppath, true); + output->write(content.data(), content.length()); + output->close(); + delete output; + FileInputStream * input = (FileInputStream*)fs.open(temppath); + char buff[1024]; + int64_t total = 0; + while (true) { + int rd = input->read(buff, 1024); + if (rd <= 0) { + break; + } + ASSERT_EQ(content.substr(total, rd), string(buff, rd)); + total += rd; + } + ASSERT_EQ(content.length(), total); + delete input; + ASSERT_EQ(fs.getLength(temppath), content.length()); + ASSERT_TRUE(fs.exists(temppath)); + fs.remove("temp"); + ASSERT_FALSE(fs.exists(temppath)); +} + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestIFile.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestIFile.cc new file mode 100644 index 00000000000..e1e32d41460 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestIFile.cc @@ -0,0 +1,199 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "lib/commons.h" +#include "config.h" +#include "lib/BufferStream.h" +#include "lib/FileSystem.h" +#include "lib/IFile.h" +#include "test_commons.h" + +SingleSpillInfo * writeIFile(int partition, vector > & kvs, + const string & path, KeyValueType type, const string & codec) { + FileOutputStream * fout = (FileOutputStream*)FileSystem::getLocal().create(path); + IFileWriter * iw = new IFileWriter(fout, CHECKSUM_CRC32, type, type, codec, NULL); + for (int i = 0; i < partition; i++) { + iw->startPartition(); + for (size_t i = 0; i < kvs.size(); i++) { + pair & p = kvs[i]; + iw->write(p.first.c_str(), p.first.length(), p.second.c_str(), p.second.length()); + } + iw->endPartition(); + } + SingleSpillInfo * info = iw->getSpillInfo(); + delete iw; + delete fout; + return info; +} + +void readIFile(vector > & kvs, const string & path, KeyValueType type, + SingleSpillInfo * info, const string & codec) { + FileInputStream * fin = (FileInputStream*)FileSystem::getLocal().open(path); + IFileReader * ir = new IFileReader(fin, info); + while (ir->nextPartition()) { + const char * key, *value; + uint32_t keyLen, valueLen; + while (NULL != (key = ir->nextKey(keyLen))) { + value = ir->value(valueLen); + string keyS(key, keyLen); + string valueS(value, valueLen); + kvs.push_back(std::make_pair(keyS, valueS)); + } + } + delete ir; + delete fin; +} + +void TestIFileReadWrite(KeyValueType kvtype, int partition, int size, + vector > & kvs, const string & codec = "") { + string outputpath = "ifilewriter"; + SingleSpillInfo * info = writeIFile(partition, kvs, outputpath, kvtype, codec); + LOG("write finished"); + vector > readkvs; + readIFile(readkvs, outputpath, kvtype, info, codec); + LOG("read finished"); + delete info; + ASSERT_EQ(kvs.size() * partition, readkvs.size()); + for (int i = 0; i < partition; i++) { + vector > cur_part(readkvs.begin() + i * kvs.size(), + readkvs.begin() + (i + 1) * kvs.size()); + ASSERT_EQ(kvs.size(), cur_part.size()); +// for (size_t j=0;j > kvs; + Generate(kvs, size, "bytes"); + TestIFileReadWrite(TextType, partition, size, kvs); + TestIFileReadWrite(BytesType, partition, size, kvs); + TestIFileReadWrite(UnknownType, partition, size, kvs); +#if defined HADOOP_SNAPPY_LIBRARY + TestIFileReadWrite(TextType, partition, size, kvs, "org.apache.hadoop.io.compress.SnappyCodec"); +#endif +} + +void TestIFileWriteRead2(vector > & kvs, char * buff, size_t buffsize, + const string & codec, ChecksumType checksumType, KeyValueType type) { + int partition = TestConfig.getInt("ifile.partition", 50); + Timer timer; + OutputBuffer outputBuffer = OutputBuffer(buff, buffsize); + IFileWriter * iw = new IFileWriter(&outputBuffer, checksumType, type, type, codec, NULL); + timer.reset(); + for (int i = 0; i < partition; i++) { + iw->startPartition(); + for (size_t j = 0; j < kvs.size(); j++) { + iw->write(kvs[j].first.c_str(), kvs[j].first.length(), kvs[j].second.c_str(), + kvs[j].second.length()); + } + iw->endPartition(); + } + SingleSpillInfo * info = iw->getSpillInfo(); + LOG("%s", + timer.getSpeedM2("Write data", info->getEndPosition(), info->getRealEndPosition()).c_str()); + delete iw; + + InputBuffer inputBuffer = InputBuffer(buff, outputBuffer.tell()); + IFileReader * ir = new IFileReader(&inputBuffer, info); + timer.reset(); + int sum = 0; + while (ir->nextPartition()) { + const char * key, *value; + uint32_t keyLen, valueLen; + while (NULL != (key = ir->nextKey(keyLen))) { + value = ir->value(valueLen); + sum += value[0]; + } + } + // use the result so that value() calls don't get optimized out + ASSERT_NE(0xdeadbeef, sum); + LOG("%s", + timer.getSpeedM2(" Read data", info->getEndPosition(), info->getRealEndPosition()).c_str()); + delete ir; + delete info; +} + + + +TEST(Perf, IFile) { + int size = TestConfig.getInt("partition.size", 20000); + string codec = TestConfig.get("ifile.codec", ""); + string type = TestConfig.get("ifile.type", "bytes"); + + vector > kvs; + Generate(kvs, size, type); + std::sort(kvs.begin(), kvs.end()); + + size_t buffsize = 200 * 1024 * 1024; + char * buff = new char[buffsize]; + memset(buff, 0, buffsize); + + LOG("Test TextType CRC32"); + TestIFileWriteRead2(kvs, buff, buffsize, codec, CHECKSUM_CRC32, TextType); + LOG("Test BytesType CRC32"); + TestIFileWriteRead2(kvs, buff, buffsize, codec, CHECKSUM_CRC32, BytesType); + LOG("Test UnknownType CRC32"); + TestIFileWriteRead2(kvs, buff, buffsize, codec, CHECKSUM_CRC32, UnknownType); + LOG("Test TextType CRC32C"); + TestIFileWriteRead2(kvs, buff, buffsize, codec, CHECKSUM_CRC32C, TextType); + LOG("Test BytesType CRC32C"); + TestIFileWriteRead2(kvs, buff, buffsize, codec, CHECKSUM_CRC32C, BytesType); + LOG("Test UnknownType CRC32C"); + TestIFileWriteRead2(kvs, buff, buffsize, codec, CHECKSUM_CRC32C, UnknownType); + delete[] buff; +} + +// The Glibc has a bug in the file tell api, it will overwrite the file data +// unexpected. +// Please check https://rhn.redhat.com/errata/RHBA-2013-0279.html +// This case is to check whether the bug exists. +// If it exists, it means you need to upgrade the glibc. +TEST(IFile, TestGlibCBug) { + std::string path("./testData/testGlibCBugSpill.out"); + + int32_t expect[5] = {-1538241715, -1288088794, -192294464, 563552421, 1661521654}; + + LOG("TestGlibCBug %s", path.c_str()); + IFileSegment * segments = new IFileSegment[1]; + segments[0].realEndOffset = 10000000; + SingleSpillInfo info(segments, 1, path, CHECKSUM_NONE, + IntType, TextType, ""); + + InputStream * fileOut = FileSystem::getLocal().open(path); + IFileReader * reader = new IFileReader(fileOut, &info, true); + + const char * key = NULL; + uint32_t length = 0; + reader->nextPartition(); + uint32_t index = 0; + while (NULL != (key = reader->nextKey(length))) { + int32_t realKey = (int32_t)bswap(*(uint32_t *)(key)); + ASSERT_LT(index, 5); + ASSERT_EQ(expect[index], realKey); + index++; + } + delete reader; +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestMain.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestMain.cc new file mode 100644 index 00000000000..8af4c8a3080 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestMain.cc @@ -0,0 +1,116 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#ifndef __CYGWIN__ +#include +#endif + +#include +#include "lib/commons.h" +#include "lib/Buffers.h" +#include "lib/FileSystem.h" +#include "lib/NativeObjectFactory.h" +#include "test_commons.h" + +extern "C" { + +static void handler(int sig); + +// TODO: just for debug, should be removed +void handler(int sig) { + void *array[10]; + size_t size; + + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + +#ifndef __CYGWIN__ + // get void*'s for all entries on the stack + size = backtrace(array, 10); + + backtrace_symbols_fd(array, size, 2); +#endif + + exit(1); +} +} + +typedef char * CString; + +namespace NativeTask { + +int DoMain(int argc, char** argv) { + signal(SIGSEGV, handler); + CString * newArgv = new CString[argc + 1]; + memcpy(newArgv, argv, argc * sizeof(CString)); + + bool gen = false; + if (argc > 1) { + if (string("perf") == newArgv[1]) { + newArgv[1] = (char *)"--gtest_filter=Perf.*"; + } else if (string("noperf") == newArgv[1]) { + newArgv[1] = (char *)"--gtest_filter=-Perf.*"; + } else if (string("gen") == newArgv[1]) { + gen = true; + } + } + testing::InitGoogleTest(&argc, newArgv); + if (argc > 0) { + int skip = gen ? 2 : 1; + TestConfig.parse(argc - skip, (const char **)(newArgv + skip)); + } + delete [] newArgv; + try { + if (gen == true) { + string type = TestConfig.get("generate.type", "word"); + string codec = TestConfig.get("generate.codec", ""); + int64_t len = TestConfig.getInt("generate.length", 1024); + string temp; + GenerateKVTextLength(temp, len, type); + if (codec.length() == 0) { + fprintf(stdout, "%s", temp.c_str()); + } else { + OutputStream * fout = FileSystem::getLocal().create("/dev/stdout"); + AppendBuffer app = AppendBuffer(); + app.init(128 * 1024, fout, codec); + app.write(temp.data(), temp.length()); + fout->close(); + delete fout; + } + NativeObjectFactory::Release(); + return 0; + } else { + int ret = RUN_ALL_TESTS(); + NativeObjectFactory::Release(); + return ret; + } + } catch (std::exception & e) { + fprintf(stderr, "Exception: %s", e.what()); + NativeObjectFactory::Release(); + return 1; + } +} + +} // namespace NativeTask + + +int main(int argc, char ** argv) { + return NativeTask::DoMain(argc, argv); +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestPrimitives.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestPrimitives.cc new file mode 100644 index 00000000000..b2051c7b32b --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestPrimitives.cc @@ -0,0 +1,304 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "test_commons.h" + +TEST(Primitives, fmemcmp) { + std::vector vs; + char buff[14]; + vs.push_back(""); + for (uint32_t i = 0; i < 5000; i += 7) { + snprintf(buff, 14, "%d", i * 31); + vs.push_back(buff); + snprintf(buff, 10, "%010d", i); + vs.push_back(buff); + } + for (size_t i = 0; i < vs.size(); i++) { + for (size_t j = 0; j < vs.size(); j++) { + std::string & ls = vs[i]; + std::string & rs = vs[j]; + size_t m = std::min(ls.length(), rs.length()); + int c = memcmp(ls.c_str(), rs.c_str(), m); + int t = fmemcmp(ls.c_str(), rs.c_str(), m); + if (!((c == 0 && t == 0) || (c > 0 && t > 0) || (c < 0 && t < 0))) { + ASSERT_TRUE(false); + } + } + } +} + +static int test_memcmp() { + uint8_t buff[2048]; + for (uint32_t i = 0; i < 2048; i++) { + buff[i] = i & 0xff; + } + std::random_shuffle(buff, buff + 2048); + int r = 0; + for (uint32_t i = 0; i < 100000000; i++) { + int offset = i % 1000; + r += memcmp(buff, buff + 1024, 5); + r += memcmp(buff + offset, buff + 1124, 9); + r += memcmp(buff + offset, buff + 1224, 10); + r += memcmp(buff + offset, buff + 1324, 15); + r += memcmp(buff + offset, buff + 1424, 16); + r += memcmp(buff + offset, buff + 1524, 17); + r += memcmp(buff + offset, buff + 1624, 18); + r += memcmp(buff + offset, buff + 1724, 19); + } + return r; +} + +static int test_fmemcmp() { + char buff[2048]; + for (uint32_t i = 0; i < 2048; i++) { + buff[i] = i & 0xff; + } + std::random_shuffle(buff, buff + 2048); + int r = 0; + for (uint32_t i = 0; i < 100000000; i++) { + int offset = i % 1000; + r += fmemcmp(buff, buff + 1024, 5); + r += fmemcmp(buff + offset, buff + 1124, 9); + r += fmemcmp(buff + offset, buff + 1224, 10); + r += fmemcmp(buff + offset, buff + 1324, 15); + r += fmemcmp(buff + offset, buff + 1424, 16); + r += fmemcmp(buff + offset, buff + 1524, 17); + r += fmemcmp(buff + offset, buff + 1624, 18); + r += fmemcmp(buff + offset, buff + 1724, 19); + } + return r; +} + +TEST(Perf, fmemcmp) { + Timer t; + int a = test_memcmp(); + LOG("%s", t.getInterval(" memcmp ").c_str()); + t.reset(); + int b = test_fmemcmp(); + LOG("%s", t.getInterval(" fmemcmp ").c_str()); + // prevent compiler optimization + TestConfig.setInt("tempvalue", a + b); +} + +static void test_memcpy_perf_len(char * src, char * dest, size_t len, size_t time) { + for (size_t i = 0; i < time; i++) { + memcpy(src, dest, len); + memcpy(dest, src, len); + } +} + +static void test_simple_memcpy_perf_len(char * src, char * dest, size_t len, size_t time) { + for (size_t i = 0; i < time; i++) { + simple_memcpy(src, dest, len); + simple_memcpy(dest, src, len); + } +} + +TEST(Perf, simple_memcpy_small) { + char * src = new char[10240]; + char * dest = new char[10240]; + char buff[32]; + for (size_t len = 1; len < 256; len = len + 2) { + LOG("------------------------------"); + snprintf(buff, 32, " memcpy %luB\t", len); + Timer t; + test_memcpy_perf_len(src, dest, len, 1000000); + LOG("%s", t.getInterval(buff).c_str()); + snprintf(buff, 32, "simple_memcpy %luB\t", len); + t.reset(); + test_simple_memcpy_perf_len(src, dest, len, 1000000); + LOG("%s", t.getInterval(buff).c_str()); + } + delete[] src; + delete[] dest; +} + +inline char * memchrbrf4(char * p, char ch, size_t len) { + ssize_t i = 0; + for (; i < ((ssize_t)len) - 3; i += 3) { + if (p[i] == ch) { + return p + i; + } + if (p[i + 1] == ch) { + return p + i + 1; + } + if (p[i + 2] == ch) { + return p + i + 2; + } + } + for (; i < len; i++) { + if (p[i] == ch) { + return p + i; + } + } + return NULL; +} + +inline char * memchrbrf2(char * p, char ch, size_t len) { + for (size_t i = 0; i < len / 2; i += 2) { + if (p[i] == ch) { + return p + i; + } + if (p[i + 1] == ch) { + return p + i + 1; + } + } + if (len % 2 && p[len - 1] == ch) { + return p + len - 1; + } + return NULL; +} + +// not safe in MACOSX, segment fault, should be safe on Linux with out mmap +inline int memchr_sse(const char *s, int c, int len) { + // len : edx; c: esi; s:rdi + int index = 0; + +#ifdef __X64 + + __asm__ __volatile__( + //"and $0xff, %%esi;" //clear upper bytes + "movd %%esi, %%xmm1;" + + "mov $1, %%eax;" + "add $16, %%edx;" + "mov %%rdi ,%%r8;" + + "1:" + "movdqu (%%rdi), %%xmm2;" + "sub $16, %%edx;" + "addq $16, %%rdi;" + //"pcmpestri $0x0, %%xmm2,%%xmm1;" + ".byte 0x66 ,0x0f ,0x3a ,0x61 ,0xca ,0x00;" + //"lea 16(%%rdi), %%rdi;" + "ja 1b;"//Res2==0:no match and zflag==0: s is not end + "jc 3f;"//Res2==1: match and s is not end + + "mov $0xffffffff, %%eax;"//no match + "jmp 0f;" + + "3:" + "sub %%r8, %%rdi;" + "lea -16(%%edi,%%ecx),%%eax;" + + "0:" + // "mov %%eax, %0;" + :"=a"(index),"=D"(s),"=S"(c),"=d"(len) + :"D"(s),"S"(c),"d"(len) + :"rcx","r8","memory" + ); + +#endif + + return index; +} + +TEST(Perf, memchr) { + Random r; + int32_t size = 100 * 1024 * 1024; + int32_t lineLength = TestConfig.getInt("memchr.line.length", 100); + char * buff = new char[size + 16]; + memset(buff, 'a', size); + for (int i = 0; i < size / lineLength; i++) { + buff[r.next_int32(size)] = '\n'; + } + Timer timer; + char * pos = buff; + int count = 0; + while (true) { + if (pos == buff + size) { + break; + } + pos = (char*)memchr(pos, '\n', buff + size - pos); + if (pos == NULL) { + break; + } + pos++; + count++; + } + LOG("%s", timer.getSpeedM2("memchr bytes/lines", size, count).c_str()); + timer.reset(); + pos = buff; + count = 0; + while (true) { + if (pos == buff + size) { + break; + } + pos = (char*)memchrbrf2(pos, '\n', buff + size - pos); + if (pos == NULL) { + break; + } + pos++; + count++; + } + LOG("%s", timer.getSpeedM2("memchrbrf2 bytes/lines", size, count).c_str()); + timer.reset(); + pos = buff; + count = 0; + while (true) { + if (pos == buff + size) { + break; + } + pos = (char*)memchrbrf4(pos, '\n', buff + size - pos); + if (pos == NULL) { + break; + } + pos++; + count++; + } + LOG("%s", timer.getSpeedM2("memchrbrf4 bytes/lines", size, count).c_str()); + timer.reset(); + pos = buff; + count = 0; + while (true) { + if (pos == buff + size) { + break; + } + int ret = memchr_sse(pos, '\n', buff + size - pos); + if (ret == -1) { + break; + } + pos = pos + ret; + pos++; + count++; + } + LOG("%s", timer.getSpeedM2("memchr_sse bytes/lines", size, count).c_str()); + delete[] buff; +} + +TEST(Perf, memcpy_batch) { + int32_t size = TestConfig.getInt("input.size", 64 * 1024); + size_t mb = TestConfig.getInt("input.mb", 320) * 1024 * 1024UL; + char * src = new char[size]; + char * dest = new char[size]; + memset(src, 0, size); + memset(dest, 0, size); + Timer t; + for (size_t i = 0; i < mb; i += size) { + memcpy(dest, src, size); + } + LOG("%s", t.getSpeedM("memcpy", mb).c_str()); + t.reset(); + for (size_t i = 0; i < mb; i += size) { + simple_memcpy(dest, src, size); + } + LOG("%s", t.getSpeedM("simple_memcpy", mb).c_str()); + delete[] src; + delete[] dest; +} + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestSort.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestSort.cc new file mode 100644 index 00000000000..1c391a65f18 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/TestSort.cc @@ -0,0 +1,306 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/Streams.h" +#include "lib/Buffers.h" +#include "util/DualPivotQuickSort.h" +#include "test_commons.h" + +string gBuffer; + +inline const char * get_position(uint32_t offset) { + return gBuffer.data() + offset; +} + +/** + * fast memcmp + */ +inline int fmemcmporig(const char * src, const char * dest, uint32_t len) { + const uint64_t * src8 = (const uint64_t*)src; + const uint64_t * dest8 = (const uint64_t*)dest; + while (len >= 8) { + uint64_t l = *src8; + uint64_t r = *dest8; + if (l != r) { + l = bswap64(l); + r = bswap64(r); + return l > r ? 1 : -1; + } + ++src8; + ++dest8; + len -= 8; + } + if (len == 0) + return 0; + if (len == 1) { + int l = (int)(*(uint8_t*)src8); + int r = (int)(*(uint8_t*)dest8); + return l - r; + } + uint64_t mask = (1ULL << (len * 8)) - 1; + uint64_t l = (*src8) & mask; + uint64_t r = (*dest8) & mask; + if (l == r) { + return 0; + } + l = bswap64(l); + r = bswap64(r); + return l > r ? 1 : -1; +} + +/** + * c qsort compare function + */ +static int compare_offset(const void * plh, const void * prh) { + KVBuffer * lhb = (KVBuffer*)get_position(*(uint32_t*)plh); + KVBuffer * rhb = (KVBuffer*)get_position(*(uint32_t*)prh); + uint32_t minlen = std::min(lhb->keyLength, rhb->keyLength); + int ret = memcmp(lhb->getKey(), rhb->getKey(), minlen); + if (ret) { + return ret; + } + return lhb->keyLength - rhb->keyLength; +} + +/** + * dualpivot sort compare function + */ +class CompareOffset { + public: + int64_t operator()(uint32_t lhs, uint32_t rhs) { + + KVBuffer * lhb = (KVBuffer*)get_position(lhs); + KVBuffer * rhb = (KVBuffer*)get_position(rhs); + + uint32_t minlen = std::min(lhb->keyLength, rhb->keyLength); + int64_t ret = memcmp(lhb->getKey(), rhb->getKey(), minlen); + if (ret) { + return ret; + } + return lhb->keyLength - rhb->keyLength; + } +}; + +/** + * quicksort compare function + */ +class OffsetLessThan { + public: + bool operator()(uint32_t lhs, uint32_t rhs) { + KVBuffer * lhb = (KVBuffer*)get_position(lhs); + KVBuffer * rhb = (KVBuffer*)get_position(rhs); + + uint32_t minlen = std::min(lhb->keyLength, rhb->keyLength); + int64_t ret = memcmp(lhb->content, rhb->content, minlen); + return ret < 0 || (ret == 0 && (lhb->keyLength < rhb->keyLength)); + } +}; + +/** + * c qsort compare function + */ +static int compare_offset2(const void * plh, const void * prh) { + + KVBuffer * lhb = (KVBuffer*)get_position(*(uint32_t*)plh); + KVBuffer * rhb = (KVBuffer*)get_position(*(uint32_t*)prh); + + uint32_t minlen = std::min(lhb->keyLength, rhb->keyLength); + int64_t ret = fmemcmp(lhb->content, rhb->content, minlen); + if (ret) { + return ret; + } + return lhb->keyLength - rhb->keyLength; +} + +/** + * dualpivot sort compare function + */ +class CompareOffset2 { + public: + int64_t operator()(uint32_t lhs, uint32_t rhs) { + + KVBuffer * lhb = (KVBuffer*)get_position(lhs); + KVBuffer * rhb = (KVBuffer*)get_position(rhs); + + uint32_t minlen = std::min(lhb->keyLength, rhb->keyLength); + int64_t ret = fmemcmp(lhb->content, rhb->content, minlen); + if (ret) { + return ret; + } + return lhb->keyLength - rhb->keyLength; + } +}; + +/** + * quicksort compare function + */ +class OffsetLessThan2 { + public: + bool operator()(uint32_t lhs, uint32_t rhs) { + + KVBuffer * lhb = (KVBuffer*)get_position(lhs); + KVBuffer * rhb = (KVBuffer*)get_position(rhs); + + uint32_t minlen = std::min(lhb->keyLength, rhb->keyLength); + int64_t ret = fmemcmp(lhb->content, rhb->content, minlen); + return ret < 0 || (ret == 0 && (lhb->keyLength < rhb->keyLength)); + } +}; + +void makeInputWord(string & dest, vector & offsets, uint64_t length) { + Random r; + dest.reserve(length + 1024); + string k, v; + while (true) { + k = r.nextWord(); + v = r.nextWord(); + offsets.push_back(dest.length()); + uint32_t tempLen = k.length(); + dest.append((const char *)&tempLen, 4); + dest.append(k.data(), k.length()); + tempLen = v.length(); + dest.append((const char *)&tempLen, 4); + dest.append(v.data(), v.length()); + if (dest.length() > length) { + return; + } + } +} + +TEST(Perf, sort) { + vector offsets; + makeInputWord(gBuffer, offsets, 80000000); + Timer timer; + vector offsetstemp1_0 = offsets; + vector offsetstemp1_1 = offsets; + vector offsetstemp1_2 = offsets; + vector offsetstemp1_3 = offsets; + timer.reset(); + qsort(&offsetstemp1_0[0], offsetstemp1_0.size(), sizeof(uint32_t), compare_offset); + qsort(&offsetstemp1_1[0], offsetstemp1_1.size(), sizeof(uint32_t), compare_offset); + qsort(&offsetstemp1_2[0], offsetstemp1_2.size(), sizeof(uint32_t), compare_offset); + qsort(&offsetstemp1_3[0], offsetstemp1_3.size(), sizeof(uint32_t), compare_offset); + LOG("%s", timer.getInterval("qsort").c_str()); + offsetstemp1_0 = offsets; + offsetstemp1_1 = offsets; + offsetstemp1_2 = offsets; + offsetstemp1_3 = offsets; + timer.reset(); + qsort(&offsetstemp1_0[0], offsetstemp1_0.size(), sizeof(uint32_t), compare_offset2); + qsort(&offsetstemp1_1[0], offsetstemp1_1.size(), sizeof(uint32_t), compare_offset2); + qsort(&offsetstemp1_2[0], offsetstemp1_2.size(), sizeof(uint32_t), compare_offset2); + qsort(&offsetstemp1_3[0], offsetstemp1_3.size(), sizeof(uint32_t), compare_offset2); + LOG("%s", timer.getInterval("qsort 2").c_str()); + offsetstemp1_0 = offsets; + offsetstemp1_1 = offsets; + offsetstemp1_2 = offsets; + offsetstemp1_3 = offsets; + timer.reset(); + std::sort(offsetstemp1_0.begin(), offsetstemp1_0.end(), OffsetLessThan()); + std::sort(offsetstemp1_1.begin(), offsetstemp1_1.end(), OffsetLessThan()); + std::sort(offsetstemp1_2.begin(), offsetstemp1_2.end(), OffsetLessThan()); + std::sort(offsetstemp1_3.begin(), offsetstemp1_3.end(), OffsetLessThan()); + LOG("%s", timer.getInterval("std::sort").c_str()); + offsetstemp1_0 = offsets; + offsetstemp1_1 = offsets; + offsetstemp1_2 = offsets; + offsetstemp1_3 = offsets; + timer.reset(); + std::sort(offsetstemp1_0.begin(), offsetstemp1_0.end(), OffsetLessThan2()); + std::sort(offsetstemp1_1.begin(), offsetstemp1_1.end(), OffsetLessThan2()); + std::sort(offsetstemp1_2.begin(), offsetstemp1_2.end(), OffsetLessThan2()); + std::sort(offsetstemp1_3.begin(), offsetstemp1_3.end(), OffsetLessThan2()); + LOG("%s", timer.getInterval("std::sort 2").c_str()); + offsetstemp1_0 = offsets; + offsetstemp1_1 = offsets; + offsetstemp1_2 = offsets; + offsetstemp1_3 = offsets; + timer.reset(); + DualPivotQuicksort(offsetstemp1_0, CompareOffset()); + DualPivotQuicksort(offsetstemp1_1, CompareOffset()); + DualPivotQuicksort(offsetstemp1_2, CompareOffset()); + DualPivotQuicksort(offsetstemp1_3, CompareOffset()); + LOG("%s", timer.getInterval("DualPivotQuicksort").c_str()); + offsetstemp1_0 = offsets; + offsetstemp1_1 = offsets; + offsetstemp1_2 = offsets; + offsetstemp1_3 = offsets; + timer.reset(); + DualPivotQuicksort(offsetstemp1_0, CompareOffset2()); + DualPivotQuicksort(offsetstemp1_1, CompareOffset2()); + DualPivotQuicksort(offsetstemp1_2, CompareOffset2()); + DualPivotQuicksort(offsetstemp1_3, CompareOffset2()); + LOG("%s", timer.getInterval("DualPivotQuicksort 2").c_str()); +} + +TEST(Perf, sortCacheMiss) { + + LOG("Testing partition based sort, sort 4MB every time"); + + vector offsets; + makeInputWord(gBuffer, offsets, 80000000); + Timer timer; + vector offsetstemp1_0 = offsets; + vector offsetstemp1_1 = offsets; + vector offsetstemp1_2 = offsets; + vector offsetstemp1_3 = offsets; + + timer.reset(); + DualPivotQuicksort(offsetstemp1_0, CompareOffset2()); + DualPivotQuicksort(offsetstemp1_1, CompareOffset2()); + DualPivotQuicksort(offsetstemp1_2, CompareOffset2()); + DualPivotQuicksort(offsetstemp1_3, CompareOffset2()); + LOG("%s", timer.getInterval("DualPivotQuicksort 2 full sort").c_str()); + + uint32_t MOD = 128000; + uint32_t END = offsets.size(); + + for (MOD = 1024; MOD < END; MOD <<= 1) { + offsetstemp1_0 = offsets; + offsetstemp1_1 = offsets; + offsetstemp1_2 = offsets; + offsetstemp1_3 = offsets; + timer.reset(); + + for (uint32_t i = 0; i <= END / MOD; i++) { + int base = i * MOD; + int max = (base + MOD) > END ? END : (base + MOD); + DualPivotQuicksort(offsetstemp1_0, base, max - 1, 3, CompareOffset2()); + } + + for (uint32_t i = 0; i <= END / MOD; i++) { + int base = i * MOD; + int max = (base + MOD) > END ? END : (base + MOD); + DualPivotQuicksort(offsetstemp1_1, base, max - 1, 3, CompareOffset2()); + } + + for (uint32_t i = 0; i <= END / MOD; i++) { + int base = i * MOD; + int max = (base + MOD) > END ? END : (base + MOD); + DualPivotQuicksort(offsetstemp1_2, base, max - 1, 3, CompareOffset2()); + } + + for (uint32_t i = 0; i <= END / MOD; i++) { + int base = i * MOD; + int max = (base + MOD) > END ? END : (base + MOD); + DualPivotQuicksort(offsetstemp1_3, base, max - 1, 3, CompareOffset2()); + } + LOG("%s, MOD: %d", timer.getInterval("DualPivotQuicksort 2 partition sort").c_str(), MOD); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestByteArray.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestByteArray.cc new file mode 100644 index 00000000000..1b267370cfd --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestByteArray.cc @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/Combiner.h" +#include "test_commons.h" +#include + +namespace NativeTask { + +TEST(ByteArray, read) { + ByteArray * buffer = new ByteArray(); + buffer->resize(10); + ASSERT_EQ(10, buffer->size()); + char * buff1 = buffer->buff(); + + buffer->resize(15); + ASSERT_EQ(15, buffer->size()); + ASSERT_EQ(buffer->buff(), buff1); + + buffer->resize(30); + ASSERT_EQ(30, buffer->size()); + ASSERT_NE(buffer->buff(), buff1); + + delete buffer; +} + +} /* namespace NativeTask */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestByteBuffer.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestByteBuffer.cc new file mode 100644 index 00000000000..02acddab72c --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestByteBuffer.cc @@ -0,0 +1,47 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/Combiner.h" +#include "test_commons.h" +#include + +namespace NativeTask { + +TEST(ByteBuffer, read) { + char * buff = new char[100]; + ByteBuffer byteBuffer; + byteBuffer.reset(buff, 100); + + ASSERT_EQ(0, byteBuffer.position()); + ASSERT_EQ(100, byteBuffer.capacity()); + ASSERT_EQ(0, byteBuffer.limit()); + + ASSERT_EQ(buff, byteBuffer.current()); + ASSERT_EQ(0, byteBuffer.remain()); + + byteBuffer.advance(3); + ASSERT_EQ(3, byteBuffer.current() - byteBuffer.base()); + + byteBuffer.rewind(10, 20); + ASSERT_EQ(20, byteBuffer.limit()); + + ASSERT_EQ(10, byteBuffer.position()); + delete [] buff; +} +} /* namespace NativeTask */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestComparatorForDualPivotQuickSort.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestComparatorForDualPivotQuickSort.cc new file mode 100644 index 00000000000..f9e980ea396 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestComparatorForDualPivotQuickSort.cc @@ -0,0 +1,89 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/Combiner.h" +#include "lib/MemoryBlock.h" +#include "test_commons.h" +#include + +namespace NativeTask { + +static const char * expectedSrc = NULL; +static int expectedSrcLength = 0; + +static const char * expectedDest = NULL; +static int expectedDestLength = 0; + +static int compareResult = 0; + +void checkInputArguments(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength) { + ASSERT_EQ(expectedSrc, src); + ASSERT_EQ(expectedSrcLength, srcLength); + + ASSERT_EQ(expectedDest, dest); + ASSERT_EQ(expectedDestLength, destLength); +} + +int MockComparatorForDualPivot(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength) { + checkInputArguments(src, srcLength, dest, destLength); + return compareResult; +} + +TEST(ComparatorForDualPivotQuickSort, compare) { + char * buff = new char[100]; + KVBuffer * kv1 = (KVBuffer *)buff; + + const char * KEY = "KEY"; + const char * VALUE = "VALUE"; + + kv1->keyLength = strlen(KEY); + char * key = kv1->getKey(); + ::memcpy(key, KEY, strlen(KEY)); + kv1->valueLength = strlen(VALUE); + char * value = kv1->getValue(); + ::memcpy(value, VALUE, strlen(VALUE)); + + const char * KEY2 = "KEY2"; + const char * VALUE2 = "VALUE2"; + + KVBuffer * kv2 = kv1->next(); + kv2->keyLength = strlen(KEY2); + char * key2 = kv2->getKey(); + ::memcpy(key2, KEY2, strlen(KEY2)); + kv2->valueLength = strlen(VALUE2); + char * value2 = kv2->getValue(); + ::memcpy(value2, VALUE2, strlen(VALUE2)); + + ComparatorForDualPivotSort comparator(buff, &MockComparatorForDualPivot); + + expectedSrc = kv1->getKey(); + expectedSrcLength = strlen(KEY); + + expectedDest = kv2->getKey(); + expectedDestLength = strlen(KEY2); + + compareResult = -1; + + ASSERT_EQ(-1, comparator((char * )kv1 - buff, (char * )kv2 - buff)); + delete [] buff; +} + +} /* namespace NativeTask */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestComparatorForStdSort.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestComparatorForStdSort.cc new file mode 100644 index 00000000000..1a914b6ce9e --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestComparatorForStdSort.cc @@ -0,0 +1,89 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/Combiner.h" +#include "lib/MemoryBlock.h" +#include "test_commons.h" +#include + +namespace NativeTask { + +static const char * expectedSrc = NULL; +static int expectedSrcLength = 0; + +static const char * expectedDest = NULL; +static int expectedDestLength = 0; + +static int compareResult = 0; + +void checkInputArgumentsForStdOut(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength) { + ASSERT_EQ(expectedSrc, src); + ASSERT_EQ(expectedSrcLength, srcLength); + + ASSERT_EQ(expectedDest, dest); + ASSERT_EQ(expectedDestLength, destLength); +} + +int MockComparatorForStdOut(const char * src, uint32_t srcLength, const char * dest, + uint32_t destLength) { + checkInputArgumentsForStdOut(src, srcLength, dest, destLength); + return compareResult; +} + +TEST(ComparatorForStdSort, compare) { + char * buff = new char[100]; + KVBuffer * kv1 = (KVBuffer *)buff; + + const char * KEY = "KEY"; + const char * VALUE = "VALUE"; + + kv1->keyLength = strlen(KEY); + char * key = kv1->getKey(); + ::memcpy(key, KEY, strlen(KEY)); + kv1->valueLength = strlen(VALUE); + char * value = kv1->getValue(); + ::memcpy(value, VALUE, strlen(VALUE)); + + const char * KEY2 = "KEY2"; + const char * VALUE2 = "VALUE2"; + + KVBuffer * kv2 = kv1->next(); + kv2->keyLength = strlen(KEY2); + char * key2 = kv2->getKey(); + ::memcpy(key2, KEY2, strlen(KEY2)); + kv2->valueLength = strlen(VALUE2); + char * value2 = kv2->getValue(); + ::memcpy(value2, VALUE2, strlen(VALUE2)); + + ComparatorForStdSort comparator(buff, &MockComparatorForStdOut); + + expectedSrc = kv1->content; + expectedSrcLength = strlen(KEY); + + expectedDest = kv2->content; + expectedDestLength = strlen(KEY2); + + compareResult = -1; + + ASSERT_EQ(true, comparator((char * )kv1 - buff, (char * )kv2 - buff)); + delete [] buff; +} + +} /* namespace NativeTask */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestFixSizeContainer.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestFixSizeContainer.cc new file mode 100644 index 00000000000..d1b5c375844 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestFixSizeContainer.cc @@ -0,0 +1,55 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/Combiner.h" +#include "test_commons.h" +#include + +namespace NativeTask { + +TEST(FixSizeContainer, test) { + uint32_t length = 100; + FixSizeContainer * container = new FixSizeContainer(); + char * bytes = new char[length]; + container->wrap(bytes, length); + + ASSERT_EQ(0, container->position()); + int pos1 = 3; + container->position(pos1); + ASSERT_EQ(pos1, container->position()); + ASSERT_EQ(length - pos1, container->remain()); + + container->rewind(); + ASSERT_EQ(0, container->position()); + ASSERT_EQ(length, container->size()); + + std::string toBeFilled = "Hello, FixContainer"; + + container->fill(toBeFilled.c_str(), toBeFilled.length()); + + for (uint32_t i = 0; i < container->position(); i++) { + char * c = container->base() + i; + ASSERT_EQ(toBeFilled[i], *c); + } + + delete [] bytes; + delete container; +} + +} /* namespace NativeTask */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestIterator.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestIterator.cc new file mode 100644 index 00000000000..d25cd60b4e0 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestIterator.cc @@ -0,0 +1,114 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/Combiner.h" +#include "test_commons.h" +#include + +namespace NativeTask { + +class MockIterator : public KVIterator { + std::vector > kvs; + uint32_t index; + uint32_t expectedKeyGroupNum; + std::map expectkeyCountMap; + char buffer[8]; + + public: + MockIterator() + : index(0) { + kvs.push_back(std::pair(10, 100)); + + kvs.push_back(std::pair(10, 100)); + kvs.push_back(std::pair(10, 101)); + kvs.push_back(std::pair(10, 102)); + + kvs.push_back(std::pair(20, 200)); + kvs.push_back(std::pair(20, 201)); + kvs.push_back(std::pair(20, 202)); + kvs.push_back(std::pair(30, 302)); + kvs.push_back(std::pair(40, 302)); + this->expectedKeyGroupNum = 4; + + expectkeyCountMap[10] = 4; + expectkeyCountMap[20] = 3; + expectkeyCountMap[30] = 1; + expectkeyCountMap[40] = 1; + } + + bool next(Buffer & key, Buffer & outValue) { + if (index < kvs.size()) { + std::pair value = kvs.at(index); + *((int *)buffer) = value.first; + *(((int *)buffer) + 1) = value.second; + key.reset(buffer, 4); + outValue.reset(buffer + 4, 4); + index++; + return true; + } + return false; + } + + uint32_t getExpectedKeyGroupCount() { + return expectedKeyGroupNum; + } + + std::map& getExpectedKeyCountMap() { + return expectkeyCountMap; + } +}; + +void TestKeyGroupIterator() { + MockIterator * iter = new MockIterator(); + KeyGroupIteratorImpl * groupIterator = new KeyGroupIteratorImpl(iter); + const char * key = NULL; + + uint32_t keyGroupCount = 0; + std::map actualKeyCount; + while (groupIterator->nextKey()) { + keyGroupCount++; + uint32_t length = 0; + key = groupIterator->getKey(length); + int * keyPtr = (int *)key; + const char * value = NULL; + while (NULL != (value = groupIterator->nextValue(length))) { + if (actualKeyCount.find(*keyPtr) == actualKeyCount.end()) { + actualKeyCount[*keyPtr] = 0; + } + actualKeyCount[*keyPtr]++; + } + } + ASSERT_EQ(iter->getExpectedKeyGroupCount(), keyGroupCount); + std::map & expectedKeyCountMap = iter->getExpectedKeyCountMap(); + for (std::map::iterator keyCountIter = actualKeyCount.begin(); + keyCountIter != actualKeyCount.end(); ++keyCountIter) { + uint32_t key = keyCountIter->first; + uint32_t expectedCount = expectedKeyCountMap[key]; + ASSERT_EQ(expectedCount, keyCountIter->second); + } + delete groupIterator; + delete iter; +} + +TEST(Iterator, keyGroupIterator) { + TestKeyGroupIterator(); +} + +} /* namespace NativeTask */ + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestKVBuffer.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestKVBuffer.cc new file mode 100644 index 00000000000..e47e1697e6a --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestKVBuffer.cc @@ -0,0 +1,54 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/Combiner.h" +#include "test_commons.h" +#include + +namespace NativeTask { + +TEST(KVBuffer, test) { + + char * buff = new char[100]; + KVBuffer * kv1 = (KVBuffer *)buff; + + const char * KEY = "KEY"; + const char * VALUE = "VALUE"; + + kv1->keyLength = strlen(KEY); + char * key = kv1->getKey(); + ::memcpy(key, KEY, strlen(KEY)); + kv1->valueLength = strlen(VALUE); + char * value = kv1->getValue(); + ::memcpy(value, VALUE, strlen(VALUE)); + + ASSERT_EQ(strlen(KEY) + strlen(VALUE) + 8, kv1->length()); + + ASSERT_EQ(8, kv1->getKey() - buff); + ASSERT_EQ(strlen(KEY) + 8, kv1->getValue() - buff); + + kv1->keyLength = bswap(kv1->keyLength); + kv1->valueLength = bswap(kv1->valueLength); + + ASSERT_EQ(8, kv1->headerLength()); + ASSERT_EQ(strlen(KEY) + strlen(VALUE) + 8, kv1->lengthConvertEndium()); + delete [] buff; +} + +} /* namespace NativeTask */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestMemBlockIterator.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestMemBlockIterator.cc new file mode 100644 index 00000000000..8d784fb00d6 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestMemBlockIterator.cc @@ -0,0 +1,110 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "test_commons.h" +#include "lib/MapOutputSpec.h" +#include "lib/MemoryBlock.h" + +namespace NativeTask { + +TEST(MemoryBlockIterator, test) { + const uint32_t BUFFER_LENGTH = 100; + char * bytes = new char[BUFFER_LENGTH]; + MemoryBlock block(bytes, BUFFER_LENGTH); + + const uint32_t KV_SIZE = 60; + block.allocateKVBuffer(KV_SIZE); + block.allocateKVBuffer(KV_SIZE); + + MemBlockIterator iter(&block); + + uint32_t keyCount = 0; + while (iter.next()) { + KVBuffer * kv = iter.getKVBuffer(); + ASSERT_EQ(block.getKVBuffer(keyCount), kv); + keyCount++; + } + delete [] bytes; +} + +class MemoryBlockFactory { + public: + static MemoryBlock * create(std::vector & keys) { + const uint32_t BUFFER_LENGTH = 1000; + char * bytes = new char[BUFFER_LENGTH]; + MemoryBlock * block1 = new MemoryBlock(bytes, BUFFER_LENGTH); + + const uint32_t KV_SIZE = 16; + + for (uint32_t i = 0; i < keys.size(); i++) { + uint32_t index = keys[i]; + KVBuffer * kv = block1->allocateKVBuffer(KV_SIZE); + + kv->keyLength = 4; + kv->valueLength = 4; + uint32_t * key = (uint32_t *)kv->getKey(); + *key = bswap(index); + } + return block1; + } +}; + +TEST(MemoryBlockIterator, compare) { + std::vector vector1; + + vector1.push_back(2); + vector1.push_back(4); + vector1.push_back(6); + + std::vector vector2; + + vector2.push_back(1); + vector2.push_back(3); + vector2.push_back(5); + + ComparatorPtr bytesComparator = NativeTask::get_comparator(BytesType, NULL); + + MemoryBlock * block1 = MemoryBlockFactory::create(vector1); + MemoryBlock * block2 = MemoryBlockFactory::create(vector2); + + block1->sort(CPPSORT, bytesComparator); + block2->sort(CPPSORT, bytesComparator); + + MemBlockIterator * iter1 = new MemBlockIterator(block1); + MemBlockIterator * iter2 = new MemBlockIterator(block2); + + MemBlockComparator comparator(bytesComparator); + + ASSERT_EQ(false, comparator(iter1, iter2)); + + iter1->next(); + ASSERT_EQ(true, comparator(iter1, iter2)); + + iter2->next(); + ASSERT_EQ(false, comparator(iter1, iter2)); + + delete iter2; + delete iter1; + delete [] block2->base(); + delete [] block1->base(); + delete block2; + delete block1; +} +} // namespace NativeTask + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestMemoryBlock.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestMemoryBlock.cc new file mode 100644 index 00000000000..6af73c52ce3 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestMemoryBlock.cc @@ -0,0 +1,109 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "test_commons.h" +#include "lib/MapOutputSpec.h" +#include "lib/MemoryBlock.h" + +namespace NativeTaskTest { + +TEST(MemoryBlock, test) { + const uint32_t BUFFER_LENGTH = 1000; + char * bytes = new char[BUFFER_LENGTH]; + MemoryBlock block(bytes, BUFFER_LENGTH); + + uint32_t NON_EXIST = 3; + ASSERT_EQ(NULL, block.getKVBuffer(NON_EXIST)); + ASSERT_EQ(0, block.getKVCount()); + ASSERT_EQ(BUFFER_LENGTH, block.remainSpace()); + + ComparatorPtr bytesComparator = NativeTask::get_comparator(BytesType, NULL); + block.sort(CPPSORT, bytesComparator); + ASSERT_EQ(true, block.sorted()); + + const uint32_t KV_SIZE = 16; + KVBuffer * kv1 = block.allocateKVBuffer(KV_SIZE); + KVBuffer * kv2 = block.allocateKVBuffer(KV_SIZE); + + ASSERT_EQ(2, block.getKVCount()); + ASSERT_EQ(kv1, block.getKVBuffer(0)); + ASSERT_EQ(kv2, block.getKVBuffer(1)); + + ASSERT_EQ(BUFFER_LENGTH - 2 * KV_SIZE, block.remainSpace()); + ASSERT_EQ(false, block.sorted()); + delete [] bytes; +} + +TEST(MemoryBlock, overflow) { + const uint32_t BUFFER_LENGTH = 100; + char * bytes = new char[BUFFER_LENGTH]; + MemoryBlock block(bytes, BUFFER_LENGTH); + + const uint32_t KV_SIZE = 60; + KVBuffer * kv1 = block.allocateKVBuffer(KV_SIZE); + KVBuffer * kv2 = block.allocateKVBuffer(KV_SIZE); + + ASSERT_EQ(kv1, block.getKVBuffer(0)); + ASSERT_EQ(kv2, block.getKVBuffer(1)); + + ASSERT_EQ(1, block.getKVCount()); + + ASSERT_EQ(BUFFER_LENGTH - KV_SIZE, block.remainSpace()); + delete [] bytes; +} + +TEST(MemoryBlock, sort) { + const uint32_t BUFFER_LENGTH = 1000; + char * bytes = new char[BUFFER_LENGTH]; + MemoryBlock block(bytes, BUFFER_LENGTH); + + const uint32_t KV_SIZE = 16; + KVBuffer * big = block.allocateKVBuffer(KV_SIZE); + KVBuffer * small = block.allocateKVBuffer(KV_SIZE); + KVBuffer * medium = block.allocateKVBuffer(KV_SIZE); + + const uint32_t SMALL = 100; + const uint32_t MEDIUM = 1000; + const uint32_t BIG = 10000; + + medium->keyLength = 4; + medium->valueLength = 4; + uint32_t * mediumKey = (uint32_t *)medium->getKey(); + *mediumKey = bswap(MEDIUM); + + small->keyLength = 4; + small->valueLength = 4; + uint32_t * smallKey = (uint32_t *)small->getKey(); + *smallKey = bswap(SMALL); + + big->keyLength = 4; + big->valueLength = 4; + uint32_t * bigKey = (uint32_t *)big->getKey(); + *bigKey = bswap(BIG); + + ComparatorPtr bytesComparator = NativeTask::get_comparator(BytesType, NULL); + block.sort(CPPSORT, bytesComparator); + + ASSERT_EQ(small, block.getKVBuffer(0)); + ASSERT_EQ(medium, block.getKVBuffer(1)); + ASSERT_EQ(big, block.getKVBuffer(2)); + delete [] bytes; +} + +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestMemoryPool.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestMemoryPool.cc new file mode 100644 index 00000000000..e33421d68f2 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestMemoryPool.cc @@ -0,0 +1,48 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "test_commons.h" +#include "lib/PartitionBucket.h" +#include "lib/PartitionBucketIterator.h" +#include "lib/MemoryBlock.h" +#include "lib/IFile.h" + +namespace NativeTask { + +TEST(MemoryPool, general) { + MemoryPool * pool = new MemoryPool(); + const uint32_t POOL_SIZE = 1024; + + pool->init(POOL_SIZE); + + uint32_t min = 1024; + uint32_t expect = 2048; + uint32_t allocated = 0; + char * buff = pool->allocate(min, expect, allocated); + ASSERT_NE((void *)NULL, buff); + buff = pool->allocate(min, expect, allocated); + ASSERT_EQ(NULL, buff); + + pool->reset(); + buff = pool->allocate(min, expect, allocated); + ASSERT_NE((void *)NULL, buff); + + delete pool; +} +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestPartitionBucket.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestPartitionBucket.cc new file mode 100644 index 00000000000..79e1b5e9541 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestPartitionBucket.cc @@ -0,0 +1,222 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "test_commons.h" +#include "lib/PartitionBucket.h" +#include "lib/PartitionBucketIterator.h" +#include "lib/MemoryBlock.h" +#include "lib/IFile.h" + +namespace NativeTask { + +class MockIFileWriter : public IFileWriter { + private: + char * _buff; + uint32_t _position; + uint32_t _capacity; + + public: + MockIFileWriter(char * buff, uint32_t capacity) + : IFileWriter(NULL, CHECKSUM_NONE, TextType, TextType, "", NULL), _buff(buff), _position(0), + _capacity(capacity) { + } + + virtual void write(const char * key, uint32_t keyLen, const char * value, uint32_t valueLen) { + KVBuffer * kv = (KVBuffer *)(_buff + _position); + kv->keyLength = keyLen; + kv->valueLength = valueLen; + *((uint32_t *)kv->getKey()) = *((uint32_t *)key); + *((uint32_t *)kv->getValue()) = *((uint32_t *)value); + _position += kv->length(); + } + + char * buff() { + return _buff; + } +}; + +TEST(PartitionBucket, general) { + MemoryPool * pool = new MemoryPool(); + const uint32_t POOL_SIZE = 1024 * 1024; // 1MB + const uint32_t BLOCK_SIZE = 1024; // 1KB + const uint32_t PARTITION_ID = 3; + pool->init(POOL_SIZE); + ComparatorPtr comparator = NativeTask::get_comparator(BytesType, NULL); + PartitionBucket * bucket = new PartitionBucket(pool, PARTITION_ID, comparator, NULL, BLOCK_SIZE); + ASSERT_EQ(0, bucket->getKVCount()); + KVIterator * NULLPOINTER = 0; + ASSERT_EQ(NULLPOINTER, bucket->getIterator()); + ASSERT_EQ(PARTITION_ID, bucket->getPartitionId()); + bucket->sort(DUALPIVOTSORT); + bucket->spill(NULL); + + delete bucket; + delete pool; +} + +TEST(PartitionBucket, multipleMemoryBlock) { + MemoryPool * pool = new MemoryPool(); + const uint32_t POOL_SIZE = 1024 * 1024; // 1MB + const uint32_t BLOCK_SIZE = 1024; // 1KB + const uint32_t PARTITION_ID = 3; + pool->init(POOL_SIZE); + ComparatorPtr comparator = NativeTask::get_comparator(BytesType, NULL); + PartitionBucket * bucket = new PartitionBucket(pool, PARTITION_ID, comparator, NULL, BLOCK_SIZE); + + const uint32_t KV_SIZE = 700; + const uint32_t SMALL_KV_SIZE = 100; + // To suppress valgrind error + // the allocated buffer needs to be initialized before + // create iterator on the PartitionBucker, because + // those memory will be compared when create minheap + KVBuffer * kv1 = bucket->allocateKVBuffer(KV_SIZE); + memset(kv1, 0, KV_SIZE); + KVBuffer * kv2 = bucket->allocateKVBuffer(SMALL_KV_SIZE); + memset(kv2, 0, SMALL_KV_SIZE); + KVBuffer * kv3 = bucket->allocateKVBuffer(KV_SIZE); + memset(kv3, 0, KV_SIZE); + + ASSERT_EQ(3, bucket->getKVCount()); + KVIterator * NULLPOINTER = 0; + KVIterator * iter = bucket->getIterator(); + ASSERT_NE(NULLPOINTER, iter); + delete iter; + ASSERT_EQ(2, bucket->getMemoryBlockCount()); + + bucket->reset(); + iter = bucket->getIterator(); + ASSERT_EQ(NULLPOINTER, iter); + delete iter; + ASSERT_EQ(0, bucket->getMemoryBlockCount()); + + delete bucket; + delete pool; +} + +TEST(PartitionBucket, sort) { + MemoryPool * pool = new MemoryPool(); + const uint32_t POOL_SIZE = 1024 * 1024; // 1MB + const uint32_t BLOCK_SIZE = 1024; // 1KB + const uint32_t PARTITION_ID = 3; + pool->init(POOL_SIZE); + ComparatorPtr comparator = NativeTask::get_comparator(BytesType, NULL); + PartitionBucket * bucket = new PartitionBucket(pool, PARTITION_ID, comparator, NULL, BLOCK_SIZE); + + const uint32_t KV_SIZE = 700; + const uint32_t SMALL_KV_SIZE = 100; + KVBuffer * kv1 = bucket->allocateKVBuffer(KV_SIZE); + KVBuffer * kv2 = bucket->allocateKVBuffer(SMALL_KV_SIZE); + KVBuffer * kv3 = bucket->allocateKVBuffer(KV_SIZE); + + const uint32_t SMALL = 10; + const uint32_t MEDIUM = 100; + const uint32_t BIG = 1000; + + kv1->keyLength = 4; + *((uint32_t *)kv1->getKey()) = bswap(BIG); + kv1->valueLength = KV_SIZE - kv1->headerLength() - kv1->keyLength; + + kv2->keyLength = 4; + *((uint32_t *)kv2->getKey()) = bswap(SMALL); + kv2->valueLength = KV_SIZE - kv2->headerLength() - kv2->keyLength; + + kv3->keyLength = 4; + *((uint32_t *)kv3->getKey()) = bswap(MEDIUM); + kv3->valueLength = KV_SIZE - kv3->headerLength() - kv3->keyLength; + + bucket->sort(DUALPIVOTSORT); + + KVIterator * iter = bucket->getIterator(); + + Buffer key; + Buffer value; + iter->next(key, value); + + ASSERT_EQ(SMALL, bswap(*(uint32_t * )key.data())); + + iter->next(key, value); + ASSERT_EQ(MEDIUM, bswap(*(uint32_t * )key.data())); + + iter->next(key, value); + ASSERT_EQ(BIG, bswap(*(uint32_t * )key.data())); + + delete iter; + delete bucket; + delete pool; +} + +TEST(PartitionBucket, spill) { + MemoryPool * pool = new MemoryPool(); + const uint32_t POOL_SIZE = 1024 * 1024; // 1MB + const uint32_t BLOCK_SIZE = 1024; // 1KB + const uint32_t PARTITION_ID = 3; + pool->init(POOL_SIZE); + ComparatorPtr comparator = NativeTask::get_comparator(BytesType, NULL); + PartitionBucket * bucket = new PartitionBucket(pool, PARTITION_ID, comparator, NULL, BLOCK_SIZE); + + const uint32_t KV_SIZE = 700; + const uint32_t SMALL_KV_SIZE = 100; + KVBuffer * kv1 = bucket->allocateKVBuffer(KV_SIZE); + KVBuffer * kv2 = bucket->allocateKVBuffer(SMALL_KV_SIZE); + KVBuffer * kv3 = bucket->allocateKVBuffer(KV_SIZE); + + const uint32_t SMALL = 10; + const uint32_t MEDIUM = 100; + const uint32_t BIG = 1000; + + kv1->keyLength = 4; + *((uint32_t *)kv1->getKey()) = bswap(BIG); + kv1->valueLength = KV_SIZE - KVBuffer::headerLength() - kv1->keyLength; + + kv2->keyLength = 4; + *((uint32_t *)kv2->getKey()) = bswap(SMALL); + kv2->valueLength = KV_SIZE - KVBuffer::headerLength() - kv2->keyLength; + + kv3->keyLength = 4; + *((uint32_t *)kv3->getKey()) = bswap(MEDIUM); + kv3->valueLength = KV_SIZE - KVBuffer::headerLength() - kv3->keyLength; + + bucket->sort(DUALPIVOTSORT); + + uint32_t BUFF_SIZE = 1024 * 1024; + char * buff = new char[BUFF_SIZE]; + MockIFileWriter writer(buff, BUFF_SIZE); + bucket->spill(&writer); + + // check the result + KVBuffer * first = (KVBuffer *)writer.buff(); + ASSERT_EQ(4, first->keyLength); + ASSERT_EQ(KV_SIZE - KVBuffer::headerLength() - 4, first->valueLength); + ASSERT_EQ(bswap(SMALL), (*(uint32_t * )(first->getKey()))); + + KVBuffer * second = first->next(); + ASSERT_EQ(4, second->keyLength); + ASSERT_EQ(KV_SIZE - KVBuffer::headerLength() - 4, second->valueLength); + ASSERT_EQ(bswap(MEDIUM), (*(uint32_t * )(second->getKey()))); + + KVBuffer * third = second->next(); + ASSERT_EQ(4, third->keyLength); + ASSERT_EQ(KV_SIZE - KVBuffer::headerLength() - 4, third->valueLength); + ASSERT_EQ(bswap(BIG), (*(uint32_t * )(third->getKey()))); + + delete [] buff; + delete bucket; + delete pool; +} +} // namespace NativeTask diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestReadBuffer.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestReadBuffer.cc new file mode 100644 index 00000000000..1a4b290d5d8 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestReadBuffer.cc @@ -0,0 +1,69 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "config.h" +#include "lib/BufferStream.h" +#include "lib/Buffers.h" +#include "test_commons.h" + +TEST(Buffers, AppendRead) { + string codec = ""; + vector data; + Generate(data, 100000, "word"); + string dest; + dest.reserve(64 * 1024 * 1024); + OutputStringStream outputStream = OutputStringStream(dest); + AppendBuffer appendBuffer; + appendBuffer.init(64 * 1024, &outputStream, codec); + for (size_t i = 0; i < data.size(); i++) { + appendBuffer.write(data[i].c_str(), data[i].length()); + } + appendBuffer.flush(); + InputBuffer inputBuffer = InputBuffer(dest.c_str(), dest.length()); + ReadBuffer readBuffer = ReadBuffer(); + readBuffer.init(64 * 1024, &inputBuffer, codec); + for (size_t i = 0; i < data.size(); i++) { + const char * rd = readBuffer.get(data[i].length()); + ASSERT_EQ(data[i], string(rd, data[i].length())); + } +} + +#if defined HADOOP_SNAPPY_LIBRARY +TEST(Buffers, AppendReadSnappy) { + string codec = "org.apache.hadoop.io.compress.SnappyCodec"; + vector data; + Generate(data, 100000, "word"); + string dest; + dest.reserve(64 * 1024 * 1024); + OutputStringStream outputStream = OutputStringStream(dest); + AppendBuffer appendBuffer; + appendBuffer.init(64 * 1024, &outputStream, codec); + for (size_t i = 0; i < data.size(); i++) { + appendBuffer.write(data[i].c_str(), data[i].length()); + } + appendBuffer.flush(); + InputBuffer inputBuffer = InputBuffer(dest.c_str(), dest.length()); + ReadBuffer readBuffer = ReadBuffer(); + readBuffer.init(64 * 1024, &inputBuffer, codec); + for (size_t i = 0; i < data.size(); i++) { + const char * rd = readBuffer.get(data[i].length()); + ASSERT_EQ(data[i], string(rd, data[i].length())); + } +} +#endif diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestReadWriteBuffer.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestReadWriteBuffer.cc new file mode 100644 index 00000000000..f32989c4ccf --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/lib/TestReadWriteBuffer.cc @@ -0,0 +1,70 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "lib/commons.h" +#include "lib/Combiner.h" +#include "test_commons.h" +#include + +namespace NativeTask { + +TEST(ReadWriteBuffer, readAndWrite) { + ReadWriteBuffer buff(16); + + int INT = 100; + int LONG = 200; + std::string STR = "hello, readWriteBuffer"; + void * POINTER = this; + + int REPEAT = 10; + + for (int i = 0; i < REPEAT; i++) { + buff.writeInt(INT); + buff.writeLong(LONG); + buff.writeString(&STR); + buff.writePointer(POINTER); + buff.writeString(STR.c_str(), STR.length()); + } + + uint32_t writePoint = buff.getWritePoint(); + + for (int i = 0; i < REPEAT; i++) { + ASSERT_EQ(INT, buff.readInt()); + ASSERT_EQ(LONG, buff.readLong()); + string * read = buff.readString(); + ASSERT_EQ(0, STR.compare(read->c_str())); + delete read; + + ASSERT_EQ(POINTER, buff.readPointer()); + + read = buff.readString(); + ASSERT_EQ(0, STR.compare(read->c_str())); + delete read; + } + + uint32_t readPoint = buff.getReadPoint(); + ASSERT_EQ(writePoint, readPoint); + + buff.setWritePoint(0); + buff.setReadPoint(0); + + ASSERT_EQ(0, buff.getReadPoint()); + ASSERT_EQ(0, buff.getWritePoint()); +} + +} /* namespace NativeTask */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/test_commons.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/test_commons.cc new file mode 100644 index 00000000000..f7332be0d6a --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/test_commons.cc @@ -0,0 +1,344 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "lib/commons.h" +#include "util/Random.h" +#include "lib/FileSystem.h" +#include "test_commons.h" + +Config TestConfig = Config(); + +const char * GenerateSeed = "generate.seed"; +const char * GenerateChoice = "generate.choice"; +const char * GenerateLen = "generate.len"; +const char * GenerateKeyLen = "generate.key.len"; +const char * GenerateValueLen = "generate.value.len"; +const char * GenerateRange = "generate.range"; +const char * GenerateKeyRange = "generate.key.range"; +const char * GenerateValueRange = "generate.value.range"; + +vector & MakeStringArray(vector & dest, ...) { + va_list al; + va_start(al, dest); + while (true) { + const char * s = va_arg(al, const char *); + if (s == NULL) { + break; + } + dest.push_back(s); + } + va_end(al); + return dest; +} + +GenerateType GetGenerateType(const string & type) { + if (type == "word") { + return GenWord; + } else if (type == "number") { + return GenNumber; + } else if (type == "bytes") { + return GenBytes; + } else { + THROW_EXCEPTION(UnsupportException, "GenerateType not support"); + } +} + +string & GenerateOne(string & dest, Random & r, GenerateType gtype, int64_t choice, int64_t len, + int64_t range) { + switch (gtype) { + case GenWord: + r.nextWord(dest, choice); + break; + case GenNumber: + uint64_t v; + if (choice > 0) { + v = r.next_int32(choice); + } else { + v = r.next_uint64(); + } + if (len > 0) { + dest = StringUtil::ToString(v, '0', len); + } else { + dest = StringUtil::ToString(v); + } + break; + case GenBytes: + if (range < 2) { + if (len > 0) { + dest = r.nextBytes(len, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + } else { + dest = r.nextBytes(r.next_int32(32), "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + } + } else { + if (len > 0) { + int64_t nlen = len - range / 2 + r.next_int32(range); + if (nlen > 0) { + dest = r.nextBytes(nlen, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + } else { + dest = ""; + } + } else { + dest = r.nextBytes(r.next_int32(range), "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + } + } + break; + default: + THROW_EXCEPTION(IOException, "GenerateType not support"); + } + return dest; +} + +/** + * Generate random string sequences + * @param dest dest array + * @param size output array size + * @param type string type (word|number|bytes|tera) + */ +vector & Generate(vector & dest, uint64_t size, const string & type) { + Random r; + if (TestConfig.get(GenerateSeed) != NULL) { + r.setSeed(TestConfig.getInt(GenerateSeed, 0)); + } + GenerateType gtype = GetGenerateType(type); + int64_t choice = TestConfig.getInt(GenerateChoice, -1); + int64_t len = TestConfig.getInt(GenerateLen, -1); + int64_t range = TestConfig.getInt(GenerateRange, 1); + string temp; + for (uint64_t i = 0; i < size; i++) { + dest.push_back(GenerateOne(temp, r, gtype, choice, len, range)); + } + return dest; +} + +/** + * Generate random string pair sequences + * @param dest dest array + * @param size output array size + * @param type string type (word|number|bytes|tera) + */ +vector > & Generate(vector > & dest, uint64_t size, + const string & type) { + Random r; + if (TestConfig.get(GenerateSeed) != NULL) { + r.setSeed(TestConfig.getInt(GenerateSeed, 0)); + } + GenerateType gtype = GetGenerateType(type); + int64_t choice = TestConfig.getInt(GenerateChoice, -1); + int64_t keylen = TestConfig.getInt(GenerateKeyLen, -1); + int64_t valuelen = TestConfig.getInt(GenerateValueLen, -1); + int64_t keyRange = TestConfig.getInt(GenerateKeyRange, 1); + int64_t valueRange = TestConfig.getInt(GenerateValueRange, 1); + string key, value; + for (uint64_t i = 0; i < size; i++) { + GenerateOne(key, r, gtype, choice, keylen, keyRange); + GenerateOne(value, r, gtype, choice, valuelen, valueRange); + dest.push_back(std::make_pair(key, value)); + } + return dest; +} + +/** + * Generate random string pair sequences + * @param dest dest array + * @param length output bytes count + * @param type string type (word|number|bytes|tera) + */ +vector > & GenerateLength(vector > & dest, + uint64_t length, const string & type) { + Random r; + if (TestConfig.get(GenerateSeed) != NULL) { + r.setSeed(TestConfig.getInt(GenerateSeed, 0)); + } + GenerateType gtype = GetGenerateType(type); + int64_t choice = TestConfig.getInt(GenerateChoice, -1); + int64_t keylen = TestConfig.getInt(GenerateKeyLen, -1); + int64_t valuelen = TestConfig.getInt(GenerateValueLen, -1); + int64_t keyRange = TestConfig.getInt(GenerateKeyRange, 1); + int64_t valueRange = TestConfig.getInt(GenerateValueRange, 1); + string key, value; + dest.reserve((size_t)(length / (keylen + valuelen) * 1.2)); + for (uint64_t i = 0; i < length;) { + GenerateOne(key, r, gtype, choice, keylen, keyRange); + GenerateOne(value, r, gtype, choice, valuelen, valueRange); + dest.push_back(std::make_pair(key, value)); + i += (key.length() + value.length() + 2); + } + return dest; +} + +/** + * Generate random KV text: + * Key0\tValue0\n + * Key1\tValue1\n + * ... + * @param dest dest string contain generated text + * @param size output array size + * @param type string type (word|number|bytes|tera) + */ +string & GenerateKVText(string & dest, uint64_t size, const string & type) { + Random r; + if (TestConfig.get(GenerateSeed) != NULL) { + r.setSeed(TestConfig.getInt(GenerateSeed, 0)); + } + GenerateType gtype = GetGenerateType(type); + int64_t choice = TestConfig.getInt(GenerateChoice, -1); + int64_t keylen = TestConfig.getInt(GenerateKeyLen, -1); + int64_t valuelen = TestConfig.getInt(GenerateValueLen, -1); + int64_t keyRange = TestConfig.getInt(GenerateKeyRange, 1); + int64_t valueRange = TestConfig.getInt(GenerateValueRange, 1); + string key, value; + for (uint64_t i = 0; i < size; i++) { + GenerateOne(key, r, gtype, choice, keylen, keyRange); + GenerateOne(value, r, gtype, choice, valuelen, valueRange); + dest.append(key); + dest.append("\t"); + dest.append(value); + dest.append("\n"); + } + return dest; +} + +/** + * Generate random KV text: + * Key0\tValue0\n + * Key1\tValue1\n + * ... + * @param dest dest string contain generated text + * @param length output string length + * @param type string type (word|number|bytes) + */ +string & GenerateKVTextLength(string & dest, uint64_t length, const string & type) { + Random r; + if (TestConfig.get(GenerateSeed) != NULL) { + r.setSeed(TestConfig.getInt(GenerateSeed, 0)); + } + GenerateType gtype = GetGenerateType(type); + int64_t choice = TestConfig.getInt(GenerateChoice, -1); + int64_t keylen = TestConfig.getInt(GenerateKeyLen, -1); + int64_t valuelen = TestConfig.getInt(GenerateValueLen, -1); + int64_t keyRange = TestConfig.getInt(GenerateKeyRange, 1); + int64_t valueRange = TestConfig.getInt(GenerateValueRange, 1); + string key, value; + while (dest.length() < length) { + GenerateOne(key, r, gtype, choice, keylen, keyRange); + GenerateOne(value, r, gtype, choice, valuelen, valueRange); + dest.append(key); + dest.append("\t"); + dest.append(value); + dest.append("\n"); + } + return dest; +} + +/** + * File <-> String utilities + */ +string & ReadFile(string & dest, const string & path) { + FILE * fin = fopen(path.c_str(), "rb"); + if (NULL == fin) { + THROW_EXCEPTION(IOException, "file not found or can not open for read"); + } + char buff[1024 * 16]; + while (true) { + size_t rd = fread(buff, 1, 1024 * 16, fin); + if (rd <= 0) { + break; + } + dest.append(buff, rd); + } + fclose(fin); + return dest; +} + +void WriteFile(const string & content, const string & path) { + FILE * fout = fopen(path.c_str(), "wb"); + if (NULL == fout) { + THROW_EXCEPTION(IOException, "file can not open for write"); + } + size_t wt = fwrite(content.c_str(), 1, content.length(), fout); + if (wt != content.length()) { + THROW_EXCEPTION(IOException, "write file error"); + } + fclose(fout); +} + +bool FileEqual(const string & lh, const string & rh) { + string lhs, rhs; + ReadFile(lhs, lh); + ReadFile(rhs, rh); + return lhs == rhs; +} + +KVGenerator::KVGenerator(uint32_t keylen, uint32_t vallen, bool unique) + : keylen(keylen), vallen(vallen), unique(unique) { + factor = 2999999; + keyb = new char[keylen + 32]; + valb = new char[vallen + 32]; + snprintf(keyformat, 32, "%%0%ulx", keylen); +} + +KVGenerator::~KVGenerator() { + delete[] keyb; + delete[] valb; +} + +char * KVGenerator::key(uint32_t & kl) { + long v; + if (unique) { + while (true) { + v = lrand48(); + if (old_keys.find(v) == old_keys.end()) { + old_keys.insert(v); + break; + } + } + } else { + v = lrand48(); + } + snprintf(keyb, keylen + 32, keyformat, v); + kl = keylen; + return keyb; +} + +char * KVGenerator::value(uint32_t & vl) { + uint32_t off = 0; + while (off < vallen) { + long v = lrand48(); + v = (v / factor) * factor; + uint32_t wn = snprintf(valb + off, vallen + 32 - off, "%09lx\t", v); + off += wn; + } + vl = vallen; + return valb; +} + +void KVGenerator::write(FILE * fout, int64_t totallen) { + while (totallen > 0) { + uint32_t kl, vl; + char * key = this->key(kl); + char * value = this->value(vl); + fwrite(key, kl, 1, fout); + fputc('\t', fout); + fwrite(value, vl, 1, fout); + fputc('\n', fout); + totallen -= (kl + vl + 2); + } + fflush(fout); +} + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/test_commons.h b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/test_commons.h new file mode 100644 index 00000000000..90d48ec27b0 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/test_commons.h @@ -0,0 +1,150 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TEST_COMMONS_H_ +#define TEST_COMMONS_H_ + +#include "gtest/gtest.h" +#include "commons.h" +#include "util/Random.h" +#include "util/StringUtil.h" +#include "util/Timer.h" +#include "lib/Buffers.h" +#include "lib/BufferStream.h" + +using std::pair; +using std::vector; +using std::set; +using std::map; +using std::string; + +using namespace NativeTask; + +extern Config TestConfig; + +/** + * e.g. MakeStringArray(dest, "a", "b", "c", NULL) = {"a","b","c"} + */ +vector & MakeStringArray(vector & dest, ...); + +extern const char * GenerateSeed; +extern const char * GenerateChoice; +extern const char * GenerateLen; +extern const char * GenerateKeyLen; +extern const char * GenerateValueLen; +extern const char * GenerateRange; +extern const char * GenerateKeyRange; +extern const char * GenerateValueRange; + +enum GenerateType { + GenWord, + GenNumber, + GenBytes, +}; + +GenerateType GetGenerateType(const string & type); + +string & GenerateOne(string & dest, Random & r, GenerateType gtype, int64_t choice, int64_t len, + int64_t range = 0); +/** + * Generate random string sequences + * @param dest dest array + * @param size output array size + * @param type string type (word|number|bytes|tera) + */ +vector & Generate(vector & dest, uint64_t size, const string & type); + +/** + * Generate random string pair sequences + * @param dest dest array + * @param size output array size + * @param type string type (word|number|bytes|tera) + */ +vector > & Generate(vector > & dest, uint64_t size, + const string & type); + +/** + * Generate random string pair sequences + * @param dest dest array + * @param length output bytes count + * @param type string type (word|number|bytes|tera) + */ +vector > & GenerateLength(vector > & dest, + uint64_t length, const string & type); + +/** + * Generate random KV text: + * Key0\tValue0\n + * Key1\tValue1\n + * ... + * @param dest dest string contain generated text + * @param size output kv pair count + * @param type string type (word|number|bytes|tera) + */ +string & GenerateKVText(string & dest, uint64_t size, const string & type); + +/** + * Generate random KV text: + * Key0\tValue0\n + * Key1\tValue1\n + * ... + * @param dest dest string contain generated text + * @param length output string length + * @param type string type (word|number|bytes|tera) + */ +string & GenerateKVTextLength(string & dest, uint64_t length, const string & type); + +/** + * File <-> String utilities + */ +string & ReadFile(string & dest, const string & path); +void WriteFile(const string & content, const string & path); + +/** + * File compare + */ +bool FileEqual(const string & lh, const string & rh); + +/** + * generate k/v pairs with normal compression ratio + * + */ +class KVGenerator { +protected: + uint32_t keylen; + uint32_t vallen; + bool unique; + long factor; + char * keyb; + char * valb; + char keyformat[32]; + set old_keys; + +public: + KVGenerator(uint32_t keylen, uint32_t vallen, bool unique = false); + + ~KVGenerator(); + + char * key(uint32_t & kl); + + char * value(uint32_t & vl); + + void write(FILE * fout, int64_t totallen); +}; + +#endif /* TEST_COMMONS_H_ */ diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/util/TestChecksum.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/util/TestChecksum.cc new file mode 100644 index 00000000000..d77656ada41 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/util/TestChecksum.cc @@ -0,0 +1,43 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/Checksum.h" +#include "test_commons.h" + +void TestChecksum(ChecksumType type, void * buff, uint32_t len) { + uint32_t chm = Checksum::init(type); + Checksum::update(type, chm, buff, len); +} + +TEST(Perf, CRC) { + uint32_t len = TestConfig.getInt("checksum.perf.size", 1024 * 1024 * 50); + int testTime = TestConfig.getInt("checksum.perf.time", 2); + char * buff = new char[len]; + memset(buff, 1, len); + Timer timer; + for (int i = 0; i < testTime; i++) { + TestChecksum(CHECKSUM_CRC32, buff, len); + } + LOG("%s", timer.getSpeedM("CRC", len * testTime).c_str()); + timer.reset(); + for (int i = 0; i < testTime; i++) { + TestChecksum(CHECKSUM_CRC32C, buff, len); + } + LOG("%s", timer.getSpeedM("CRC32C", len * testTime).c_str()); + delete[] buff; +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/util/TestProcess.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/util/TestProcess.cc new file mode 100644 index 00000000000..cf857d3a5f2 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/util/TestProcess.cc @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/Process.h" +#include "test_commons.h" + +TEST(Process, Run) { + string out; + string err; + string cmd = TestConfig.get("process.run.cmd", "ls"); + int retcode = Process::Run(cmd, &out, &err); + LOG("cmd: %s", cmd.c_str()); + LOG("stdout: %s", out.c_str()); + LOG("stderr: %s", err.c_str()); + LOG("retcode: %d", retcode); + EXPECT_EQ(0, retcode); +} + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/util/TestStringUtil.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/util/TestStringUtil.cc new file mode 100644 index 00000000000..5cc79a93f27 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/util/TestStringUtil.cc @@ -0,0 +1,64 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/StringUtil.h" +#include "test_commons.h" + +TEST(StringUtil, Convertion) { + ASSERT_FLOAT_EQ(StringUtil::toFloat("1.333"), 1.333); + ASSERT_FLOAT_EQ(StringUtil::toFloat(StringUtil::ToString(1.333f)), 1.333); + ASSERT_EQ(StringUtil::ToString(76957382U), "76957382"); + ASSERT_EQ(StringUtil::ToString((uint64_t )76957382234233432ULL), "76957382234233432"); + ASSERT_EQ(StringUtil::ToString(111, ' ', 40), " 111"); +} + +TEST(StringUtil, ToHexString) { + uint8_t buff[4] = {'i', 'j', 'k', 'l'}; + ASSERT_EQ(StringUtil::ToHexString(buff, 4), string("696a6b6c")); +} + +TEST(StringUtil, Format) { + string t = StringUtil::Format("%d %d %d %.3lf %s", 1, 2, 3, 1.333, "aaaaaaaaaaa"); + ASSERT_EQ(t, "1 2 3 1.333 aaaaaaaaaaa"); + string longstring(999, 'a'); + string d = StringUtil::Format("%s", longstring.c_str()); + ASSERT_EQ(longstring, d); +} + +TEST(StringUtil, Trim) { + ASSERT_EQ(StringUtil::Trim(" \taaaa \t "), "aaaa"); + ASSERT_EQ(StringUtil::Trim(" \t \t "), ""); + ASSERT_EQ(StringUtil::Trim(""), ""); +} + +TEST(StringUtil, ToLower) { + ASSERT_EQ(StringUtil::ToLower("111ABabABabAbaB222"), "111abababababab222"); + ASSERT_EQ(StringUtil::ToLower(""), ""); +} + +TEST(StringUtil, JoinSplit) { + vector temp1, temp2, temp3, temp4; + StringUtil::Split("1aaa bbb ccc", " ", temp1, false); + StringUtil::Split(" 1aaa bbb ccc ", " ", temp2, true); + ASSERT_EQ(temp1, temp2); + string j = StringUtil::Join(temp1, ","); + ASSERT_EQ(j, "1aaa,bbb,ccc"); + StringUtil::Split(" a b ", " ", temp3, false); + ASSERT_EQ(temp3, MakeStringArray(temp4, "", "", "a", "b", "", NULL)); +} + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/util/TestWritableUtils.cc b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/util/TestWritableUtils.cc new file mode 100644 index 00000000000..f692c35fcb6 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/test/util/TestWritableUtils.cc @@ -0,0 +1,49 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "util/WritableUtils.h" +#include "test_commons.h" + +void TestVLong(int64_t v) { + char buff[1024]; + char buff2[1024]; + uint32_t dsize = WritableUtils::GetVLongSize(v); + uint32_t wsize = (uint32_t)-1; + WritableUtils::WriteVLong(v, buff, wsize); + ASSERT_EQ(dsize, wsize); + memcpy(buff2, buff, wsize); + uint32_t rsize; + int64_t rv = WritableUtils::ReadVLong(buff2, rsize); + ASSERT_EQ(v, rv); + ASSERT_EQ(rsize, dsize); +} + + +TEST(WritableUtils, VLong) { + int num = TestConfig.getInt("test.size", 3000); + int seed = TestConfig.getInt("test.seed", -1); + Random r(seed); + for (int i = 0; i < num; i++) { + uint64_t v = r.nextLog2(((uint64_t)-1) / 2 - 3); + TestVLong(v); + TestVLong(-v); + } +} + + + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/testData/testGlibCBugSpill.out b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/testData/testGlibCBugSpill.out new file mode 100644 index 00000000000..168a65da67a --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/native/testData/testGlibCBugSpill.out @@ -0,0 +1,2 @@ +Ó*¤PKMÓ&:\xBD\xC8\xCA\xCB\xAA\xB4c`\xD5|A1+\xCB\xDC\xAA\x7F\x1D\xA4\x1Bx\x1B\xD1k\xE1\x01\x0E\xEA\xC82\xB7\xF8 \xBD.z\xEFH\xFB*\xE8\xBD\xD4\x15o\x82\xA1\x0F}\x03\x00\x17\xC7\xF7Ce*T\x1D\xC4tk\xE7\x0CS\xBF["\xADW{\xB9\xFFLM\xB2\x87\x03\xFC\xC2\xE2\x9C%\xCB\xFF\x9A\x97]\x15_N\xA3\x8F&Db\xA6\x172\x99\xF8+\xA4\xA5\xAC4n\x0D}\xA0/[\xBD\xFD\xC4\xA7\xBCj\xF8\x85\xC6V\x87B\xBA\x85\x8A\xCDZ\xFBU\x84\xD7\xBC\xAB\x84H}_v\xC4\xB2\x11\x19\xDB\x06\x93\xB5\xBE\x92E\xCE\xFA\x02RG\xE4\xA3HcI4\xAB.X\xA5\xB8a\x06\x1E.\xADS\xFB\x8A&W\xDA\xCA2^\\x90\x87\x95l]r\x99\x88b\x1EU\xC8\xE0l\x1F#h\x08\xA8\x80I\x9B\xC0E\x19%\xDE\xE5\xA6?\xC2\x83\xA0\xD6O1\xFB_\x94\xF8\x8F\xD6\xD9\x16\xE2\x91\x1E\x8EL\x1F\xA2Y\x05\x9CoMN\x0C\x86\xE2\xE9\x9A\xB16o\xF6\xF3Q\xA2\xD8\xB8\xD0\xDB\x86\x93\xAFesc\xA0h\x12\xB9E\x1BU\x12\x02OXS\x8BXn\x0EQ\xABJ\xCE\xB2k\xB1\xD7Z'\xE4\xB7[`~4\x11\xB4\xCD`\xF5%\x1F\xF9\xEEW\x88\xC5\x14<+O\x1B9B>\x11\x95<\xDE\xD5\xA4C]\\xF1\x0C\xD5\xF4\x0E#\x87}\xE3\x89\xA2\xC2\xEA\x86\x9D\xE7\xAF\xA1\xC3;\xD2\xFF\xA6\xB2!\xAB\\x90i|n\xDE\xBB>:\xC6\x08\x1D,Q\xC1;\x15\x9D>UV\x8F\xD3;\xFA\x12\xD0U\xA9\xD7<\xC6\xFDX\x8F\x10vX\xF1\xF9H7\x12Z\x1FoB\x8B\xD6\xF0\x04\xEB\xA2\xC1\xACH\xFE\xC9_R\xF5\x1D\xA8\x82\xBD\xC6\x11\x19#\x9A\xA8\x09\x95\x06\x98\xA9f\xD9\x12\xA0i\xFA\xD3\xB2\x01\xE9\x06\x14"~."z\xDF\xF2YV#z\xEB-\xFA$[U\xA6\xE2.\xD6\xD0kf\xA3\x83\xE0\x86\xD9\xC1\x7FO\xE9\xF4\xEF\x81\x06\xA3\xDE\xC8\xAC"t\x8B\xCAr\xE6\x82$8\x0F\xE1\x06\xF9\xBB\x0C\x9F\xAA"8\x94\xBBU\x8DQ\xC3\xE9@'\xF9\xBF\xCF\x8B\xD4\x995\xEB\xE9t3Q\x10\xD7\x0D\x9D\x94\xCA\x84\xC2\xE2{\x0B\x89r\xA6\xC6\xAA\xE5C\xC6U\xA6\xD1tqa\xA0\xD7RO\x92\xC9\xBE"\xF9\xD1\xDE\x93b\x06\xD3ae:\xB7\x8C\x99\xD6\xFFI\x86\x8CvtX@k\xE4m\x93wz\x8A\xC2U\xFBb\xA2\x9Ao\xAF\x8D\x19k\xA2pP\x83s\xFE\x0E\x0FY\xA0\xA7E'\xC0\x02\xF4\x98A5\xF2\x8A?\x04$\x89\xC7]\x0A\xFBX\x97*\xAEN\x13#\xB3a\xD2y\xD3#_B\xAC\x05:\xAC\x92\xEAO\x08H\x88N\x1A\xB9\xDC\xFA\x11ikJ\x12!\xE8u\xCD+\x88\x98\xE3c\xCB\xD9<1%\x98KDN\xC6\xF2\xB7\x86o6\x91P`\x9B\xA1\x0B\x82\xEB\x15H\xA0\xC4\x85\xDF\xAC"\xA1b\xD9\xA3b\xB8E\xB59_\xF4\xCCWH\x09&5\xE6\xBE\xF2\x19FC\x0E\xAB\xEA6\x0C\xAD5\x90/$D\xB3\x9E\x81[9j\x8A\xC4\x85\xAAA\x7Fe\xDCG8\x00\xDA\xCFi\xBDp\x18?\xF5\xA8~@\xC1\x08\xDF\xE5\xAE,\xDF0t\xCB\x92W8&V\x01F\x1A./\x8D\xAF\xD8\x87\xCE\x80w*\x18Is\x17\x15\x17DI\xB4a_\N\xB77\xA7n\x16\xDFIE\xEF\x9E\x8Cd7\x1B\xF9\x97\xF9E\x86\x98\x9F\x1D\xB6\x9F\x94\xF7\x8AJ\x1A\xCD\x88\xD3\xD3\xDEw\x92Q\\xF5\xC6\xD6\x11c\x81\x00\xE8\xD9"'\xE1\x9D5\xFC\x11},\xB8\xB2V\xE6\xC0\xB7a/\x18~=G\xAC\x9EGxR,\x9B\x91\xA0\xE9\x85\x14J\xB3\xB2O\xEA3\xB2F\xA7vo\x88\xFEm\x18*g%\xA4l\x9B\xF0\xA5`$\xEBo\xFC?\x13"s\x0D\x91y\x92\xE0u\xFA\xD1p+)\xACpi\xE3\xB4L-\x0A\xF1#\xCF\x1A\x82\x8A\xE5\xEF80\xC9\x17z@\xD1\x9AoK\xCE\xE42\x92M\xEF\x85\xBE(z\x860\xC6\x03t\x02\xA1\xD2\x09\x1E\xB3\x80t\x86|\x8E~F\xFD1i|\x84^\x07\xC9Z\xBE\x91\xA7\x06\x9B\xC7\x8F\xFB\xD4\xB84\xED\xA2\x108/X\x89\xF4W\xF6\xE3\xEE\x94Q,H\xFF>o3E\xA7q\xE5\x15\x86\xCF\x0F_\xF9\xE8N\xCD}\xEB\xFD\x0E\x03EZi\x83 \xA7D|{]\xEE\xBA\xE4\x00RR\x1C\xFBj\x81\xF0{w\x9F\xA6F\xBB\x00\x0Cw\x01\xE1\xFE\xC8\xE8\xAC\xD18\x19,\xE9\x9E\xFE\xF0\xA45ov[K\x86UT\x00\xC0*\xEF\x9De\xE7pN[\xA5~\xF3\xDA\xAD\xE0\x85\xB0Nb\x09I_\xA8B:b\x9A\x10\xC2\xCF\xE83|\xB1\xCD\x17\xE8\x95\xA6!"\xD72DR\x03\xB7\xF4"\xC2\x88\xF1Rl+t\xA7x\x04\x10\xC1@\\xC3\xE5}\xDD`\xA2\x91W\x7F%S\xB7\x13\xFF\xF2\x82~e\xDC\xDD\xA1\xC5\xDF\xC6xx\xAC\xF3!\xDC\xFE)\xCF@\x8E\x9CU\xE9\x03m\xF7\xB5\xC8\xAB\xB9\x94\x02\x8C\x910\xE6\xBC\xA3\xFAc\x18\x83v\x09\xAF\xE9u\xE1\xB6N4\x16\x8E\xD0\xFA;\xBF\xDEt:\xDAq\xC6~\x979\x0C\x9C%=\x19\x09\xFB\xC7\xB2,yV\xED\xC6}\x0A\\xFB,*\xEF+V\xA8\xA9\x81\xADOD\xF4\@\xFE\xAEV\xED\xC8\xC5O[\xE6\xC7\xEE\xC7\xA0\x10L\xFFiY\xAE\xD4\xDE\xE89\xF6\x83\xC8\xF7\xB9-\xB8\x0A8{A8\xF2k\xF0U\xADh\x1F\xB5\xEF\x14"\x8E\xB0Cl'\xAE\xC6Qn\xD4V\xB6i\x07\xBA(+\xEFZ\xE7\xB2\xCC[p\xC0j\x90\x8C.l*\xE2\x97;&\xD9\xB7\x8D\x8A\xE5S\xCEtT|\xAC\xAEp\xACg\xF2\xFC\xB5\xECac\x0E]\x09,\x09n>#\x1Akg\xC2\xD5|\xB9\x8Df\x17\x851v'|*=\x8D\xFA\x00>\xB2\xD9\x04&QI\xB0\xC4{\x18\x1A}\x8DV:\xA8\xECN4n*\xAE\xE4\x07YK\x03\xF8ms\x17/\x17J\xFD\xFD\x14/\x86X\xCE3\x1C^\xC4\x8D\x9Bi\xF1\xCA\xE6\xB2\xE9\x83\xFD\x0F\xCD\x8A\x9F\x1D\xB5\xC70\xBAU\xFD\xDCOR\xF7Y2I$^\xBD\xFC;"\xE6\x10\xF4\xA5\x80\x8B\x13\xF7'm}\xD3\x8C\xAB\xED\xE0\xE7\x1E\x81\xD1\x1B\xC3\xCA\xCD\xB1\xD4M\xD7}w\x85\x0A\x00a\x94\xE5\xA9\x96\xD0\xA2\x19\x03\xFD\xDAM\xC8w,\x11!\x87\x0D%v.k\xAB\x88<\x12\xE6\xE1<\xAA-\xF6Kb\x03\xEFt d\x8B\x1A\xB5\x08\xD1\xF6\xA3i\xDE\xDF\x90s#\x88\xE3\xE8\xA6\xE7n&\xFEv\xC2\xF6\xA1\xD2\xDC\xE6\xF1%H\xB9W\x86\xF3\x8D\x8AO\x10r\xD3\x89;\xD1\x90(H\xA6ei\xFB\xCB\xDB\xBA\x93z\x01C\x1B\xB0\xA2p\x04\x80\x01\xEA\xA0N\xF9\xE5\xE4\x83\xED\x0E\xBCM\x06\x8E\xBE\x14\x8A\xF5NJ\xA0\xD0\x15\xEA\xDBHJA\xE7\xEEyT,\x9E\\xE01\xC0\xA6HQ\xAA\xF6\xBB\xD2\xD0Y\xD7\xD2\x18\xC2|\xDFp\x12\x0B\xD1Ly\x7F\xD4\xA7\x02\x83\x18fm~\xB9\x02zAq\xF0\xF72\xE0k.\x872\x8B\xF6\x1C\x84V\xC8\xB7W\xF7u\xD4\x0A}\xF3\x8F\x05\x1BX\x86vh\x11Bt\xF3b\x8CX\xD3i3\xDA\x1E\xE0JHu*\\x0C\xA5\xBC\xAB"7\xDA\xAFdqz\xF90\x98M\xF2\xEB\x1D\x90\xEAY\x8B3\xD9\x13\x96g\x0B\xBEV\xC5{O\xA6\x8C\xF6(\x03cO\xDBAE\xFF\xA2y\xF4L\xDB=?.\xBB\xB0a\xEF\xECiO\xC6\xE7\xDF\xD2*4dp\xAB+s\\x8B\x15\x00\xF5a\x19\xEC\x0A \x0Dz\xD4\x80\xE0%\x97\xDD\xB0\xCB9\xC8`\x01\x0B\x93\xBE\xC4\xB2B\xD6Sa\xB8hI\x12\x0D\xA4\x80\x85\x93\xBA+\x95\xCA\x9F\xD55\x803k\x8E\xC1\x15\x14NsrhL9\x1E\xE9\x87\xDCE\xB5\x97\x96\xD6\x197\x9B\x81\xD6><5\xBE\xAB\xA9\xEB\xCB\x85E\x8D\xE4[\x9B1\x9B\xCC\x90\xFFc\x161|QU\xB2\x18\x93\x1E\x84\xAB\xB8\x9F\xC8G\xB6\x05\x9C\xDD2\xCFM\xC0\xAEhsj\x12\xA3NI\xA3\xA4\xA6Kt\x0D\xBA\x86\xD1vm\xC3\xAD\x8D\xA7\xFD\x1D_\x92Uw\x1D\xB3\x82\x8C\x87r\x96\xD2\xF8\xFAy\x91C^G\xCE\xD1-b\xE06\xCC|]\xB5\xD2 \xEE\xB97r@f\xB9{\x18\x90\xA7\x08\xD6\xF7"\xAC\xB1:.\x08\xE6Z-\x12\xFB\x01\xE6\xE9\xF0@\x89S\xD7\x06,\x7Fy\xC6\x83\xAEG[3\x0CO\xFA\xD7\x92\xAD\xAC#\xAFgo\x00\xB4\xA6\xE1X\x02\xC8B\xD0Tc\xA9\x86\x1F\x07\xCE\x98\x92\xBB\xF1\xCDR\x9F\x9B/\x86\xF6\xFB\xFA7\xF2\xF3\x90;=\x86\x91y\xE9%\xEDTJ\x90MH\x07le\xBC\x0E\x8C<\xB3^\x0E\xC2\x9F\xCB\x18\xA7\x9BL\xE7\xEC#\x8C4U\xE5&#\xECYn\x0E\xFE\x0A&\xD4\xBA\x15\xDE\x13\xE17\x0Bl.\xE76\xFA\xCF\xC2,b\xC5\xAFh\xF9;4/\xDF\x1B\xB4.\xFD\x0A0\xD1|K\xA6\x90**}<\xEC\x94\x8E\xD3cMH\xFA\xAC\xF2\xB9[60t\x09\xE3\x8E\x82\x05UU\xA1T\xC50\xEC\x1F\x99 `t\x12\x18?o\xC2\xB0\x0B7\xA1\xEC\x15\xC7\x1C\xF3\xE8\xB1\x95\x9CG\xA1U\xB7\xA4)\xEAe\xC4br\xDA\xFC\xE6\xEAdu\xD8Y\xBB\x93w\xD7R\x80&7\x96r\xD3\xBA`\x8D\xEC\x8A~\xE6\x02\xADK\xE3\x9C\x1F\x07\xFD\xD3_%\xEEk6\xE5@\x15\x96g\x1FN\xB2\x03D\xD7?9\x9A\xB5x\xEAS_}%\xDDT\x05i6K\x8A\x8D"3U\xD7O\x04\x10\x8F\x93\xC8\xB2u\xE9\xC4MJ5\xE8z\xB0\xC5\xAD\xFD\x9C\xBE\xB2lT\x99v\xA2\xD0\xD4\xA5=\xF0\xABwF\xD6\x97\xB6\xA4\xFB\x9E\xAC+\xFAz\x8BtxzKx<5\xE9\xE33o\xC3\xDC\xA7\xAC`\xD8\xC4\x91<\xCBh2\xD2\x1E\xF8\xF6\x95zv\xC1\xF5;_a\xE76\xF4GkV\x04\xE9\x84\x12\xD0\xE3b\xA6\x99\x01\xF8\xB4\x1Auw\xA3\xA5\xD0,\xB9*\x8D\xE8Nv4\x14\xB6\x9A\x9F\xF0\xB3\xD7\xFD\xE9\x8D\x8B\x02\xA5\x9C\xE8\x01\xB0Q\xE0\xCD\xD4D\x8E\x9E\xA6\xCAL\x95\x86=Ac\x13^e_\x8A\x1BR\x99`\xB2\x1E\xAC\x1A\xD0\xE2\xB1J\x87U\xE7\xA4\xF3\x11\xFD\x99qQ\xD8Ug8\xCD"\xC1q\x8DJ&0\x1A\xC0\x83S{q\xCE\xE9+\xED\6\x19\x14\x0A\xE2\x98\xC2Lv\xC0\xBF\x19IL\xD7^?\x0B@\x1B\xBD \xD5?\xF5\xEE\x1E\xF8\x128d\xDB\xE7h\xB3v\x8Ae\xEB\xE88X\xC1\xDBT\x0FN\x932\x1E\xC9\x8C\\xAD(WVf\x8Fp\xAA\xCE\x00N\xEC\x19\x9B\xC5\xE3#y\xE8\xDC\x8E\xBD\xB6\xAE\xC4>\xA8\x12\x88~\x1D\x01\x8F\x1C\x13\xCC-\x88A\xAEj\x92\xF0q\xCE\x1E(\x9E8O\x16\xE8\x8C\xA3\x98\x9F\x948\xF5\x8D/9\xF1\xB8!\xB7 0\x9B\x0E\x1FQ,iB\xC37\xB5\x85\xBD\xD2\x08w\xA8\x18\xDB\x7F\xE4\xEB\x93\x9B\xB1X\xF4\x9C\x1C]\xB8\x08]:f\xD1z\xCB\x89\x89\xD5V\xF5\x92\x19b\xC0\x10\xAA\x0A\xA9\xFD-\x16\xE3\xB1tm\x8E>\xE02\xD2V\xB7\x09\xF8\xAACZ}\x8C\xBCL\xCB\xE5\xDD]\xDF.B\xD2\xFD\xBF\xA0\xA8\xEB\xA1,V\xAA\xC3J=\x1E\xD3\xA1\xC64\x98{\xD7f,3\xBBF\x00\x09[\xB0\\x07\x0A\xE0?T\xBCr\x13\x17b3M\xB3\xBD*\xBA\x05J\xC4G%\x91HT\x18\xB5\xA4U\xF0r\xAD.T\x1C\xE5e\xD7\xF8e\xFD\xD5\xBFE\x0B\x08\xEB8Q\xD1\xF4\x93\xA1\xF7V\xA3\xA5\xED>w_\xBA\xF9\xC47\xC8\xF7i\xF2\xA9n+^\xE8\x85}\xE3L\x90\x86\x8Dt,\x96C\xDC|\xD9eX_\x0C\xF3\xE3\x84\x0E5\xC6\xD3}\xBB\xBFA"\xAB;K\xEE\xB1\x14\xFB\xBC\xC6e\xE7D\x03r\xAD\xFFr\xA3\xBFv)\xBAA\xAA\x8F\xF6\x04\xB1^\x01$\x9E>\x98OE\xFB\x09:\xDF\x95\x9DI9\x83\x8D\x8C\x05r=\xDC\xD9V\xE3\x9B\xC4\xD1\xC2\xE19\xD9\xCB\x9F\xE7\xEA04\xD8tj\xABQ\x13\x17Qj\xC4\xB2)`\xFB6\xC5\xDB\xBF\xD53\xF8\x90\xDA\xB6!\x95p2\x0B`\x18D\xA2\xDD\x87\xDB\xD4\x9FW\x92\xE4:\x9DB\xA0F\xC7n^\xF6]%\x88\x9D\xB0\xCBk\xDE\xB26\x81A\xC6LrAG\xB3\x8DE\xE0\x04\x0DV\xBCU\x9E\xB8\xC8\x91\xE2\x08\x1A\x9E,\xFB\xFDvh_L\x9F\xF8\x9F\x98\x06\xCB\xE5\xA3\xF6t\x87\xBD\xDF\xC0\x9C\xB1\x84&\xC38\x1C6\xFA\xFE\xC3kE:C\xA67h\x81\xCE\x0AM\x0D8\xCE(\x13\xC8&\xF9\x85\xE4u\xD3FN\xB8\xBA1PI\xD3\xEB\xB8\xA6(#3})o\xFC\x93\x89h\x19\xFCy>U\xFF'\x833v\xAE\xEB\xDD\x8E\x12\xBC|\xAB\xB4\x1F\xD4vI\xB6\x1F|#\xA2\x87\xF0V\xA4'L\xCB\xE4\xBC\x9C\xDA\x97c\x94~\xEDw\x18\xAB\x8B9}\x8F\xF5#\xEAd\x9Dv\xD4\xDE\xF5\xBAV\x9Ey2\x1Ahg\x02\x94.\xD6\xEC\xF4\xB8\x13h\xD5\x14\x08g\xD8\xAA\xB5\x03\xF9\x05\xDF\x19\xABV\xB2\xB5\xDA\xB2\x06\xDC\xA1-+\x06\xFE>\xCE\x08\x17\x82eDe~p\xAE\xB0\x1B\xD1?\xCB\xFA[8~~&\x19\xD1\xC6\x97Ri\x0B\xF7\xC2\xA8\xAB\xCA\xBA\x0C6\xEC\xC9\x8E@\xAC?\xD1O\xA8:\x81\xD7SM\xD2\xB8\x12\xDF.r\xFFJ\xE1\x89\xA2h\xB6\x1C\x1D\xF3\x0F\xE3E\x9F\xFCT\xABH\x19\x84\xA1s)s\xF9\xDB\xD8^\xE3\xA2\xF42\x7F\xBD\xCB@\x14\xAEj\xB8z\x1F7\xCC\x07\xE7\x17\xD7V\xC8\xDEN\x8Fj\x0Ei\x17Yf=\xBB\xE7r\xE7?'\xE9^\x90\xF4\xD7\xADh\xBAC\xE7\xF0\xCB\xDC\x8C\x11\x9F\xF1\x16g\x19N\x98\xC4\xF4\x08\x15N%\x9CUZR\xE2$W\x16\xF7\xAD\xB8\xAB\x85^\xECp Z\xC8\xFER\x96G~\xD9\xA4(6\xD6\x1A\x8B\xA5\xA8\xA3o\xE6bh\x93\xFAul\x15\x8C\x96\x12\xE4\xEE\x82\xCA\x92\x9CW^\xCF\xEF\x8FrP\x9B\x91v\x17}\x07\xDE\xD1C\xDF\x14\x99H2#\x9F\x1D@\x13cJ3\x8A\xE3E\x95S\xC35'\xB0\x12\xAF"\xC4\x98(\xF7uu\xCF0f\x8AN\xB2aX\xEA\xD5\x09\xD6\xC1C\x98\xBC\x1A=M\xFEz\xAA\xBDB\xE8\xCE\xDD[\x09\xD3\xDD\xD6a\x89\x1C\xA8?\xBA\x03\xBF\x99\xDDV\x08\x02\xEC\xBB\x81\xD7\xFB\x12\D\xC9\xCF\xD4,?\xE7\xDAS8\xC0~Z:C\xDB\xFE\xEE\x0B\xFA[\x10\xFBJU\xC9A\xC7I\x11\xAB\xC3\xDBoqC\xFE\x89&\x88\xB6\x9E}\x9A\x0D\xEE\x85\xED}MM\x99K;\x9D\x09\xA4Y\x01\xCA\xA0\x08\xDD\xC9\x05u\x87\xF4\xA8e\xE8 >\x89M\xE87\xB6d\x96W[\xE0\xE7\x8C8\xD5\x83\xEA\x00\xB7=\xDA0\x83zp\xDF{\xF9L\xCE\xAF\x01\xE0\xF7\x8F\xA7\x9A\xAE\xB2\xE1G3\x9F\x90\xA8\xE8\xB0\xD7\x9BJ\x83\xC5\\x1D\x09\xA7\xBB\x85\xBB{\xEE\xFD\xB3X\xF3\xCDE\x19\xF5\x0F\x16\xE6\xDA8\xA9R\xE6\xE9-\xDCk\xDFj\xFC8\x15\xF1\x84\xCC\xB079w\xC8^(\xAE\x1A\x95\x90}\xAB\x8E\xCB\xCB\xA5\xE2\xC5\x99'\xC2\xCB\x89\xA7\xD4\x0DS\x89R\x9C\x86`\xE4\x10\xBB\xE2\xCE\x19P\xF2I\x13<\xE9\xE8!\xCE8p/\x93\xE7\xD8\xBE\x95\xC8\x0C\xDE\xF6\xAFT\x06D\xFC;\x9F\xD1\xABV\x1F\xE5\xF1P\x8A\xE8\x8DG\x87\xBB\xCA>f&\xD0J\xF6\xDA\x0D\xC4\xC2\x98\xF2\xB5\xFB\xA6I\xBA\xEAV\xE8\xFD\xE6\xC9\x1A;\x82.\xBF\xA4\x9E_t|\xC7y}\xEA\xF5\x98\xD0\x8E\xCB\xC4\xF0G\xB3\x9E}b e\x7F\xFD\x1C\n\xC0{x\xF7KV\<\x1D;\x0F\xA1\xFDne\xA5c\x9A~yo\x90\xB9\x1C7`Y\xB1E~\x80\x95;\xCC\xA4\xDCZ~\xE0\xF9WH\xB9R\xBA\xFA\xF0\xEA \xCC\x93\x02\xA8\xA1\x1E)\xC4\x99\xB5p\xF8\xBA\xE8\xEA(\x0EF7E\xAF*6':n.\xCE\xA4\xB8\xD5\x04\xF1\xA2\xD3\xFEn\xC8\xCD\x94x\xB1}\xEC(Cr\xAA!Q\x9AU\x80\x12\\xCAS\xAB\x16\xDAEn\xBB4\x15\xD9P\x94\x18\xDBO\xBA`L\xA5,F\xBE\xA1\x08\xBDZ\xA5$\x0E\x12rE\x15Z\xF7\xF3\xAD!08\xD9\xA7\x8F\x1E\xC5/\x90J{\xF2\x0Cv\x0B\x8Af*\x8D\xC6-"\xD1\x89\xF0\xDF\x8Fi\xB1"\x9Ft\xFE{\x1A\xF6\xA5g`o\xD0\xDD\xD2\x06\xC4\xBE\x0EAx \xE6\x89\x05\x13\xC48\x03\xA2\xCA\x8Dk\xE2\x97c#\xCE+\x8D\xF2\xCD\xA9V\xC0\x11\x80\xE4\xEC\xA9uc\xE2\x9B\x03d\x88\x8F\xDA"\xAA\xDD6\xD7\xE0\xA5mm\xBD\xE5\x9D\xC4\xF3\xC0\x92\xFD\x10\x07\xE6(\xAF\x13\xB8M\xA6r\xD9\xAD\x92\x81\xC7_\xBB\xA44\x14\xEAO\xB7#N\xD8\x97\xAE\x1FF\xED;\xED\xE3\xFEX\xCD\x8A2U{\x1Ft#\x07\xA9\x13\x8C\xBCN\xA7.k\xB9\x07n\xC4\xA4\xBFF\x97zj\x85\xBFP\xB83(\xD0\x88\xF4\xFD@\xE9H\x93\x1A\x84\xD6\xE7\xF7\x99\xF7\x01/\xF8\x09\x85\xA8\xB2e|\x09\xE9\xD6\x9E\xF9_C\xB2\\xD81\x12\x16\xD8L\xF4\xBC\xD0\xE3u\xFC\xF3\x12P\xF3\x02\x12\x0E)\x0E{(\xB3\x13\x8F\x95\x11 \x80V\xDA\xBA\xA8\xD8\x09z\x8A\x98\xCB\xAA\x02s\x81=\xF5}\xB8-\x95\xE1\xCE\x07P\x80\xD0OL\xB6\xCC\x8B\x15\x1D\xA7\x18\xE2X!C\x0D\x1CV\x13j\xFB\xEEs%\xA1'\x84\x89\x1A$\x96T'\xC8\xFB)\x9C\xE4;\x9DiV\xCB\xE3\xEE\x8F\x12\xB8\xC8\xC1\x01|\xB7m\xEE4\x04]b\xA3n\x1B)9c\x9A\xFD\xF6\x84\x15{`\x86-\x10"\x9D"\xF3\xF1\xF4CZF\xD6nR\x1F\xEBk\x8F\xDBf\x87\xF2\xD6\x16V\xA1?\xAD\xA0\x02s\xD0\xA8\xCA<\x9F\xD3k\xFA\xD5i4\xBC\x91$\x98\x04S\xD5'\xAEG\xA0\xBE\xA8Y\xA3\xC7D\xF7\xCC\xC6\xB8\xC0\xF5\x962\xFD9`G\x1D\x91qa}\x06\x1FoX\x14X\y\x82\V\xD7:d:/`\xD3(\xBEw\xAC\xF3i\x15\x81\x8E\x82p\xA3b}O\xD2\x97c\x14\xE7\xBA?\xAE\x96\x14QhLgp+8\xDF\x1DD\x90~k\xC8L\.\x8DBSI}]Z\xF6\xB6\x90W8\x87\xBB\xDBP\x90U\x00H}\x05\xD0\xF5\xA7\x97\xF0\xA5\xD8\x9FZ\xD3\xC34\x0C\xCB\xD5p\xCB\xFBO0\xFFd\xD6\xB5\xB6\\xA7\xC3\xD83\xABX-o\x9E:4&o\xD5\xA8&\xC3\xA3d\x7F\xDE\x15\xA3\xC5(\xBB\xEE\x7FG\xB5\xAC\xBE\xB7\x07B\x04\x8Ex\xD2\x15\67\xB4\xDCw\xE7Q\x8F#\xBF;\xE2\x13\xEDw\xFC\x0A9\xF6\xEAf\x07D\\xCE\xB4y\x04\x02F:\xC8\x7F\xD2\x87\x0F\x81\xD9\xEB\x01)\xA5`pd\xB1\x7F|x+,\xB2\xBD\xF7,J^\x1D0n$%\xDC\xFD\x05\xCE6!+\xBD\xFEB\xD0\xEA\x8E\xDC\xB7\x86\xD5\xCEE\xBB\x9E\xF9J\xDB\xE3\xC5F\xE5\x8A1\xEE\x09\xBB\xC8D\xAAU\xCAP\xBE\xA5S\xF3\x14j\xBE\x09A9\x0A\xD9E\x0C\xFA&\xA4\xF9'^\x14\xDE5\xA9>\x1C-\xA7\x19\x10\xE9]$\xD5\x87\x90\xFB\xCFoE.H\xBC\xC6-\x0EVi%S]\x10#\x82iG\xD0\x8B\xE3\xB9S\xF1\x00\xD0\x1D\xF3\x07\x81\xE22\x8F\xFA\x92Ke\xAC\x1Et\x901Fij\xFDW\xD9=\xDF\xD1_\xD3-\xAC/\xB6FK\x01M\x7F\x82p\x82!Y\xE1\xFA\xDA\x01A\x91?]\xFC\xE3\xE7\xCA\x8E&8\xE3\x0C\x9D\xAA\x17\x12S$l9\xA9}\xBC\x95\xEE\xEF"-c\xD1\xED`$\x1C7\xA1r\xF3f\x80\x1DgLk\x12q\x88qG\xBE\xCE)\xBFL\xF1{>\xBD3\x14\xFD\x86\x9A\x0E{\xD1\x88\x1CT3\x86\xD6 {@\xE4\xBB\xCDL\xEB\xA3\x1Df\x90\x07\x927\x12"\xF7\xE0"\x19\x86$f\xA83\xD1\x97\xDA\x88\x00\xC5\xB09\x19\x1FQ[\xD9\x14\x9EO\xA7mL\x0E\xEAq\x0D&}\x1E{\xD6(\xD2%\xB9\xEAX\xEC\xD1\xC7RR\xEB\x9D.C\x15\xA9\xE4\x11F\x90\x0A.4H\x93\xB6\x01\xEF\xF2\xDB\xB7\x83\xD7M\xE3\xCF\xCB\x81gkN\x0E8\xA7n3:\x1D\x8F\xFCGz\xF7\xA0\x0E#\x94\x97\x95f\x9Fg,A\x1B\xAD\xC5\xC3Q-}\xC0\xC0\xE7\xE3\xE1\x1E\x94\x0DP\xA4\x1DI\xDCAz^\xBC\x89\x83\x1A\x94?\xA0\xFC\xAE\x0A\x17;ni>\xD1%Yx\xB8\xDCG\xD0\x10\xCE\xA6\x93\x91\xE0\xF6\xD2\xC3\xACr\xBC\xA2\x0BU#\x0E\x95\xB4,\xC1\x83j4\xA9\x8Ck\x00EC\xB49\x1Dym6\x97 S\x94\xC4\xD45\xA8\x81UM\x18\xA8\xC8\xFB?H D\x18\xA7pa\x8C\xE4\xFB\xA90\x89Q\xFC\xE2\xC8\xA1}\x10\xF6\xB4F\xC4\x1A\xDF;lc\xC5\xF1\xF1X\x10p\xAFot\xC6*\xA4!\xB7\x1CN\x80_\x1Db\x0F\xCA\xBB.\xE1\x87\xEF\xC8a~\x0E\xB9\x95w:\x88\xCFX\xA2,\xBE\\x86\xC8fx\x98\x8CG\xA2\xBE\xFA \xF0\xD0\x08\xA5\xF8\x99V\xEDv\xE5\x8DK\xE3n\x07\xD7\x10\x11\x09d\xB0FFG\xD9\x09\x04\x83\x83\x03\xF6PY5c\xB8\xC2\x09\x85\xC2\x8C\xEB\xA0\x08\xAC\xCD\x16<5q\xB9\xE8\xFBAI\x0B8\xEE\x9B\xB8\x09\xA0\x14\xE3\xFE\x0B\xE3\x03\x9A[\x8A\xFD}\x88\x1D\x97^\x13\x8C\x9E\x15Q\xF0\xC7oS\xB0\x99\x17\xE5\xDD\xB8X\x1E\xE1:\x92\xFAnu\xA0\xF0\x8D\x10L\xF2\x0E\x92\#Qg{E\xE8\x12/9\x8C\x1AIox\xCFjyC\x82\xE9!\xAF\xE4?P*\x0EM\xC0\xE4\x1D(\xDD\xE3V\xAA\xD8\xDD\x1C\x935\xA6i\xB7k\xBC\x83\x8F\x96\xF0\x9F\xEA/\x97\x07\xAC \xF4\xC3+\xE2\xF30>\xCD\xD4ct\xCA\x917\x88O\xF6X>\x96"\xE9\xD1\xFA\xF4}n\xBE\xD6v\xFE\xBC\xED\xA4\xE0\xDB\xF3k\xC1\x86I\xE9zR\xC9\x7F\x15\xF6-\xC37\xB0\xC2\x7F\xA8\xDB/\xA0\xD6gf\xC2\x1E\x1C\x10\x84\xED~\x80\x82w\x19}%\xF7^\xCD\xB9a{,n\xA8\x85\xDB\xA4\x90t\xD5\x0AO\x97\x01\x96\xE8/\xC8\x1EfX\x9B3\xDBE<\x08\xA4\xFB\xEC=\xC7S\x8B\xBD6\xB5O\x93w]\xECx\xF6\x1F\xA6\xEDA\xA0vw\x8F\xB2(\xD2D\xC7hQ\xA3%\xF6\xF4\xC8E\x135U\xFC$\xF4\x12x\xD1\xE2f\x13\x18Z\x13\xCA\xEE\xFF\x1FXn]kJx\xFFwR\xC0d\xFA\xBFD\xCBJ\xCC\x04\xFF\x8A\xEC\xB3TX%_UT6\xFA\x93j>\x9A)\xC0l\xF4\x0Dp\xD9\xA4\xCC,Z\xD0\x0B\x03\x18\xBE*\x18\x98\x17\x15X'E\xA7\x9DQ\xD6C\xFE\xDA<\x18go\xFA\x83\x17@\xFEQs\x1F\x1E\x0A\xD0\x9D\xC3mvBR\x1B\xCE\xCC\xD9\xD9\xF3\x08\xB2\xEE\x840\xC7`\xCD\x1E\xBC\xD2\x8E#\xB0<\xD0\x9E\xC8#\x88k\xA9\x0EP\xE9\x12\xD6\xCA\xF4\xF0\xBD\xBB\x144\xAD\xEA\x8D\x15\xE9 \xCE\x00\x84\xDE\x19\x9FC\x9D\xE8\x1D\x93\xA9\xFE\xAC\x04\x02s\xD6AW,\x9F\xFF\x0A'\xF3\x0B\x18\x92\xE2-*,\x9F8\xA2o3\xE9\x00\x8F\xA0\xD1m-(\xE8[$qOA\xF9\xC2\xCA\xC6\xE6\xFD\x15\xC9EL\xBBJ%\x06\xF7\xA4\x17\xDB\xE7\x02x\x87\xCA\xF6\xF8 s=G\x8B\x9A\x9E\xC2y\x7FB\x9DQ/K\x04Z5\xA2\xFC\xB8\xC9H{\x87\xAE\x11\xD0<\xDD\xFF\x83\xBA\x913\x8A p\x7F\xD9\xA5vP\xC0f\xBF+{r\xF0\x9BD\xC9\xAD\xD3\x1B,\xED\x0A\xB4\xE0\xAF\xBC\xAC\xC1\x02w\xC3\xFF$\x8C9o\xD6\xF6\x0E\xA3\xAB!@\xE0\x19ged\xD1\xFB\x1DD1\x19:\xC3\xD1\xCF3"\x88\xEE\xEBL\xBC\x86\x16\xC2v:\xCB\xE4\xA1\xBB[Vp\x1B\xEEG"M\xEAK\x92\xF8X\xED-\x83\xEDo\xA7\x16Y\xFE\xDD\xEA0\xCC\xD5\xB1\xB7\xFC2\x9D\xAEf\x8C\x8C\x03B,B\x06Cnt\xCD\x99M\xAC5_\xFA\xF0vb\x1D&9\x81\x1C\xD2\xE3-\xBDTF\x0A\xB9\x0D\xDE\xBCG*+160\x86\xB4j\xE6\xC1L\x0F]\x85\x96\x8F">\x183(\xFE\xB1&\x14\x8E\x1D\\xA8m.\x187i\x9DJ\x0DNbR\x0C\xF9\xB3\xD9|&\x0F\xB2\x1DA\x8C\xE5\xEF\xD75h\xD6\xC6\xE0\xEE\x86\xEA\xA5ZK\xD6\x16\xE8\xBFez\x17\x1C*\xB8\xB2\x06\xDE\x13\xA1\x05\x8E\x1C\x18\xBB\x01Y\xE7\xBBYv\x86\x96MD\x04e\xE1\xAC#e}\x05\x95\xEEW\x9F\xE9\xA6\xFB@\x9E\xD6d\xCB\x0B\x1B\xED1\xA1\xA7fg\xEC\xA0k\xC0\xB0\xBC\xE4t\xF7+\x07\xC3\xC0l\xD2T\xE4\xD2\xCC\x03\xE7\xB2\xD5\xE0\xB2}\xCB\xC7$gh!Ga\xB3\xE2`\xF4\xF9\x08_c,\xA5\xCD,\x81\xE4\xCF\xAF\"\xDB\xAEnh\x15\xB1v\x96]\xEF\xE6rRU]\x09\x89\xEFd\x04\x84\x7F\xC6T\x1E\xA1\x96\x02\xE1\xEEz3s\x8B\x7F\xAF\xC5\xBE\x0B\x10.x\xF7\x10(M2\xA5o.#\x8A\xFA\xE7\x9D\xA9\x07C^\x83$\xC1<"\x07\xD9D\xCBd\x11\x85\x1A\xDA\x80\xB9\x11\x98\xFB\xEB\xBD\xDB\xC6N\xBF\x0D\xA1\xD83cc\xFB\xE2\xDFD\xAD\xAFd\xE6[z\x8C\xF1\x13k\\xEDQ\xCDr\x84Y9\xAB\x90l4\xFEmbEK\xEA\xD9\xE5\x0EuI;L\x06\xD1\x94\xA3JV\x9B\x99o\xEE\xD18\x9A\xB0\x023q\x15[\xA6g\xCB\xB7\x92\x02+\xB7\xC0\x11\xED\x8F\x7F\x9E\xDAN\xB9\xA4\x12\xE0\xF4\xA3\x02\x12\x82fq\x07\xB9\xF2\xB48\xD7\xC7\x17\x8A\xFA\xD9\xB9\xFE\x9B\x157\xE27\x9A\x86\x15\x0A\xA3\x814\x8E\x07nO\x8AMUT8\x06\xC9\xE8`v0\xDE1\x03\xBE*K\xF6\xBF\xBF*\x97y\xE5\xD7\x93\xBE\x0C\xEB\xE8\xE7\x93\x84\xF5r\xE5P\x96\x9D\xECM@\xE7'\xB1+p\xF61\xAE\x8D\xE7xh\x91\xDB\xDE\xE1\xF7\xE9W\xEC\xA5\xDC\x00\xCA"SG\xFF\x96\x13\xBBU\xAF\x03\x09\x8E\x98\x99\xFE:\xC0\x90\x97\x94WG-\x9F/\x14\x09\x89R$4z\xF3\x86\xE2\x92L27\xC9\xE5\xFB\x92~m\xEB\x02\x1AN*\xB6\xD5C\xA9\x7F\x04\x8C\x9B\x03\x8BSE\x92y\xAEj:\x13s\xB2'\x14\xAA~\xBD\xE0\xC1\x92\x02\xD3\xD0\xA5\xB0\x9A\xCEF$\xEA7\x03\x1A\x92`n\xDE~l\xC36;\x97E\x86\x92F\x86R\xAF\x83\x9D\xECpa\x9F\xCE\x86S>uO\xD37\x92\x91i#\xF4\x04\xBA\xAAq6\xA8D\xCB\x03)\xB6\xC6w\x8A\x19\xA8\xFD\x84\xF4\x87\xEF\xC3D+\xD4s\xB3\Q\xCD\x04\x10\xCA\xCBWm&R\x86\xFF\x0Ck\xEE\xD4\xDA\xB5\x88\xB4\x0B)\x9CG_)w&A5\xF1\x1E\xEC\xDF\xD6LT\xC3*\x91\x9E(\xB6\xBF\xB5\xEA\x97h\x0F\J\xE00\xB0\xD1\xAD\x17\xF8\xE9\xCD\xFFY\x92\xB5R\xC1\x83^g\x03,.'\xA1vr\xEA\xF2*\x1F^\x08T\xC0\x83\x0E\xE5"\x871\xE0\xD1\x9C\xFB\xD6<\xC7\x83\x11R\x91\x94q\xDF\xBE\xDD\xD7\x11\xFAs\xB2w\xA5\x89\xD3\xE5$\xF6A\xA4\xD7V\xD4\xEFKKL c\xA2\xC6>\x9E\x99\x1C\xF7TG\xED\xAF\x1B\xCCM\x1D\xD6P\x94\x07\xB2\x13\x80\x95b+\xBDRab\xD2,\x91\xC7\xF6a$\xD4\xE0LM\xF8\x8BM\xE4\x1F\xF3\x97v\x1FBv\xD3Z\x8E\x075G8M\xD9\xA2["\x90\xE31\x14\xF88H\xAF\x02\xF7{\xB1\xD1B\xF4\x14 \x06\xE3;\xB0bKX\x95y\x84v\xD1\xA7\x07\xCD\xF5\x92\xCFc\xB7\x94$m?@\xA6\xAD\xC2/\x08\xE7\x00\xB3"8u\xD2\x1CEv\xFBu\xA6\x0B\xC6{?'\xD5\x10\xE6?@\xE1\xE8\xC5\xA1\x09\xA7|\x11\xDB\xD3Y\x10Id\xD6\xDDW\x8B\x04r\xCE\xE7m\x1C\x9Bb\xE2\x12R}2\xE5\xA6\xEB\xC9d\x80D&\xDBfC\xFF2\xF6*\x85\xD1\x8C\xF9\x1E\xC1\xA2;\x814\x00\xB1\xB5t\x07hzR\x83zs\xC8\xA0\xDF\xCEp\x96\xEB\xDE\x98\xFDh\xBD\xAF\x07e\xD6\xAD\xB8\xF3\xF62\xDA\x9E\x83\x89}\xE9\xBF`\x07D`LB\xB2\xE2_\xF5\xA0q\xB7\xFA=\xBA\xDC\x17O\xF2P\x06}\x1D\x98\x0F\xE1\x06=\x98B\xF3\xE6\x0CY!\xCBq\xC2\xB7'n\x8BK\xDAxL>\xDB\xF0%nY\xBD\xAEl\x90\xC8\x80G\x1E\x0A~\xC7\xBE\x96\xC7\xBAd\xDE=\x06\x12Y\x1C\x92Q\xC8j\x0E\x196\xF5\xF8\x1E\x8C\x15\xFF\xD4\xC2j(\xF6\xBD\xC83\xD9\xFC\xDA$9\x09Mj\x9B]\xC9\x7F\xF0\xDA\x0Es\xCB\x83\x0As\x84\xFE=\x12\x1C\x11\xF4\xDA\xADl\xAC\xF2b\xD68\xCB\xF2\xC1e\xE3k\xE8\xBD\xDF\xDB\xC1\xF0\xBA\xDB\x86\x8At\xAA(\xB4\x88\x19(\xA0g\x85\x99\x87\x03\xF9S\xCE\x10!\xBA\xCBU\xDF7k\x95\xA8\xA6x\xB4\xE3u3\xC8q\x05Jg\x0F[N)\x9An\x0B)\xED\xFB\x85\xC8b9=\x0A\x1EA\x1D\x15\xCAY\x8E7:\xFD\x91\xEC\xCD29Z\xEE)\xD7Q\xBD3]l\x9A\xFA\x09\xBB`<\xC1,\xC5\xEF\x80\xEBP\xD0I\x9B\x0F\xF0\xBD\x93\xE7\xF5\xDF.\x06\x03\x0Ca\x9AY\xB6\x97\xC9xk&\x98\x88+L\x1F\x82V2\xF9*\xD5=\x9APL$\x0F\xB1,UFZ\xFE\xB2-S\x03\xB7%\xAAc9\xF5~2\xDE\xEC\x03a\x1E\x89 \x8A\xFFR\x81\x84:\x7F5Ff\x0E8m\xEF\x8A\xB7\x0E\xA2\xC0\x85\x07\x9A=\xB7\xE1\xBA\xBC)\x02r\x7F\xE5\xF5\xC6A\xB1\x0E"\xEF\x9A\xA2\x9B\x8E\xA1:\x98\xF3e;n\xA7Z3\xE1J\xAE\xCB\x9D\xD4\x0E\xD8\x0A\x12\xEB\xF7\xFBY\xD5A`\xF5\x86\x89Q\xB8|\xD4\x80=\xA6\xAD\xF5\x86\xB2\xA7\x1A\x15\x11\x9C\xA6\xA9\x97 S|\x0F\xA1\x0B\xE7\xC0\xEF*:\x0E\xF2\x8B\xBE\xD1\x8EP\x89\x7F\x08X`4\xCDF\x8Dn\x93\xD9\xE8z\x9C\xCE\x9D\x19\xD2\xE7\x08/\x0E\xEBy\x99\xC7p&\x8C\x07\x02I\xBF\x91yMyY\xD9GZ\x04\x9F\x0F3*\x91\xE8\x99\xD9\x85@\xCF\xE3\xC2Wx\xE4\xC9g\x1D\xCEf\x96j\xA4\x7FU\x05\x9B>\xF7I!D\x94ZW\xC5\x9F\x8Az]\x0C\xA7p\x01\x00\x0C|\x84\x1D\xA3\xB3\xA0\xD9\x93\xD6VQ\xD6\x06N\xB6\xB7Ix\x9E4\xB5)fI\xD6\xEC\x94Z\xA1\xAE\x9A\xB3A3\xC6rZ\xA8\xBF\xCE\x1C,\xE0:\xBE\xDD"S\x8C\xCFOd\xD3\x8D\x1C\xC4\xAD4i.}\x05\x8E\xE4T\x8E\x14-\xD6\xC9\x80\xBC\x82\xF6k\xE3'.HKCA\x9C\x14bX\x10\xF3N:K\xD4\xE6\xF3\x90\x18\xDE\xED\xCF\xBAo"wj\xC5\xE9=_cyY\xFB\x86\xAA\xB2\x12#\x03z\xFAL\x87\x0CU\xB8\x9D\x8D{S\xCED\xD5\xEA(\x05}9\x01\xA3wRl<\x84\xB2K\xF5\x9C\xFF\x9CK\x8D\xD2\xA8z\xA9\xFA\xD7S\x83\x8FUE\xFC\xFC"\xCC`\xEC} \x1B0\xA7\xE3\x1C]G\x82\xE8\xCEDOk\xF7\xAE[\xD4\xB9\xAE\x1B\xDB>\xC7\xB9\xFB\xFF\xAC2\xFC\xDC`\xB8\xCA0?y#\xFA'L\x9F\x17\xB1\x95\x14\x03\xAFz\x8F~\xDF\xD7L\xAE\x0E\xC1bL4;\x9B}\xF2=\xBBt;Y9\xC9W\xC2\xD8\\xAD4\x0C\xF0C\xC4\xDD\xC6]X\x92\xAC8a\x8E\x12\x80\xAA\x0Fn>\xBA\x1C\xA8\x1A\xDC\xF3\xDE\xA6\x09OU\x95UD\xD4\x07s\x14\xEF\xCF<8\x07\xF8\xC7)\xFB'~?\x82\x91\xE09\x0AL\xF1\xEB\xD5\xCA\xC4\xD2\xC1\xDB\x93\x8D\x0C\x1EL-\xDD\x0F\xB7\xFC$$\x1BFR\x13\xB3\x9B\xB6\x01\x93a8\xB4\x896'\xDAl?v\x84\xAB#*\xAB\xEBsh\xAC\x1DTc5\xD9k\x02\x05\9\xA9\xE4v\xCC\x05-\xD2\x8F@\xD29r\x8E\xAAw\xB1\xAAX!\xE0\xE7iN\xFD'\xCA\xC9G/\x11\x08\x87\x8BT\x99\xF0\xDD\x01>\xC3-\x13\x9B\x05\xB7\xFB@ft\xD2\\xAF\x89\xBC\xE0\xCF\x0A%~\xD5\xD1\x1Dy\xD8E\xB2#\xF5\xAAsa\x1A\x12\xE0?\xD3\xE78\\xF6\xE8J*\x0F\x17P(.\x17\xACa)Rg\xAAB\xB3 8\xFE7\x9C\xDC\xBD\xE1\xAF~\xEC\xB7\x18\xA1#\xF5\xBE\xEA\x8E\x83\x07\xC5\xE7iZ<\xBD\xFC&\x82q\x06N\x18E\xF5\x93)c\xA4s\x8A\x9D\xE2\xFE\x95\x9F\x8D\x95-\x93\xE8\x91\x83J\x8B\xF9Z\xDFB\xB0\xE5\xBD\x8D\x06u(\xC9~\xB8\xCC\x17\xCD\xB9\xBA\xB6^S\x15\xCF\x1A\x0D\xFC\xC7~\xF4-\xE3;\x1A>o4w='1\x96\xD1\xC6=F\x80\x10\x00\xC1\xEDE.\xD8\xD6\xFBi+\x05\x98kc\xD4h\xDA\xF3\xA6\x0F\x15\xDD[\x05Hn\xB3nG\xBC\xE5\xC5*\x86\x9A48\xC3SW\x19\xA5p\x8C\xEEw\xAC\xB3*\xEC\xC9\x82\xBD\xAD!\x9Flh\xA3\x82\xFB\xBE\x158\x94Ci\xEB\x83[\xB7\xE2\xF5\xDB\xA2\xE9\xA3\xE63\xF9\x02!\xFB\x11\xB1I\xA6_\xF6\x86]sCU\xDB\xF8\xB6\xE5q\x02\x96\x14\xA7\x0EW\xA0)\xE2\xF8\xCF\xB1\x98#\xEE\x98\xEE\xDFp\x8F\x1B\xD4\xE6$\xFD\x14\xE9\x00\xF9\xBF\x8F\xB81*\x97EyE\xFD\xB3#"1\x07x\xD5!\x90\xB8\xA2\x11\xD1\xDBc(\xEF\x13\xD0\xE1\x8B\xE1~\xEC\x9D\xE9)s\xFD*\xFD\xD7\xFEFra\x9A\x9B^c\x0E\xD9Dx\x00\xE7\x93\x0D\x0E\xADy\x99\x08u\x00\xEC0 I40,\x17O=\x87R\x8Dm\x01x\x0B\x09<\x07h'\x8Dhf\x92\\xB4\xD1O\xFD{\xBFM\xE1\xE0\x18[z}c\xA0\xE7')|\xB2\xCA\xFB\xA3k\x83\x1Au@\x15\xF6\xE4\x18n|\x8Ch\x0D\x92\x9F\xE6\xEC%\x03}\x9Fe5\xD1\xA1\xC1\x01\xEA\x9CS\xE7\xFB\x07F\xA3\x95\xB1W7\xDANk\xBDX\xA6g\xB06\xC6,\xCB\xE9\xFF\xE2\xDBe\xDB\xA8P\xCC\xE62>\xBF\xC2\xD3T\xB3r\x810w\xAC\xD6t\xD2\xD5\xB7c6j\x16n\xECT\x17Yx\xE74\x17\x9A\xC4:7}\xCE\x87m\xEC\xBE3\xA6\xA7\xC9\xDC\xEB\x16\x98&\xDC\xD1\xEE\x83\xA0<\xFE\x95KIa\xF0\xBB\xD6\x061\x87\xD4\xDF\x80f\xA3*\xF1z_\x07\x13\xE3 y\xBD \x96\xC2\xA8-u\xE9\xF2\xE6\x82|\x1B\xB0\x8B\x16\x81)\x04\x00\xAB$ \xA9\x81\xF2\x91\x8C\x04\x9D\xBAfh\xC5\x1B\xCD\xD0\xB5\xE0\x88F\x10\x8D\xAB'\x92\xB3\x9E\xB8\x10\x88\xBEN\x1F\xDA(n\x16[\xEE\xAA\xA8h w#\xEE\xB5\xD9\xBC\xAF\xD6\xAF\x8A\x98\xEC: \xF7i\x09gk\xEA~\xD6p\xD7\x89*A\x99\xF7{\xF3<\x1D"\xF1N\xB3\x08r\xEA\xCD33\x97\xB0\xFA%\xDF\xCA^r^\xAA\x99\xCC\xD6b1\x80`P\xDE\x99,\xF4\x8E\x87\xFD\xE5O\xED\xC7FPw,\x976\x15\xAA\xF4\x92}\xED\x0E\x9E!"\xD3\x80\x91\x84\x0C#6\xB6x\x06\xFCc\x088\xAB\x17C\xE8'\x1C1\xC0\xCDi\xA6\xF7\xC8\x06Ae\xCF\xBEvfa\xB6\xF83\xE0,\x87l\xEEzI\xA4\xD8j\xF23L\xA9v\x8D4\xB0\xA2Z\xE8;\xA8sV\x1A*\xDC\xE4\x18\xD5k\xD6\x02\xE7\xF4\xC7\xC0\xEBSP\x85\x02\x18\x1C\x19\x8F\xA0\x96:\xCFs\xA3l\x00W\xDE\xA3\x92L\x01\x07\xD9@\xB7m\xC0\xBBw#\xC3\xD0\xEA\xE9*\xB2O\x1F\\xDA\xC2\x0D\xB5\x85\x13\xFF\xD8\xFC\x05E\x95g\xF8o*\xBFU\x87\x1E\xEE\xF9\xCE\xBA\xADm\x8E\xA2\xF5#\x0B\xEF\x9C\x9B\x0B\x04\x8E\xA44\x14Y\xF8Z\xDF\x06\xCA\xF0f\xD3\xB2\xB5p\x82k\x19O\x15\xB4-\xA7W\xA6\x90\x0F>J\xAB\x0D\x06\xDC^l\\xFF5_">m\x1Ee\xE5+\x0C\x81\xAC[\x12\xA8\xEA'\xFC\x8B\x19*\xB6I~\xB8G3\x07q\xEA:\x0F\xF3\xC7\xD4\x88\xCFWA\xFB\x04\xA9\xDC\xD2\xA3*\xAB\xF8AdQ\x85\xF5\x93\x94ba\xCC\x073.p\x02\x04\xB8\x10p\xBA\xC1\x07\xD5\x1C\xD1\xE3\xDA\xEF\xD4\xD0\x86p\xDE)N\xC3\xA2\x89\x1E2f\xD9\x92\x0F\xFD0\x81\x8B\xF8\xF3\xA1m\xA8\x9E\xB7}l\xBA\x0C\xEA\xF5\xD2\x94\xA1{\x98\xFC\x9A~.\xC5\x96\xF0R\x01\xA1=2|\xF5np\xA8e\xE2z\x05\xE4\x9E\x13\xD7m'\x11?\xA5[\x83\xA7\xBE\xE7M\xC6;t;.\xE0\xD6\xD15d\xE1K\x96\x0EUq\x8A\xD0Q5\x8B6\xF7\x03n\x81<\xBDv\xBB\x82d\x12>\xFD@\xC3\xAC\x94>D\x17\xA1\x8A\xA7\x11\x9AL\xBC\x91"N\x0F2\x8D2G\xBA\xEF\xA1\x8B.R'od|.\xE9\xB2\xD8\xFC\xB7\xCA\xEE\xF8\xA5o\xB6F\x85\xCB\xB4\xEC\x16A}\xBA;\xEDq\x8C-\xD1p\xFBiI\xF4w\x88&\x13b\x92d\x14\xA6]\xD3\x1F\x91\xDE=q\x84\xEB\x95\xDE\xCFfO\xDC_\x06.\x8B|\x1A\xE1\xE5\xB3\x19vr\x1C\x8Cj\x11e!\x0E\xF9\xD1:\xD4K\xEF\xC4\xF3\xA75<)+\xFEn\x11_\xF7\xB4\x04\xFE\x19\x06W;\xAA+\xFA,L_\xF0\xDA\x9F\xC0G\xC3\xE8\xB1P6\xC6\x86\xA9]\xD3\xCB\x06w\xF1\xEC\xED\xD0\x0A\x98\xCDD\xE0+=\x9D8E\xF02\x07U\xDE\x8B\x8F\x10\x9CQ\xF0\xB6\xA9\xE4K\xF9t\x10\x9E'\xCCc\x87{\x12&e2\x94\xB9GuP=\x0Av\x10>\xE9\x96\xAB\xF94\x81=\xAFW\xC8+\x9Bj~\xDD_\xB6\xCEw\xBE4\xD6\xF1\xD9\\xCA\xB8\xE4\x1D\xE5\x1F\xF1]\xEB\x90\xC3\xA8\xCC'e\xED\x8At\x89t\x91\xB5\x0Da\xC2\xAF\xE1\x1D\xF6\x1F\x1B\x9F,s]\xA8!\xE9\xE08\xCD\xD9\x95v\xF1\x8E\x88\x85\xB0\xF77\x0E*\x9C\xA2v\xCA\x16\x1DE_\xE9\xBC\xFAu\xBE&\x88\xB3y\x1D*\xCD| [G\x8AI\x9Dr\x09\x8D?\xAD-\xFD\x88^\xE3\xBC\xA1\xC3a\xB4\x9Df\xE98\x8EE5\xCA\xC7\x95t\x83)\x04c\xCF6\x91/\x8FA^\xA7\xA9LJ]r\x7F\x00\xC6Yz\xA9'\x8B\xFE\x8F\x93\xA1\x08\xC4K5Ej\xA2\x9CT\x1F\xF2\x9A\x03q\x89\xE9\x1D\x8E~>\xFE\xB4\xAE\xCE\xC9\xE8R\xC8\x11\x13\xC1I\xC7O\x1Ba)GG|\x81_I\x10\xA7\xECx\x85y\xCF\x9F\x8E\x92(\x8F\xD6\x86\xF2\x09\xFEs\xA1\xAC\x85F\x84\xBD\xA1\xE3\xC1\xBC\x17J\xB0:H\x05^\x8Bc\x82Y\x12\xCB\x81\x81\xBA`\xEE\xEC\xDFM\xC5\xBAKu\xA9\x8876\x95yl\xEE\xC1\x88vc'Zf7~\xAD\xC9\xF1hKi\xF0\x06\x9B\x8D,\x1C\xB6\x1F\xE7wx\x9B\x89\xF3\xF3\x05\xE9\xF9\x84\x09\x0B\xCB\xD0\xDC$X\xA3v9\xB6Myd\x14\xB1V\x87\x80\xBCE4\x1D\x0C\xE5.\xC8[\xD5+\x8E\x82r\x8C\xE4.\xF4\xD8\x1C\x1A\xB6#/\xB2\xE1]#9\x15\xC9\xCB\x9Bl\x13\x1B\xC5\xA7\x1F\xE1?\x1E\xA2\x07bX\xD5\xDD\xCC\xF2\x93m\x84\xC4\x0B\xE7\x12\x8A_\xDB\xFA-\x84\xE5I6\xE7'\xDF\x05\xEF\xE1rC$}\xA7\xF7\xF2\xB4\x9D\xB7\xFCq\x9A$Z\x9Bz\xB0\x94\x1F\k\x1F\xF9U\x9F\x98\xEBl/#z\xD5fJp\xBD\xCE\xCE\xDD\x0D\xD8fL\xF5\xFE\xF4\xA2\x03\x0A\x0B\x08\x09A\xAF\x8B$\xE3Qq\xF2=\x0C\x1D\xA1H:*\x18Z\xBF\xE4\xDA\x1B\x14k^\x18@\xFFs\x82\x90\x87\x8A\x92\xEF"f\x12\x12b\x134B\xE9\xC1\xAA\x0B\xF8\xCD/\x03=;\x01bc\xBA\x18%M\xAD{'`\x930\xBD5\xB1\xE4.k1@ M_|K5\x90\xF2:\xB9V\x9E=@\x97\xDD\x911\xCB,\x86Uo\xB4\x9B\xAC9\x9C\xCD\xF4\x00\x05E\xBB$\x9Bz&\xCBU\xE6\x93%o\xA5 \xC6Y\xF6\xD5\xF2\xF8\x98/6\xA6.\xF2\xC7kk(\x8E2\x14o<|\x8D\xA3\xF6\x82\xF2\x07\xF8\x1F2&\x1A:\xC8t\xE5\xFC\xFB\x8Cl\xF4\xC3\x93Q\xF1WGl\xCF5A.\x9Bl\x92ag(y(k\x8D\xB3\xA6\xB0\x00\xF6\xA7"\x83\x85\xFC.\xC5q\xD5\x815Q\x09\x0F\x12\x8C\x14at1\x02Q\xB9,\xBA\xAE\xF2\xFA\x16\xD9\x9C\x9B\xD1\xE2\xB5\x1C\xB0\x8AH\x80]5|\xFA_w[ \xD9R\xF51\x15\xC8\xBA\x91\xE6\xF4\xB5\xDC\xF8!\x1C\xBES{M\x84\x97m\x82\x17H\xDC\xF9\xF2\x81e\x82Il\xB9\xB4\xA2\x95\xC2\xA1\x19\xDB\xC8\xB9\x15\x15\x08\x07\x99\xCC\xCB\xB8.\x05(L\xD4:IJ|\xB4\xB5@\xE2'\xA3k\xAA\xD7%\xCC\xA0)W\xFA\xBD.:d'\xB77\x9A\xB1\x09\x89\xA5\x08a\xA5dP\x19q\x0Ey\xD0\x11E\x12\xD0\x09\xFAf\xAD\x07\x05\x17\xC4\xECA\x10\x0A\xE7Jx\x990/\xBC\xD7\xD6\x0E\xD8\x1D\xE8\xAD\x84\xE6db\xA0\xD2X\xCF\x97\xE6\xF4{\xAA\xAA\xBE0\xA3\x17~QF\xC6\xDC\xB0\xFA[T\x86M@\xAB\x09\xF0\x9A\xB1\x07f\x0Av\xA6e\x9F\x93\xF6-\x1B\x19\xABMM\x96~D/d\x8DJ'$3\xD7]\\xB2s\x87f\xEC1=\x83#\x80~]\x9Dm_J\xCA{\xC7m\x1Fo>XL\xEB\xB4\xEA<(?\x83\x07\xF8\x00ksZX\xB0J\x8E\x06\xE1\xC7\x9BH\xF8P\x97\x84\xCE\xE9\x06\xF4\xC3\xC6\x8CK\x12\x98%$\xB1L\x89\xB7"\x110\xD7\x95\x92\xE7\xB0\xA4!\x80\xF5\xCA\xD4\xAD#\xC8o@\x03\x9F\xD0\x05\xE8\xDD\xBE\x0F\xA9\xBE8\xD8\x1F\xE5eG\xE9\xAF`W\x14@\xE5\x0F*\xE7\xCE.\xC5\x9D\xBA\x16^\x0B\xB7\xB6\x8C\xDC\x17\xB6-E\x9A3\x10\x81H\x8F8\xDC\x81\xEE\xB7\xE2*\xE1Z~\x08\x8B\xE1E}\xA7\xD8\xCA\xC0)3y\xAC@`%\x0CbP\xB6\xA0-'\xE32[D\xCE\x86I\x9D>\x17\xA5&\xEA\x16\xF3G\xC0>\x13\xB4n/\x0AJ\x01\xBAM\xF2\xB8\x11-\x09\xEA\xB8\x09H\xD7\xF7A\x08\xDE\xE9$_je\xAA\x96y,\x13\x9CKSD\xD2\xC14\xB4U\xB1tE\x95\xFE\x89\x8FH\xE7%j\xBB\x97d\x00\xF7\xD9g\xF45\xA2`\xDA\x8D\xF4p`\xA7\x0FWL\x0D=#I'\x8F\x05#\xEA}\xF0\xC4R\xA4\x0D\xCB\x08\xFC\xB0Uc\x8EM\x95\x84!~v\xE5\xDB9\x14x\xEC\x11\x01v\xF0\xBC!\x8C*M\x08\x07\xC9\xC9\x9E\xFF\xCE\xA9#\xF8\xB2Q\xBE\x03\xDDS$\x9D\xD88\xB9\xC5\xC3\xBA\x81\x0D\xDBK\xE7\xD7\x13v\x9A\x1B\xC9\xA8\xAF\xC1\xFE\xA3-\xDA)\x98\xB9\x03\x08E\x9F\x93\xFC\x06LI\xBB\xD7B6\xEC\xC0verh\x96\x84\xEF\xC1\xDC\x07p\xBC\x85\xB00\x89\xDC4\xD5\x04\xF21\x04\xD3\xB2qA\xED\x83\xF0!\x96\xB8\xC7\x15\xB3q\xE0\x86 \xD0\xFE\xB8\x8D\x932\xAB\xCA\xC2\x04L\xDD\xA0\x9E\xED{\x8B{\xB4\xA4\xC7R`9O\x08\xDD\x94\x1D\xFAa\xC0\x7F\x8E\xA2\xB2\xDAB\x9F\xD0\x12\xAC\xC95.j|\xD5o\xF4\xEB\xF6o\xE9\xF1$D\xD9Ak\xBD\x09T\x9A!\xAD\xAD\x18\x1F\x0A\xB6\xFD\x13m{i9\x0C\xB8\xFC\xCDs\xAC&\xC5\xAC\x00\x88\x0F\x89\xC9pL\xD3\xB8\xC0\xE4\xF2\x8A"\xD1r\xBES\xB8\x15\xE6\xED1\xACj\xBC\xC6\x816\x8B\xF1\xC1\x1C\x7F\xBC\x13\x93\xCB\xCC\x93\xEB\x8B\x01<\xA2\x9A\xEB\xB7*\xB4\xFB\xC9b\xC9\xD8U\xA4\x01\xC4\x80\xB8*\xBC\x82\xBB\xDC+\x82\xD0\xEB\xD9f\xCE\xD6\xF2\x86\x8Eu\xAD5\x8F\xB0\xBA\x15\x99Y\x0A\xC77`\xB9\x92\xD7$\x0C7\xB4\x81\xB7&H:\xB8oEK\xEAd\x9Cd\xD9M(\xEBbG\x0Dj\x8Ay;\xA7@\xDF,\xED~\x82\xC3E\xB8,\xD2\x16<\x9A\xBB\xBE\xD1BQ8e\xFCS\x07\x1F\x1F\x8F\x9A\xCCh\x8B\x85\x04T\xC4U\x9B\xC7\x08p\xB0^\xDD&"9\x9B\x9Ek\x89\xE2\x12\xC3\xAC\x12*`\xF0\xC9\x15\xF3XF>+\xF5\x9Eik\xA9\x88\xBF\x1C\xFD\xEB\xF3\xB2 \xD8ld\x13\xB9j.\xFB\x8B\x0A\xE7m\xB6\x97}\x11Pm\xB3\x171\x17\x87c\xAB\x03.\xFE\x10\xDA\xCB\x1DfLg\xC0\xF6\xDC\xA6P\x89\x92\xAEz$\xC4b\x13\xCE\xDB\xF4k\xE3\xAA\xD9\xE7\xBCD\xED\x14wF\xA7\xD2\xBE\x9D\x87\xFC\xEB\xCF\x82\xB3\xF8\x0EZ\x849\xCD\x8D\xCF\xAEd\xB7\x92\x93\x19\xAC\x90m|\x8Cl\xDDE\xFE\x13^\xAB\x91\xEB\x9F\xE5\xC3\xB9l\xF0\x08\x1E\xEBi\xFAG\x1D\xE9\x91\x13\x10\x1B\xBE\xBCP\xDE\xE5\x1A\x14c]\xDAGf\x14\x88M>\x97E\x9B\x1B\xB2\xCC\x86\x1C\xE9R\x0EU\x83\xEF\x9F\x14x\xDA^\xB0k\xEB\x82\xD5\xC6\xBC}26n\xE2\x8A\xAB\x97\xDE\xC9h8+\xC9\xE5l\xBA\xB3\xF7\xB6y\xD3\x7F>t\xB3\x0AJ\x9F\xFF\xFB\xB2\x8B\xC3\xA6:\x82\xEFFN\xB5\xF9,@K\x9C\x9A#\x1BT\xAB\xFEJ\x17:\xA1\xD1\x1B\xC1\xC3z=\x08\x8F\xFC\x08@^\x03\xB6F\x1B@o)\xC0/A\xA9\xA8o\xFD\x1DK\xB4\xEC\x02F\x9A\x19\xEC\xC85\x03\xE76\xE3*(\x07p\xD0rV\xC6D\x814th\x04\x09\xBB3\x88\x0E\xCA\xD7&\x9EW\xF1\x8D\x1B\x85K_(T\x96\x86H\x87+\xCF\x142\x0B\x0F\xC5\x87\x9E\x83\xDAF\x8C\x84!\x95\xCE\xE6\xB0s\xA4\x0E\x9A3Vn:\xE8\x19\x1E\xFA<\xD1\xD4\x18\x91z\xB7\xB0-r\xAB\xEE\x19\x12\xDF2\x92\x03\x11\xB1\xBF)9\xE5\x9D\xB6\xDB\xE0=\x12^\xE14\xDB\xBC\xC2\x95\xB21\x81\xFE\xEA\xE3\xBE\x86\xBA<\x072\x80\xF8\xEF\xEF5w\xB65\xB2\xD0ot\xA6\xBC\x95K5G#\x15\x0Bg\xEA\xE5O\x97\xD3\x9E\xE9\x8C\x05Y\x8F\xD5\xCC\x1B\x94\x8D\x99\x01\xEF\x8C\xFE\xB2\x14l:\x0E0\xA7v\x8Bt\xCC\xBA\xA2=\xF3\\xB9\x06wy\xE0\xF7\xD8V@\x0E[#\x1Ar\x92\x91\x9F\x0E\xBD\x97B\xE3\x7F\x98\x94hW\xCCH\x0DF\x91\xF2 6)\x14\x07|\x17\xBD\xE5[\xAD-\xEE\xE2%\xEA%\xC0V[`\x1Autj\xF0w\xBF\x8A2*\xA9\xA3\x94X4k\xD7\xE1\xD7\xDB\xF3\x13\xFDa(\x10\xC2H\xF8!\x05\xB5?\x17\x8F\x17\x85\xA7C\xFB3\x87\xFF\x1A\xFA\x16\xF6\xDD\x0A\x935\xCA\xC0\xF3\xDE\x06\xE3\xE3^N06\x9F\xBD`\xB5\xF1\xC7\x1BE\xE3s,\x91]\x08\xBD\xC2\x02\x9F\xFFfd\xCBwh<\x8F\xF6\xBFw\x93\xC5~\xBB\xC7\xF5\x0B\xC7\xBE\x8Ao\x03\x80\xF7w\xED\xC6*\x00v\xBE\x0F\xE4T\xF3\x0E^\x12\xB50o\xC9\xA6\xF9\xB0\xA0\x04@f\xE4\xEA\xB4\x8F\xDA\x17;\xC8\x1F\x80\xF7\xFE`7\g\xD9\x975\x1Bt\x18\xA3D\x96\x05\x1D\xFA\xC8\xCB\xD6\xF1=7n#\xF5\xE6\xF0$&0\x08\xCDG\xDA\xDB\x0A+)]\xCA\x05n\xEA\xFC"\xE8\xA4\xBCb\xAD\xAA\mki\xD5\xB2\xE2a%y\xBA\xC8\xA1\xA3\x07m\xF5f\x9A\xD4l\x81\xFD\xBC68\x1E~\x88\xD1ThH2\x9C\xD1C\xC60\x8EuR\x0E\x80\x81`:t$\x0BZ\xB8\xD15pZF\xA3\xFB.\xF3+;e\xD1\xEE+q\xA9\xB8];\2[TT`b\xD1e}\xDA\xB8\xE0\x82\xEF\xB6@\xB6T\x9A4\xBA)\x80B&[\x88wc\xE3"7[U\xF1\x90\xF6\x0E6\x88\x85\xAA\xF9\xC6]\x93{\x1C\xC5\x8Auu\x7F\x8C\x9F\x12\x07i\xB5\xD0x\xFF\xFART\x8A\x02\xE7ki&\xBF\xCF\x1D\x8BZ\xD2 6\xB0\xAA\xA8\xC3\x8C\xAA\x94\xB7s\xDCC\x90\xBF\xF9\xD9S\xC2i\xC5\xF3\xE9|\xFF.\xD7k\x85@W}\x18R&A\x8F\xE7\x81#+\x82\x0E\x99\xC9\xDB\xF5\xBF\xFB\x82{)\x84\xA9\x98\xDA]\x19\x1EL\xF8\xE4\xED\x0F\x15\xB58\xEB1\x1F\x89\x05\xB3R\x01T\x98n\xDB\xF6\x14\x17\x13\xE6z#\xC3\xA9z)\xD2\xCC\xAB\x10}\xCFy\x18'\x0F\xE3yX\x1D\x9C\xAF\xDB\xC6n5\xB6\x9C\x13\x8E\xDD8);\xBB\x01\xF0\xAD\x82&\xDC 1\x16qz\xE4\x95\xB0\x9B\xA3o\xC5\x9B\x1B\xCE\x1C\xF1\xBE\x05\x8AG {~\xF0qp\x06m\x0B\xFBD\x14\xB7\xD2:@ii\xD0\xDFD\xB1\xAF\xB9\xA4\xEE\x03\x92\x08Ze\xED>L\x8E\xF6\x1Ev\x8F\xB8\xBB\xCE)N$\x04\xCB\xE3p\xFE\x1C\xAC\x1A\xCF\x7F\xB2\xC4\xCC'S:\x15\xF4\xCC\x7F\x0FUr\xD4\x08\x902\xC9\x88\xEE\x81\xB3B\xB8F+\xC8\xA1\x07\xE8e\xD1\x8A\x9B\xB2\xCE\xF6>\x86<\xDA\x16l\x8C\x1D\xED\x0E\xBB\x8Ce\xF4?I\xFD5z\x04\x93\xC17\xC6\x97HY\xCF)\x0F\xB2\xC65Q\xA3W\xA4\xCE\x8F?\x17\xE6\xBB\xCC\xADD\xCC&\xE1\x1C\xF8]+\xE51\xDB\x19\xFEW\xC3\xD9\xF4\xBE9$\xEE\xE1[9\xE3P.\xDB\xDEP\xDF0\x8A\x8B\xF7iHg\x98\xE1\xB6\x19\xA5\xB2@\xDC\xFA\x13\x98fa!(M\xB0A\x1F\I\xE0\xBD5\x84\xFA@\x98\x14\x97\x9Ey\xE9\xAE\xB8{D\xFC\x7F\xD5\x0AS\xD5~\x80\xF6\x9Fk\xC1g8\xED\xA0\xDF;\xDE\xDC\xE6\xC1\x97\xA7\x19\x18\xDCJa\xF6\xC3O\x0A]\xF685\xA8\xB2mzF\xDC\x9B\xA4\xAB\x13\xBB'\x84\x00(\x82\xCD\xB2\xF3\xC3D\x05\xCF\xA2{*v\x180gU>\xB4\x82\xA3?\xE5\x8C/36\xE7(\xD1\xB9\xEFs\xDF\x09\x1E\x95\x9E\xC3SQ\xF0\xDA\xAF\xE3\xEC\x82H(W\xC0\xD5\x1F\x87\x98@S\x0B\\xCC\xDDGn\xC6Q\xA0}2\xF9U\xCB|\x9B\xB1\xA7)x\x9F\x93\x05\x1D\x9B5\x19u\xCCNfB\xDE\xE4\xC8z\x99-a\xD3\xDE\x14\x16\x91\xF8\xA6JZ\x0E\xFC^#\xC7\xD5v\x15\xB0\xA1\xF1\xAE\xA9J?\x8FKZ\xE8\xFF\x0C\xF2(^\xCA\x1F\xF4\x80\xCC1\xAB{l\xF54\xF8&o\xD4\x8E\xB76{\xECC\xA6U\xC3*\x8D\xB0\x95\xE4\xAE\xAD\x1C\x8F\xD2\xC5\xCDY^\x0E\xD0\xBD4\xEB\xC8\xD4\xBCx\x82\xE3K\x1A\xD2\xEB\xCBB(S\x0F\xA6`\xCE\xC5\x10\x19\x8F\xC6\xAAK\xA4\xB2\x14\x09\xE4]h^{\xC9r\xAC\xDC\xDA\xDB4\x1F\xFB\xC5r@\xB9\xE0\x90u\x8F?J\x0Bv\xD1\xCE\xF6\xC7\x8Do{\x9B\x96\x9C\xCA\xDA\xE8!s\x01f\xA1\xA3\xC8*JP$\xB0\x1F\xD9\xDA\xFD\x1D\x1A\xC2\xEF`\x8F\xCC\xC6\xEAM\x1A\xD0%`\xE5Ja\x85\x81x\xA0\x03\x99\xFF\xE5\x190P\xED\x89f\xC0I0nK}\xF2\x00)3\x89\x8B[Os\x15UF\xA5B\xFD\xDAR,\x1C<\x8E\x81\xAD0\xB6hW\xEC\x8F\xA4R\x95\xA9:(J\x94\xA3\xF8xWH\xE2\x8B\xC5\xCD\xA8\x7F\xBF\x0E\xF8x$\xFD9k\xF4\x08iJ\xA9n\xC4_\xB7d\x81\x91\x09\x9B|\x19x\x92\x8E\xC5%\xD0*\x8C!%Q\xBCSO\xD1R\x14\xE3\xBB\xAF\xD7=i\xB4\x1A\xFB\xC8\x1B\xEC\xB1~\x12\xCA\xB8)\xFB\xC5\x9E\xEE\xDBj'"T\x00g\xADc\xD8\x89Q?\xECe[\xF6N\x91I\x10\xA8\xA6\x14\x1D\xCE\xB6\xF9O\xE6\xACk\x1E\x95 \xE9\xEFO\xF8j\x0C_\x00Q\xBC\xA7\x9E\xDFN\xD7L2<\xCF?\x9Fa(:\xCD_z\x15\x06\x17m\xF0=\x86\x8D\xF9\x1D\xA6.?\xC1\x95\x9B\x85\xCD:\x88d\x15+\xCC\xC5\xA6\x8C\x81&\xDE;\x03\x17\x7F\xC8d\xCB\xB8\xE6b%v\xAAK\xB4\x13\xBF\xE9\x18\x88,q\xA8\xB6`\xF7\x84\xC7\xF2\xDD\x11\x841\xF6\x94\xF5mh\xB7(2\xB3{\xF3\xD9|\xBF~\x1F\x02>\x86D\xFE\xFA)\x8E\x93O\xAE\x95\xD7\xC7\xB6\xC4\xB1\x92vc\x8C\x11\x1A\xB3\xCE\xBE*D\xE54(\xA2\xCB=kb(\xCEA\xDC6\xFA$\x1C0\xC5`\x88\x05\xBC\x1D`L\x08\xAD\xD0\x8D\xF5\x19dh\xDD\x1F1\x9EB\xAF\x10P\xAFM\xA5\x10\xDF.\x0F\x00\xBE\x81\xBE|\xDE\xC5\xA3\xFE!\xBC\x15\x1E\xEC\x8C\xC2\xE0\xF6)%\x12\xDD\xD7\x0C\xAE\xBB(8LZ5\xEE`\x18!\xEA\xEElI\xFA\x0F\xB1R\x86\xF1\xB2\x91\xD0\x0D\xAFY\xF4\xF0\x82@n\x1A"\x98~\x8AMD\xEC\xCFp\x10\xBDT\xFCR\xB6\x97fs\xBDM\x19\xFD\xEBA\xAE{)\x82\x08s\xADI\xAA\xF9\xA0\x0D\x9DVh\xAF\x12~\x0B\x83\xC7\xBD\x05\xD5\xBF.\x8Dm:\xFF\xBFE\x8AP\xEE\x06.\x10\x0E\x85.B\x01\xBB\xB3\xB2r=\x81W\xAF8,\x86A1\x8F\x09\x1B\x05\xEE\xC7s\x9AQ\x97\xB2u\x11H-R\x1AL'\x89\xFBV\xF1\x0D\xF5{\x85\xDF.J\x1Bu~\xB3\xB2=U;Y@\x03\xE8\xB9n\xB8\xE2\xB6s\xF1uxHhv5\x97\xD8\xBE\xEE{\xF1Y\xCA\xF8\x88\x0D\xC9\xEBS\xB6\x0Dl\x14^\x9A\xF1\x89\xD8\x82+\xC8\x90\xD4\xF6\xEE\x04\x14\xA8H\xBA~\x89@X\x9A\xB9|\x80\xE9\xD6\x0E\xE3> \xEE\x12\xF6\x92\xD0z\x9D\xAC\xC8\x1Er\xF7\x07T\xD3\xAE\x99q\xC2\xEE\x0Ak}i~\xA3\x87hr\x9D\x85vmh\xF9\xD0?,\xFC9\xAF\xE1\x93\x99/\xBF\x7F\x90\xD0\xC3H\xC5\xE1\xFB\x83\xBF\x852\xEF\xFB\xAD\xE7\x08~a#h\xACh\xA9\xE0\x84P\xB9\xF1Qhhyp(\xAEVnz\x08\\x8A\xDDT\xCCV\xB3\xEE\xDA\xFA\x0FVC\xDBE\xE1,|\x0E\xD2\xEE\xEB\xB7\x04M0\x91^\xF1O/\x03:H\xA73\x06\x87\xBB\x1EB\xFD\xB0\x1AR\xC1\xB1])\xE4e#\xF7\xC0\xA5\xB8)\xA0,\x16(\xA1\x80C\xCDQT\xE0\xE5\x7F\xBFG`<\xF1\x1D\x17\xDA\xED;\x80\xBCb>\x9E\xB5\xBE\x04\x86P\xD0\xDB\xC7\xDF\x8D\x06"\xF8.\x8B\xC3U\x00\xD2\xE9[r\xF9\xFCf\x1C\xB5n\xB0%lYU\x15\xC2\xC5\xB5\x89\xFE\xE2\xE4\x9E\xFF\x92O\xD0\x09\xB4\xE4\x81\x02\xDF\xC8G^\xC3\x03\xC66o\x8Bf\x1C\xEF\xE6\xBF.\xF3\xD6\x13h\xD6\x10\x9Cx,\xC4\xA8\xAD\xF0\x03\x87Oy\xA5z\x0Fw:Y\x0B\xDE\xF2\xEE\xA3\xF5\xBCS\x0A\xDD\x10c\xBF\xB6\xB2\x95\x02#\xFE|j\xF3$\x1F\xC5\xBEP\x86\xAC~O\xA3\x92Zs\x19K\xFBVq\xC2+\x8F\x1F[O\xA2;\xB6?\x0F\xE2L\x81b\x98ymr\xDEK\x86EZ\x0A\xE7F[\xAC1!7\xAF?\xFD!\x04\x1D\xFFe\x04d\\xC6@\x1D\x91\x05\x121\x18d\xE5S\x88\x94\xE6\x08\x17\xB7b\xB6\xC1\xCD_\xEA\x98\xF7\x87\xEE)\x8D\x16\x878\xE8'\x9D\xD7\xBCVT]\xF2\x8C\xCE\xC4O\xBAkdI\x08\xD3\xEB\xDB\xF6TAf\x1B\x15ZQ\xBF\xCE\xB0[@\xDB\xB3\xD9\xD7`J\xD5|\xC23\xEA\xAF\xC8+\xBE\x84\xCE\xA2\x0E\x97\xA5T\xE3\x8CN\xA2\xF3\xFA\xA5\x9B\x08\xDB\xBD\x14\xBC\xA1^\x16L\xF0+\x04\xAA\x91\x14\xD6\xD7\xAB)\xAF\x97\xDF5/\x18G\xD3\xD4\xD9\xFF\xF2\x96)b\x0F`\x86\x01\xA6\xB7\x0D\xCE\x12\xA17b6\x80\xEA+a\xCA\xABxl\xE7e#2y\x0D\xDF\xCEC\xCE\xAF\xE0\xCF\xA1Yu\xBE\xC1"AF\x1C\x85\xC8,a\xCC\x8E\xAE\x04\xB0\x8Bq]\x0C\xE4\xF1\xBD\xB4`\xB8[\xB4o\x905\x06\xBD\xC7\x84k^\xB6Jw\xA6\x808\xFC\x83\xC8^%\x07\xAFEp\xC1\x02\xBCh\xBE\xD2\x08m\xCCl\xB3Q\xD3rf\xB09\xEC\x95\x17IA\x83\xB07\xC4\xFB\x862\x0D\x98\x83\xC3$\x00\xFF\xF4\xD1`*\xB6\xA5Ny\x02\xA9\xECnLP5\x7F3\xEA\xE6\x92\xA1\x8C ^[?\x85S\xBBv"x\x9A\\xC2&k\xC3}\xC1"2\x8FT\xC0RGj\xF2T\x1B\x80\\xA1\x96\xEB\x9FPo\xA8\xE8\xA5\xE1A\x8B\xE6\xE3ld\xD0{\x9A\xB2\x05;\xC9\x81IJ0p\x9DpV\xAA\xD5)\x14\x15\xC2l\xB8\x9A\xDC\x9F7\xB59J\x0E8p\xC7\xD4\x1E\x84\xD2I)\x19\xA3L\x9F"F\x14\xB3\xA5,]\x0D\xAA\xC7\xA9D\xA0\xE22\x12\xC0\xD3\xA9\x1B\xB3\xA5\xE5,\xC8\xA7\x92\xC5~\x19w\xBD\xC1\x93F\x19P\xF4\xF8\x92\xD1\x7F\xE5\xAF\x8B\xD4+4\x0F-B\xC1[\x9A;\xB9\x8C\x04\x9A\xD0\xC7YL\xB10a\xC7=\xCBX\xE3f\x9D\xC596\xFD\xC4\xE9\x04 \d\x88\x8A\xF3\xA2;\xB7\xA4Z\xD9ds\x86D\xAAM\xCC\xCC~8\x0E\x17(\x82\xCC-$\xA3C\x9B\x8F7\x9E=f?\xBA\xC3s9n\xAC\x0A[\xC5<\xF5\x08Enc\xF3\x9D\xFDR\xCF\xDD\xF0S\x88\xF0G@\xEBD\xE2g\xD1v_\xF3\xE7w\x05\x05i\xE7\x94-\xDA\x89\xB3\xCB\xEF5;\xBCzZ+&-\xE8;\xB4v\x8B6d?\xB9\x1DJ\xC7^\x13\xF5\xD9\xF1X\x9D\x1AZ\x9C\xA2\x14U\xFEw\x88>X\xC1oSj\x85-\xE9\xFFJ\xE5\xF1\x1E\x9EeXYuL\x89\xE6`\xB7*M]Q\xC2\xA9#\xAD\xC7\x98\x8B\xD1\x0C\x88p6\xD0E\xD9c\xD5e\xD5C\xC3\xB6\x03E\xFA\x93\x88\xB2\xC4\xD06\x16\x09\xACi\xD6wO\xAD\xFA\xB0J\x83\x0F\xB4\xFE(\x1B!Z4T\xD1\x9F!\xAD\xD1\xFF\xE7\xA13\xFF\x8D\xD9\x05\x1AU\x9F\xE7(\x0A2?I \x05`\xE7\x1D\xB4o/\xEB\x81\x02\xD1\xD1P\x05\x8B\xC9.\x04\xE4f\x91\x82^\xE4\xDDh|\xC2\xE9I \xB5\xBE\x9D~,\x9A\x1D\xA2d(o\x07z^\xAC\xBFJ\x96\xD2=">\xE3\x90"\x16y.\xE21\xB7\xBB1\xB0+_\xDD{=\xBCD\x97\xE2\x87\xB6\xEBG\xA6<+)\xF1v_\xE2D\xAF\x04\x04\x7F\x9D?\x11\xE8\x89\xA7\x03r\xBC\xCB\x9C\x94j\x95\xC5~\xDCo\x9BK\x01\xD3\xAE\x88\x9Az]\xE5\x04\x17vm_\xEEf\x8D\xCCC\xF1\xB2\x18A\xD89\xF4\xDA\xD8\x82\xBFF\x15\xF9\x05\x86\xA5\x1CO\x981\xEC\xFD\xEF\x9E\x9C\xF8;\xBC5\xA6wx\x81\x16X\x80;8\x93\xBF\xC4\xCD0\xC7\xE1'\xD3\xB8;>\xC5'\x89\x11\xE5c\xE0p\xCA\x0A\xC1v\x0C\x0C\xB8\x1B\xCFM\x83\xE4\xDFY\xB5\xBD\xD3\xEEE\x87\\x1C\xAF\xA1\x94\xF1\x89\x80\x83B\xDFX`\xD2h|\x1C\x94\x03\x8A)fp\xF6T\xEF,\xD74\x0EO\x0BU\xFA3\xBC\x9A5\x953\x07\xA3q\xFCf9u\xF8\x97D5\x11.\xB0f\x0Cz)]YB\x94&\x1F\x092\x84\x0D\xEF\xAB\x0A\\xE5\xFA\xA8\x81m\xBDE\x9C\xC1\xC3\x88\xA0h8D\xA5N\xDE\x17\x9EK\x15\x09\xFFUfH~\xB0J\x1A\x01B\xBF\xA8\xD3\xA4s\x8F\xFF\xB2\xA0\x18#\xA7\xA5n>\xC1\xAA4b\x85\x13XB+\\xCD\xF9\x7F\x82\xE4\x82y'\xBB3d\xD9\xF2Z\xD4\x19\xFB\xC0~\xBDj\xE57]\x1F\x0A\x87W\xEC-\x11\xA9\x96\x0C\x01\x8B\xB5\xC5\x9A\xBFKn\xA54KDi3\xC1S\xC3\xF8/\xBE\x090\xD9\xD0\xCD\xD8*\xC0\x9F\xB1((_\xBF\xAD'\xE6\xCA\xB1\xFC\x86\x84Y\xB4\x03\x1ER\x1A\x13(\xAA3\x03\xD4\xF6\x8E76\x9EV\x05\xF8\xA3\x1D\xC6\x0Ai\x9BUv\xF4\xCF\xC9\x01\xAD/\x0A\xED\}K(\x1B\x04\xE6Je.\x8A\xBE\x16C\x82\xBA\x0B:\xE7dwB\x10\xDB\xF2\x1BT/\xEB\x86:\x9D\xDA\xE2\x10\xA7N\x1F\xE7\x91\xFF\xEE\xED\x08\x93\xA4\xEE\xE1Q0w^\xB8\xAA\xF7\xD0\x99=\xB1z\xD9D"kZ$H\xF7\xD1X.\x1C?Wn\x1Ds^1@\x82\xA6\xB0\xBD\xEBa\x1B\x91\x11\xC2\x8El\xCA\x8A\xA5y\x129\x9F\xF5\xA1DY\x1D\x91\x0B{-\xB8\x16\xC9\x1E\xA7\xCC\xCF*\x09\xEBE(\x0D\xA8>iP\xCE}\xC8\xEE\x09\x04\xFD\x001\xF6\xA3\x1A\xCEi\xDCR\xBAI\x1DA\xDD\x94\xEC0An\xB9\xA5/7\x01X\xA5\xB3z\x183)\xEBf\x14\x0C\x84\xF5\x97\xF1\x17\xC2$\xD4_l\xC8\xC5\xB4G\xFCE\x90k\xF0\x92\xD1\x0B\x90(m\xAF\xAB\x065\xBDr\x93\x110\x14\xAE\x80\x84.\xA6\x0D\x0D\x94\xAA|\x8F\xDB\xAC\x03\x97x\x8F\xF4#z\x10\x1D\xB0\xE9V\x0BY\xB1\xF7\xAA\x19\xC4\xA0b\x1E\x94\x8B\x1F\x9D,\x92q\xCF\xF2;(\x83k\x0E\x02\x83\x7Fr\xDE?\x1D\x18\x8Fe\x0D\x99\x13\xA6\xBB\xAB=\xB6\xDDf~u{N\xF1\xDC\xF6\xBCR\xDC\xF0\x16\xA0BZ\xA9b\xD9\x8B\x0F\x16\xB0lN\x9E\xF13\x19\xDE\x89\xAD\xACq\xAC\x98\xB1\x96\x97.\xADj,IQ\xA3\x91\xC2\xE6\x8E\x13\xE9C\x7F\x08\x8D\xDE'0)\x14\x05\xBE\xA1\xE6]\xE3\xD7\x16V\xAA]\xC1\x0C\xAF\x87\x8E\xBF\x05\xF3\xAB\xA2\xFC\xC7~\x97\xA7\xAA\x86\xE1\x90\xD8-\xA1JD3\xD3\x9D@\xD9\xA9\xA3\x96_}\x97\xC4?\xC8BvQ\xAEC\xE5\xD0\x8DM\x92w\xEB\xE09\xD8\x96\x05Z\xC3\xEB\xFB\xBB\xDC\xCE6B!k2\x96\xF8\x80\x19]\x83Y\xAA\x17\x0Cx\x0A8T\xBF\xF6\x7F\xED\x18\x0E@]\xFA\xF1\xE2\x04\x11\xB8\xD1W\x81\x8DB\xF6\xFD\x7F\xFE\xC1\xF9x)H\xE7\xE2W\xB8j0B)\x91\x1A\xED\xDA\x88W\xE1\xBA'&\x83\x82\xCA\x8E\xE6\x96\x94\x05m\xDE\xF8\xEE\xBAa\x8C\xC2Y\xAE\x99\x8E0\xAB\x18k\x9A\xA7\xA6gSk\xA2RU\xD9\xE2\xA5\xC2\xD9[\xA4\xDF\x83\x8B\xE9\x92u\xECn\xAE7q6\x1Bw\x80b\x0EG\x87\x8C\\x08e\xFB\xCA\xC7\xFA\x80\xF8\xE7<\x12f\xAA\xB7:pg%l\x1F\xC89d\xA5\xF6\xE9\x07\x01\xCFp\x90w\x874\xE7ck\xA9oH\x88\x93\xF3b#\xABj\x83^\xC2\x05\x18\xC9\xD9\x183t\xEF\xF2\x18i\xFA\x8D\xA9`SW\xC3\x16\x8F]\xC8\xAC^\x91p\x12b\xDD5F\xA0\xED\xC1\x17 \x0C\x80\xA1\d\x8D\xD1\x9A9\xD2\x10.`S\xD1\xC7\x8E!\xE5\x00\xF5\x86o\x9D\x96\xC8M\xE2"\xEC\x82\xDE\xAD\xD5\x11w\x8D\x90\xDB\x86^\xCD\x9A\x17\xFB\xD4\xD4-\x88\x9D\xE8\x90\x8Bt\x84)\x16\xA2g\xF6\x12\x17P\xD4?\x05\xBC\xD6GC\xEB\xDF\xA8\xFA\x00\x16\xE3\xB4\x10l\xCD-\x10\xBA\xB2\xFCst\x06\xD8\xCB\xA9&\xAD\xB8hR"~\xCE\xBF\x19{2\x17\x8A\xCE\xBE\x8E-\xA6\xE0^\xA5\xDB,\xD19\xAEt\xB7\x9EtM-ch5.y\x98d\xD3F\x99D\xAD\x9C\x90#\xD96nO!\x8Ek\x9F\xDC2}\xDF\x9F\xCD\xA2\xEAW\xF8\x00a\xF4c-\xDB'\xFAf4B\xE2X\xCE+\x04qd\x99_\x05^o\xEE|\xAF^\x95V\x87\xB6\x11\x95\xC9\x7Fp\xC6\xC87\xFB\x98\xE6\x83\xDE9\xCE;Zo\x06\xA5_\x95k\xCF\xAF\x19\xFB\xF6\xD8\xD9zi\xB9/\xFFP\xC0\xCF\xC0\xDBq\xF8\xC4\x89h\xCE\xD3\xABUZy\x1C!)2\x89t\x1A\x1B@Y5\xD2\xF8\x1DJ\x0E\x0F\xAB\x17\x8C\x0F{\xE5\xCC\x90I\xB4]%T\xD9P\x85gr\xC3\x7F;\x15!\xC4\x06\xBA\xC4\x83\x8AY\x1AgsT\xF1\xF5~\xD0\xED\xBA\x18\x0B\xF5\xBA\x91\xC62A2F\xA9\x94\x18\xF7\x9D\x86[{8\xBA4>\xC8TM\x9D\x0D]\x1B\xBE\xB7\xEB\x92\xF9y\xA5\xB4\xB1i\xE2\xD4 FI\x9A~\xB8m\x93\xCFV\xD2i\xD4x\x1D\x0C\xEE\xE7\xB4O\xFFRs\xD7e\x9Cxeh!q\x0C\xF9\xC4\xBD\x12R\\xDF}\x0Ag\xBB\x05h\x08\x06&M\x14a\x080\x81z\xD8\xCB\x90\xB9\xEC\xF6\xA1v\x7F\x96\x17\xA0\x0E4\x1B>\xAE\xDEw\xE4B\xA7B\xF0\xF0$\x0F\xBA\xF8\xA0I\x83RV\x19\xDE\xC2]\xC4\x98\xF2\x1C\xFE\xAB\xE5n\x9E~~\xA4\xBA\x11WpK\x8B\x9C\xA0Y\xED;\xA4\x08!\xB3`'o\xB6*\xAB\xBF\x84-\x06&<\xEC\x8Fl\x82I\x87u\x02y\x1D\x9F\x89EG|Qc\xB5 \xE9\x8A\x10\x07\xF0\xDFA\x00\xB5M\x85\xDF\xBE\xB1\x8D\x8Bk?\x1AOL\xAC\x97o\x10\xB7\x0D\x9F\xDFY\xE8\x89_6S\x98\xBBo\xE7H\xD0c1\xEA$Q\x18\x92\xB3\xF9 \x89i\xAAOy\xAABe\xC9+\xD41Jl\x0Ck\x18U\xC4\xE8\x08w\xD2\xCF\x03-\xA38\x15W5\x81eK\xBE[\xBB~\x90\x9FB\x96\x0C",7\x8D\x7F\xEDZ#\xE7\x14J\x1A\xE4y[\x99f\xF8D\x9A\x82\xF1I\xF0HAR+w\x14^\xA5\x09\xB1\xF9\xA4\x10$\x15?VQr\xCF\x90\xEF$$P \xB2\xB18\x1A\x1F\x88\x0Flk\xEEL\xFFo\xD4\x10\x8E\x82\xD5M\xF1x8\x0A\xB9\xD5^Qy,\x8Aa.D\x84B\xF5_\xE8\xE6\x8FT\xB4\xCD\xF8\x8F\xB2\xB4x\xF0+"F\x07\xF6\x158\x09=\xEDl|v\x08W/\xB18\xB4\x9C\x88\x04PL\xE2f\xB7(\x1F\xFB*0\xA1\;\x88?\xE8\xBB\x97\xE0]\xE3\x00\xA1\xAE=\xBC,\xCA\xD7\xF1\x11\x00\xD3\xC4\x8A\x818\xC9p\x9Fy\x87@J_\x86"\x85:{\x8C\x89\x02\x08\x071\xD9\xC9NB\xA9{\x8B\xEEO\xE5_\x0FE\xA3\xB5\xF4\xF3\x0D\x9E\xFE\x84\xD1f\xD7L\xA5\xEA\x9CF\xC7\xB3\xD5\x9DI1R\xC0\xDA\x96\x06\x0E\x07v\xD3\x9E\x0C\x84\x9F\xD8-\x9D\xC4\x1E\xFC\x12\x0C\x01zv\x0Dr\xD7\x18\x02\x08\xBF^7|\xB5\xBC\xDF\x98;\xD6\x10\xA4\x00[\x89\xAC'\x87q"\xDE\x00*vS\xB7\x8E\xE2\xB4\xF63\x09\xC7\xD0\x99`3\xC9\x9E[\xC3\xE0\x88\x82\x9B\x92\xAFK\x8Eq\x94\xD3\x12\x82W\x06\xFCJ\x84\xC8<\xD5\xFE\xC6\x8E>\xBB7\x828\xA1\x0D\x94\x7F\xF3\x85\xA0\xDC\xAF\xDD\xCB\xF4\xBB\x94w\x14\x80A7\xC0\xBA%5\x0C\x10\x92U\xBB\xD1\xB4S\xB3y[\xDB([\xA9\xF5T4\xB2\x982L\x0E\xB0&L\xBE7Aq\x87\xC7[{\xF9\xF1\xA4\xA7\x12\\x9BO\xFFu\xB1\x06V%"\xA1\xAB\x85,\x9F\x8E\xA4\xEC\x9C\xD3%\x0E\xFE&\xFE\x14\xD2dN\xE2\xDA\xD3\xD5\xA7\xF3\x0Bu\xEF\xDA%\xDC\xA5\xA5\x88vji\x84\xFFC\xFE\xA0\x9F\xC7\x97{I\xD2\xC6\xAD\xE7qU[\xFC\x91;\x86\xA2,^\x92o=\x93\x0F"\xF1\x9CY\xB0\xA8\xC0h4\x89\x0DO\xFE\xBF_\xC8PH\xD9\x8C\x91\xD1v\x88\xF6h\xC7\xB4R\x92\x9B\xD8\x96\x88D\xC2i9\xAD"\xE9\xD3w\x16\xD4t\xF9\xA6\xAD~\xB9\x06Zi\x0E\x14 m\xC3\x9E\x9FzX6\xB1R\x11\xC8"\xCC\x85Z\xB7H,\xA7gZ\x9C-8\xD1\x1A\xCF\xA0\xC3\xA1e\x03\xAD\xD9^\x96i?\x86\xA6\xB1\x94x\x97\x12\xC3\xE1\x0A3~_\xB7\xA5f6\xBEmU\x80\xB0\x9E2\x185\xFA\x9Av\x17p\xE2\x04|~`!\xC5\xCEB\x98C\xE3\x15\x82\xA9\xDF\x0C_#\x12R\x19\\x092\xA4\x81\x06\x04d*\xCD \x1C\x91\x8F\x87rq\x17\xD8\x937\xD9\xE8\xD1\x84\xFD\xB2\x95\xD9z\xFC\x97xo\x80\xCFe\xB6\xBD\xE2w\x0E\xA9\x03\x13\x8F8\xB5\xA1\xAC\xEF:\xAF\xBE\x1Ctv\x09\xA0!m!%m]\xB6\xB2s\x95C%\xB5\xCE\xC0nv\x86!m\x81 \\xBAz\xE61_\xBC\x0D[\x8E2\xFBJl\xAAhi.\x98v/F\x18\xA1\xB0\xF51A\\xE7\x02\xFEu\x8F\x1D\x0E`|\xCF\xBF_\x9A\xD7\xB4f\x10\x84|\xF6\xEE=\xA3\x050\x81\x85\xBA\x94\xEE\xF0\x8B\xF7\xEA\x0EQyj\xCBo>\xF7b\xF3\x11\x9D_\xBC\xB9a|\xFA\x05cl\xEEQ\xE5\xB5+\x12\x82\x13K\xC4\xA1g\xDF\x1D\xA3\xB6\xBB\xDF\x19\xB4H\xA6\xF6\xD6j\x9DB\xD2\x9D(\xB4R\x11\xC6\x9A\x8F\xB2;\xE8~\xE8\x0E'\xE4Ru\xA9\xDB\xDC\x99\x06\xD4a\xC2\x09\x84\xB6\x91\xAA\xEB\x00\xDC\x1A\x8D\xC7\xB6\xD0\x14\xDF[\xFF\xD7\x1D\xAEW\xA4\xD1\x00\x13;\x85\x1B0\xC7\x18\x08b\xEE\xA7\xED\xA6\xB9\xB8\x12\xD7\x86\x9EG\xBBl3\xAF\xE0\x1C\x169\xFA\x8A:s3K*\xEF\xFC\xF4\xB75\x98'\xFAM\xBB0[M\x1B]*\xAC\xD1`\xC4:\xDF\x1A\xC4\x9C\x0A\xBE\xF9\xFD4s\x7F\x1C\x0D\xA8"\xF6\xF9ZY\x99\xAF\xC9\x1B\x902d\xA8V\xE8\xDFi\xA6a\xF6\x88\x959*\xED\xB3(\x91\xC0\x8E\xB3\x93\x8D]\xCFC\xF1\xDDI\x01x\xBF\x0F\xA1qh\x84y\x7F\xFC\xFD\xA8*Gz\xFDX\xB4\x15s\xCC\x09iI\xC7\x14\xF1\xB6K\xE2\xF7\xDB\xF35\xC6P=\xCE\x80\xE74qx{\x1Am\xC5,\xEC\x0Fr`\x0F\xB8-\xC3\x10u\x00\x17\x7F\x83MZ\xE6\xA4\xD3_3\xB2\x00\x81n\x93\x88\x8F\x0B\xDD\xEE\xEC\xD4\x99\x1C\x90=\x9B\xA5\xDB\x85\x16\xB9\xE1\xAC:\x06\x08V\x92S\xF1\xCE-\xB6\xC65\x89\x92W\xD9U\x879\xE5\x16\xE3\xAF\xDDi;\xD3\x15\x93\x81 \xD0c\xE9r\xE5\x05-\xDC\x90e\xB7\xD8\xB99\xD4\x1C\xBE\xD4IS\xC7|\xDC^\xA3\xA3\xBC\xCF\x0B\x80\x97\xF6\xDB\x1F\x8A\xAA\xCF6\x0B*\x82xw\xFD\xDF\x86\xE0w\xD9\xEA\x80\x1A\x94\xD2\x97HXd8\x19\xAF\xA6\xB5\x04<\x94H|\x9A\xB0\xA7^M\xA4z\xBC\x0Fi7\xCDZG\xDB\xAC\xFC5_\xC7\xF5\xC2&2\x10`\x96\xE1\xE6\xE0\xA9{tB\x9Cd\xB8\x13\x0F\xED\xFE\x18\x98&\x1D1l\xD6S^\xFE\x96\x0C\xC9\x07m\xE0\x1A\xFE7\xBE\xFE\xECT\x92\xA6\xF7!\xF6p\xA5\x88\xA8\x82/45A\x88j&\xE6\xF7w\xCF5\xC8\xC5\xA5\xAEc8\xFBXPA\x97p\x1F.K\xE7\x93%<\xAD\x07\xD9<\xEA\xA3D\xD3\x91\xACg\xB7\x0F\xF1#\xD6b\x7Fw\xB9=t\xC1?\xA7/Y\x81\x99\xB3\xD9\x1C\x9B\xFE\x92\xEFK\x16L\x0E6\xBF\xEF\xFD\xC8GgayE\xD5y\xD6v\xBC\xD6\x92&"f\x8E\x8ED`\xFC\xCE\x18\xB23,\x1C`\xEE\x9E>"t\x9EE&\x89\xB7c\x9E\xB0fL\xBF\xDBK\x80I\xAD\xAE\x13Q\xB1\x8Cl\x09\xADj\x0E\xA3\xA3\xB1\x89g\x08\xC6Iz\xA8\x96\xC3\xF0\xD5Mv\xEE\xF8\xEC\xCD\x81\xCA\x1F\x1E\xEF\x1C?\xEF "cG\x87\xE2\xD8\x0EV\xB6\xD4\x8F\xA5g@d\x1DuW\xD2n\xEE\xC8\x8B\xE6\xC3v\x04lG\x83-D\x0C\xBBP\x11\x02KH7L2od\x9B@\xB33\x1A\xD2v\xDD[\xC5\x85V\xAD\xEF\xDA\xAF\xD0_ph4I\xBD\x17\x9A\xFA\x8A\x9B\xAA\x1C\x1Fg\xF7a\x8F(w\x10O\xEB\xDA\xC6\x9A1\x0Du\xC3\xD2\xB2\xB4\x98\xA1\x83jN\xC5I\x06U\xD6H\x96\x86\xD4xGBR\xBCje\xDF\xAD\xC6\x0A\xDE(\xA2\x85\xA5\xD4\xF0n\xAAc\xF0\x13\x1A\xCE\xEA\x06|\xC9\xF0\xD4\xC3\xA0\xD8\xDA\xEF\x80\xE2\x8D\x12\xBE\x7F\xB7Da\x12#(l\xF7[a\xAFJ\x0Alhq\x9F\xEB\x9Ee4\xBF~\x0A\x02\x9F;+Mq\xEAL5Q\x9F\x8F\x1E\x141_sH3\xCF\xCC\xE0\x94\x94W\xC1\xBFn\xE4K\x8B\xCFJ\xE4J\x19\xCE\xFF\xA5\x12\xE3w\xD0\xF1\xACS_u\xD2\x05\xBE@\x0C\xF3\x10\xD5\xA8bk\xD1M[R8\x8D\xA9\x8D\xB95Q\xE6M\x81*s\xC1N\x84\x89\xAE\x9A\xE2\xC0\xF7\x9B\xF41\xB9]s\xFE\x8C.\xD7\xED\x0E\x14\xB8\x8B\x93\xAC\x10b\xA2\xE9c3\xEFax;o9N\x80N\x12\x87\x8Bp\xC9b\xD7\x1F\xD0\x1CPwCB.\xD8\x01{\x1F\x82\x99 \x972\x13\xB8lVBZ\xD42+#\xE6\xD5(\xDBJ\xD4Vz^^\xE6\\x08\x7F\xE3\xE2R\xC8\xBB\xE1\xBA\xE1\xB6\xFC\xC2s\xDC-\x1ET\xF9\xB5\xA4\x13\xA6\xCF\xEF\xFE\x19{\xBF\x1D\xDF\x82N\x9D\xB9\x8A"\x1B\xD4\x00\xA48\xB1R:[J\x0B\x80"\x87\x84\x1B\x0B\xFE\x12\xEE9G\xCA\xE1\x8F~\xE2\xCF\x0FE!\xB0v^\xA7I\x17\xFE\xE1o\xF4%\x8A\xCB\xD5\xC5\xC1\x86\xAD\xD4\xA5_s;Ii\x87\xD71'\xD2\xAC\x9C~\x02\x8C\x16pP\xF7|\x0B\x8A!9\x14\xD7\xF5\xF5\x1D\xD6\x81O\xF6s\xDD\x13\x88\x95\xCF\xF4\xFB\xF2h\x8F/\x1DhT\xEB\x1DqX!x\xB1\xAF\xA2\xB2\x9E`C\xAF\xA0zJ\x07S\x19\xFC\xEE\x92\xF1\xF63\xB4\x84\x060\xDAN\xBC\xB1b\xBF\xBAJ@\x04\x11\x00wt\xA6!\x9D\xB5\x8BL\xE0\x9E5Z\xDE\xB4&\x07{w\xB3\xDD\xB5TI\x11\x82\x8D\xE4\xD7\x95Vw\x81\x11W6\x15r1\xC1<\xD1\xB9\xCDK\x81\x0Ct$\x92X\xEDO\xA5\x9A&\xEF-\xB6\x0D\x1D\xE9F\xA8Kye\xE4\xED\x12E\x9A\x88\xC8\xD6L\xABq\x8B&\xA9\xE9\x8C\xDC\xADd\xB8n\xC5P\xBE\xB5\xF9\xD3x}\x09\x8F\xAC6\xEE\x1D\xEB\xCE/Q5A\xFA\xBF\x09y\xF3]mU\x05\xDD+\xAB\xB2N?k!i\x174\xACio\xAAi\xC0@\x10t\x1Aj\xA5\xD7\x17!>\xAC\xFB\xC5\xE20l\xD1L\xDB\xFDg\x1A\xDF\x9DN\xD9\x1A5\xA4\xE6\xF0(\x07\x89\x09\xD8\xDB\x96\x19>\xB2\x94\xB0\x08W\xA0\x84\x0Eq\xB4Q\x1Fw\xAB\x83\x12\xD0\xC6\xB2\x09v\xBE\xE1~'\xEE\xA6ZF\\xF7*_\xAC\xCD\xE7V\xE5K.1\xCB\xC6\xCCE\xF1\x99\x05P/\xAB\xFF\xC3\x03\x05\x1A)\x1FW\x178\xBC\xFD\xF3\x10\x9A\x80\xF9\xEC\xBEa\x94\x1E+\x85\xD5\xBB\xE79\xE7\x0A\xBB\xADQ\x9E)$\xA0\xBBV.\xFE\x96\xA3\xC7\xB6o<,\xF0\xB5:nT\xA8\xD7x\x13VB\x15\x93946\xBA\xCE\xB6\xC0\xC1/\xEBD3\x18\x1C\xB5\x1Al0w\xAAA\x81\x92\x96"\x86EW\xA7J\x17\xB1\x9EC\x8BWN\x88W\x8A\xFC\x9E\x19\xF7\xC9\x92\x1A\xCD\xBA\xD5\xC3\x8A\x95\xC0\x8D\xCFFv\xAD\xA8\xD5\x0E\xB2\x1D\x00=bJ\xCB\xE3\xD9\x9B<\x81\xBD\xCD\x89n\xA2\x90Oc\xF4n\xAA\xE6\xA4O\xB0\xDA\xCA>\x1A\xE02\x84\xA6\xFB\x7F\xF3)ZF8-^k\xBE\x8B\xF6\xDA\x15\xE8\x0B\xED\xDF\xED+\xD7\x0F^\xD1\xDD\xC1B!\xB8\x86\xDF\xCE\xE8,\xFEy\x8B\xAF\xB0\xBFlW\xD7\x88*\xD8\x822\x86\xCC\xBEm)L6\xEC\xB0\x1E/e\xA2\xE8zvq\x1B\x16R\x1E\xA3\xCD}n\xFC\xC9 \xA4\xA7\xE2\xAE\xE0'\xF1X\x12\xC9\x80I\xD6qW\xDD\x9A1N/\xC3=\xED\xC3\xEE\x93-\xDF\xA6\xE7\x90-v]\x0E"N\x0FPdQ\x99hz\x8D\xA3\x8B\xD6\xB2\xFBS5{\xF2\xD9\x1D\x10\xAAJ8\xE0S\xA2G|\xEA\x16_\xE3j\xA3\x85\x10\xA4\xA3"\xA6+\x90\xE7\xE4W\x9A\x85y\xF1\xD7g\x15*\xA5B\x82\xBD\x91\xB7\xDE\xA8*9\xBDu\xC7m\x9F\xAFE\xEA\x82\xC2\x84n\xCE\xAC[q\xE8\xF8\xB2\xF9\x1F\xBDf\x1D\xC8j\xF0:aK62-\x09\xDC\x9C\xEE\x83\xDBYl\x94\xAF\xD3\x9A\xBB2\xE4A-\xFAx\x81=\xB0*\xA1\x0C\xCD(+\x98\xB6\xC9\x1E\x04\x9D"\xDB\xC9+\xF5\x16?\x80\xCC\x06eo \x02\x1D*\xA5BA\xA8W\x9E\xF7:R2ZW\xB1\xBD\xCB\x91\xF65m\xF6\x8A\x12\x1A\x9F=\xE2\x87\xBB\x90,}\xC6\xD8\x9C\\xCB\xF9ut=\xA7\xC2\xA7w\xA5\x00P\xB6\xFDA\x87\xF6\x9DY\x0Fm\xD7\x94/\x0D\xDD\xC4\xF5>h~4\x12L\x82\xA0\x9C\xC2\xFBx\x80.\x1D \x90\xE58\x19G\x83\xC8\x03vt\x97\x12@AR\xFE\xF0\x06\x0Ba\xD7bA\xDEE\x1AQ\x8E\x07\x95\x0E\x8F!\xF0\xC6\x96\xB4Q\x9F\xCF\x97\xEF\xF7`\xF0\xD4e\xCA\xD8R\x19 \xA7\xA0\xD5\xD5\x19\xE4\x0A\xA7\xF8\xD7\x14\xE8l\x08\x8D@\xC5\xE4\x00\xC7\xDF]\xD6\xE2p\x0D\x0CF\xC3g\xB3\xD7b\x11\x85\x05J\x19\xC3\x07?a1\xB3y\xFB\xA0N\x82\x05v\xD2`V\xEBf\xF6C^"\x13\xE3\x98hb\x949\xE2\xA7d\xECP\xA9\x8A\xAC\x09\x0E~\x08\xEBKBk\x17\x848\xFE\x80Rs\xF4\xF1j\x11\xB9P}i\x01\x88\x872G\xA5\x01\xC2\x91\xFA\x8D\xBBC\xFCA\x1E\xB00\x96/m\x98\xD7\xB1jU\xCE\x17\xBF\x9D%\x88\x8E\xFA\x17\x8Bm \x94@/\xFF\xB2\x86\xBF\xBF\x0B\x08\xF9\xF6\x92\x08\xABF@%\xE17\x0C\xCA\x82\xAF\xFE"\xB7\xF5R\xDAI\x9D\x9D\xD7\x98\x7F\x0D\xE9d4\x08\xF7^\xD9q\xCD\xBB\x05\xB4O\x80\x1B\x84\x88\x93\xCA\x99\xDD\xF6M\xE6J\x9B\xCC\H$g\x82\xBA\x07U1\xA5\xDC\xC5t\x7F\xB9.C\x9E\xEEu\x98\xEF\xB3zB\x85\xE9\xE0\xB8\xE3v\x9B\xBF\xFB\xEE\xC86\x1E\xF8"<\x1B\xD2\xA1;8QHt\x12\xDA\x1C`[Z\xC5\x04\x91\xD1\x15\xED)\xC2\xE9\xE6\xB2U\x94\x9B>u\x80\xBF\xAB\x85R\x9EoF\xA5\xBC\xB9t\xC2hB1,WH\x16\xEE\x82\xA3\xBB\x90\xFA\xF6}Y\x8Bf4\xDBk\x89\x9CU\x8F"\xEDR\xFEf\xF1\x81\x9C2\x98\x7F\x123\xC1\xA5\xFB8p\xB9\x07\xA4\xCC\x1D\xAC\xA1\xDD\xA6\x9D\xDB\xA4\xE9\x88\x1D\xAFWe\xCB\x0A|\x9C\xCB!\x81\xA1`\x00\xE4\xA0\x1EE\x83\xE3\xE7m@\x87b\x8E\xA7\xD4\x93\x8D\xC6F\xBB\x8BA>\x9D}\x83"j\x13V\x92'\xA5{Q\xA0q\xFAKs\xD0n\x09IU\x0C\xDAM+f\xCE\xFE\x91\x04\xA0\xF4\x8B\xD9;X\xE8\xC9\xF39\xA8\xBB\xF5\xE4\x81^\xC1h(\xA9\\x08\xB9Y\x9F3\xB6\xDC\x07\x0Eh)\x03gy\xFAn>\xCF`(N\xA1O\xFD\x80\xD3\xB8\xD1\xC9\xEBVN\x972$ 5JAi\xB8\xC9K \xB4\x0Fz\x1EB*:\x19'N\xB0\x88y\x1C\xC3\xD0\xC0Vk\xB3J\xAC\x9A\xD0\xE3h\xA6v\xE3\x01\xE9\xAF\x07\x1C\xF0\xBA\xB5\x11\xC3\xF2y\x13$ ,\xE3\x1D6*\xE7\x99|5\x09\xE1b\xE8s\xA2\x18ms~\xE5\xEC\xEF\xF4\x95\x7F\xCE8\xD5\x0AuO\x1Ai\x03\xD7\x1B.\xE1\x9Al.\x9C:\xEDX4h\x0BR\x14\xF8\xBF\x11\xDF-hd_\xFB"]\x9EU\x14\xF1-@\x97\x8F\xCB\x7F\xA2'\xAE\x04\xBB,Wo\xE8\xAC\xEDn\x89\xE1\xC5i\xDC2\xF8\xAFV\x7F\xDD\x88\x1Dpc\x15\xE6\x94\xF1\x17j\x18\xFC\x80R\xAA\xEC\xAC\x8Cp\x9D7 \xCF}\xCD\xB1e~3\x8B\xCD#\xABx\x03~\xF3\xA9\x10\xE2d\x04\x967py\xF3\xE6[\xDD\x96\xD4@\xE3\xE0i\x10G2\x0C]\x1F\x01\x86\xBE\x14Q\xAA\x1E\xAC!\xF0\x1EZ\\x83|B\xC2\x9FU-\xDB\xD9\xC1[\xB1\xED\xC8\xA0!r\x90\x1F\x87\xC1e\x1F:\xE5\x98\xE3\xB3\xB3I\xCAs\xF8sm\x01R\xFA\xC4\xFD\x059\xFE\xA0\xF4\xC8\x10\x08\x84\xBA\xBB\xD9P\x9E\x9AqB\x805\xB5\xB7\xD4\xB0\x05\x85o\xDD`5\x06\x86\xEF\x9A^U\x16\x179\xEC\xAEE+\xBF\xB2l\xA9\xA0\xE1`\x05\xBA\xB7\x0Fv`s\x9D\xE4\x04r\xA8\xC0\xE6\xAC\x14\x90j,\xC9\xD8`G\xFB\xC5\xFB\x99\xEFa29\x83c\x8F {)\x052\x04q#\xF56\x11f\xFF\xDAr\x9E\x1D\x170\x87(D\x0A\xF2\xF7+\xA9\xE5FGC\xBC\xEC\x87\xF5\xD2\xCA\xC0_\xD2\x03\x8C\xCDDF\xFD@\;\x9A\x03R\xD5""kV~EA\x1B.\x8F,f\xB8\x80\x12\$.')\x07\x17\xF3\xCD\x0B\xAC1\x8E\xDD\x92\x04#?\xC8\xF2\xC4\x0E\xD9C\xD3>\xEA0\\xC2\x84\xA2\xA7w\x80A\x8E\xDFG\x9A\xC2\x0CuP\x16\x88\xEB\xB5\xAF\xD6\x1CVM\xAA\xD4\xDB2H\xDB\xFC\xEBL\x98sq\xEC_\xC16\xD0K\x93\xF2,\xB2\x0E\x9C^\xB2\xCF\xA8\xD5\x12)x\xA6+o\x0F\xCB\xF3)\xD9n\x8A\x0D.\xECHLM_F\xEE`\xD6/e\x10\x7F\xCF\x94\xE1\xD1\x13C\xE1\x00zV\x8A\xD7P2vo\xF1\x07\x01\x1E\x9A\x0A\x80\x12\xD9\xEB\xA7\x16\xA6u}w\xF5\x959\xE2\xD6@\xDC,\x82^\x1Bg\x93\xF7\x1C\x8C|\x90\x0B\xBE\xE5*m"\x94\x84+\x7F\xEE\xFF\x86\x1A\x8D\xA0\xA0\x99\xAE\xBDO\xFF\x17~\xA3\x7F\xB2\xFEc\xA5\xDC\xA2\x00}\xBCIB\xE39&B\xD4!Ph\x10gw\x9D\x07YE+\x18+\xCC[l)\xB2\xDDjj\xE2\xA1K\x18\x82\xFE\xA8\xE6\xF5\xE9\xFF\xC9OX\x9C\x15\x08\xFF\xB3\xF9\x1B\xFF\x81?\xCE\x97\xCA"4\x921>ZK\xB8!i24\x90\xEC\xFD\x18K\xA3lw\xA9\xE2\x93M\xCD\xB0\xE5u\x98r\xE0d`\xACm\x96\x88m\x81n\x84\xDDc(\x9F\xA4\x96a\xE1H\xBCfDXG\x9B\x8C\x9E\x17\xF3\xDE_\x91"8\x9D\xEE\x81}\x08\xEA\x9C\x9E\xAC)\xE7\x1C\x13he\x9B.#\xE1OO\xC7\xF3\xDC%r\x93\x9C\x1D*E\x14"\x17\x84\xD7<+w\x025\x8F"6\xB8,\xA0\xDD\xD8x\xEE\xF5'`\xDF\xDCwb\xAB\xC3\xCCk\x12\xF1}\xD7\x0CR\xEEPU\xF7\xD8Y\x9A\xBE_\x16\x07\xDFX\x85o\xA4\xB0\xC0\x0E\x9B\xD0\xFF\xCE'pEb\xE0\xF9\xCB\xF80\x8F\x8BT\xF8@\x9A\xB0\xAAqf\x1A,\x93.\xAA\x90*\x98\xB5\x9Ea^\x85\x00\xC5\xD0\xA5\x88\x13hK\xB6\xECYE2n3\xE5\x95\xD2\x8F\xE6#\xD6\x97*0^@\x84^\x0CeJk\xAB\xE1\xA2\xA2\xFB\xE88\xAD\x0Bpc\x09\x9DA\xD3=T\x84&y\xC0-\xA7\xBF\xBF\xE5\xEF\xC8\xEC\xAF\xFE\xE7\x1E\xEAM|d\xA9\xD3\xE2\x14\xED\xCB\x93\xF7\x8A\xFE\x05\xB6\x0F\x8B\xB5w\xD8\x9A\xBC\xA3\xDF4\xBB\xB3I\x8C\xD9\xBE4\xE2w\xA0\xB0\xC9\xA6Q\xB2\xE6\x1B\x18d\x9Aq5b\x05\xB3.\xCE\xB5j\x83*\x83\x8D\xD1E\xD6\x08\xE7\xB7\x96\x89\x10\x97\xA0N8\xED\xFF\x9F[\xB2v\xAC\xAE,\xD5"\xFC\xBF\x1AQQ6\x11\x87p\x85\x00!X\x03\x14\xBC\xE2\x19\xC7\xB4\x88&\x1FS\x04\xF6j\x05M\xF0\x04\x06\x01[\x9B\xBB\xDDzed?1\xBC4p\x0A\x1E\xAD \xF8\xA4\xB4xh\xC1\x1C,\x86\xEAm\xCBc\xF16\xDFW\xCC8K\x84\x03\xD6\x0B\xB2\x8C5\xF3\xCC\xBA\x0E\x0E\xF3\x8A\xB0\xF0M|\x16\x87h\xE8\xFBD\x10s\xDF\x7F\x92\xD6\x1A\x93i\xCD\x01-2\xE8|c }$\xD7\x0B\x06\x0D\xD8\x0C\xB8\x0F\xF6n\xD4h\x95\x87C\xFF)\xE4_\xFA\x19\xDF\xD6\xFE\xBD\xF1\xADE\xEA\x1B\x81I\x8FX\xA2\xB4q\xCD\x9E\x09\xE9\x84F\x94I\xD6A\xEB\xE8\xB9\xC31TW\x1BZ\xA8\xF7\xAB1\xD0\xE8\x15k\x7F\x0A\x9B\x92\xC8\xE0\x17\xBC\x91V\xE0\xFF\x1F\x13L\xC9B\xA1\x18`z\xE3\x84\x94~\xE9\xD4\xC3\x85\xF9\x06\x8C\xC4\x7FN\x18,\xA8%\x11\xE6\xBB\x08P\x19.~\x17?E-\xE9M\xC6\xF5\xA2&\x14V\xE4;\xE9\xF4@>z\x8E\xBB\xBC?E\xA8r\x91g\xD2\x18a\xC8"\xBD\x95\xBCs\xED\xEA\x92lT\xEF\xF4`\x0C\x8642\xCD\xD5\x0Du\x08>\x7FS\xFD\xE8s\xF2\x14\xE4\xF9\x90\x1A\x13\x96i\xB9\xB1aP\xD4\xA5\xFAg\xB2\xC78\x9F\xE1W>B\xB7\x1A\xB1\x99\xF7\xBB\xF9\xC2\xD7\xC6\x8E\xD7)x\|H\xC5g\x9D\xA5l{\x0D\xD3\xB4\xA2\xD9Yr\xEA\xA4G\x0E74\xC1\x897yO\x12\xCA\xC3x<\xCA\x1Dl\xE9\xDF\x18\xE5\xB2\xF6\xCA\xD5x\xB0\xC5\xB0\x13\xB8 \xDB|\x86\x93\xBA\x8B\x17\xF1n\x93\xE7\xF4\xE6\xA8 \x04E\xF6\xC2z\x87t$\xFAL,\xEB]|\xDE\x8A\xBF\x12>yY'i\x13(\x9E\xF1z]\x8Cx\x83\xACgq\xD8\xEF\xE39C]\xEE\x11\xA10\xE4\x9B-\xE1\xFE\x04,}\x8E\xF8j\x03\xD5\xCEq\xB4s\xDC\xAC.\xC7\xF5\xDD\xFB\x03\xCD\x9E\xB2G\x9A\x1EKn\xB4\x90u\x9CZ\xDA\x11\x06B\x81\xC2\x95=\xF8\xE2w\xBB\x88\x7F\x1B@}\xE0\x8A\xDFk\xD7E\x9C\xBF\\xD0\x06\x18\x909\xF8<;\xE7\x1B\xC1\xD3\xCB:{\xCA\xEE\x92l\x94E\xEE\xC9\xEE\x00\x05\x0Cf?\xB4\xFFht\xDC%\x8E*j\a\xC1\xCF\xFD\x7FU\xE0\x19\x90\xBF\x8EF\xE2\x16\x17\x1Dd\xED\xEA\\x81\xFB\x0E\xB3\x09\x96\x84\x1C\x85z\xA3\*\xB2a1@\x18'\x1F\x8A\x90\xC7\xEE\xB3x\x7F+\x0FVQ{47\x14\x04)\x0D"[\x83\xCD\xE3)\xB6z\x98\\x04g`\xD3vh\xF4x}\xC2\x14\xD4\x1AK\xCB\xA9<\xDB\x1B\xBA=\xE4F\xD5~\xA4\xE9\xCE\x91\xEFn\x16M}\x02+\x87\xCA\x1F\x9C^8\x8A\xF8\xF3?^p\x9E\xE6\xDCfmI\x17\x83\xDF\x07{Ac\x91\x91\x9E\x0C`&\xA7\xD2\xBA)I,\x02\xD8\x91\x95\x95\x02Wu\x91\xF2\xCE\x8D\xF0\xCD\xDF\xFB\xDB\xE2>\x92\xFD\xE6\xBF\xA7\xD1\x0B\xC668I\x98m\xE7O!\xEB\xAF\xB0\xB4\xE8\xC4i\x1Av)p\xC24\xF5\x9F%\x9F\xD4&&\x95(g\xED=B\xAE\xFC\x0A+d\x08Bn$\xFA\xC7I\xB1W,{E\x15\x13\x1A\xE5B\xF4\x01\xDC\xFC\x9F\xFC-\xD7u\xE2\x9F1\xD6\x91-8\xD4\xEF\xEE\xC2g\xEF\xF1x\x9A\xF5/9bf\x06\xB2\x9C\xE6\xB7\xC2k\x0E,r\x823\x82\x9D\x92vjK\xEE\x9AH\x93L(\xE3\xD1\x14\xF0S\x99\xF5\xE9\xB6?}\xB4\x0E1\x1C\xD2i\xDE\x02h\xC3I\xE7\xBA\x1B\xC6\xE6\x09T\xB3\x8E\x8B\xAC{\xDE\x17\xED\xA1Fv\x10\x95}\x0E\x0E\xDD\xC5 \xBE%\xB8G\x8Aj\xF7C\xD1\xA1\xD4\x8B\xB0\xA6&RF\xDD3\xEAd\x84m#(\xEC]\x8F\xF7\x85\x8F\xB5\xB6\x19\xEA\xA9\xB4\xBD\x09z\x06g\xC9\xA3\xDC\x13\xB9\xDAi\xAF\xCC<\xB9\xF7\xBC\xCD\xB2\x12bB+\x00\x88\xB0\x10\xD6U\xFC%[d\xCC\x8Ee\xED\x88hER'\x12^S\xB62/\xA6\x91\xB9lG(\x02\x879\x15\xC1\xE9\xDF\xC1e\xD0\xDB*\x12\xDE\\xA3\xF8\xAE\x9C]\x8C\xE9iRk\x817T^\xE9?\xB6x\x7F\x92M\x8Dh\xC2\x0E\x8E\xA1\xD5\x89\x99.\xED\x13\x18 aH\x18\xA9\xF6\xE0\xA4y\x9D=\xB0\x1B8T\xA9\xF5\xF2\xA43g\xF5\x0C\x8A\x89\xA7c+T\x11,\xDB\x8E\x8A\xD5\x18\x91\x9D\x84oM\x8B5\x90\xE9\x82\xDF\x16_\x0D\xCA#\xA4\x1Ez\xA4\x13N5xS\xED\xF3Q\xA4z\x97\xD4\xDE|6\xA0\xF0Tn\xA5\x82!'\xC7k\xD0S\xC7^k(fhn\xFF\x96ZH\xA4\xCAt7C\xC6K~@\x97A\xD2\xD9a\x91Br-\xF0\xBE7Z\x9FU}\xC4gx\xC7\xD1\xADu-\xE4\x0D\xDE4}*\xD0\xC4\xD6\x07\xD8\xAE\x16\xD8?\xF7\xE41\xF2RSq|\xF2\x9Fj\x87\x16\x82\xB1|\xB0p\xC4\xD0\xE7\x0D\x0Fd4\xE9\xBE0\xE8\x18\xACUd;!\x82\xE5\\xD2d\x95\x92EQy\xFD\xA2\xC0\x05(lK\x80\x12\xE5\xA2\xD8\x97g\x84\xC6\xF5\x00\x8CY\x8BI6\x13\xDDW/\x87\x0Eg\x0C\x01\x92\xD2(5*\xE3bD;\x95\xE0Kq\xD9\x8BL\xB7\xF5\xCC\xEBf\x821e\x0E\xCD\x0C~\xCC*\xB7\xC3\x92pR\x00R\x9B\xF8\x1Do\x9C{\xFE\x9FNA\xC08\x16\xF1"\x92\xAB\xC1G\xA8K\x82D\x8A\xBC\x93Yt?\xA5XW\x0B\xD6\x19|6\xFF\xB4\x10$}-\x8B\xC2\x9D{\xCD\xFD\x9B\x89\x17\x91[6\x19$\xFD`\xF9\xBC<\xE4\xC11\xF7\xEBW\xFE\x10\x04\xE9\x07\x93\xE3in.fp\xBA\x95\xDEF\x92\x80\xC5\xBCT\xF3\xF8n\x94w~\xAB\x93\x06i\xF0%m\xDBM\x10\x11\xF5\xBE\xAA\x85\xC9\xD3CX`\xF7\x8F\xC1\xF8\xD8Y\xDDG\xF9k\xA7\xB5Ra0\x0C\x8C\xA7\xB6\xF7yt\xB7\xB97+\x8F{\x8C\xE8\xA6\x0A\xA9-\x13\xE9\xF0\xFA\x09\xF6\xEF^\xCBL}\xAA\xBDs\xBA\x12km$\xE2\x1CL\xE99p\xCAu\xEB\x8B=\x13M\xA2D\xF5ph\xB2J\xB7w\xB9\xAA\xCC[\xE0\xD4\xD6\xDB#7\xA98\x0C\x05K\xE0\xF6\x8B\x92)<-\xB0\x9D\xCB\xE2\x06\xCC\xAC\x1D\xB8\x0D\xA7\x16\x85\x8F\xB9\x0E-\xA9W\xD579\x1C\x9D\xA2\xE7\xB3\x96F\xFB\xAF\xC6\xA3\x91\xD4\xB0\xBF\xCE\x1A&\x8B.t\x8BP\x96\x08\x16\x04\xDD\x16\xB2\xA0\xA2\xE3x>N\xAB\xA3\x0D\x0A$\xB04\xB8\xC9\x8F[\x10\xB4f\xA3\xE4\xB4\x04\x03\xE4\xFCC\x8Fn\xC6\xB6%\xAE\x8D\xF9uY\xFAP\xEA\xF6\x89s\xB1\xAE\xA7wV 7\xD4&W\xAC!\xC1}f][\xA9\x9C\xF9\x00I\x88\x0E\x02\x13\xB0\xE7\xE9\xC4\xB4\x9Cz\x97\x80\x06\xBA\xDA\xE6\x111\xFB\xD7g\xC5\xAE=\xE3\x0A\xAD'\x04\xE6\xDD\x09:_8SF\xEB\xFB\xDB\x91c\xCD\xF9\xAE\xDC`\x04>\x01\x1FeU\x9B\xF6\x1A\xF3\x1B\xFD\xC3i\xF5I\x85\xA5\xBB\x1DZ\x9Bh\x14\x1C\xFC%\xF4\xCC6h [\xCEd[\xB7C\xBA\x9B\xBD\xB7Y\xE2'\xAE\x1C\xFB8F\xE3C\xB3\xEF\xCD\x1B\xF6\xBF\xA9_G\x85A\x8C\xB8|\xF1\xEF\xE5\x19\xAA\x00\x86i\xDB1\xD8{\x1C;\xA1\x11\xDC\x1C=\x81&(\xCE\x85#\x82\xCC\xC1+DlC\xE0N8\xCF\x1B\xB5\xFC\xDE\xB2\xE7\xB3*\xAF\x17\x04B$\x7FO\xED*\x81l\xD2KOO\xC2@i\xCDi\x9B%\xB0\xBD\x9F?J\xAD\xAC\xE5g\x96\x89-\xE7\xAA\xC4\x93/+\xFA[{\xAF0I\xDB\xC9\x98\xC6\xB3\xA0Q\xFF\x7F\xC4\xE3\xC7\xBD\xD8\xC3\x10\xF8D0\xD9\x95\x1D\xA9\x9F\x9CV\x07\xA6\x0C\xE4c9\x0D\x97\xBBF\xFB. 7\x8B:\xA3\x1CG\x15+\xFA>\xDD\xDA\xF5\x9E\xDD\xF0\xE4EJ\x06\xA3\x13\xBD\x87o\x97\xC2\xB4\xE7\x07.\xA6O\xF0\xB0\xB2\x0B\xFF\x96\x0D;d\xED\xDF_U%)\xFDP\x0A\xE1\x10\xE9e|\xBC\xBFm\xE5\x00<\xD6\x12\xEE|\x85\xD1\xA5\x9Fri\xACi\x01c\xE5Q\xBA\xA3y\xD4\xFE\xFF\x1B\xC8\xD0\xAFG\xDD@\xED6\x84\xDB\x00\xA72E+\xD3\x05\x8E\xA5\xAE\xA2\x09?-\xEC\x91[K_\xFEn\xADR/R\xCA\xE0\xB9D\xEB\xCA\xD9\xB0\x83\xC7\xDE\xB2\x90\xB2 \xC5\xC66\x11ga\xC7\x85\x19pp(\xA9\x83\x0B\xFBp\xB2\xCA\xCAbN\x80\xD1t\xA6(\xA5\xC1IN\xC4Z\xF1\xA1D7\x17D\x18\xCB\xA6\xFE\x8F\x15\x16\xDA\x8D:./\xC8\x87|\x1B\xB4^\xBD\xF2!\xA4\x04"\x15\x9D-1Hp\x05\x0AI=y\xEF\xB5~z\x8CJ\xEC%\xBB\xA7\x876\x96\x00\x84\x02\xF9\xB7\xFE\x83\x9C\xE2>\xED\x8C\xDE\xD6\x94\x85y\xAD\xBD\xA2\xD3\x0EcQU-\xB9\xA9\x8E-\xD9\xEBoha\xC2\x154\x12\xCF\xEF\xECG(\xDF\xB1=da\xE2\xCEf\xF5\x9A\xD2=\xDC\xD7\xEAL\xB0\x12/\x9D\xB1a\xF9\x08x7g\xF0C\x93\x0B\xD2|\xA0\xF1\x19\x13\xBF\x1D\x00\xE5FT\xC8\xEFr\xC4\x8A|\x02\x9A28\x06\x9D:\xBCt\xFC\xDA\x0A\xCC\x04(\xDC\x82\x86\\x10\x82k)\xE4\xCBZO\xEB\xDE`[\x1EF\xDA\xB1\x15\xF9\x1E\xFBB\xB8-\x8B\x05\x1A%\x1F\xFAn4\xA9n"\xF0\x0E7\xEC\xEA\x91m\xF6\xFBOJqk(\xE8\xA44\xA2\xA2@\xB9\xA5\x8A\xD0~}\xE2\xEB\xBD\xBD\x0B}\xEC\xCE~\xDD\xDB2\xE1%[\x05]\x8A\x07(\xD6\xB7w\xB8)d\x8C\xEE\x16\xCBh_6\xED\xC6\x1D\xD2C\xAC\x00\xE4\xB3\xC7;\x95;\xA1\xB5\xC9\xA7bG\x9Br\x97|1tM\xD0mV~\xB5\x02I4\x8F\x0D\xE1\xC7*\x11\x18=\x98e\xF2\xE5\xA7\xD8\\x9A\x9D\xA4\x1C\x1Bb@\xC8\xBE\xD9I\xED\x99\xC1\xE6\xA1*\x9E\xCF\xC0\x8AK\xFD\xD1\xE2\x99\xF3\xF8\xB7\xBA\xB5\x8F%G=//\x8F\xFC\x1A\xEA<\x9D\xAA[\x9C\x8A\xFFh\x1Ad\xB2\xBER\x86\xF2\x04qnw\x06\xDE\xCE\x92J\xE8\xCA\x09\xD7_\xEE\xA2\xFEOb\x93F\xB1e\x8FH\x96\xD5S\xC1\xA4\xDB\xA5r\xBA\xEBU\xCD\x9A\x82\x9BB#\x1AA\x85\xE0\x12\x91\xEF\x0B\xFC\x19\x02@\xD5G\xA0\xE9\x81\xB9\xB4\x9A\xB8\xF8\xAA\xF0O\xC5E\x87\x1E\xF0:"\xBB\xDB\x8CT>\xDF+\x8F&}\xD7\xDC\x82g(\xAD\xBE\xC3\xD0\x00o\x1A\x16\xF1\xC6\xCCJ\xD2-gU\x12n\x0D\x16\xB3N\x98;\x9Ew\xE4\x14\xEE\x1A\x0B\xBF\xC3\x8D\xD4V\x98\xC1\xE5o\x83\xCC\xDD\x17\xBE\x17\x12\xA3\xA4\x9FCA&.\x04\xAA\x1Co\\x9A0SS\x1C\xCDa\xD7m\x95\x8E\xBA\x97\xCE\xC4\xB0\x85 \x0E-\xD5\x8E\xF5\x94\xEB\x8D\xA5ag\x94\x17\x14w2A\xD5\x19\xB3\xF2\xCC8 J\xF2\xB0\xDE$\xECo\xE1K\xAE\x09\x08\xEB\xE5\x17\xFA\xFE\x17\xB8\xB56~'\xD8\x00O\xAE\x1F"M\xCE\xD7Hy\xDE"+X\xFC\x80\xA3\x0E\xAAP}TX4x\x8A\xDA\xD0\x0D8\xB7\xD9\xAA\xDA#\x01\xF0\xB0SI\xDAV\xEB\xF0'\xA1\x12\x8D]%\xCC&\xE8\xBC\xB35\x85\xF7\xC7\\xAA\xD7\xC3B\x9B\x19\xDC\x0B\x7F\xD6b{3.\xE1\xFFU\xEAq/g1\xE6Prik\xAD\xE2\x0D\xD8s\xC6\x03 \xF2\x07\x12+5)\xB1\x0Df)\x02\xE5\xEBB\xB3w\x9F\xD0i\xF0\x18J?\xB5|x!\x9AR9w\xA0\x1B\xE7\xB8n:\xA4\x17Gv\xBB\xC5\xB1\xB4\xC7\xD1\xD9\xAB\x9B\xAF?\xC9q\xFA\xF6;\x0C*\xEA\xDD\xF7\xD1n\xC7%b\x8E\x1A6\x824\x0Cn\x83\xAF?\x91\x82K4\xDA:~5\xBCJO\xB4\xC3\xF5"\x18\xA5Y\x18Q.\x91z\x96\xF9\xAA\xF0\xFEt%\xF5\xD48\xD2C\xB0\x1C](2\xD9\xE3Afw9R\xAF\xB2\x0Bq\xE8\xBE\xE3\x1A\xB72B\x93\x12\xAE(z\x9E\xEC\xE0\xE1\xA80\xB3\xDC\x18r\xD2+\x02\xD5h~o\x11\xA3M\x0F\x10\x11UH\xB3(\xE6\x86k\xC4\.\xA8\xC29;/`\xA0EV\xA8\xBD\xF0Q\x80a\xCAqs\x09 K7}WO\xE2\x0C\x8B\x0EQh\xF9\xFC\xFD*\x9A\xDB+\xF1\x99\xB7Q\x19\xCB\xED*wX\x14<\xC7\xC4P\xF1\x8C\xB8a2\x87\xC5q\xF7\xF6\xD5j\xEB?\x8AQ\x9E \xFAv\xA5Y\xE1\xC4\xED\xDFP*T^|\xCF\xEE\xF3\x82`\x14d\xCD#\xF3\xE0\x80Hw\xFB\xE5\x03s\xFC\xD1\x80\x02:\xB4rCf\x13\xC6\xD2\xEF\x1C\xAA\x08\xB2\x90\x81\x82.\xAFq\xF1j\x19<\x08i\x19\x0B\xFD9\x8C9\x8CL{D\xD1\xE5\xA2[\x941J\xAE\x0B\xB0\x01o\xBC\x19lAW\x0C\xA5C\x8C\xB8\xA7\xC3Vs\x1A\xFA\xD7\xAD\xA2; p#\xD1?\x97\x04\x9B\xB3\xF9\xB8\x0B\x007y\xBCwu\x8BM\xEE.\xA5\xBCv\xC6r\x9C\x1DmE\xE0\x83\xCD`\x1F\xAD\xA3\x17w\x90\x90\xDCG\xE6\x0A?\xCA\x05u\x18av\xB9=\xF6\x83O\x0C\x18=\xF0\xB9\xE3\x18dG\x82O\xD7\xA87\xD0\x0CY\x05\xD6\xAC\x99ZJ;\xFCV\xD6\x00,p\x03\xC9f.+s\x04\x93\x05"k9\x85\xE2\xAF\xB6&&^\x0C?\xB7Y\x80\xE9\x00\xCB!\xE5\xEED\x08\xB9\x95\x80'\x97b`\x19f\xC3\x81\xD8\xEE\xFCw\xF9M\x8C\xDE\x0F\x8F\xB3\xC2[@F~\xA6J8\xEA\xA8UY`\x9E\xDB\xB9\xBC\x92\x8E\xAF\xE4'0\x85 \xC7\xD8+\x0F\xC2\x12Y\x0F\xD5\xA5\xB7\xEF$\x9E\xA1\x98\xC7L\x0E\x90]\x8C\xBC;\xEE\x8C\xB4\x12\x95\xBCV\x1D\x8FQ\x19\xED\xF84\xEA\xEB&\x18B`0\xB9e\3k8\x9BK3\\xB2\xA0\x14\x1B-3\x91\x95\xB7\x9F\xDF\xE1\xB8\xE2\xCD7\xF88!\x0B\xF57AYX3\x09m\x93g\x0E[.'>\xE8|K\xFE\x09\x87\xAC\xEC\xEDqJtVH\xCA\xFB\xCD5\x9F\xA9%@\xF5\xF1\xEA\x8E\xD5\xE0\xC4lY\xC4\xA5\xE7}\xE2\x88\x00\xA5\x84\xF7a\xEC\x02\xDE\xE7kC\x97\x8Df0<\xDFKZe$\xFB(\xA7`\x8C\xA9\xB4}q\xF9N\xE3\xDAiS\x93\xDA\xC3\x9FOK\xB9\xF7\xCDc\x97\xEF\x92\xBD\x80v\xF3\xABM\x0A\xAF\x84n\x01\xF2\x14 \xA8\xC8x\x17\xF1U\xF1\xF3\x1B\xF1\xCC\xE7\x8D\xA9\x0A\x9Cy\xCB\xE2\xD0g\x1Bf\x94\x0D49E\xEC\x19o\xB0\xB5\x9CH,\x83\xBB[\x90\xA3\xB3\xF6\xAE59\xC5o\x8F\x8F\x14\xA4\x1E\xC3\x9E\xF2\xAF~e\xE9Zo\xFFV\xA9\x1D\xCA\xF76\x1C(\xA0\xFFm\xAA\x03Dy\xDC\xB2\x8E\xF9j\xF9\x05\x92\x1E\x0C@P\xEC\x085\x90\xAE\x03T`\x99#\xBF\x93\xECk\xABk\xB0k\xF4\xCA\xF0\xB3:\xB5\x0B\xBF\xBE6n\xF0\xA5!\x0Af\xFF\xBFN\xD8zL%\xB3:\x7F{U+\xEE\x91\x00\x95o\x02\xF6w\x85\xC8\x869\xE1Ri\xB9\x9AW\x1D\xE5c\xAC6\xFE\x1D\xB6\xD3\xAE\x03\xA8A\xCE\xABC\x03\x0D\x11\x0A?r\xC0\x0D\xC0\x9D\xC6Z\xEC\x9F\x1A\x9C\xB9A\x84.P\x81\xE1\xC36_\x87\x1A\xC63J\xA0J\x11\x01J\xA3\xE9\x12\x87\xF6\xD2W\xC9\xF3\xD9\x1F\xF5>\x05h\xB3\x1D\x9D\xD8\x8B\xE2\xAAx:X \x0C\xA9\xF8\x1B\xB3v\x0F\x0C7\x83\xDC\xC2\x96\x90{>\x83q\xB0\xC8\\x99)N\x87L`\xDCRQo;\xF8o\x8C\xE2\xF8\xD3\x0C\xA3er\x02G\x89I\x91\x011\xA8\xB2<\xED\x85B6F{H\x87\xA6\xC1\x93Er\xE8\xC6\x01/`n\xAE\xFD\x91\xD6\x07e\x0C\xD9J\x9A\x82\xB1\xC3{\x17\xC4\xFB\xE6,\xCC8R\x94\x03\x193P\xA4C\xAD8\xBA\x19\xF3\x96k\xC1{\x09\xCA\xF6\xF9\xBA\63\x96\xFF\xB7\x86\xD9\xFE\xA7\x8Bs\x0F>\xE3<\xA7\x88\xAE\x14\xAC\xFE\xD4\xFB\xF7\x93\xA4\xAF1\xDD~\x0B&\xE8]\x02\xB9\xE1\xA5\xCBW\x8E\xBD\xA2\x9E\x19\x13\x0CS\x94\xC3\xC9\xB1\xB7i\x0FS\xE4N+\xACg\x085\xC5\xBB\xE8\x1F\xA9\x07c\xB14\x10\x18\x86\xA9k\x9A\xAF\xB2\xE9"\xBAn\xC2\xCA\xF2~\xCC\xE0s0xo?\xB6G\x84\xD2\xFDZbCT\xB5\x95g\xBE\x1D\xF9\x1D\xD2\xB7g\x057r*\xE9\x1A\x1CCo\x84\x9F\x95\xDA\xB6\x0A\x16Z\xD5\x09,\x1C\\xF1v]~a\x93GB\xD6\x91\x14\x99r\xAD\xB6\xED\xE8\xBC\x0D\xC3\xA3\xB4\xB4J\xB0k\x83\xC5i\x0B\xAAS\xA6\x82\xBFF\xAA\xB7sA\xD7\x7F\xAFub <\xF87o>\xFC\x02\xE3I\x09\x8Al\xE8\xC6\xA0\x0D\x91\xEB^\x8E\x8C\x1E\xDB\x89Q\x03-H\xB2Ej^\xF8>&D\xED>^\x00W\xF8L\xCA\xE0\xFF\xDEU\xED \xC5d\x16a\xC7\xF4\x85\x01\xE3\xDC\x9D\x8D\xD6\xD9B\x1E\xCE\xE5\x95\xBD\xFF\xD5_\xF4\x05\xA2\xDAx\xA6=\x8F\xB3\x7F\xA2\x81\xC3\xE5>\x93\x1B\xBF\x9EY\xD8j\x88)%\x0A\xBC\xA2_\x80 *'\xF6q{>\xB5D\xC8\x8E\xDEW\x9D}\xA2E\xAFd\xA8y\xB2\xD3\xC5a*8[\x0B\x17\xCF\xC2n\xFC-\xDF7)\xC1\xB2\x8Cp.ie\xE3\xCD\x0B\xEDp\xA1\x19l\x8E\xD1!\xEAb\x0F\xDF\xFB\xEB\xFD\xE7\x8F\xB9\x96\x1D\xED\xE7Tx\x7F"%\xBDk\x19t\x8E(\xF6\xCDc\x9A\xBDG\xA5$1\xB5\x96\x18\x82\x9BS\x1B\x8Bg\x93{O\xB1\xE9\xC5,\x98\xBCh\xB36\xC2\xAE\xF6\x98\xC0\x97\x00PCO\x95\x0A\xFD\x00\x00\xA2\xC0D~\x9Abu\xC2t]\x11\xDE\xC1\x0C\b]F\xAA\xE7\xE34\xCFf),\x0AnA\xEDF\x14\xCBen\xEA\x99w\x19\x0D\x9B\x95y\xFCn\xE4\x8Cj7\xAE\xF9\xCCEC6\xDB\xB6\xCD\xCCzb\xD9\xB2\x95\x17*+5\xC7\xE3n;\x0CHq\xF0\x80*Kv\x93}\xD0\x94\x89n\xB3\x90\xFCc\xCA\xEA\xC9Ph\xEAH\xE9\xA2\x8B\xF7\x07\x81\xC4\x0F7\x93in\xE4E\x9BH5\xCB\xE2.\x8C\xE2\x02\xA5\x19\xA8 \xA5\xD6\xA4\xF3e\xC8\x8Au\xF3\x8E\x06 \xD0\xD9\xC9\x09\xBF\xF4\xD01\xAFo\xC8\xFF\xE6\xE6 k\x7F\xB8\xA6=z\x08\x13y:\x9A#\xBA\xF67\xFDz\xDE\x94\x93\xF1\x93)\xB4\xEE$\x0D\x19<\x171\x0B\xDD\xFD\xE9!\xF9\x9F\x14\xEC\xB3\xD5S\xF0\xEB2q\x04\x87\xAF\x82e\xDE\x1B\x9B]i\x88p\xD9q]G\xD7\xB8\xB4\x07\x87C\xC1\x80a\xA7\x0B\x91\x16\x14L\xC2\x80O\x1A\xCCn\xEA\x1DZ\x91\xD9\xC2\xCB\x85}\x06\xC33\xC5\xDF{%6^@\x09i\xF1(\x9Bb\xDB\x06\xD2\x96\xDB\x90>\xE3qn\xF0`9|\x1Bs\x94\\x97\x0D\xDC\xB1z\xDBK\x1BFYc\xD2\xEC|\xECx&}\x12`\x0E\x9B\x86%\xF1\xA5\wY\x0E?\x1E*\x95\xAD\x96\xDBm/d\xE6\x90\x80\xD8n\x00\x81\x8B\xB4\x19\xC4@\xB3\x8E\xDD\xB0"\xDF\x1A\xC7\xF1\pf\xB2\x09x\xA9\x9D\xC4\x06\xFFrv+\xDF\xF5\x12\x0D\x95e>YJw\xB8\x8D\x14\xD6\xAEj\x16\xBE\xE9H\xBA/\xE5\x08\x9C!\xCA\x9E\xB7\xE8\x82\x8C\xB7hg\xF9I;\xD5\x1C\xCD]n\xBEe\x86X\xC5MI\xC0\x17h\x0D\xD8I\x83a\xFF\x1D\xE8\xD5\xBA\x8DD\xF7\xF0#\x07\xFA%\xBF\x0A\x94\xB8.Y\x9A\xEA\xA7?@x\xE5\xF9\x16\xE9\xCF\x97\xE4Cyo\x16F^o\x99\x9BZ\xEC\xE1\xD9\xD4~\x10\xA3\xAF!Y\xF0\x11e\x9B\x18\xECw\x98sP\x86:S\xFE\xF7\xA7\xDD\xF2+\xC8\xC4\xE3\xC6\x80\xC2U\xB7\xA2\xAB\xA6\x9E,!\x0A\xAA\x93\x0A\x1B{T\x0F%P`\xAB\xCC\x8DP|\x80\x8D\xA2\xDB\xF7\xCB\xE6?\x1C\xBD\xF5\x93\x8E\xDA\x8AK\x19J\xB4\x84\x95\x0F:y\xCE\xBB\xB0\xD9W\x85\x11\xDC\x02\xEB\xF0\x83B#\xC8\xA1l\x0CG\x8Ds\xD9 k\xCD\xBC\x9B\xCE0g\x04\xC7kUB~\xE5\xB1\xA0\xCF\xB9\x13\xB8\xD3fAU\x06f\x1D\xD4\xE9x\xB7\x18s6\xB2=~\xF7[.\x8BC\xFF\xD4\xAF\x13\xECat\xA7\x93N\xC7v\x12\xD4\x08\x95|@>Q\x17\x95\xD6i\x1F\xB8W\xA8\xC2\xE3\x11A\x12\xB1\xCCQ\xE8\x9A\x8E\x13\x08&\xD4{\xF4C\x09csv#\xCA\xE0\xBBB\xFFZ\x0D\xC97\x8D\xDA\x8Ar\x0E\x1A/a]\xDB\x1E\x09\x84\xBA\x96\xF3\x81\x96\xF5\xA1@\xC4\x97>O\xEAN\x96IU\x13I\xBD=\xC7\x88\xDB6\xAE\xDCz\xD3d\xD7\x04Z\xF4M,GD\x03\xE17T P\xEC O\x9A7\x13\xBA&\x14.Z\x99\x91N\xAD\xAF\x12\x11\x92\xF6\xB5\xADn\xA6[?\xA1g{Iv1Q$N\x13\xC1B\x18\x02\xCD\xACb\x00\x91\x07\x93\xC0h\\x8F\xC8pK/\x1F\x17\xD6x\xE6\xB3\xDDX\xA07\xFD>\xEE\xE5\xFE%O\xDC\xB4=R\x8D\x0D\xA4.\xE3\x18\xEA\x91\x19\x82\xDCK\xEA\xEA\xE7\xE6$sv\xF7*\xD0\xCADCSX\x07\x91\xCA/\xDAb\xA2\xC5\xED\xA0\x95\x02\xC6G\xA7\xB6Bjz3r\x9A5\x90\xDD\xEB\xD1%\x8D\xF1\x8E] \x8F\xC4\x9C\xFD\xA3\x082k\xF6[\xFB\xF8\xC8\x95r%X\x07\x03\xAA\xDB*\xFB3>\xD3\x83&z\xAD\x91^\x97\x9E\x90\xDC\xCC\xD7\xFD\xE3\x9Ba:\xB4\x12k\xB9\x9B\x03o\xE4\xF0\xA7\x08#U\x16&\x9D\xF5A/\x87\xF7\x86\xAD8\x82\x1A\x9A\x86\x0B\xE0H\xEDZj\xDC\xA6\x1D\x92\xA8\xC6\xA2\x00a\x03\xA3\xBF\xCA2\x11\xFBT\x85\x04\xB9\x15g\xA5\xE7N\x08\x02\x19\xAD\x81\x1Eu~K\x0E\xF5\xF8}]\xC1K\xAEe\xD6L\x80~\xEF\xD1\x07\xC53\xA0\x12\xF9\xB0&\x0D\x9B\xCDF*\x03">,\xA6\x98\xD4A\xD9\xC8\xD2\xCA\xF9.\x19\xCF\xFD6\xF1;\xB1Kn\xD4\x0C#\x90\xF4\xF3P\xE8^\xF4\x1Fv\xC1\xAD\x15\xFF.Q4\x0C\x10O\x04_\xE6\xE6)\xDA\x84\\xA6\x96k\xBD\xD3wrZ\xCA\xF0Z\xE9Q\x80\xF9\x07px\xC5{o\xFC\xCE\xB6\x07\xC0\x94\x15\xA3\x18\xF8'\xC7i95\x89n\x0D\x83\xE3\xD8\x9C\x19\xF3^\xB2\x0C\xACni\x13\x1B\x10d\x02,,)\xE6\xE2\xCD\xE2\xC4\x8F\xF7\xC4|0D\xA3\x0F\x97\xE9gA]\x1DB\xB3\xC4\xB9\xE3\xEE\x0B<\xCA\xF1EG\xFAA%\xF7@\x87^r6\x9B\xE5\x87\xE2e\xD9\x02B\xF6\xA2\xD4\xF1\x8CL_\xDF\xA9\xE4\x97\x09\xF2\xDB\x9F\xE0\xBB<\x07E\x88\xB47\xDDF\xAFG\xCD\xD5\x15\x95y\x0Bp\xD4|\x8FC:m\xDD\x0B\x96\xBD+\xBF\xCF\xB9\xBC\xC4\xA8\xD8\x98\x8D\x99\xAC%\xD0\=\x10\xBA\x95\x9A\x06\xE2L\x94\xAF\xEB*\x80\xE8\x00\xD2\x9A\xE1GX\xE6\xBF\xBC\xDE\x14\x04\xD4\xFE\xB9\x9D\xCF\x8B^\xEDID\xFA\xA3J\xFA]K\xA6!rHQ\xCC\xE4\x1EO\xAD\xCC\x9F\x9E\xE1\xC6!\x9A\x94\xBD5\x9C\xC1.\x83\xB5\x0A.k\x0E\xC0\xF0d$\xEF~\x81\xB0\xD1\xF5\xB5?kS\xF2A\x07\xF2\xB8\x03\x95\x97\x85i\xC1\x01\x8C\xEB\xA0\x92S\x11\xD4\xD9\xACs\x03E\x97\xF4\xB8\xBB\x8E\xD8%ju\x1E\xBCO2\x09\x1C\xC9\xB6+\xA9\xFF\x1C\xE2\xE0\xC5xc\x18\x99\\xB2,J\x15\xF9\x197Ez\x96\x81\x8B\xBF\x14\xC6\x9A~\x9D\xF9\x94\xD2\xCC\xA4\xAC\x8Fe+\xDF\x1F\x85%\xE1s\xF5v\xA7\xAA\x1D\xFF\x17\x1A2\x0D\xC8z\xC6\xF7u\x08Sr.\xA6\x8A@i\x8E$jH\xAF\x10eU z\x94B\xBD\x0D\xBC&4X\x07\x8C\xBBf\xB3`\xE8c\xA0\x04g\xE5u\xDFc\xAF\xED\x17\xE1X\xB6\xCC\xD8k\xD6\xDC\xCEX\xAD\x00W]m\xB2u\xA8\x83\x83\xCB\x1B\x97\xCC\x13\xE3\xBC\xF0\xA6\xAEdG\x8Ckhm\xAA~N\xB6\xF8\xD5#\x83"\xAD\xC0L\x91\xEF \xD5\x04A\x8D\xBFv\xE9\xE0\x19~vBk\xAAqA[\x1A\xB0v1\x11\xB1\x03\x08\xD4 \x85oa\xFA\xF9,\xDD}\{\xDC\x93\x80\x090I>\xC7\x1E\xAC\xF9qT\xAA\xA9; \x8FG\xE4\xB9p\xC4\x0Ex\x91\xB0%\xE3\xDB\x01s\x96\xC7\x92\x86\xC0\xF9\xD3r\x9B%\xBC\xCF\x86\x07\xA7E\xC8(}6(X\x8C\xEAh&\x9D\xCFd\x83 \xEF*\x1F\xDB\xA6\xD3%\xBF\x8DV\xB9\xAB/4`\x15\xCC\xA5\xCEF\x05\xC9\x9Cm\x8BM\x0AI3}L}\x9ET\x1EwUQ+\x88\x84\x81\x92[\x14\x87\xDE\xFBo\xE7\x09\xD8\xADa\xAB\xFCN\x1Cm\xF5\xA3_2\x84\xB63\x03W)\x83S\xF2d\xB4\x14T\xC2\xEF\x87D\x9F\xA0\xD1}\xA2g\xE5R\x84$\xA7\x11\xE2\xCAd\xC2\xA3Rs\xBE\x8B\xA6j\x8AB\xBF1\x93\x0A\x97\x8DA\xCD\x98\x9B\x12y\xFE\x0B\x8E\x98Af\xC5\x0D\xCE\x86iJ`\xB5\xC4.- \x1F\xAB\x93\x8D\x08\xE5o\xBB&;\x99\xE5\x89I9nNS\x978kiI\xA5\xD0\xD6\xC1\xA2\xD3\xD3%\x19C+8u\x19\xDB\xF1\x8C\x8CP{\xB2g\\xB9\xA1:#\xE9\x96\x12\xEC\xD4\x92\xF1\x1D^\xFE-b\x87\x93\xCE\xE2\xF7\x99\x1DB\xC6\x85\xEE\x83y\xDCF)\x04\x96zz\xDE\x00\xFD\xA3\xF6\xA1\xEA\x8DDhcMX\xD6[)@\xB6\xE2E\xF2+,\xD3\x84\x0CT\xA5*\xC4:;\xC6\xF5"\xE9\xD2)|\xAE\x11\xB8\xDFK\xECo\xCAB\xDE\xBD(\xC3Gh\x0A\xCC\xA0\x9C\xD3\xE1\x9B\x15-4\xAB\x94\xAC_\xC0\xDC\x8F13"[]\xB2p\xBC#\x8F\xFF$\xF2&!\xB2$\x88\xA9\x97\xFA<\xDE\x07\xAD\xCBvz\xCAi\xBB\xAC\x93m.h!Mf\x1AF\x13\xAA\xFE\xE0\xDA\x9A.\xE4\x1B\x1E\x8BT \xEF\x02\x03\xC6\xE7\x9D\xADgZ\x81LE0\xE9}\xEF\xD7\x8F\x8D8{S\xBE\x1A\x88\xEF\x1A_\x91,,vXZU\x0C\xF7\xDE\xC0{Ca\x8F-\xA4\x95\x957j\x09<\x8C\xFB\xB3\xF3y\xBCI+\x01f\x0Ct\x90\xEA\xD1Aq\xFE52\xD8v\xC1\x9B\x9E\x8Ex\x0E\x02\x9E<\xF6\xA6\x8D$\x10\xD1!\xF4\xA1\xB8\xB8P\x03\x14\xE7,\xB1\xDF!S\xB8\x1Ct\xBD\x9Du\xBCr\xA8\xEFR\x1F\xD8D\xC4\x9D\x82\xE9\xE8\x8D\x9E\xF0P3\x14\xB1\x9C\xB3\xB3\x8F\xFC\x19u\xF3\xBD\x90\x1E@\x8E\xB6#\x97\xD3l\x99\x9B\xE6\x8C$\xF6\xEC\x12\xCC\x8A\xF5\x81\x12\xFD\xD8\xB5mJ(\x1F\xA8w~\x1F\x05U\xCAMw\x9D6$\xC2\xA0FQ\x94\xA2\xE8j\xE9\xB7=\x1D\xBAG5\x02\x14\x8F\x8B.1\xD0\xCDo&\xDD\xCB\x91W.M\x09\xEF1\x11\xC1_\xC3j\xDB\xE1(4{\x85\x85Do\xF8\xAAc\xC6\xE2\xA7\x1F+f-G\xB2\x0C\x8F,#&Q\x8C\xA3\xFE\xF0o\x92u\x1A\xE9&l\xA9\x91V\xA6\x16\xD0\x99\xA4m\x87\x1Fg\x14\xC64\x99\xC5\x9D<;\xE7K6\x9D\x97%\x1Fr\xFD];\xF1\x07/\x13\x0F\xAA<\x0Ef\x86\xD6\xBF\xCB\xFD\xF0o0\x8EcdD\xBE\xC1\xAA\xB6E\xA2\xF6z\xBD\x0B\xED\x81\x9DP\x88\xC6yh\xBF\xE0\xDA\x12\xA1\x06\x0D\xB4\x0E\xFD\x18Tm\x1E\xA6\xB1\xA2\x7FCN\xEFa\xE8\xA2\xFF#R\x0C\x99Oo\xEF\xFB*kg\xFE\xBA\x91Q\x917J\xB9o\x01\xF5~\xB8 \xBDN\xC6\x0F8\x8BMt\x94\xE4\xB1x\xEE,E\x1A\xD2{5\xADw}\xCB\x8CvGF%\xD6\xFC\xF9\xC0\x09\x85\x9C\xFC@\x16C\xF5\xE52<\xC8\x19\x06\xD3u\xE2\x12IC\x94\xAFd\xD4\xD5?\x0Fv\x18ge`\xD9\x9At8GOd\xAD2\xE1+\xF9\x87\xAA\x0F\xF9\xC7\xEB^\x95\xF3\xF4W\x17&\x01\xAFXomp\x82S#\xB7\x03|\xD0\xC4\x15\x0E"s\x87|\xA2\x1A&V$?\x0E\x87\xAAu\xE68^L\x7FW\xC7\x84\xA8p\x10\xB0\xF7%\x0C\x8FX/\x01\x8EL\xF5\x91D\xE8n\xC6\xDB\x9B\xD7\xB5\xE1\x00e\x8F\xD1\xCD\x11\x9B}\x9C\x18\x9B\x11\xBFu\x06\x80\xDF\xC6\xB6\xF8+\x1F\xF0\x95\x06\xAB\xBD\xC4o\x9D\x02\x93J\x16ynNf\x1E+\x8B\xCFCm^\x09\x93j2\x87\xA1\xB3\xCF\x03\x93Hf\xAE-\xAFO_F\xD5\x12\xF6N\x166!<\xD4\xEE\xFB\xC0\xBB\x0C`\xC7\xB3%{\xAC\xC3t\x82WJ\x1D\xD2\x04\xF6u{M\xC9\xAAeP\x00\xF9{\xB5\xAFI\x0F\x87\xD9\x9B\xC0y\xD4X\x03\xAF\xB3\xC7\xE5]\xBFT\x0E\xB2\x19\x02<_\xE0KEx'o\xE4*i\xB0\x1B\x16\x07qTR\xDA\x04\x95\x06\x0F\xD1\xA8K~\xFBM\x188\xF9\xD8\x98dNA\x7F\xCA\x08\xD4\xB3\xA4$\xA0_h\x0Dy*\xE8\x1A\x14C\xE8\xF1<\xC3\x90H\x964\x9B\xD6\x89y\xEF\xAF\x1F}\xEC\x12\xA91s\xBF\x95f\x84&\x8A4\xB3\xB2\xE2?S\xF0\xE2\xCA\xB5\x0D\xACo+\xAC\x08<\xF2\xE9\xC7\xCA\xD5\x0B\xB4U\xE0\xAB\x07\xB3\xC9N\xA6\xAC\x04\xC9\xFFl\xEA\x13\xE9+\xDE\xD9 ?\xF6\xD2(\x040\x18\xFF\x83\x8F\x07\xEBfg\xF1\xBFQ\x05.0\xA1:N\xCF\IR\xE0\xEB\xB4\xEB\xF1\x8C\xAE+cY@o\x12-j$\xF5/x\x0E\xD3\xDF\xEEI\x0E\xB8\xC5\x84e\xE4\x92\x8B\x9A\xE1\x10\xF4"X+\xEFy\xE1\x0E\x03\xEA\x8Dx\x0F\x80"\xF8b\x14\x91\x9A^\xEB\xB3\xAC\xAFo=\xEA\xD6\x03\x10\x81\xA8\xFE#\xE4\x0E\x96\xD0Z\xDD=\xC9\x11\x99\x11\xA9\xC0j\xBD7\x07G\xF9\xE2\x08\x11\x14\xA2\xFA\xDE(\xE1\xC9%\xE7\x16z%\x80\x0E7d\xE7\x13QY\xC7\xD4\x1D\xC8\xD1\x12\x94u\xF8\x8E\x878c\xCCnN\xFC\x93`"\xE0\x1C.\xF7\xD6\xA2\x8D\x10\x895\x95d\xB6\x10O\x1E\x0A\x90\x86\xFC\x85\xFC\xEA\xA14\x9CyL\xAD/\xF0\xF0<\xFDf\x82e\x94\x98t\x06)\x02\x10\xDDH\x0A\xBCO=\x85&\xF2\x85\x87\xA3\x88\xE7P\x09\xA1\x17\xD7R\x1C\x16,\xA0\xFA\x09h\x92\x86\xC8\xFE\xC5\xD8\xFE\xF7\x15\x13\xDD\x1C\x9F!\xE4\xC7\xAC\xC9"\xAAZa\xEB\xA8\x1A\x9C[\xAE4d%_\x82\xFAm\xB5\xEA\xD1\x1A4\x11\x07\xF0<+;\xC6\xA9\xD4\x86\x1FGh\x12\xB6\xAA\x9E\xEEK\xBF\xEFo\xC3\xB6ib\xD6\x95\xD0O\xE3\xD0\x1D\x0B\x0E\xB9\xF1#o>\xB8\x81\x99fhA\x91W\xFB\xBB\xC4U\x9D\x13\x06\xF8\xC0Jc\xD2\xBC\xE6jP!N\x17\xCBS\x0C.+\xA9)\xABLl\x1E\xC7\xDF%y\x09\x09\x06\x1FP\x84\xEA;\x0B\xE3\xFB\xF1\xEE-1\xF4\x9D\x8FU\x8F-*,\xDE\x8B\xC4{\x93\xF8j\xEB0\x82\xE5\x01s]\x8E\x16\xF7\x1F)z\x80o>\x1E\xA8\xE8\xD9 \xC0\xEE\x94g\x84\x8A\x9F1\x17\x9B\xCC\xE3\x08\xE8[u\x0A4\xDF\xC3\xE9L|\xA8\x183\xDD\xF1\x0F\xBF\xF5.\xE1\x8B\x9C\xFDE)\xE8)\xB0"3\xB2\x83\xB9\x915$\xB1\xFE\xA2\xF5b\x8B?\x0DJ\xDC\x190\x94\xCAJ\xB7\xE8\xFF\x126\xEC\xEE\xD05E\xC3\x9F1\x9D\x0F"s\xD6q\xF0\x0FJ\x10]\x13L\x96mm\x14\xB4\x8A^-\xF0LmR\xF5\xD5\xD3\x7F\xB3\x1Bd\x90u\xE2\x1B\xAFQ\x07\x8F(;sn9\xFC2+k}\xFD\xA4.\xE5\xD3\xA4\x1Bn\x9A\x88-v\x83\xB5{\x9D\xAE5\x8Ao\x8F\xB1K\xAEhyy\xBAeS\x9F\xC8\xCF\x8B\xD0\xBAc\xB88\xFFB\xA8\xED\x9F\xD4}\xD7\xCB\x8BN\x05\xD6\xE4\x16\xA0\xDEG )\x8F%\xD2\xFFT/\xCA8(\,L\xA1_\Z\xC4\x05]`\xA0\xAC\xE5\xE6p\x99B\xBA\xDA\xAFe\xB9\xABb\x19\xA0\xF6\x82M\xD1\xFA\xB4\xA7\xBA\xFE:\x1E\x0F\xC3p\xB6\xDB\xB8\xE5\xF0\xC8\xE5\x80\x1Co\xBA\xB6\xDE\xDD; \x9D\xE4P\xD6\xB1\x1A\xBF\xFCqKt\x03?\xFF>\xCE2\xEC7\xB5X\x93\xE7\xEDp\xFC8\xF45\xCBk\xCEX\x1F\xA6h\xC9N\xC1\xF3\xFAXU*b\x1C:\xBF9\xF6\xA1/x\xC6\x8E\xA7p\xC1;\xF9\xA7\xC5\x87NF!\xDE\x8A2\x0D\x81\xEAuf\x0E\x0F\x99\x12\x03\xCB[D\xC4^\xF6\xD0\x0B\x1A\x1De\xBB\x02\xEA)\xA4\x98\xB6\xA6\x13\xA7\xBD\xD5\xED\xB51\x09f\xC3\xD0'$\x11\xD0!\x00Y\x96\xE9\x80\x1F\xBF\xCCM\xA79$\xD3S\xF8{\xBF\x08Q\xCB\xFEJ-\\xCB\xA7X\xA8G\xF5\xCF\x10\x12D\x81\xFB\x06?\xED\xE6\xC3Y\xE5\xA5\x8A\x07C\xAE1z\xD4\xD8-\xA6\xCC\x97\x8C\xE3\xB4\xA7\x8E\xE46\xBFJ9\xF4\xE9\xE8\x01j_\x02o\xA9If\xCC\xDF\xAD\xE3g\xEAzl/|\xF7\xD9>!\xEA\xED\x8Bn\x81\xD6\xA2WkN\xE4\xC1%lz\xDC\xA1\xDCwH\xCD\xC0N\x13C\x02\xD2\xB1>\x823\x98mpS@\xCC\x0Dv|\x8B\x82|\xF7\xEC\xE6]\x03\xB0)y\xBC\xC7\xFEz\xB8Y\xBB\xC1\x8C1\xBF\xA8\xDF\xDEI\x0F\x81\xB9U7\xDB*\x8A\xD4\xC9\xAB\xEF\xA5\x00q\x09y\x0B6\x86\x99\xE1\xF5fG\x1E\x19\x12\xAC\xDF \xB9\xD0Y\x88\x90i\x0E|\x0A\xF0\xAA\x1D\xBF\xA3\xD6OBF]\x1A\xEB\xDD\x86\xE4\xA5.\x97C0\xB9\xFF\xC8\xBA\x00\xA4\x19\x1EK\x94\x88\x7F\xB8\x81A~\xF7\xAF\xAB\xFF\xD8eW\xF5\xBE'\x09\x09\xAF\xAE\x80\xFFb\x87\xA3\x8B.\xAAsl\x02\xBE\xA9\xC2\xC9\xBF\xDB\x8A|\xE6Z\xFCv\xC37\xB9\x8B\x8C\xD9\x7F\xEA\x98\xA6\xA2o\x07.\xFB;\xA2@\x18\x9C\x94\x0F\xE1\xD8(\xF1\xCB\xC9\x0C$}B<\xE4?[_\xDD\x16[\xCC\x0C\x96\xB9\xA0\x1C\x8E\xD1`O\x9D|f?B\xAF\xE6N\x16\xB8\x92F\x1B\xBE/\xEF\xBF\x18\x974\x06\xCA\xA6\x12\xDCg\x96\xD4pD\x19\x12\x97'\xA2\x8F\x1E\xF4)\x02\xA1\xA0y\xF1^\x0F\xD8\xCCe\xAE\x85\x0E\x10\xAA\xBB\x979O\xF9\xF19Xx\x1E\x91~\x9D\xABE>\xA5\xDF\x89E\xB1\xC9)\x0A\xE6S\xAC\x90\xB82/\xEF6\x81\x82\x8Eb\xC0|\x86\x0B\xADg\xD9\xEA\x135(\xA5\xFEi\x96"f\xF1N\x9AAE,\xC1y\x95\xBDH9\xF6\xB7\xA3\xC5+\xB6\xB1\x1F8\x9A\xE7\x9A~`e9\xFA\xC2!\xD6\xC9\x05\xBD\xB5\x91\xF8hP\xFA\x89\xFF,\xAC\x19\x0B6\xCB\x8C\xC5t\xE1\x1EB\xE8~\xF0\x87\xAE\xC7M\xFD\x19@\x00\xBD\xB3\xAA0\xCB:9\x85OK\x10\xF7Z~s\xC3\xCC\xD4\x142O\xF9c3AB\xF8\x10\xA4\xA4\x04L\xCE\xA4\xF9tLL@mG\x8Bo\xC5\xDA\xBC\xA3)\xBB\x07\xF6])\x9D\x837\xE0\x1B\x1Fg\xE8\xDFe\x80\x17\xD4`\xD7n\xB0N\x1D\x9Cf\x94\xBD\xF9B\xE4?C\xFDK\xC2\xBE\xF6\x01\x84\xD8%!\xEA\xBA\xA7\x9AP\xDC\xF3\xF3\x13\x0F"\x83w\xC5YsT\xD2\x169\x94AHAP$\xFC\xC7|W\x8F)z\xD3\xCC\xDC,\x1B\x95@\xF8\xADv\xBA\x81\xE0d\xE7l~tdJ\x0B\x9D\xB4\x8D\xBF\xFC\xC9\xDE\xBCK\xAE~\xA3\x94S\xFCB\xB2&;\x07\x10\xBE\xCFk\x8D~T\x94I\xF9yKW\x19B\x1A\x15\x9E\x0E\x03\x91\x84\x93\x187\xCE9}&AG]j\xC2\x94\xBC]V\xDDT\xBA=L&\xF4\xE7\xAE}\xBAb3A\\x05\x14\xAB`N\xFD\x872\xDE\xB9\x8F\x915\xF6\xBBa\x08'\x0B\x9B\xDD\x03\x8C\x96\x9E5\xC53\xF5W\xF6\xEBA6p\xB2b\xBCB\xF9\x87\x98H\xA9\xDDy\x15\xAA\xA6\xE8\xDE\xF9lX\x01\x82Q\x8D2\x1Bx\x0C\xBABH\xA8kAQ\xCB\xDF\x04\x1D\x7FJeG\xA9\x80N\xC8M\xE2\x91\xBA\xCF\xA5\xA4\xCB\xE9o\xE3)BD\xA7w\xE1(\x15\x12\xE9#\xBFxH0\x8F\x84D9\xE5\xA5\xB8tV\xF2\xFE\xEB\x0A?\xB6VN\x8B[{%\xE5\x99\xB8\xAB\x19`<\xFA\xAB\xF3\xBC\x86:\x9E\x0A\x0CF\xFB+\xEF\x8F\xDDJe\x85\xC5\x83\xF3\xD5\xAA\\x0C\xD0\x19\x8Bs\xF3\x85{h\xC5\xC70\xBB\x00\xFB\x8B\xE5\xB9\xD9U6!\x94*\x8B\xF0\x19<\xBF\xC2\xD8 o&SDS\xAC\xA3\xBA#*\xF8\xF63\x0F\x0EM\x95i\xE7\xCB\xBA\xD8pr\xF7\xAA\xA6\xA7p\xA0\xED\xF2\xA4\x19\xF7\x92"\x0D\x917&~Ke\x08=\xED\xBA\xC5p\x11D>\xF0\xEBhG\xA8\xAC\xF1\x1B\xBA\xF6\xED\xC8\xC2\xF9G.\xA5\x8C\x83\xD2\x1C\x875\xE8N\x16w"\x0Bh\x808\xDB\xE5\x09\xBD%\x95p\xA6\x0D\x82\xDA8\xD75h\xB7\xA4\x1A\x80j!\xA1\xD6\x94\x95_\xB3\xDE\x10\xF9\xC0SI\x89\x92\xBF\xBAk\x91NRjR\x19m"\xB6q\x87\xF4u\x96\xFF\xFA\xB1b\xDC\xED\xE6,\x83\xCD\xA2\xED\xF8z\xC5X\xF9Y\xE5#O\xAD\x86\xD2\xCF\xCC=\x06\x8FS\x09\xE4\xAB&\x07\xBC\xA7\x89\xD9\xC7(\'\x99YAU\xB4\x9E\xC6Y\x87\x81F\xE0\x8Dd\x88\xC1\x92\x0D .BT\xF8\x0E\x9F\xC3\xED\x93l:\x03\xF8\x9F\xFE\x0D\xF6\xA8S\xFAU\xB3\x13H\x1A\xB9\x9E\x06\x82%\x80\xCFE\x86\xA8\xE6\xAC\x1D"\xE9<[\x1F[\x19w\xE1R\xD3'\xFDk32#\xAC@\x8A\x04\xC9\xC0Ey\xFB?\xE6\xB2\xFB\x13\xDB\x09nL\xDA9t*Rt\xCD\x88\xCE\x9C\x16HdW\x984xC\x1F\x88i[\xFB\xED\x80@\xD8j\x94\x94\xE8\xC6\xB2\xC3Q\xFC\x91\x84\xF1IY\xC1z\x84\xFD\xC7\x0D\xF4\xBCT#\xB8\x7F\xE3\x0A\xB9\xD3\xD9\x8B\xA8\x94}vd\xB0\xBA3\xC6K\xED\xDD\x95+\x87-y\x833?\xE8\xD6\xB1e\x14f\x83\xC7\x91DKC\x9A=@\xDA\xA0%\xDD\x81{\xCC\x19E\xB1\xCB(\x17r\xD3\x85\x07\xEB\x0A\x99;\x12u\x8C\x0E?\x9B\xBD\x0F@\x86\x86C\xB2g\xB6i\xD0\x10X\xF3"a\x1F\xC37\x9C\xAE:\x89\xDDa\xE1s\xF3)\x86)\x83^Huv\xE7FNN\xBB\x81JL\xFB\xDC\x9A=\xD3c\xF1\xE2\xC7\xCAD\x9D\xE1\xE2P\x9C+[`\x0D\x99H'\xAE\xF5\x9E\xF5\xB7v\x03SfN\xDE\xFEQ\xDCk\x94}\x8C\xFB>\xD7\xDF{\x08#\xA0\xFD\xDA-\xDE\x8C3\xDD\x9D\x908\x05\xC6n\xA0xV\x97\xD3\xB2\xD2\xDEH\x97\x1E\x1E\xC0\xDF\x9A\xE2\xBE\xAA?\xE6\xEA<\xFDodI\xD5\x0C\x07\x9B%\xA8uQe\x0D\xDB\x1B\xAF\xBB+2\x1E\x8F\x87K\\xAErK\xA6\xAEgt\x0C\x0B\xEAM\x98\xE9\xA8c\x0D\xE4$\xF3{\xFC\x8Di\xBB"\xE3\xA0\x0F\xF1\xABx\x1D\xCCk\x93^\x06_w\xE1\xF9\x1A\xD58\xCCkJ]\xF1\xFC\x16}\x02\x08 \x13\x19\x8A\x09\x12\xDD\x18\x04<\xB3\xC1\x01\xBCN\xF9\xC9\x19\x06?\xE3\xFC\x9Em\xC1\xD9\xB4G\xA4/\x0E\x1A\xE4\xB3\x0B\x94\xE8\xE5\x83dR>\xCC\xFA\x8C\x85\xE7\xD2Q\xB3\xFA\xA3\x0E\x0D\xAC+>\xB8\xE7H;\x11\xBCy\x01\x1Etj\x8EC\xF9\xCC\x09\xA8;S\x1ApvA\xDC4"C\xFE\xB2\xB7\xA7\xB9;k<\xAE\xF8\x8Ao\xE5\x84@\xB1\x9E\x81#\xAA\x95\xDE\x82\x0D\x0Ai\xB3\xDB\x9Af1\xCC\xF1\xE7\xB3\x05/a\xC3+\x84\x88\x12\xF9\xA0\x8F\xE1P\x8F\x8B\x89\x86\xA5\x1D\xA9K\xAB\xB0\x83!\x9F\x9A\xA0\x0093\xE7}#\x9C\x8A\x12xq\xA5\x0Fk\xA9\x1F\x9F.(y^\xAB{\xDES\xC2\xC4mQc\x85\xB5\xE8\xBC\xD8\xA0`\x18\xA3\xF01\xF7\x84\x09\xA7\x1E\xE2\x19B\x19\x90?:_\xFE\xCA\xCF\x08\x1B\xB0OC\xA6\xBF\x91sW\xD4\xB1\x18L\x96\xA3\xA5\x97/\x03\xB7^\x10\xB3DTnu<\xBF\xFB\x89\xAA\xAB\x84\x02\xFE?I\xB3\xEB76\x940yX4\xD83\x157\xDAY\xDC\x98x\x94f\x8A\x02 i\xC8K[\xAE8\xE1>\xCF\xC7*\xB4T\xF1\x14\xDCO\x1B\x1C:\xFAL\xB47\x8C\xCF\x85\xA4&2\x0F\x09\xED\xF6\xD7\x14\xAC\xFA|O\x1F;wbh\xF1\x1E\xEDM\xAD\x9DS\x85w\x156::I\x85\xA1\x95\\x9C=\xBD.\x89J0\x13\x07\xE8\x93\xB98\x18H\xC8\x02\xC3\x00\xB3'\xD2\xEA\x9B\x91C\xFB\x11\x81\xAC\xB6\x1D.\xF0\x1B\xFB\xE1\xCB*\xE9e\x98\xAA\xF17\xE7\x14\xA0z\x8D:\xF6\xB9m\xD6\x1D\xAD\xA9+\x9C\x139c"\xF2\x03\xFFN\x946\x1BR\xF6rs\xE1\xD3\xF8\xF5\xCF\9\xB7c4\x07\x91\xF9m\x145\xF3\xCC\x1D0yw:\xCE\x0D\x03!\x9D\x07\xA3[t\xBB\xB9\xDE\x91h\xBB\xFC\x84\xEC5\x09\x17vO\xBEY\x88D\xF9\xF3\x03`\xDD\xE1&\x14\xB6,\x12\xD0\xCBF!N>\x11\xBE\xFE\xFE\xE6\xD8p\xD6\x84\xB3Q^*\x99\xE8.I\x1C\xC66\x04\xA0B\xF0\xA6Ax\xDC\x17r|\xAF\xA2\xD4\xB0\xD5\xD2\xFA\xC2\xB5\x9B+\xA6\xF9\x11\xE6\xE3\x9E\x10H\x02~\xF9o\xF7o\xD15Q\xCC'i\xB1\x0F\xF6\xDC\x99!r\xB01\x15B\xC2;!\xC7\xB8\x93\xE7\xEB\xFD\xC2\xBE\xF3(3a\xD5\xF67fN\x0C\x1BE\xC0\xC0?\xFF\xA6\xB6s\x8E\x04f\x8C\xC1\xDF:H\x94\xC2y\xA8L\x1Cs\xD2\x9B\xBE\x1Dh2u\xEA\x87\x17<\xBF\x1A\x8E\x80\xCB\xF2\x02\x8E@NU:\x1CI\x9A?\xA1\xD6\xA9\x0FW\xF7\x88\xFB\x8C?k\x18\xAA\x7FU\xA4\x19\x11*\xC7 o82w\xEA\xFD\x90\x89X\xEAQ\xF8.c^Xa_\xE2\xB8\x90D\xCB\xE7n\xF5\xBC\xCF\x0B\x13u\x9E\xAE\x9Ag{\xDB\xBE\xEEr.\xAA\xAD\xA5$I\x0D`\xBE\xF7*\x80\xC52\xB2d\x00DGl\xB6&9\xF5\xE1)F\xEBT\xDB2"\xA6\xDEH\x87\\x98\x15w>\xD1o\x94T\x85\x07\x85\xFDy\x8F\xE1\xBB\x00\xF6\x80\xA9(\x0F\x02\xD7\x1F\x91!\x98\xEC\xDEV\x8B\x19\xE2P\xF4\xDD\xB1rK\xD6\x97\x1EPE\xE1u\x12NB\xFB\xE3\xCF\xA2\x98\x8F\xB3\x12r\x9A[o\xDEC\xFC\xD6\xA5\xCCU\xD5\xEB\xEE\x86E\x97\xFF\xE9\x0E\xC0(`\xE8\xFD\xB0)\x07\xB6\xAA\xE7\x11\x12!\xB3\xBC<\xA74\xC4]&\x1E#=\xB4\xBF\x86SC\xA1\xEC\xB3\x05\x15fUQ8\xE6\xAF\xF4\\xBD\xD3\xB8\x1F\xCE9)pu\x8AUK\xC6\xB8\x140\xE4t\x04\xC6\xD3\xBE\xAD\xF9p#\xCF\xB8\x0F\xDBo\xC2\x99\x83V\xCBp\xAB\xDAI&2\x9B\xE0O\xFE\xFD\x18|\xE8h/!\xF4^$k\xD1\x97$\xF4\xCB\xBFa\xFF^\xF4x\xB0\xE9\xEBB\x08\xEA[:3\xC3\xE0\x02\x7F\xC5A\xD3\xB6Iv\xA4\xF3\xD2q\x10*'\x8C\xA8\x98\xDA\xF7\x00bSY(\xBF@\x9F}H+\xA0\xDE\xB4\xFBvky\xE4\x0F\x8EU8x\xAA\xEC\x01=\xE0\xE5\xB8\x19\xC1\x9D\xE2\xF3\xFA\xE4\xF8!\xFFL\xB1\xE36\xF4Q\xCAb\xD1t\xB4\x97\x15\x11\x06\xE4\x98\xD2\xB2O\xBAp\xCA\xEF;\xD17#\x83\x13\x85\xD3^\x9F\x8D\x85\xAD\xB4\x8B\xBE,\xA3\xA5\xF8j\x9E\xBB\xC7/\xF1\xDB\x14\xBD\xE3L\x08]M\xA3\xB6\x9E\xAAc\xA1\x83\x17X\xB7`\xD4\x18\x14{\x8C\x9B\xB6\xBDU\x07\x97\xD9\xA7I\x1E\xEBd\x012\xE6=\x7F\xD8\xA7\x9BY]"\xAC\xDAe$\x14B\xDA\xB4N\x05\xDA.\xB3\xDC\x8D_\xD3&\xCF\x14\x0F\x9B\x9A\xFB\x16L\xCC\x0A\x02E\xCF\x88\x88zV \xC8\xEE\x8FO\xA5\x1E\x10\x0F\xDC\x82\x96\xB0\x132\x02Zk98\x89\xBED$\xA1\x81L\x9Fe)\x07[\x14\xC4\x9AB\xCA\x95l\x1Ag\x11\xA5\xCA\\x8C\x9DR\xB6g\xA0M\xBF\x80\xA9\x92>at0N\xA5\x05\xC7\xD19\x87\xF8%,s\x0Bp\xF2\x0EZ\x1C5\xF6\xCBs\x9D\x08X\x8F\x14\xC5H%u\xCC\xBD9\x85\xECJ\xBC\xE7\xB8cgG\xB6\xB8\x19\x8F\xBERH\xBAtd\xB1\xE7A\xC32\xB0\xDDz\x8E\xD9\x80\x06\x03-\xD2,P\x97\x1D\x0C\x17vW\xFA\x84J6\xD1_\xEDY\xEF\xE3I"\xDE\xA1-\x84\x94'}WT\xED\xD3O\x84\x99\xEBr\xD0\xC3\xE2\xE2H\x89\x8D8S\x83\xC58\x87Q&{\x0E\x1C?\xF3\xE4\x91{d\xCF\x1B\x0D\x9BU\xB9\x7F\xC86}P\x1D\x0A2IWB\xFA\xEFO\xCA\x97\xC4\x0E1\xA7\xB3p\x0F\xDFG\xFF\xE0\x14\xE0\x17&fU\xB7\x86X'\xE5e=I\x01O\xAE\xF0T\xA5$(@g\x88\xCB\xE2W\x1A\xA7B\xDFEq\xE5\xEAj\x93\xA8\x10\xEF\x90x\xCC\x9DV\xF7\xDF\xAE\xD2R\xD3\xBC6wQ\xCB\x9C\x0B\xF8\xBFz\xA1Y~:'\x00"\x94\xC5V\xDF\xA4\xB2o\xF9)S\xAD\xABh~\xAB\xF7.s\xDA\xBE\x87\x1C\x06>[Z&s\xD3\x0C.\x00Dk\x05I\xA5\x11\xD1,.\x8A\x99|\x1D"P\xC0n\x05Eu\xBB\x93\x19}\x02\xD4\xBF\xF5\xD2\x0D@\x822\x7F*\x94\xA3\x8B\xF3i\x06\xC4B\xA3\xBB\x8B0\xED\xEE[\x86g\xE1\xB3c\xEE\xB2\x8FR+y\xB8Vm\xCB5\x1BQ\xB2\x00\xEA\xB4\x02\xB18f\xFD\x86\xFE\xC7\xF7\x96\x83C\x17\xF4\xE3\xD0\x8D%\xB9\xD9\xEE\xC2\xABg\x95\xD91\x88!&&\x1A.\xB6s\x1C\xF1\xFBn\x0E\xADk\xA7\xD3\xD8k\x81\xAC\x17^\xB6T*a\x87.\xC0\xA0p,o=\x9E\xE9tl'\xDA\xBB\7[4\xB1gW5\xCD\xF9\xC1<\xF8\x08\x8Fb\xBB\xB4\xE1\xF826w\xD1\x11\xBB\xC9\x94y\xFB:(\xAEg\xA7@\xD6\xB1J-\xDDt\x14u\x08**S\xC8YO\xC4h\xE5\xE7g\x00R\x8CaZd\xD8\xFFW\xA6\xE87\xEB\xA3u\xBF\x96\x13X\x85\x89\xE0M\xBB\xD9\x123\xF3\x01\xAAH\xFA\x9A r \x1A\xD5\xDF\x98\xAE:\xB0\xB2\x90\xF1fj\xBFz\xE8V;/\xD2q\x0EB\xEF\xF7\xA2\x1Bz\x81\x7F\xACfPL\xE9g\x11}\x14\x99a\xDA\xAF\xF9\xFE\x01\xC59\xF3\x1C\x93}\xD5\xA1#\x99v\x9B\xEF\x81\x82VJ3\xE7t:*\x9E\xFC\x064{{M\#{-a>\x96\xD3\xC4u1q2\x12A\xF9\x9B\xA9\xAD\xDB\xA5\x86\xCF\x1C\x13\xD8\xE8\xF7\x1BN>\xE2\x87\xBB}\xA5Gp\xF8\x8E\x12\xEE\x0D\xF8IaPMY\x82dH\xAC\xA1Z`s\xCBhq`\x99\xA6\x9E,\x8D\xB2\x87(\xCA\xD3\x8Ch\xF2\x18\x8B\xF2\x8D\x84\x84}\xF4\xF7\xCBh\xF5\x84u\xA4\x1B\xB4\x86\x03\x93s\xCF\xD0\xBFJ\x8E-"\xA3\xFB\x8F5\x0D\x005t\x97\x17\xA2\x88\x0F\xC72\x12=\x1F\x8C\xAD\xE7\xB3\x94b\x1A\x16\xC1^(\xEEba\x0Ad\xC5\xF0\x1A\xE8n)\xE4\x94\xAD\xEC\xAD\x94V\xDA\x97\xCB\x89/\xEA3c\xA5\x10FP\xDA\x96~g\x06eU\x7Fa\x94\x0FPt\xD9\xF7}r\xF1\xA4\xBB\x06\xC7\xEA\xAE\x8E`~\xDA\xEB\xE6\xB0\xC8\x86\x93\xEF\xF7\xA2\xA4\xA5OI\xAA\x96BM<\x8C:\x91d\xFF=\xA1_\xBE%}\xB2\xDF\x7F:3\xEB\x1F\x1C\xA6P\x92Z\x7F^@l8\xB5\xF1d:\x07%c\xDE\x8EJ\x8B\xF0Z\xDF\xF5\x1E]4\x89KT\xD58Ij\x15h\xEE\xB1V\x15\xA2{S\x9CL\xC0L&\xF3\xD8\x17\xF7\xE8\xD5>\xAF\xE0V\xD2E\xD0\xEAb\xD8\xE2\xABm\x9A\xFC\x8F\x17\x8F\xBE"\x12\x8C\xE93:\xBC\xF4\x02\xA7\xED\xCE\xD9|\xACb\x9A\xFA\xD0\x068O\xE2L\xB0\x17\xD2\xE4\xB7\x02\xAD\xD5\xBCq\xFD\x07:\x84*\x83F\x93\xC9\xC5\x1A\xEC\xAE\x84\xD6\xE8\xFD\x03\>\x9E\xED\x9A~\x84\x80^\xFAC\xACY\xD7oq\x9AC\x1C\xAD7\x98\xBAde\x1C\xBC\xEF\xA3s\x96\xA6\x84W8`\xCF\x02;\x06\xC4v\xAA\xA0\xEF\xE6\x93\xE4\xE8\x84`\xA0~\xA1D\xDDA\x17\xA2z\x93\xF0\xD6aY\xF3@\xAD\xC5\xC3\x14\x18S6@\xD7\x9B\xC5\xD2\x07\xD3+f\xEA\xE6(\xBEqe\x96n\x9E\xF4\x90\xEF\xD7%\xCF)\x13\xFD\x1DA"#\xD4\xE6v\x0Bn\xC5+J6\xC7H\xE6\xA1\xD5;l!\xF4\xFAE\xF0\x86D\xCD\xEF\xCD^O,\x87\x09\xF8O\x80\xF5\x1F-\xBA\xDD2\xF1\xBB\x09\xFD\xB3\x07C\x95uK\xEB\x81\xF92\xB7\xD0\xF6\xE7\xD3&\x82\xC0)\x19\x1Cyt M6J\x84{\xA1\xFC\x91\x0F)\xE3zwN*\xB9\xFC\x00\x1E\xF2\xEA\x97\xA5X\xC2Z\xA4\x99\xB6<-\x0A\xAEno\x01\xE8{\xF2+\xBB\xE2\x82\x014\x1D\x87\xAD\xCA\xF2\x1F>]\xE2\xFE\xA5\xAC\xD7\xFE\xEB,\xBC\xED\xD1\x89\xCC\x1F\xF6ho\xCE*\xD1-\x9A\xF6"\x99\xA9^\xF0{\xC7\x86b0\x9B%\xBAK\x11\xDB)\xED\xA4\xA8\xEBp\xD4\xA14G&b\xC8\xDB\x08\x1A\xF3\xEB\xE6\xBA\xB8\x05\xFD\x98\x10\xCC\xEE\x17g\xE1DBWH\xFF\x94q\xACO:<\xF2r7\x8C\x0F\xBD\x8B\xA4\xFD%\xE6nk\xD1\xB6\x0Dh\xDF\xE7\xD6V"\x1F\xEEK\x13\xF4\xC7\x87\x0F\xB0b\x01\xD1%\xDB\xC0\xA9\xD7\x9B\xFF\xD3\xC8w\x7F\x98 H\x96\x0CZ\x95|0\xD6H\xF7\x1D\xB3\xEE;\x90\x9E\x9B*Q\xC9\x9C:\x0D\x1A\xA5\xE4\xE8\xD8=\x85\xD3\xB6\x1AP\xA8,\xD6\xB9"\xC5,POT\xC0\xB8^\x12>\xC9\xD8\xD3"\x9D\x07\xF6\x93\xE2\xFBN\x96\xB6\xEB\xFE\xFAp\xDF\xA9\xBA\x85W|I\xE1\xA6\x10c\x1F\xFB\x0E\xE2Z\x92\x8D\x92]\x81XJ\xF6g9;\xBF\xBC\x14L9\xD2\xEE\xD2\xF0\xA69\x1D5\xE0\xA8DG\x8B\xFER\x00\xEE\xC2\x06\xC0aAu^\x80\x1F2?\xEFR\x19\xCC\x1C\xE9F\x19\x81~\x07_o\xB7\x01;]u|\x022BTc\x15\x0D<\x1D\xD5&{L#\xBCJ\xB4\xEFL\xD1\xB8\\xDB\xD3s\x8D\x95!\xB99\xF3\xB9H\x9BJ\xBD\xB6d\xF8sz\x87\xEC0\xEF\xEAn\[\xB8\x05\xFD\x95uJp\x0AU%\xE0\xB5\x86\x8C\x9D\xE2\x0D\x8FJ{\x9A\xD8\xA6\x81\xAE\x84U\xA3\x94\xAE\xC1\x92Y\xE3\xE3\x0E\xDB\xB3\xD3\xC2\xEE\x12W\xD49\xA5\x14\x81U\xAE\xF2K\xFAAa\x80\xCBQ\xE5\xDA\xC5J\xE3\x0D\xF4\x85\x03\x95\xCEtR\xBC\xCD^8\xF2\x9A'\xCD\xFC\xF5B3\x11\x87\x96\xC9\x8BN\xA6lx\xE5o\x18\xE5>\xCA\x9B0r\x04\xC0\x1D\xFCB\xF4\x9C\xD6\xE0\xE0\xCD\x8B\xEC@\x8C\x19\xB7v\xFA*bIVV*\x10\x14p8p\xF8\xC6\x0F\xC6\x8Dw\xC5\x94\x97`\xED\x17\x92\xBC\xF4}\xD2\xC6P\xDA\xE6{\xFE\xF5\xC0\x81&\xE1\xFC\xB47\xB4\x9A\xFB\xA6\xCA\xBB\x9D\x89\xD1W&_\x86\x8C\xB7qy\xC8\x96\x00X\xAF8\xB97\xF7\xB1w\\xE1:\x08`\xD9\x0AV\x98\xD6\xA8\xB2\xDE\x88\x91\x87\xE4#F\x08S\xAA\x8A\xC7Ox\xF9\xD2\xCD\xB0\xBCoOj\xC7\xC5*\x0A\xAAB\xBC\x15<\xE9A\x89Z\x8F\xC4`l\xAF\x01\x89\xF3\x88\xF7\xA9\xCB\x10L\x94}\xD1\x17$\xE1\xF4\xEB\x96\x87\xA971\x00\xD6\x88\xEC*F\xB3q\x99\x17\xA6\xC8\x18\x8D\xDCm\x16\xF4\x1E\xBE \xE8L\xFF\x87\5{\xD9T\xB3\xE6O\xA3\x14\xF8\x0FTe(h\x97\xC3\x9F.BK2\x8FZT@=MG\xCF}.\x8C\xCC;\xE6\xDCv\xF4WN'\xBD6M}\xEF\xBF\xF4\x98\x9C\xB5\xA8+>x\xA7\x9E\xBFg\x00\xCC\x1E\xC0\xC6-\xDF\x0D\xF7%\xF2\x1C\x80\xA8\x9E\xB4Y\x08\xA3\xFAr\x15\x94\x7F\xFE\xD1\x92]{Q\xA4\xED\x19\x12\xCAU\xBAW\x07\x09\xEF\xBEd\xC0?\xDE\xBB\xAF'\x87\xC3\xD2\x92\xC8\xF6\x1A\x97^\x88{\xE3E\x82\xF2\xDC"\xDA\xC2\x92\x9A\xD9\x01{\x0Cl\x07\xCF\xDFi\x82\xA5^_\xCC(8\x8D\xE3\x8DP\xDA\xD7\x95[\xE5L\xA7_-\xE0\xE3V{*\xDEb(\xA1\x16\xF5\xCDO\x01\x12\xE3\xEA\xA4C\x8D4\xA3\xECH\xE3\xA6\xE8x\\x8D\x92>\x1B\xC3\x81\x80\xAD\xF0\x14\xC7\xCC\xE8!0\xF2\xBE\xCD9I\x95\x96paz\xB9\xED#;4\x02{\xEDg\xCD\x9F\xFD$\xAA\xCD\xF2\xFB\x9E\x04\x09\x93\x1Dq\xFD\xDE}e*7\x1B\x83\xA4\x01\xA0%\xEF\xFC*\xA2Q\xEE\x16\xDE\xCD\xDE\xF4\xCE\x83\xF6\@\x0E3[)G69\x02J\xFCQS\x80Sib\x92\xF1\x1B\x10C\x1A\x9EoI_\xF7\x82\xCEc@\xA0\x95\x1C\xA8\x10\xC3\xEB5\xBF\xB7\x11\x81\x90\x04\x04\x0A\x15\xF67\xE7\xF4\xA2E\x84\x9C\x1E\xEE\x90\x92\x9E\xAAg\x93c\x1BP\xBF@\xB8\xDE\xCB\xDCv\xD2\xA3\xFF\xA9\x8D'\xFD\xE7\xC2r\xB2\xAAq\x03\x1F\xE4\xE7\xDE\x9A\xB2,\xCB\x014\x8E)d{/U\xC2\x7F\x94\x834\x9E\xEF\xAF\xCE\x8D\x13{3\xEA\x0D&\x83/\xB8\x93Rj\x91\x8D \x1D\xBF2)\xB75\x91\xE4R\xF0\x0B\x02\x82\xCF\xAC\x08\xAAFR\xF3\x88\x08\xDC\xC8\xD0\xF1\xC4#B\xBC8\x82\xC2c\x84\x12\x10!\x8A\x9El\xF0G\xEF\xB95\xF4\x143}\xC4\x9Em\xB1\xEE\x8C]\xA7\xB1C\xAF\x84\x09\x80\xBF\xF3R\x9A\xD1\xE3\x0A\x11\x1D\xD7d\x8C\xE9g\x86N\x10\x06U\xF7d!_\xC6\x80L\x06Z\xAA\x0FwG\xE9\x7F\xFA\xE6icO\x91\x07\xC5I\x95}\xCD\xB6y\x9E\xA8\xF2_\x9F\xF2\x18XuD\xB812|\xB5\xC7\xC6$\x9DX\xE98Z\xDE\xA3\xAF\x0D(%\xE4\xDC-.\xBF\xFA>0\x89\x13\x04\x90\xC0T\xFB\xC5\x9F1\xE7\x0FM-@\x88\x01\x12\x96\xBC\xA7\xC5.TD\x7F3\x83!\x95\xE2\x91\xEB#i\xB5\xEE\xDC}\xEB\xD2\x17\x015\xC4\x8D\xF3\x1F?\x88\xA5\xF1oe\xD1\xC1\xB5*\x86X\xDF\xB2k\x1D+\x01\xDB\xDEw\x89\\xAC\xCD7\xDB\xDA\x98\xB1}\xAE\xC8\x0B\xBA7c\xAC\xE1\xE6Sg\x9D\xD8\xCA9\xC3\x94\=\x92\x99N\x0FI\x14\x94\xD7\x85\xEF\xB5r\x01\x83\x17\x95)\xD3\xD2f\xEA\xE7\xC9q$5\xC43\xEEP\xB3\xD2+\x9E\x96VX\xDC@>\xE2C\xDDw\xC5\x93\xCA\x1B)\xD7\xC3\xB8/]\xBF5D\xC3s-M\xEF\x10\x91*\xC1\x9F\x10\xB2(\xEA\x1Bx7\x14H\x82}\x04\xF2{\xC6G3\x1DY\xE5\x95r\xE5f\xB6P\xAA\xFA\x0Cj\x86\x06\xC2\x06\xE9\x85 \x91\x0F\xDDa\xD7^\x97(\xB01fL\xC0w\x97y\x96g}_\xBEa\x12k\x15\x19\x94\xD0\xD4K:1\x98\xC1\x83\xFC\x1B\xFA\xEE\xA5\x9C\x82\xE9\xA5\xEC\x96\x9D\xE4\xBB\x0A\xC8\xC8x\xD8\x093\x16\xBC\xADF\x09\xFE\x99\xF32x l\x0E6!\xFA6se+\x04Z\xF0\x96@\x023309;\x84OEC;\x0C\xBA0U\xC8\x12j\x13j\x9C\x8Et\xBC\x95\x8Dz\xD9\xA9\x8D0\xB6y\x00\xAD\xC2\x8E\xD1\x14u\x9E\x0D\xD9\xDF\xB5\x1F\xC8\xD6\xA3X\xCDY\xDA\x12\x1D\x1F\xCB\xDB\x8F\xAD/]K\x80\x0B\x13cvH\x81\xBD\x96D\x1D\x9F(.\xCA\xC6\xD5\xF0\x97\xF8\xCFC\xC5rY\xCC\x86\xF1\xAE\xDA$=\xD1H\x08\xE1?\xBB\xD0\x93\x0F\xC9\xB8\xB4n\xE6\x91p~\xF5\xC9\x8E\x08LI\x12\x06\xA4\xC8\xD2-^\x8Ds\x8C6#J\xF5\x9F\xF0\xD4\xA5S\x8BjI\xA2\xA3Q?`\x99\xF1\xDC\x10\xAF\xA5Z3u\xE9\xED\xB16\x9C\xC1\xCC\x06\xD5\xA6\x91$#O\x1A#Co\xAA\xD3\xA7O\x13\x9CW\x1C\xCD\xE3\xBFo\xAC\xE0\xEF\x9B\x90\xDC\x0A\xE8x@\x14T\x90\xBB\xD7:\xED\xBF\x1C\xD6M\x8A\xB6N\xA5\x05\x03\xCFe\xB2\x85\x91\x18\x16\x0Dr\xF9\x8A\x0F\xBE\x9A\xA2\xD5\xDC\x80\x98kz\xAEqV([\xC0\xFB\x9B\xE2)\xAC%\xDESF/\xD1]\x9D\x83\xAF\xE2.\xB4\x07o\xA2[\xAAJ8\xDE\xD2\x86\x0A\xD5\xA9\x0BX\x9DG\xCF\xC9\xD9\xE2\x8Fe\xE2\x07\x14\x15\xFE\xBAmn\x18\x87Q*\x0F:\xB6\x13c\xE2J\xB8\xEA\x91\xBB{\xF8\x87Q\xA1\xEE@m9\xEF>\xCF\xF7\xE9\xE4\x03'\xCAV*#\x97\xC0L\x88\xDB\xFC\x14\xF7\xBCo\x05+]\x08\x94H\x16ir\xBD\x94\xCE\xD6\x1D\x9C\x1A\xBFh\xE4\xC4\xE9\xE2\x8C\x13w\x81g\x81\xD7\x92\xF6\x05\x0A:\xC5\xFA\x95N\xD3\xE8\x1D\xF3\x1B\xDCkw\xDEx\xB3\x87\xC75\x8F\x89\xAF\x1A\x0EyVO\xA3\xAC\xE2\x90\x02\xAC\x1Ao\xF6\x1D\xB4x\x1E\xADD\xD8<\xC9`\xD7\xBD\x9B\x85\xC9\x887\x87Q\x99\xB9|H\xAB\x9EX\xB6\xEE\x05\xB7\xF6\x0F\xB4P\x05\xEF\x82\xF3J\x16\xDB\xAA'\xE8\xE7\xE4\xDA\xF4\x1F\xF0\xD9}!L\xA3\xE7\xDBh\xAE\x84\xCE&m\xD8\x16\xBD\x0B\x83\x8F4\xBAh\xC5'\x89\xCF\x18\xBC\xE5V\x9Ai&\x89\x1C\xD5[48\xB7&\x8D\x1F\xB4\x14Yo\x82\x97\xE7x\x0F\xB7\x80EB\xD4Vh$\x0E\x98\xB4\x0F\x7F'A\xAC\xAF\x85\xCF\xBB\xBD=B(\x0E7\xEB\xF5\xCAa\x1A\xFCQ\x83\x93\x06\x14)\x95h\x99\x97\xD4\x07\x7F\xEA\xED\x88\xA2,\xEF\xD0\x8Ac\x8Cq\xE4\xCB\x16\xBAY\xDD\xE3}\x9DzK\xE5\x05\x0CX\xE9rK\xCB<\x97_\xA1~|+3F\x93]\xC8\x06\x01\xCE1k\x10\xABH\xE95r\xBB\xE0\x9C\x02A\xDB\xA6p\xFB\xB0\x896\x06pG\x9AI\xC5W\xE7\xB1\x006\x89@EJ\x8F\xD7\xA7\xB5\xA3(\x86\x7F?&\x95\xE8\xCBu\x1F\xEE\xB7\xED\x7FR\x1B\x0E\xB1E\xB3Q\xA98\xA7\xDB\xE8{ \xD6\x88?\xB3\xDD\xF4\x88\xE7\x8E!\x0D\xFA,\x1F\xB2\x8B\xB2\xD1\xB2_\xEF\xCBB\xD5A\xB0\x1D\x88\x00B\xA7uy\xCD\xF8\xFB\x13\xDDE\xA4\xC3\xE8\x90\xD0\xA2}\x93\xCF\xBD\xDF\xBC\xBB\xD0^(\xFD$J\xE3*d\xFA\xE8$\x16\xA9\x89\xEC\x09\xD1{\x06o\x94\x0FN\xB1\x10\xA5}(\x0C\x8D\xCB\xD9MA\x81\xDA@\xE9\xA5\x0A\xCF\xEB\x91\xE1\xDE\x9Fs\xD8z\x9F\xB8\xF7\xC0\xCC\x1AQ\xD1\xD0"\xB3\xD4\x82'\xE6\x04\xD089at/%\x97s\x8C\x1E\x00k|\xD9I[\x81\xFE\xAB,\x99\x7F\xABP\xE5\x8D@\xC0(\x87\xE9\x88&[\xC2,\xB6x\xC8\xD5>\xCF\x8E"{\xB1\xF2\x0F\x16\xAA\xD2;\x86\xA6\x115\xDB\xAA\xB3\xAD\xBD\xC9\x0C\x13\xF3\xC3\x19\x9C\x09\xCF\xCB{lF\xF2~\x09N\xADN\xBD\xAA]'*'\x0C\xE1\xB0\x94PuN2+\x8C7\xEC\xAE\xB5\x924\x82b\x002\xBC;\x93kt]\xC1\x1FL\xC1\x18\xEB/\x8D\x9F\x03w\x86\xB1\xA0\xA5\x05\x98\xFB\x87K\x9C\x04\xF2\x9B\xEB\xF85\x9B\x12t\xAA\xB7\xB2\xC8\x89\xFF\x81\x1C\xA1\xC3\xB3\xAA\xBA\x140\x0E\x02\x02\xAE\xBB\x18\x97+\x061\xCDS\x86\x8F\xE3\xDC\xC8o\x8Bz,\x80|\x12h\x09\xE5c\xF7\xE2\x96\x9AW\xAF\xFC\xC2\x0D\x14\xB3h\x1BG\xB1\x11\xDCQ\xDB~\xC9\xA6<=\xA0=\xF7cj3\xA5v\xBD!Gm\x85;\xE0Zm\xFF!\x97E\xF3\x95\x7F\x06\xE9R\xA9)\x1A\xE0\x0CX\x00\xD0\xFD*\xCF\x8B9\x09\xB4\xA6\x04D\xE8\x8D\x8EI\xCFE\x9E\xFF\xF2\xDA\x97K2\x98-hz\xC2k\xEB\xCE\x8E\xE5\xC6\xBDs\x07\x92\x8D\xF6\xE1}\x8DZ6?"\xE6!1\xAAvc\xAF\xFC\x03\x0Ay\xEF\xE1\x9E\xF7\xCA[\xBF\xAC$\x0C\x1F\x87\x84\xBF\xFFI\x06\x8D\xE4}\xA8\xB1*<\xD0s\xB8'Sj\x86\xF4\xCBn\xD0\xC9\x15\x86~\x0CsZ\xC9\xB0\xB0K6\xA0\xF8\xE4\xAF\xE1\xE3\xB6^\xE7\x14nH\x199\xAD`]\x87R\x02;r\x00\xA6\v4\xD0\x1FV)\xB0\x85\xA4\x10\xCE\x8B\xB4\xE9\xC9&\x86\x19\xFF\xF7:+\x09P\x85\xA5\xD0'J\xE0\x18\x17\x95\xC6D\xE5\xC0\xAEn\xA3\x8B6\xFE\x03\x15\xA26\x05\xDE\xB9\xB0$\xD6I\xEF\xACW8\x04.a\xDFz\x0FI\x11\x96\x8C\xECo\xDEx.l\xC3,\x00\x1D\x160\xC6\xA8\x18bD\xF2\xDD\x0F\x1A\x0D\xF5\x99I\xDD \x05\xFDf\xF7Q\xAF\xC9{\x9C\xD0Bo\x94\xBA\xFB\xF8\xE7\x8C\xD4'{\xA8\x12h&=\xD9\xBC\xAD\xA3Z\x91R\x83\xEF\x16OfY\x87\xBC16\xFC\xEC\x9F\xC0\x97W\xBD>\xA3\xF4\xF2\x1Ae\xB7\x98\x899\xACJ\xFD\x94\xDCu&$\x18\xCD\x84\xCAQm>\xB8\xB4$Sk\x93\x8B}\x12\xE4\x16\x7F}m\xE3\xB9\xDFQ\xD6\x11\xD7\xA2\xF1\&\x83\xC0\xF0k6\xBFC\xBFY\xF3\x80\xD5\xC3\x0A8\xFEEP;\xC7\xB6\xBF>]\xA5B\x03\x16\x94J3\xA3\x93)\x09\xD4\x92\xBF\xA0Eb\xEBy\xD9;\xB2\xB0~mNKrKe\x9E\x0BJ#\xE5\xE3\x87\x86$\x95\xC42}\xA1\xD2\xC4\xA7\xB2cPQd~\xCC3\x1Ag\x0E/\x85-\x8F\x932\xBE\x82\xEE\xF6\x7F\xA8\xFB\xB1*7\xC0\xAD\x93~\x1C\x8B\xD2\xA5\x80%t\x09\xAA\xF3h\x12m\xA93\xBE\x8C\x1A/q\xF8\x09\x93\x17V\x01)\x90\x89!\xC1\x88\xB8+\xF5\x8Bb\xF7S\x93\x0CI\xAAl\x0D\x08q\x10,\xEF\xCCQ\x01M#\xB7)\xC3\xB1\x83S\x99L\xAA\xA7S\x83q\xB7\xD7\xFF\xB3\xE8A<\xC5\x1E6\x0C\xE6\xC9q\xC8(\xAAeB\x98<\xA6M\x1A\xDDY7\xAF\x0A\x7F\xBC\x14%p\xD8N\xE0\x0D\xBE\x1B01WL\xEE{d\x87\xBB\xFFd\x86\xABNc\x91\xAB\x94\xDDQv\x11\xFF\x9D\xB1.I1(S\x06\x87\xD9k:\xB0\xD9Q\xC56\x9D\xED\xC7\x13f,ys\x82\xBC\xB5stP*\x95J\xEE\x8E\x82\x0B\xED\x1B\x9E1\xEAD\xA9\xFE\xC4gm\xDE\xD8(4\xAF\xA1k\x1D\xF0\xE9\xF5\xF9\xFF-U\x12>/{if\xFA\x17\x87Un\xF3\xC6\x82&j.\xB1\x82\xB4\xE6\x9Ey\xD1\x9C\xC2O\xD1\xFE\x09\xE3\xA3Q\xC3\xDF5U+<\xCB\xE1\xE7\xB4\x00*\xC0\x09\x11mk\x94L\xEA\xA0\xAE\x08a\x8B\xBF?\xAC\xF6YFAp\xB4?4\xE0\xC3@\xE5\x8C\xC1\xD0[\xC8\xD61\xB2\x07\x00\x87\xF9\xF4\x80\xA5-$>\x81\x01\x1Ei\xE9\xB7\xC1\x107K\x1E\xF2w\x10m;IF\xDB,mL\xA3\xF0\x08\x96-\xDD=\x1A&\xA8\xCF\xF8P\xDD$\xC1\x96\x7F!K\x12\xC5\xEF\xBF\xB7\xD9\xA8f\xF1\x14c\x87\x01K\x1F\xFD\xB3\x12\xCB0rf\xF0\xFEJT\xB0\xD4\xB4\xBB;\xBD\xFEv\xDD\xD2\x1B\xE0/V3\x04K\x01\x07\xBE\xB6yA\xDA\x1Bi\xAA2\x98rB\xE7h\xDCBH\x92\xD8\xB9l(LN\xAB\xAB\x8B\x80\xAE\x99\xF9?c\x15\xEAh\xAC\x10U\xB5\xEB\xD2\xED`\xA5q\xA4N\x99\xE4[+t\x85\x84\x8AM7\xC9\xEC\xA8\x9E^X\xEF\xF7\xF9\x0Bh\x9C\xCE?z\xE1oA\xDE\xF8\xAFF\xCC\x94\x14\xD3RK\x14\x0B;\xC3\x01=\xDCCs\xA3r\xF4C\xE1H\xC3]6\xC5?\x1Av\x93\xE1\x95\x02\xE6*/\xA0\xF4?\x1C\x8F\xE9X\xC8T%\D\xBDK\x00\x92\xE1\x0B\xCFg\xAF\xFA\xF9\x8C\xFDPx\x93\xFC\x0BY\xB6\xE8\x90\xEC\x9B\x8F\xFC/)\x89\xD0\x9Ee\xEAujxjUq\x98\xBE\x13\xF1^=\xC3\xE8\x0FU\x02c\xFE\xF8\x9D\xE5\xC6\x9F\xFD\x9CF\x14B\xC7\x17\x9E\xFE\xA1/\xC5\x1D\xDC}\x01\x00\xD9\xF1\x9C\xB0E>Q1\xFEf\x83h\x95\xA75\xD1h0\xD1\xE2\xD9\xC1\xA7\x82[agQ\x19\xA4\x90V/\xB0\xF4i\x8D\xDA{\x93O\x7Fk\xA9\xDFmr\x91\xB7I\xD1\xE7\xE5\x8Cp\xD1J*W>\x0A\xFB=\xF1\x90\x98\xE4h\xA0\xA0Q?\xBF\x918\x1F\xEA\xE9\xE2\xC2\xDC\xCAR\xBB:\xEA\xEF\x14l\x9AEB\xD9X\xDD\xDC\xFA\xBA\xB2\xC1\x9E\xD0\xFD\xC9-\x17X\xF3R\x12\xD00\xCC>\x07\x1E\x9C\x0C\xB0S\x197y1\x18\xF1\x1C\xDA`\xBEy\x82U\xB0&\x95\xE7>0\x954\x81\x1F\xD3\x9E\x05\xAA\xBAUj\xE2~\xB7x\x88\xC0\xFB\xE4\xED\xF0\xE4[\xA7Y\xAE\x09\xCAYbk\x02\xF5\xE1\xF6\xC3_m\xD3\xE6%\xAC@\x84~:K\xE4z#\xB0|\xD8)\xE0\xCA\x1DE\xA8)\x82I\xB2\x9DH\xF9\xD1\xBDi\x94.\x90\x84.\x0B\x93\xED{\x902\x10\x05\xBA\xB95\xF0\xAF\xB3\x10`\xDF\xC7$\x9E_\xE1\xC3F\x99\xAB/P\xF3%R\xD9\x0FQxd\x9Bx\x02a\xCAq\xF2l\xBC\xDF\xF7\x88\x01t\xB2\xB7q\x0F\xEF\xF3y\xEA{\x80\xD1\xAB\x01\xD0\xD4\x99\x0E4\xB6\x15\xFF\x1D\x8B\xF6.\x8D\x12:d\xEE\xE9f\xA9\xC2\x1A\xEF\x84\xAB\xBEF8O\xCC\xCFr\xB0\xA5F\\xC9\x9C\x8Dl\x87\x0EW\x90\xAAN)\xC3\x85to\xDF\xF2@\xBF\x02\xADZ<\x97f\xBC`u(\x10\xA39\xA5\x00#\xF72G(\xED\x08"\xEE\x12\xA0\x02/5\xFF\xFF\xF8SFd\xC7\xF4]\xCB\x14\xD5\x82h\xF1\x05\x8B\x04B&\xC0\x8F\xDD\x9A\xD4\xD3QTD\xF9e\xC4\xA4%\xE2C\xCD\x96\xC4\xD0\x06\xFB\x9F\xA7VF\xFF\x1D\x0B\xC2\xBAD< \xB1\xDD>\xBC\xA4\x13,BP\xDB\xDF\xB5\xEF\x9E\xFD\xCE\xE1\x84M\x9E\x1A\xD7`\x04\xCA\xE0\xF8\xC7\xCB%4\x9C\x1C=\xC4\xC9\x0C\xA3\xAF\xCA\x11WAe\xF8-\x94\x8D\x1E\x98s\xDC\xB7"\xD5A3\xF4\xC9\x93\xFC\x90d\x87\xE1\xBE\x9E\xFD#\xE0H\x023/G\x1F7\xF5\x19{\xDC\xD1\x830\xCC\x0F!`\xC5\xBB \x1A\xC8^\x89\xC8\xA1J\xE4\xEC\xE6\x9E\x94`-D\xE7\x84\x1Da\x16\xE1\x7Fn\x02\xEB#\x850\x08\x883PF\x17\x90\x02,\x08\xB8\xD7A\xF3\x13\xE4\xDC\x07\xC3\x8Bd\xF6JJ-\xA0\x17\x06\xB0\xA9\x0A\xC1\xA5\xE4\xA0{r\x8B\xEA\xE5\xE3\x80I\x81:\x16\xD8\x80t\x03\xB0\x98GX\xFF(r\xC8\x81\x18\xF6\\xE75\xE6\x9A\xCB\x10\xF0\x98\xE3\x9A\x01\x82\x95\xB9'+_\xBF\xA8Wj2\xE7g\xB0\x7F\xE5\xC7\xD1w\x8A\x98\x97\xAC=\xC5\xB0\xBF\x85q\xE4M\xFEc p\xEEI\xFC\xDC\xFE\xFE:e\xB4\xEA\xFD\x1Ea\x92+\x94\x0A\xA9U\xC6b\xED\xE1\xBE\xE8\xBE0_7\xCA(\x1D\x8AE\xCDo\x7F\x93@\xFEO)}e\xE4\xB0\x0C\xEFj\xB3\xAE\xB8\xD00\x02 F-\xFApk\x9Bh\xFC\x87z'\xE08;J^\x0F\xA2j\xBD\x10BT\xD4s\xEB]\xBCGu\x134\xC1\xC5j\xDF>\x8A\xCC\xE4\x88\xED_\xFC\xBB\xA4sO\x7F\x8B\xEFz\xAB\x8A\x1A\xBF?\x1A\xE8\xDEH\xAD\x85\x83\xEC\x18\xB0<\xB9-dO\xC2\xB9\x089\x9B\x13\x94n\xDD&\xA5\x0B\x1F\x16\xBA\x9E\xBFt\xB1\x90\x9C,:\xAAP9Q\xE2\xC8\xA9\x0Cf~\xCF\xFD\x98\xF3|\xD2\x09\x9D\xE2?\x13\xFAf\xAC\x9A5\xC2\x87\x06\xCE\x0C\xED{\xEB\x85Y\xC8\xBB\xE7\x97\xC0\x9B\x02\xDB\x89\xE0\xB3\xF0m\xE5L\x8C\xE4o7\x1Cf\xBA\xD2\xDA\xAA\xAC\xA1\xB61\xACD"\x9A\xC5^r\xCD\x09i\xB5:\x02\xA6\x1F|\x0E\xD6'\xC1\xD4IO\xAE\xB9E\x1Dh\xCA\xFD\x96\x05\xF8\x0C\xC5o\x80l\x09\xC1O\x092\x14\xFF\xA7n\x0A)c\x9Fm"\xC9I\xB1r\xA0\x07\x8B\xFE\x86=\x8D(\x02\x81\xAAh=tM\x05\xD9S\x02\x01\xD2'\x01x\xB0\xDD\xF2x9M\x94x\xB4\xB7X\xE5\x9A~Y\x09\xDE\x9C1[E!R[\x0B\x9B13l\xAB_\xF0\x83\x13\xD9\x99\xF8\x14\xA43V\xE69]C)\xDCZ\xCB\x8F\xB4\x1FH\x8A)\x91\xAFO\xBAGk\x9CS\xBE\xAF\x83\xC3iN\xF2B_c\xAD\x89\x09\xFB.ZQ\x10{\xA6\xDC\xF109}\x9F\x11v\xF3\xFCoU\xBF\xE4\xDC\x17s\x0D*\xEB\x8C\x19\x98\xAB\xD0\x81O\xBC\x17\x89>^\x9E\xFFe\xEE\x08\xBE\x07\xE5o$\xB2\xCD\x06U\x0BGf\xC35V\x9C\xBC\xF7\x09^\xC1\xBAdG\xF2\xB1%\xD4\xF7\x9C`\xB1\x85H\x99\xF8f\x91\x1EZ&\xAC`\x93y\xCA\x8BG\x8D\xB6\x02\xA2\xC1Z\xCCs\x03\xCD\x09\xD4rNh\x08\xE7U\x18Q\x88\x83\x0D\xB5\xB4\x8C\xD5q\x05\xC7U\x9A\x0F#\x96N\xAD\xB7\x8E\x9FY\xC8\xECU\xF3\xAA\x174w\xC6\x83=W\x15q\xC6\xA4\xDF\xB0\x1A\xE9kXs\xA1m\xE0[\xE6\xA7\xB7\xC41\x81\xB2\xF3N\xA0(n\xEEu\xA3\x06\x8A7\xB7p\xC6\x11\x1B\xCB\xC3~\xD8\x07a\xD2\x03\x82*>\x9AN\xF3\xA9^\xAE\xA6\xF3!\x84\xF6\xD6\x1C\xF9\xAA\x9API\xC7h\xAChR;\x0B]c\xA9.\xC3\xC7\xA74\x9F\x8A\x91\xA3k\xEFq\xABWI@\xBC\xE8\x14\xECM\x1C\xB5\xD5\xF0\xF5\xFF3\xA6\xD1:\xD7\xD5\xE2\xE0\xEC(\x8A\x93\x8B\xAFr\x0Ay\xC7]\x1FO\xB6\xA6\xFF\x05\x84gP\xA5\x81\x1E\x06\x84G\x92\xCDW\x11\xE5\xC1\xC4\x9E\xD8SC\xFE\xEEm[n\x1F\xEE\xB8\xB0\x8F\x9Cd\\xDE.\xF8D\xB0\x1D\xF58#|\xDDE\x98D\xF0\xF6\xC6\x85\x83\x92p]`V\xBCv&3\xFDBr\x0F\xE6\xAD,\xB6\x1E\xBF\xFA\x02\xDD\x97\xBE\xEB\x09E\xCC\x14\x85\xF2l)\xABP\x0C&\x0E'\xB9\xDC\xD5\xBD\xBB4P\xC7\xDF\xBA\xE3E\xF7BeK\xCAH\x91\x01\x88\xB2\xEC\x17N\x07\xE5\xA6\xB7e\xDCD\xFB:\x0C[\x18\x83\x0B\x9B\x04UCM\xD0y^\w\xEC\xAD\xC4\x1C\xD8\xFB\xFBX<\xF4\x91\xE7A\xB5\xE8W\xC2\xF4Z\xA3\x8BruB\xB3\xDDc\xCC=HrY\xD5\x15\x9B\xBD\x9FR\x010\xBE\x11\xA6\xBAl\xD5N\xCF\xC0\xE0\xBDa\x94\x8B\x18\x1A\xDA\xD3\x88\xDDo}\x88\xD9\xEC\x9CH\x90\xB7\xEC\xB1\xD3s\xC2\xFC\x13\xD1\x10\x01\xD6\xC74\xB7\xB9\xD3\x1A\x1B\xA2\x00PJ\xF6q$\xBD\x17\xA3V\x9F_\xE0\xC7\x01\x11\x8C\\x16\x1AgOf\xD5&z\xD2\xF8\x98"S\x04\xCFy\x98\x93\xC3T1e\x914\x00\x18\x1Enf\x0C$q\xBD\xB9\x18 \x00\xA955\xCA\xCE\x04\x10\x84\xFD\xECC2.\xAE\xA3h\xC9\xEC\xE6rNxe6\xBD=T\x86 \xB6\x13\x1D#oJ\x96\xD0Q\x96\xC3^\xE0\xECo\xCB\x01\xEAg\x7F\xC8h-\xB6J\xA7\xB1o\x06=\xD2A\xFA\xD1*\x87[\xFCf\xF4\xACz\xA6\x8F;M\x10m\xE1T;u(\xE2F\xAC%\x81VBm\xB8\xF2T\x9F\x1A\x7F\x0DK\xCC\x18\x17\x9E\xD2l\x07\x1CMw\x9E\x9F\x13\xBC\xCE\xE3\xC9\\xAC>\x81p\xA9\x09h'U\x83$cd\xE0\xC7,z\x00w\x13\xD5\xF8\x1A}\xEB\xAA4f`Wq$\xD9pP!\xECQG\xB5\x81\xDC\x0Ci*k\x0DxA\x8B\xADf\x1A\xC1\xFD\x86f\x8A\x83\xCF5\xE8c>y\xCD\x9B}\xA7!\xF1C\xDD}H\x97u\x12\x91\x8C\xF3\xE9J\xF0\x8DJ\xDC##\xEAy\xD8\x0EVD$v\xBCo\xBAI\x90\x9F\x02\xAF+I\xC2M\xCFlT\xFDd\xCF\xE1\xF5\x0F\xD4\xCF\xBB\xB7\x95\x00\xDB\xDD\x11\xB5\xDF\xAC\xA6\xD1\x96\x17\xE0\xD3\x03\x00\xC9\x80/7Ex/\x1A@\xE9\xB3?y\xD3\xCCN\xA6_D,\xFF\xB6eUMv&\x0A6\xE4'\xDFm\x83\x8C\x16\x8D\xF0=\xC5\xBE55\x1A\x9Alv\xB5\xE2\xA5# E\xA1\xDE\x84\x1E\xAC\xE4Y%\x9D/\xFC\xB6\xBCG\xDB\xB1\x90?\x18"\xCF\x84\xA0\x9F\x8F\xDF\xE8\xDA,\x08]\x9B#\xC6\x82x\xD7\x8F\xAE_\xDBrmf\xB2;\xCFzr1\xA4\x10\xCA\xB7\x92\xE5\x99\xB09\x96\x93\xB4\xAD@,\xB9\xFFm\xA5<\xCC\x0D\xAC\x0A\xD1\xD8\x85\xB3"%\xE7tQ`\xD0}\xBE\xA3>\x97\xB8p\x98\x9E6\xBD\xA0\xFA\x95\xD4\xBD\xD2Io\x9AX\x01\xFD\xBC\xF0\xC6\x06\xFBKh\xBC\xEB\x98\x9DB\xD1\xC3\xB2\x89\xE3qx\xC8\x98\xF0\xD9r\xCB\x8C\x97J\xC4\x7F\xD9\xDD\x99\xA7\x18\xC2\xA7_)\xD4~\D5\xD1k>\xD5<\x8C"\xFD\xAD\xA3\xFA\xAF\x08{U\xE7\x80\xE4\x09\xF0\xDA\x80ZT\x88<\xF6\x93\xDF4\xA0\xB2DG\xD7"9\x80\xB5D\xDEC\xF2f)\x02\xFA\x8Cc\xB4\xFC\x95\x12\x98\xFF\x88A\xD2\x09+\x13\x1E\x06\xE8\x00\x15\x0B\xAB\xC1\x96\xF5$\x92\xA2F\xBF,X\xC8\xBF\xC7^\xCA\x8B`\x00\xC6\x9B\xD8\xF4\xC0\xDF\xC2*\x11\x7Fw\x166\xF6\xF9G-Y\x93\xB5Y-\\x09\x17\xB6\xE2\x15>-<;\xA1\x13\xE1\xDCr\xF4\x9E\xFE\xD0\x90\x02\x8EO.\xF0\xC2?a#\x16J\xFC~u\xE6\xBF\x8AO\xEA\xC7*\xC4t \xC2\xA5\xD9\x1E\x0BUH`\xF1G\xC6-4i\x8B\xF0\xEC\x85c\x03\x14P\xC7\x9A\x82HMk\xB1\x86\x9E\x05S\xD0\x0AT\x1E{;v\xC9\x0Em\xDD\xE9T\x9Cf>b\x1Fi5!\x11\xEC\x1B\x80\x05\xE9\x8DbQ[\xB5\xC0\xFF\xEA\xB5\xD3N\xF8H5w\xB3+\xCC\xAE\xBB\xD65\xB5\x95\xA4\xC3h[q9\x16\xF7F\xAD\xBF0\xA3=\xAEW\x9ARuU\xB8\x10\x85e\x9A\xD1\x01\x8B\x91';\xB7^\xE6\x96\x07N\xFA;\xA6o\xAF\x15Y^\xF5\xB0\x00z\x01\xAF\xA1\x02x\xC0\x1F\xC7\x95\xF9$j\x86Vy\x04\x8E\xAEO\x15\x0FQ\x9E\x8E%Dm\x0D\xF6\x7F\xF1\xCC~\x17;\xDDK\x09\xD3\xBD\xFF\x11\xD3\xA0E|\xD2Q\x93\x83*\xA3\x06\xC2\xD2u\xBF\x9AL\x9A69k\x8A{D\x92\x00\xE91lU)\xA1\xB7Hy\xC1\x08\xDD q\x86*3\x12\xA1\xFB\xA32&\x15\x0B\xF9\x95\xF7>\xF4/\x15\xB9K\x06\x14\xE3i\xF3'\xDD;PV5pk\x8C-p\x8Br\xE8(U6\xB3\xC2\xD4\xBC \x0CR\x81\xA2\x03je-\xFE\xFA\x9EO\xF2\xA4\x8B%~\xD9\x7FOZ\x01\xF1\x1C\xA9\x99\xD8\xCE\xF8}\xDD\x0E\xE7\xB9\xB4\x92\x0El\x9A\xC0\xF1E?Q]\xC2\x86\x18S\x9D'8S\xE8v\xBF\xC7x,\xDFe\xFA#\x0B\xF4\x85\xE9\xFB\xA5\xFC\xA7\x86\xDC\xC1\xD4\x89wZ5\x8Ah\x95`K\xA6\xD6B\xC5,\xCD\xF4\xCE\xD4\x8C\x12\xAC\xA40\x92Q\x14\xFA\xE4\x1E-\xB3\xE8A^\xEE-\xCAO!(0<25\x18\x8E\xD2Sh9Do\x9A\xAB\x0E\xD6\x8DQ\x18\x16Y\xCB\xED/\xE7\x81\xEAM|X\xB5\xF7Q\x7F\xA5\xF3\x14\xFA5\x8F\xDEh\xDA\x0F\x14\x8B\xE6\x8E\xAD\xAFo\xEF\xC0\x8A\x8F\xE9\x8Ef\xE8\x1F\x18\x87\xCC\xD7^P\x9C\x9B\x0A\xF2\xF4\xB8Bb\x81\xA0js{31\x97\x84\xD3\x0Bm\xA6\xEEl\xF473i\xDB\xB29\xC9\x0A\xBB6\xBDT\x15Z\x0D'\xE1\xBE\x83q%\xFC\xA0S\xDA\xFF\xAB\xB4l\x16ZX\x12\xD0\x0E\xE7\xE1\K\x99\x81\xD0\xE7\x18\x80\x13\x9C#\xC8\xE8X\xED\xD0W\x01\xF0b\x87A\xC7\x04\x9EWt\x18\xBE\xFC\xB3\xE9!]\x9A\x8C\x00\xB5\xD7\x88\xA8\xAE'Plwx\xFFxb#^s$\xE0\xDEu\x05\xE0\xFE$\xFA\xFA\x1F\xB2\xC0\x94&\xF9G'\xEC\x0D\xE8\xEEy\xBD\x80\xEC\xA3[UMy#\xE0\x922\xB2*y\x89\xE9#\xAA\x8FP\xF6;\x1B\xAE1\xC5N\xE7Q9\x81S\xAB\xD9\xF3%n\x82B\x8E\xB2\x1D6\xDF1\x848Kh\xBB\xE2\xFD\xC6\xC4\xFEs\xFD\x90\x87T\xD6skvAE\x88/\xC6\xA8@S\x0D\x8C\xFD\xA4\xA7\I\xF1\x0C[@V\xBCI[\x8C\xA7V>\x0F\xC7\xF0\x923\x1F\xB8gK{\xA4B\xA8\x17\xA9+\xFA\xBE\xB5\xEC\x07&^Y5\xA6?vo\x1Fi\xA9\xA0X\xB00\x066\x9D\xD3*.\x94\xB7\x0B,\xC2\xDE\x1F\xCDj\xD4\x88"\x09\x1D:\x18\xFA\x9FH\xCB\x0Ct\xE6!\xB9&\x9F\x0D\xF0\xF2\xCF\x83\x1D"NZ9\x83\xC4\xCD\xDFzL@&\xD08\xE9??\x06\x02\xB2\x175\x9F\x00\x8D\x9D=;\xB4\x10\xA4\xC9\xF8\xF4\xE4\xE7u\xF6\xDE\xF1\xC5\x0B\x14l\x80\x07\xB4\xEF\x0A\x93\x92\xFF1%\xB1\xE3\xC2\xF7\xF4\xE6\x80\x1B\xBFq\x851\xC0P\xA0\x02\xC0w\xE7\x0B\x044\x0E\xD6X\xB4#J:\xAD\xA1\x80\x1B/\x07Ks\xD7\x9B\xC8\x83\xBB\x95\xA6\x19\xA3x\xF6ZR\x9D\xC8\xCD\x80Fpx\xC9\xFF{1.t\xD3\x06\xB8\xD8E\x90[ED\xA7\xA5\x0E\x00\xCD\x8C\x0F@7\x0D3\x93\xFFT\xC7]\xFC\xCFZ\xE6\x9E+\xEE\xDB~\x84\xA1\xE75k\xFEFd$\xB5\xEF\xEF\xDC\x15\xD2\x04\x0F\xE7\xC6|Y\xA8\xD0\x8E\xB2\x9BU\x1D\xCF8t\xF3\x83n^\xDF5\x85\xA2\xF6\xCD\xBDzF\xF6\x03E\x14Z\x95\xE5\xFD\xD3!\xB9\x1E\x9AbB@\xDD}\x97\xB8\xD7\xB5\xE1\x1F\x01ec\x1E\x97\xF5\xA3\xCD\x11\xCD\xA9\xDC\xDC\xC9\xA9\x8D\xED\xAB!_\xF20"\x0C\xA0|\xD3\x87\xABm\x07\x1DW3(\xA3\x9F\x95f1Q\xC8%wR\x9C\xDD\x0CIP,G~]Nx\xA1\xE1\xCE\xFC\x9D\xF5\xB6\x10\x85\xD4\x98\xCC\x0E\x14\xA6V\xA1\xB9\xFA"\xB3\xF7\x8F\xAD\xE9'\xA7\x93|\xC6\xD8\xF15\xEB\x8B\x15\xB9\x94\x0B\xC7ia\x19\xE7\xFF\x83/\xD2l$Q\xC14/\x14xi?3A\xDC\xF3a\xD9\xD6$\xB6\xB8\xFA\x8D.#\x94\x88\xED\xC6~V)q\x1ER\xF6Y\xDB\x02\x12\xC9\x7F[f\x13\x81\x9B\x08\x03MC\x99-m\x0Do\x9A\xB1\x84\x02=\x94\x8EV\xAFs\xB6B\x94\x99u\xCE\xCF\xD7W%\x13\x98\xB9\xD69\xABkV\xA0\xCFo\xA4\xB6L\x02\x7F\xA5b\xBAbA\x9F\x9B\x88@\x01\x17\xC0\x0E7\x1A\xB2\x0A\xFC\xAE\xA4\xB7\x18o\x8C\xA1\xCE\xA65\x94\xDB\x8E\x09\RC\x04\x8C;@\xBE\xD0\x83\xA2s\xDD\xF3S\x8D\x07\xAA\x17G\xADk\xC5\xEE\xA3\xCC\xBB\xF6f\x1EkoCN\xE7",\x0D\xD1\x91\xD9B\x16\xC0\xE9\xBB\x8BY\xDEEK\x00\xC0\x93P6\x80:\xB3k\xF1\xCD\xDA\xF6>\x10mXo\x95\xE8\xB8\x96p\xA3K\xB0\xAA)b\xA6\xAE\xB9\x9A\x89\xD42n\xF3\x7FR\xE6\x10\x9AK1\xB8}\xE5\x11\xD8t~\x18e@\x1Am\x07\xB0\x7FF:\xA3\x95E\x14\xD0A\xDE\x1Ct\x8Ab/x\xED\x92\x1C\x14\x0CP\x9C\x9DpUHg\xB3\x87\x95F\x08\x8E\xB9v\x7FIca\xE0\xBB\x00f\x88\xFB\xD0A\x96n]e\x98\x85(V\x10ye,Y\x19UzU\x98\x07\xD5!\xEF\xE9FIY\x07\xB5\xAFQ\x0A\xA3\x0A6o\xA4\x92Z\x99\x0B]\x98\x87\x09\xD2\xD5\x18?jpJ\x97\xF2}\x10\x9D\x94\xC2|\xF9\xFD?\x05Y\x06\x08\xCBA\xFD+B\xF4\xD6\xD7\x9A\xDBnS\x01\x17x\x88m\xA8\x89\x0D\xB3(\x02\x97\x11\xBD\x9B\xCD\x7F\xC0\x9D\xA6\xEF\x97e\xF7*\x82\x13\xB92\xA3\x1E\x00\x07\x09;H\xA0\xF9?\x00\xA4qRtX\xC3\x9B^J\xB4\xD2\xE9\xDC\xA7-\x02\x8B\xA5}Z\x05\xD5\x09Pv\xE7m\xA5\xD6\x86\x08b'\xAD8yK\xE2*\xC5\xCB\xBBv\xA3\x96\xE5\xA0\xF4T\xDF\xEB4l:\x17Yn\xE6\x10\xB3Ek\xB5\x12ux/;\xC4j\xB2\xFA}\x89\xB4\xB2\xA8\x14&Q\xA8#\xF6\xED\xE7a\xFCXc\x82|1\xEA\x05\x1B\x97;c:\x0B\x06!\xAF\xF6l\xC9\xDA\xB6\x9D4 (]\x8C5\x09\x96\x9F\xBB\xF5\x9B\xB6z\xAE\x02.\xC3\xA8\x18J^\x8C2\xC5>O\xBB?Bj\x88}P\xA9~\xDB\xD7\x9D\xC0\x9D\xB1b\xB3\x83\xE0\xB1\x92w" "\x81\xDAm\xD3+\xA6\x0D\x1E7i/}l\xCB\xBB\xCA\xCD0\xB9P}\x94\xF6\x1B\xC6a\xC8\xE1\x87\x81\xA1b\xCEl\x92S\xE6Qg`?\x9E\xC3\x16\xE0\xD2\x152=3\xC2S\x86\x06)\x95\\x99\xFB\xF9y\x0C\x89S4*\x0D\x83{\x13\xDA\xDF;\xD4[\xEFD'f_\x13\xFC\x04{h\x9E`\xBA\x9E\x7Fk)S\xBA\xEEg\x8C\xB6#\x170\x9D\x80\x0B\xC2y\xA9)\xD2\xA1\x00)\x0C\xD9\x88\x9F\x0B\x87tu#\xC9J\x85\x87\xFE>\x82\xF1\xE4\xF4(_~R\xEA\xC7mf\xEB\xD5)(!Huv9\xF0\x18G\x85\xD7\xE7td\x8Ev\xD1}\xFA\x0Az\xB0b"i\x97\xA2k\x10\xDC\x11W\x80\x08\xAF\x15\x9F\xE6\x1F\x0Fi\xFFc\xA81\xE1\x86\x05\x1B\xA4\xC4\x90X\x11\x0C\x94Q\xBFT\x88m\xAB'SiV"\x0F)\xEA\xAD9G\xCB\xE4\xA5\x7F\\xEC\x0F\x959\xCE\x87`\x8F\xAC\x07\xE9"-\x9BL\x88\x15\xCC\x08\xB4\x7F\xE0\x00\xA9\xC7\xCF\xFE"\xEF\x0Dl\xF6Z\xC97\xEF\xA0R\xA4\xD1\xADm@\x18\xB5\xAB\xB5\xA8\xC2\x09\x8B\x82s\x9Aq/U\xC3\x96\x16\xE8n\x93\x18d\xC6qoL\xA7\xCCd\xBA\x8F\x89\x09\xEF\xBEg\xC4\x9Bx\xB7R\x1B\x7F2\xA9)\xB8\x06\x0A\xAB\x8A\xE4\xECrD\xDB\xD6\xB0v\xAB8vz\x1E\xF4\xE4\x9D\x12\x9A?;Lkx\x03K\xEA\xC3\x80&6\x80g#\xE2\xC0\xD9\x7F5\x99\x82\x17!\xC75J\xE9\x86o4k;\x95\xB4G\xB2\x9Ci\xE7\x9EB[$c\x19x-Z\x7F}\x10\xA6\xAC\xC9W\xAD\x0D\x98\x8F\xD9?\xE4{\xD7@\x96\x15)\x03\xAD;\x12\xA4\x996\x99\xFD\x89D2'\xE4\xE0\x07HL\xF6\xAB\xED\x14\x9Ft\xCE\x1B\x95\xF3\x01b7X\xD5j\xA4\xC2\xA5\x1E\x1D\x98bEaHP5\x91\x09\xF8\x0B\x7F\xC1\x90\x1CfQ>D\x84\xF3\x07\x8C\xC5\x88\xC41\x84\xA2\x09\x13c<\xD6n\x05\xDCJ\x9F\x04k\xE5@U\xF0\x87\x02G\xE9\x80\xE2\x9B\xBB\xF0P\x09T\xB5 a\x82i'\xE3O\x94\x94r\xB1\x1E\x14\x8E\x8BT\xB6AWY%7\xA4\x96A.\xBD~\xF4\x01\xF6}\xAFe1_\x19K`\xCF\xC30fE\xA8wd\xE6m\xEF\xD99\xC0@\x97\xFE\xE1\x17\x13T7\xE1o,1\xDE-`\xFC\xA1\xE5\xCD\xA4\x89\xD5\xAA9}S\x0E\xBBoY#\x1E\xFE\x92\xEFF2\xAEDY\x8Ez\xFE\xAA\xBF\xE5.\x13\xBB\xB8\x15F\x0C\x8D\xA5;N\xB5\x86\xBA\xB4|I\xA7%\x824s\xE1\x91\x11^#Iu\x16\x1E\x87\x03\x01\xC5\xD9\x1F\xEC\x0DQ\xD9\xA8\x11P\xCE\xF8\x18\x09/\xA0\xF9\x17\xC6\x08\x88 \x9Frp\x1B/\xC8\xB4`\xCE\x1B\xBF\x86N\xB0#\xB15\x88\xDE\x8D\xF8\xB1\xD6\xCA\xDDW\xD4\xCE{\x87\x12x\xF8@v\xA0p\x80`\xD25\xB3\xFD\xA1\x1F\x97\xAA\xAC\x82&A\x87ZT\x8F\x0D\x03\xF1\xA36n\x98j\xDE\xB1\xB9\xEC(\x88\x9D\xA4\xCD12\xA5h\xD5\x0A?g-"\xBB\xDD\xDE\xD6\xC6\xA4\xF2\xE7i\x93\xE4\xAC\x03>|Y\xBD\xA9t\x03&\xE6f\x1B4y\x0FUG\xEDF\xABAf\x0A\x03d\x84\xD2\xF5\xBB\xCB\xE7xQ\xB2\xFB9\x88\x8Ez\x8F1\xF2\xA2\x02\xFA)\x0E\xC7g\x08\xE7\xE5\xBB\xA3\xFB\x094\xE9p\xF7C\xA7\xD4\xFAN$3M\x1F\\x90Y1;\x1D\xD0\x99/\x9A\xBD\x0D$e1\x86\x11\xEF\x9Ah\x11\x87\x0C>]\x87\xD2\xF6\xF6\x16\xFB\x08#\xCD\x98;>\\xCC\x8A\x93\xCA\x92\xE6A\x193\xF3=\x129\x12\x85j:\xFDr\xFA\xA3\xCB\xC3\x18\xF9\xFF\xC1B\xBB\x82\xFC\xE2-\x98\xFA"\xDDf\xFE\x96\xE7\xC6\xB4\xAF\xBD\xAC\xEEn{h\xEAr"Q'\xBE\x9Br\xF8\xED$\xE3\xDB\x07$b;\xC4\x10C\xA5\x94\xA9\xB7\xB9\xFD\xCA\x91\x83zJv\xC0\x93*\x93\x9D\x94\x12\x03I\xA6\x14Z\x17\x97\xA4\xDDD\xA9\xB4\xFAU\xF0\x11\xF4\xD2\x19s\x81\xFC\x8Eh\xB6\xBB\xF2\x02\x9Cn\x14\xF7\x0A\xAC7a\x8B\xBF"\x94\xD0T*\xE3I8\x85\xD0\x9D#\xFB}!\x1EI\xD0\xC9\x8A\x08t\xFF\xAADW\x11\x12\x10\x1C:K";W~@\xBA\xB3\xC0\xC2!G\x96e\x88y\xD1\x98\x89\xE52\x96\xE9P82\xEDV\xB6*\xAA\xD3\xB7C\a\x80C\xB5\x00\x058Qz\xD7'\xADt\xCC3VT\xCE\xD98\xA9\xED\x8B\x84LA#\x8F\xE39\x90\xAA2\xEC\x1B\xA7\xB9 \x85\xCD3 .\x89c\xCA\x84\xFD\xF3\x9A,\xF8&\xC0\xF5\xA7\x1A\xBB\x9A\xF9\x9C}F\xD0\xE2\x9B#1\xB0\xA9d\xAEc\xD032{T\x19U\xB4X\xE4\x8Di\xFF\xE4\x8F\x1ANX\x1BUw\x8C\xB1\xDBx. v4\xBF1m\xD9\x1D'R\x1A\xD0\x00\x1C\xF8\x91=\x17\xA2\x17\xF5[\xD9\xCFz\x08\xC4Z\x18^\x92u\x0E\xE4\xE8\xFA\xA0\xAC\xF8GXf\xDAIL\xC5\x98\xF7\x83X\xA2\xF8\xD8 S\xF8\xB6\xD3\x99C\x81\xFF\x83^\x06\x93&\xF9C\xEB\xC1N%\x96\xDA^m\xDD\xD7O\x03[j\x83\x8E_\xFB\x9B\xA9wH\xF7R%,Y\xA7c9t\x83\xEBy \x95\xA6\xF0\x9A\xF5\xA6n\xC0\x1A\xD0PxNC^\x8Co\xDCI\xA8d\x8B\xB2M{\xF8\x1D\xAF \xE0\xC0^\x1C\xC0\x1A\x027\xF4 \x12\x05l%\xF4i\xAB&d\xA1\x8B\xE2\xB0Y\xC2\xDET\xC08V\xA9t\xF4\x0C[\xFD\xEE\xA7\x9F\xE6\xB2\xFB\x07\x04h\xCD\xBC\xBE\xA9\xC0\xC0\xF22R\x1C\x03\xAD\xBE\xB4\xE7\xCE\xCDH\xFD\xC3\xF47\xAC\xA1\xF0\xA1U]\xE3\xEF\xAE\x03\xF0\xD4h\x03\xCC\x1D\x81$\x94\xF5\xA9\x03\x9D[p\xAA\xCE+\x1B\xDEI\xF9\xA8-\x9F\x040\x87rF\xF4\xFB\xB2(\xCD\xB5^\xBCV\xD6\xAF}\xDF\xD0GS\x90\x7F\x05\x15\xC7H\x03\x8D\xF0J\x88\x0B\xCEU(\x88\xBF\x18\x87e\x01l\x17@\x09d\x99\xAB2\xF4\xA6\xE6UD\x96#2\xFC\xF7\x16}\x95\x13\x10\xCC\x02\xE7\x89}\xA2\x04OE\x0D\x00\xEC\xE6\x0A\xA2\x97\xF4\xA2\xA2s\x86\xB4@I\xB8di\x09M\x0D4c\xCAZ\xC2\xF2\xEA\xE5\xD7"\xBA,@\xA9\xD8\xAAx\xB4\x07\xE3Y#\x86\xCE\x94\xB0H\xE3]\xD4\x0F\x96\xF0E\xED?\x1E\xB1\xB1\xB4\xBD\xDD\xC4\x95\x9FA\xFAL\xBA\xF7\x8F\x11\xA9\x02\x01U7\x05lM\xCB5\xE6y|:\xF3(\x1D\x85[\xE4\x8Fs\x90\xC7\xD8w\xED\x9A\x12T<\\x005\xE3P6\xD0\j\x91t\x9B\xE2\xDF/~\x9D^\xFA\x08\xCCaL\xF5t\xBB\xE7\x17`\xEC&\xCCH\x8A;k\x8BmZ:wD\x10\a0Jz\xBC\x0Dk-\xCB\xAC\x98\xA3\x03\x1F\xD8N\x12\xB2{e-\xA2\x8A\xC6\x15\xFB\xC6:\xA4\xC7\xAF5jYIc\xB7?\xE6I\xC2\x8CN\xCE\x0E\xA5h\xEFF\x9EFK\xB6\x9A\xE7\xB5\xC1\xC3W\xE5\x96\xB7X\x9B\xD5t\xD0\x87T\xA2\x13B\x96\x0C\xE2\xBC\xE4K\xC5\x045\x1C\xF9\x84b\xD4H,\xA5\x07\x0E\xCA\xE7\xA49\xC0^\xB3\x0FPlzno\xB0\x82\x0A\x9A\x08\xD1I\xE9?\xB8\x11\x13\x07$2\xB8\x9D\x06\x19\xE0\xA1\x1E\x91\xDA&\xD5\x92\xFBl\xF2q\x08|\xFD&\x8E\xB0\xE3\xBE\xC2d\xA0\x89^J\x89\xC7\xCC\xC9\xB4\xC4\xB0\xC7\x8C{G026@\xD7\xB8\x90\xCA\xED\xBF\x13\xB4G'\x1BU\xCB\xB4A\xAB'5\x10\xAD\x0A\x7F\xDA\xB8\xCD\xDA\xB1\x17\xE5R\x84\xB2\xC1\xEE\x11\x17\xF7\xCD\x82\xBF\xEB\x05r\xEA?(\xD1wo\xE0#\xD1\x89\x1F\xA6\xF6\x1A\xF2\x82\xC4\x90\x18\xFE\xE5Uf-\xDC\x14\x89)<\xEFR\xFAy\xAC\xB0W\xDFEr<\x1A1\x82\x10o\x8D\x04\x92\xAB\xE3u\x0F\xC2Q1\x01\xB5\xC0\U%[\xBDV\xCB\xA7G5D\xA1\xF6\xE5\x0F0\xB9\x82\x90\xF5\xA6#wq\xB7\xB2\x9E\x85\x7F:\xA4\xFDz\xB95g\x12\x8A\x0E\xE4z\xC9\xC4\xCD\xE4\xC6\xADz\x01\x83\xBE\x98\xBB\x03\xC81\\x04ZX\xCD\x8B\xAE\xD0\xA8\x87\xB7\x04PAD\xBDL\x9C=\xEA\xB5\xBA\xFEF\xD7=\xFD\xAD,NM\x01~I\xBECbJc\xC2\x1A&\xCDS\x87]\xDD\xB2\xA4\x92\xE6l\xCB8\xDF\x8F\x1Am\xA8\xE2v\xA4\xF5!\xCA*>S\x1F\xCD\x12_a\x14#+\x8F\xE7+\xE3O\x10\xEB\x9A\xA5A\xC6\x94CO]\xD6\x03\x9A\x0C\xB4\x09&C\xAB\x9Df\x0B\xBAe\xD1\xBB\x97\x86\xD7\x9A\x98\x91)\xB7\x0FjLaX\xA7\xA0\xC3\xA0Ta\xE6C:x\x08\x00\x9D\x14\xB7\xE8u\xD4\x0EV'Z%\xBACF\x16<\xBA\xEE$"\xCC\xC8\xADF\xFC\x03396\x02C\x1B\xC2>\xDD\x80a\xEB\x03Z\xE8}1W\x87\xD8\xA9\xE3\xD98\xB1\xFE\xCD\xAD\x1CGj\xAF1g\xED\xE9\xA4[\xA5\x1E\x9D"\xA6\x8FlI\xF0q\xC5!\x05\x09\xB1\x9D%\x00\x0E;\xD3\xDF\x0F\x12\x85\xE0\xC3\x82-\xFA\xA101\xAB\xEE\xED\xAB\x04}\xFF\xD7\xC0\x09\xF0\xBDz\x94V\xD9\x91P\xEC\x90\x0E\xAF\x8D\x14x\xCF\xA0\xFA\x02\xB8\xA1P!\x99\x06\x12Qo\x0A=1._\xEE\xE0P@\xAD\xD4\xCF\xC9\xFF\xFF\xDD+\x19\x85iW\x8C<\x13\xDA\x8A\xDAo+C\xCFQ\x00\x13\xF8b\x0B\xDE.\xFDk\xCB\x01\\xFD%\x94\xC7\x8EH\x8D\xF3\xE8\x04#\x08\x9B\xF2F~\xA2e\xA6\x06\xDE\xD9\xC4\xD3\x0EE\x08$ob\x0B\xF4];\xC9H\xF6r\xE9K\xC5\x8B\\x02\x090\xD0\6\xBAJ.\xBD$@\x1C]R\xBE.a-ZQI\x11\x9C\xF3\x1C[\xE9\x9F\x98\x95\x18cd\xE7\xD74S\xA1\xC1\xE4\xEA\xB1\x12.\x03x,\x1A\x01y\x9E/o|3\x0FA\x8D\xCF\xC2\xDA\xA7tc\xFA\x08'wS\xD3\x0A:?q\x1B\xDDo\x07u\xF8\x93\xD1]\xD0\x8DC\x87\x17g`(\xAA\x1F\xA1\xF7\x8Fk\xEE\x99V\x84.\xB4\xB4\x07G\x9CbL\xDE\p\x13\x1E\xDCy>y\xEA8l\xED\xE5\xF0\xF7\x8A\x82FBj/H:\x91\x02\xCC\xC1Qs\xD7\xE4\xA5A9\xAC\x82B\xF3\xD1\x92\xB5\xD6\xE8\xE5\x9BSa\x97\xA8;\xD9\xC3\xE8\x8A\xF51\x1Fl\xA5<@\xBE g\xD4\xA1\x8C\xA4\x17\x0B=\xCE\xC4\x07\xE3t\xE95\xC7+2\xF6\x91\xD9\xED\x9A\x96'uv\xFFh\xFC{\x0Bux\x0C\x03)6\x12\x15\xB9\xBF\x16Q\x93\xFA\x1C\x93\x1BiS[\xE3\xD5\xBC\xA2\x13o@\\xF8\xDB\xD5\xEC\xEFdm\xEC\x89o]\x9C\xEA&\x01lz\x0D3Mt\xAE\x01\x88\x8F\xCAu\x98 \x11\x10\x82\x01Ey\xF1bm\xCEr\x99\xF2\xC6\xDEB\xF5\xFC\xD1\x1D\x14\xC6L}\xC4\x03\xF5sx\x12T\xC6\x7F\xA5;zIwc>\xA4\xCE\x1BO^)\xDE@:\xECx\xD7\xDC\xC9\xF8\xCC)3\x80\x0De"\x84\x06`\xAE\xF2\x9FW\xC3r0\xE0\x1E'\xB8"\xE8\xCEAs\xEDp\xAF\xA8R\x98\x95\xDC\xBA\xCE\xC7O\xF8-\x13"P\x1A\xE9\xC3\xB5\x8D\x9E\x8B\x03=%shd\xBB\x91\xCDv\xE9\xB8\x1B\xB3\x8B\xDF\x9Ac\xC7\xB8*B\x91\xB3\xA4i\xC9f\x89I\xC1\x0B\xD7l\xEF\x95\x92-\xC3\x8C\x8EV\xC2(\x01\x02\x08\xE4$\x06p\x85\x15A\xE9\xCA6\xE6\xD2\xC7\xE0\xDA${\x88{n\xCFR\x01u\x14\xE8\x1D\x87[\x87\xEFF\x8F\x82x\xE1\xFFV\xEFW\xF9\x87\xBE\xFD6>\x1E\x90i\x18\x82\xFA~\x1B{\x0A~\xC4\x1EpbT\xA8\xE7\xEA.~\xE4\x1BR\x1A\xB1\xF5\x8C\xF4 \xC4\x8A0\x94\xD1\x1B\xDC\x12Fb\x87\xB5G\xC2\xC1\xE9\x00\xB0\xBB\x0C\xB3y2\x02\x01\xAFl\x06\x1E.\xD8\xE5;\x90\x97Fz\xF4\x015\x1C\x92\x8A\x96.\xA4\x16\xED\x19\xD9F\x0F\xE63\xBA\xA7\xE31\xDE\x03\x9F\x97\x9F\xE5\x99\xFD\xB9E\xC4/\x85\xE7\x9C9\xBF\xC0\x85\x87B\xA0`\xA0\xCF\xF7x\x13\x0B\xE2\xDFC\xD0\xC4:R\x01\xEB\x97\xA2\xF8aH\x0C\x94\xBA=\xB2\xFD\x12\x89j\xDB\xDA\x80U\x0D\xDB\x16\xE1C\x81\xBB\xA0\xF2-\x0C\x7F~0v\xA3\xA1oE\xBE\xB3C\xB5Om\xCAp5\x19\x051\xDC\xB8\xAAC\x0A\x85Im\x1A\x06\xC7\x8C\x8C\xA1\xA23\xEE\x8B\xB7\xEA\x10\xA0\x9C\xCB\xB0 [\x823r\xAF~\x11]\xA9\xF5\xA0\xE7\xC7\x11\xAF\xA5\x8FbSL\x8F\xF4\x85\xBD\x17+\x98P\xE1\x86\x16\xA3\xED\x02,!\x0B\x0FJg\xED\x0B\x10g\xCA_\xD6(v\xFA\xBB\x0F-\xCB\xD4\xF3\x81\x1B\xA6S\xB4g\xC4C\xD8\xF9\xB6yn\xEF'\x84\xE4\x14x\xB7\xE5,YA\xE0\xF2\x8C'\x13\x10>|z\xA1\x1D\x16\xBA\xB5{\xD1-\xC3w\x08\xD3\xF5)\x06\xCDdn\xB7\xEE\x01\xE5\xD5&V\xAC\x08\xBDJsN\x9Dq|\xB8\x1C\xDCc\xE8-r'\xC8X\xB1\x96\x9D;|\x18\x89\x82\xBF\xCD\xCE\x14\xA5]/\x0B\xAAMH\x16^\xB6\x02\x07\xD6\xF1,\xCF\x03\x99'\xBF\xEA\xA4;\x96\xBE\xDD#~R\xAF\x06k\xB1FB\xC2\x0C.\xE1(\xF5\xBB\xE1,\xAB\xA0\xCE>a!8\xEE\xB4\x03\x95\x99x)]\x87x\xE1T`HE\xAE\x0A\x9A%\xA9\xA7o\xC6\x9A@\xFC\x8CuY2\x0D\x1Fo\x0D$Z\xD56\xF7\xFB\x84\x94\xEF\xB3\x1B\xAD_\x96\xEE\xE9hn\x7F\xEF\xC2\x89}\x9FEN2\x80\x0E\xD0\xF0\x0C\xE6\xE5-l#h\x1E\x93\x86\xDA9\xE3YR\xDF\xBD\xCF\xF1+\x0Ew\xD1 Mc?\x90'\xCC)\xC5\xA7\x8B\xD5Xh\xBA\xEBG\xDF\x8A9K\xC9\xB9\xBD1Ic\xA9>\xBB8\xDD\xE9[\xB9tl\x1B\xFD\xC8a\xFE\x12\xB7c\x9E\xBFI\xB0fH6U\x03DH\x9D\x09=.\xDEjS\xF5\x9E\x8D1Tww\xB9I\xE0=Z\xBD,;'\xA3Q\xAE\xEE\xA3O\xB5;\x10\xBE/8\x99D\x94tp\x88\xEB\xA4\xA0\x93b\xEB9\x81\x10\xAF3\xE8\x0B\xFC?\xE5\xF6\xCA\xF3\xA8\x0D\xEFM\x94\x977@=\x80\xB9=\xF4\xB2C\x07V\xC1\x09\xB3$\x9E\xAB<\x9D\xB4\xEB\xD7kq\xF2O\xBE\x9FZ\xFF\x04Q\x02\xFC\xACg8\x9C\xB3Q^\x94\x8A\xB8\x86l\xD0\x1C\x83B\xA96\xB3b\xA6\x83N\xD8f\x8E\xED\x11U\xB8\xF8\\x06\xE2\x1E\xD6\x9Ar\xA1\x94\xB0\xFF\x9B\x1B0\xF1\x1Fa9\xC7%N\x9E\x1C=\x86k\x86\xB8?\xB4\x1E$\xFB\xD4\xA3\xBF\xBE\x03\x1A\x178x\x03_ \x10_\xB5\xFC\xD3\xF5\xC74\x1D\x197\xCF\x07\x89\x91t\xB1\x02c\4\x8D)\x84J\xD2~\xE4J\xD8F\xD3\xE5\xC9\xA6\xA9\xCD"9\xD53\xB8.\xFBk\x86\xF6\xD6\xC0\xD8\xB3\xC1Y\x08"\x1ER\xE8\xCE\x84\xC0\xFC\x8DAC\x85\xE6\x84\xD3E\xE5\x17\xB3\x1F\x98G=\xC8\xB8\x7F\xB9c\xE0\x8A\x07\xB8\x9CE\xFE\xB7\xF0K)\xEC\x19\xCAd5.\x1Ee\x04\xB9e\xB4\xF0M\\x15,\xBB\x82Y\x9D\x0B\xC6\x17v\x0Ai\xB7\x08\x0AQ\x08\x81\xD2\xD7\xA8\xBF\xB2\x1FV\x18\xD2o\x10\xEC\xC3K\xFF-M*\xBF.\xE4\xEE\xF9\xA1\x19\x83\xECy\xE5#\x94'\x93\xE9\x0F\xCB5\xF1N\x06f\xCD\xE8\xA69T\xFC\xC2\xEC-\xEFx}\xD7-\xBF\xC1\x12\x8E\xFFK\xF86\xE0\x1F3\xC1\xD0\x96\xAEI$Y\x82\x1EO\xDF\xDB\x80\x03ye\x18{\xC4\xC5\xD8\xCB\x8F\xEBZ\xE9B\xFD\xC2\xE2\xDB\x80iE\xF2\xFF(tf\xBBT\x1B\xA4-\x8D\xE7w\xED\x0C\xB0\x8EB\x95\xB9B1\xFC\xAC\xB4b\x86\x81\xB5\xB2\xE2r\xEF\xB4\x8F\x85\xD2\xAD\xEC|PtxS\xCD\xFB\xD8\x8Ce\xAF\xD4h\xED&\x18\xD4\x11\xFB\xBB\xDB\x8FQ_t\xBD\xEB/\xAD\xFC\x82\x0FE\x8D\x14|\xF1\x03\x0BY\xFF\xB5\xDC\xEF\xDB\x1A'\xFC\xC6\xA1e\xF2\xEB*\x04C\xB3\x90X\xAB\xADa\xD1\x1E\x8E~]\xDF2\xC3\x8E\x80\x05\x8C|=~E\xA6\xE7\xEC\xB5\xC0\xC2'\x18\xA5\x03\x1F\x84\xD0\x1B\xAA\xF9\x87\xFB\xA5ub\x98Kog\xC45P\xA9j\xE8G\xA8\xBA\xC8\xAA2\x1D}\xD6\xC3\xBB\xC1\x9C\xCEs\x07Hb\x1C\xB7&z\xE0g\xAApU\xFA\xD4^c\xA7#G\xF4\x8C\x95d\xA5\xFCN!\x8Dd3\xF0n\xE9\xD4v\xF4\x0DY\xBF\xD8O:\xF6*\x09\xC9\xFC\xCA\xC7E1\x01\xC1\xD7\x03\x1F\xC3\x945\xD3mhx\x12-\xB2\xAC\xA94\x0B\x92>+\x8C9\xDD\xE2\x0B\xC6\x04(\xE7'\xDA\xD1\xAB@\xEA\xF3\xCA\xAA%c\xE1\xCD\xBD\x02H>\x1B_1\x150W\xD4\xEEObpd\xCC\xD2$\x7F\xF2\xA7~Q\x90\xD6\xDB\xDE*\xB9\xD2\xF7\xCA\x89G=8\xE1\xC9\xAF\x00\x80\xD4\xBC,\xA70d^\xE4\xF2\xA3v\x9C\x93\xEE_i3a\x0E\xB6\\xC8\xFD\xACL5\xDA\x9D|\xDB\xE5\x0F\x1E[\xC9\xEE1\xC8R0\x19\xD4\xD9\x1B\x8D\xB0\xFBd5\xCD\xB8\xFBY\xE8'H'J\x90\xDD\xD2\x92)a\x9B\xC8\x99g\xB3\xDBM\xFFh\x19s\x87\x98\x88,\x17uo\xA6\xFF\xCF\xA41\xF2(\xB3\xBA^\x11AC\xE2\x06\x1D\xDB^\xE3[\xCD|x\xF7z&m\xAD\xB9\x81\xA8W\x1B\xBC?YJM\xCBU\x00\x8B\x82\x13\x94s\xCCF3\xE7\xC0:\xAC\x15H\xE9\xB3\x9D\x07\xE9D\xDDq\xABk\xF4|\xC4\xCD\xE5\x85h<\x93\xFFd\xAB\x0F\x1A\xB1\xDE\x14v4\xE4\xEF\xC2V,[\xB5\x8B'\xF9\xDA:T\xEC,\xA4\x95\xFE\x82\x19:F\xB8VN\x8B\x0A\x85\x9A\x16C\x9A\xED\x06]Ska&\xD9i\x135\xAEZ]c\x92\xD6\xDF\x14\x98\x1A\xC3-\xE4 \x80W[\xF8\x1F`\x9F\xC9\xE1\xE6\xCD\x9B\x05\xCF\xEFU\xDAG\xEBJ\x9C\x99\x8B\xD3H!\xD0\xB42\xE4K\x05"p\xED\xF1@\xA5\x1B!\xAB\xFB&e\xE8e\xDD\xE6\xB5\xC7\xCF\xED\x8F+W:\x95\xA1\xE8\xD0\x0B\xE6\xEB\x17^\xF8\xF7@%\x10\xFC.m\x90\x17\xD0\xCFd\xC3U\xB3\xE2\xBB\xECp\xD8\x7Ft\x8D$\x12\xE5\x9AA.\x9A\xA5E\xED\xE0\x90ECX)n\xE7q\xB9\x8B\x0BwR\xBA\xEC\xAB]D\xDC\xEE\xF5J\xA5-\x1E\x84\x85\x9E\xAD\xE3w$G\x09\x9A\x93\xDD\xAF\xF3Wi^\xAC\xD9\xF8\xE2\xA6%\x9Cx\xA7\x99\xAFH\x91:HFy\x87\xF4\x0E\xCD\x08\x8D\xC6o\x02\xECD\x85m\x0F\xA3}\xDA\x9A\xE40\x10\xDB`)#\x82i\x1ALd\x9F\xC2\xAB.;\xCF\xB0"\x0B\xAB]\xC3o\xF7UZ\xE5\x9C\x1D?\xBB\x9D\xD8\xE2L\xEF\xAEv\x8B\xE8\x18\xA9\xACx\xB1\xD3\x8F\x002c\x09\xEA\x17\x19I.\xF5s\xF4\xE1\x1F]Yg<\xEEp\x94\x0B\x00\x9Ee\xD7\x7F\x10Mr\xE6fE\x1D5\x17SW\x80=] \xF1cc\xD2\xBB"\xD9\x8BQc\x1A\xA9\x0B)l\xA4\xA6n\xD8z\xB9\xCEvm\x99.\xF5(\xAB\x8B\x1D1\xB3\x09\x0BraoJ\xDF.\xA4\xD1\xD1|\xC5E\xA1\x1E\xF0\xF6v\xE2\x09\xC5\xC5\xF1m\xB8\x8F-\xC6\xD4t\x17\x81:\x0DZ\x0D)\xC9\xB4\x10\xD2\xE7\x81\x9F\xF9b\xC7\xC34\x1D\xC7\x0F\xEA)\x8A\x96\xDEP,Vk\xB2\x95\xAA\x7Fi\x96\xBB\xD3N\xCCm\x03\xA9\xA9\xFA\xEA\x8Cb\x98Jk.\x09,\x9A\x8D\x8F\x13\xA0\xFB\xF7R@\x1C'Y;\xE9\xAFD2*\xE3\xB5\xBB\x9C\xAB\xC7\xB0{%\xAAE\x09\xD7/=P\xE3\x0D\x0DT8\xDDd\x0D\xDF\x0A\xE24\x12\x8C\xD6n~\xCA\x05\xE6\x9B\xC6\xCDY\xA2\x1A\xCC5\x8B\x9B\x01\xC5?\xBFTn\xFD\xE1\xFA\xBE~\x82\x190\x7F\x1AI_\xADk\x90BI6\x09\xB1Me\xF5X\xEC\x88\xE1\x07\xF5\x14\xF8\x08\xFE\xB5\x94\xC2\xF3KT\xC4\x88\xDB9I\xC6U\xFA\x87F[zD\xE6\x11D\x0A\xF4\xC71!|H\xBA\x14Fq\x97\x09\xF0\x95\xAF\xEC1 \xECR\x80\xAF\xBAN\xB6\x9E#\x0933\xA6uS\xF1\xA6\x89\xED\xBFh\x87\xB4\x85\x08.nF\xB3(sYj\xCFwr\xB63\xD5\x0Cs\xA4}C\xD2G\xE9H\xFA\x81\x88~\x8E\x9E}\xA5\x07\xC6&\x1FP\x0A\xBB\xA2\x86\xAE\xABc\xEA\xB2p#\xE4Q\x12\x11\xB31OpX\x04-%\xF5\xAD\xA8\xF9.\xAD\x18\xF2\xCD"h\x1Cr\xC7\x01\x9C+Sh\xF0\x9CT\xC1\xBA\xB4\x8FO\xE9\x03\xF1\xE4\x82\x15p\x91\xA8S\x9C\x08\xE6\x9B\x96P\x16\xF5\x0B\xC1\xA0@\x193\x80 \x1Ba\xBC\x04\xCAhh\xD5\x1AU\xB5\xD9\xB0f\xAC`=\xFC\xCA4\xEC;\x0A\x92\xA9\x16\x0C\xD5\xFE[\x9Cp$J\x0B\x17\xD3K\xF7\x83\x03Q\xD9R\x15\xAD\xF9E&\xBF~\x89>gf\x1D\xBD\x91\xC5\x09x\xFC\xD98\x87\xDAB\x02\xC2`\xE7\xDEjGKD\xB5\xBC\xF55\xCBba\xA3\xD7\x02(\x94\x84\xA7\xCA\xA3\xE8J\xF8\xDC\xB4\xF1\xE0\x84\xE6B\x94cO\xCFw\xA65@=\xAB\x85\xB5\xD9p\\xB3E;\xEA.\x87\x1BH\x09\x8F\x84\xB3u\x92\xC5\xDC?\xF6\xD8\xA1#<\x83\x15\xB7\xBA\xF0B\xD2\xE9\xED\x1E\x12\xEAQ\xDB\xE4\xBD\x0E\x1A\x13\x0D~\x93\xCF\x8F \x17\xD9\x04\xDB\xB8\xA1\xD6\xCD\xE8\xF5\x0C&J\x93\xD3\x1A\xE0,~\xE0\x1B\xE8\x00\xD7N\xD6\x06\x93Ul\x09\x94\x0CG\xE9\x7F\x84Jg\x18O\xA3=\xFA\xCE\x17\xCDrG\x00\x84n0?\xBAF\x96\xD3\xD4'\xD1>\xA4\x9D\xBA\xF5\x00\x81\x9DF\x00I\x8E\xBB\xC7\x96\xB3A\xC5\xD4\x99\x04A\xA9\x85P\xC4\xCE, \x82@j9\x06\x9Bq\xFF\xAF\x91\x8E^F\xB0\xDB\x0E\xEEt\xF198\x10\xC6\xA08E5h\x92\x8E1\xE7\x0A\xC5\x90\xD6r\xFF\xF2\xBA\x03\xCE!\x81\xA1#\x88\xBEa\x17\x9E\xE9\x13\x88\xB1\xB1v\xA4\xA67\xE9\x10"\xE5\xEA\x9E\x13\x93w\xF0\xC0,%k\x0F?\xFD\xFCu\xC48\xE2e\x80\xAC\x9D\xCB\x08\xAA\x0B\xD1R'\xB7.\xEC\xFB\x89Kp\xA8\x1B\x1F\x8F\x9B\x13&Q\x19"zk4\x8B\xA4\xF3\xC0\xD5R\xE9\x0Ep\x14\xAF\x1D\x15\xB9a\xA4\xB2\x02sl\xD7\xAC\xD2^\x99\xE8\x0Fju\x8B\xD3W\xDC\xF7w\x8F\xE9b\x8D)(u+x\xBFs\xBEU{\xC7%\xDA\xE0\xB0\x17\xBA\xE7\xA7\xF8\x88R\xEEo\xCE\xC2F\x09\xFA5\xD7\xA0P\x09\x86\x07\xB6NI\x11[\x03\x0A\x14\xA4H'6\xFE^S.5\xF8\xDB\x87"\xE4\xBB\xE6\xBA:I\xC3\x07\xBCsg\xB2\x98f|\xF7H\xFDO\x15ab9\x04\x04\x95\xF7\xE3\x01\x80\xB7\xC33 \x13\xA9\x1B\xF7\x0B*Qs\xD2\xBCb\x82\xB3\xD4\x00\xB6\xED\x1D\xBF\x97\xDE\x7F-R=\xE1R\x88n\xDDBW\xD6\x0CV*\x80\xE4aM\xB5A\x0E\xC3\x81\xC1|j\x86o\xA0\x02\x19"\x99T\x0F\x00\x15\xEEp}D|:\x04\x1C\xCB\x9F\x80D\xDE\xE0\x02\x02qC\xC0;\x08\xB8\xA9H]\x8F\x8B\x12\xB3\x1E\xDB\xAC\x10U\x0A\x00D\x90\xF7\x07)\xD9\xFE\x1F+\x07\xE0\xD1\xFAke\xFD\x8C\xA3\x96'S\x1B\x0F\x16\x8CA\xA5\xC5\xB5\x08\x0A,\xD5\xE9\x1D\x1A\xA6\x12\x81\xE8\x1AB/g\xAE\xFE\x85r\xB2nw\xDA5LD\x19\xC8\xF1\x89\xD6\x03H8\xEB=\x9C\x112\xDD"\x85\x8E\xF9\x8D\xA5\xAB\xF0\x176\xE5\x84\xC0`Z\xAF\xE5ic\xE4\xCE\x9D\xC3\x16*\xEDe\x0A\xC6tv\x11W\xEF\xEA\xAAI\xCFx\xABb\x17rnG\xA7\xE9c]\x98\x9F:\x18_|`\x95\xD3\xB9E\xC5\xA5\0\xF1\xE41\xDA\xB9\x18\xCE\x1F\xA1\xF7\xAC\x194\\x92v]\xC4\x92\xD46\xC6\xB9\xA1\xC4\xEF\xB9[\xBC\x83Bt\xA5v\xF6\x81\x86f\x8FH+\xBF\xCAO\xBD\xD9G\xABD\x91\x9F\x9E3\xE6=\xE9\xC8\xF58\xE7\x13C\xCC\xC1\x1B\x1B\x09\xE0<>N\x80h\xAF\xAA\x9F\x9A_\xFDq\xA6\xF3\x01\xB7<\x1D7\xB2\x04\xF0\xD7u\xF4Qx.p\xF9\xBAG\xCB~\xDF*V\xF1X,\x89\xBFC~\xC9\xA3\xEC\xAA#\xD5\xA8\xEC\xAF5\x93\xAF\xCFL\x1B\xBB\xB5\x03PL\x06\xA9\xBF\xB9\x07t\xE4z\xCB\x19@\xAF&`\xF2\xAD\xDF\xD3\xFBtU\xB1\x87\x1D\xD6\x0261n\xE1\xA9l'\xB8\x87\x80!\x1B\xA2x\xA4\xA9\x0D\xF4\xEE\xFFd;\x0A\x1C\x18BVw\xAA\x00\x82\x8AW>\x13\xAAu\xC0I\x8A\xF4t\=7<\xDE\xA1\xDC\x88\x83U\x94\x1Ca]\xAA[f\xAClF\x0Cf\xFD\\x92of&\xED\xD8B$\x08s\x055G\x19`a\xFA\xE0\x16\x82H\xF5v|\x0B\xBC\x85\xAE\xF5\xB7\xA3\xD6\xCB\x98F\x1Av\xC1\xE1\xDD\x84\xB4\xD1\x95.\x07]\xD5\xA0R\x86\xB9D\x7F\xDC\x1E#\xDF]\xA2\x7F\x87\xF7.\x13\x0C\xEA\xA8\xAD\xDD\xBDQ\xC8\xC8\xC0\xC8\xEAOl\xACr\xDDY\x0C~\xF5\xE7\x93[\xF2\xD2\x131\x15]\x94\xB2)K\xEF=\xEC\xA6\xA6\xDC\x03\x03\xA4S\xE1Av\xA3Y\xC8\x7FGa\x9C\xAF\xB8\x9CQ\xF6V?<\x86e\x96\17\x09\x92[_U\xC9\xE7G\xDF\x0A\xB5\x1A7\xDC\x80\x8E\x1BP\x87\x12\xC6|\x8A\x7F\xF6\xC4\xBD\xDC\xD5Y\xDC\x90v\xBA\x1C\x01\xA7]G'\xE0\xB4\xBF\xF1?#\x03l\x9DA\xB9\x94]\xDD\xC1\xFD\xC1\x1D\x8A=\xB5\xA0\xB7\x9F\xF4\xE2\x13\x08\x8Bx\xE0W90j\xF7*\xA4;\x99\xE0\xC5\xB6>pTuhT.=\x9F\x85]\x1E\x9F\xAA9!\xCF:.\x8D\xC1[\xFFq/\xFE\x03\xED\xF3O\xB2\x94c\x8FI\x06\x1A0x\xFA\x90&\x94[3\x9F\xA0\xD8C\xE5\x0C\xEES@\xA5eOA\x05-\xFEG\xE4\xF7+\x87\xCFG\xB5[\xAF5\x90\xE0O)\xDD\xC0\\x15dMFc|\xE4\xC4=B\x00\xCB\xA6_'\x08\xCE\x12e9:\x99&\x05s\x94\x0F\x04\xE3\x85~mt\xCA\xB8\xFEl\xB3\xD6\x03'\xA6\x9D\x89\xA0`\xEF\x01\xA5g\xCE\xD98o\xFDVg\x83\x9Dg2\xF8\xEF\x0E\x0C\x1E.\x1B\x14\xF0\xD2\x01\x0COu\x8Fvpt\x99\x9D\xCE\xA6\xE6\xB6\xA1N\xB3j\xBCLU\xDDg\x8E(E\x9C\x03)\x0E1o\xF7F\xC2N\xCF\xD0\xA0\x1EL(\xBF\x06\xBB\x8D\xDF~\xE6K\x8F\xD2z\xE2\xE4|\xAA\xD1\x98\xBD8H\xF7\xD7\xCD\x82\xBB\x9FV\x93&:f\xF5\x05\x82\xF1+\x9B\xED\x01\xF8\xBF\xC1\xE0A\xE8`\x1BY\xF5<\xC6e\xC6\x9C\xC1;\xA7\x9EYm\xDE\xD7\xC5\xC3?\xBE\x10\xAA\x8E\x09\x0F\x15\x07E\x95\xA5\xD0\xCA\xD8\x9A\xAF=\x08\x8A\xA8\x8C\xE2\x7F+%\xBF\xF5\xC4=\xE9\x03bY\xC4\xE61u`\xA3\x91\xA9\x03\x9E[.\xCCsS%As\xAB\xA2\x02\x88\x9BbVw{\xE7*\x975 \xDCQE;3\xF5\x80\xB9\xC2L.k\x96k\x82!\xEB\x88^\x02\xE6\x81\x83^ \xEA\xC9\x16MM\xD3\x94\x8B\xFAK\x13\x92\xD0h\xE6\xE3'P\xE5s+r\x96\xD9\xFEX\x04\xC6l"KW\x1A\x18\xF4\xB6$-\xC5\xA3\xCA\x0D\xB6\xAC[\xD0C\x0D\xF7\xAE-[\x87l\xDD\xA9\x98\xB1Ry9\xEA\xA7\x1D\xA9\xF7>\x05\xBC\x86q\xC1\x95\x13B\x15\x88\xB7Q\xE8J\x98:\x18\x90OS\x1D\xEA\x87\x15\xD3w\x024\xFFe\x97\x8E\xD0\xD5\xF5\x82\xA9\xC8/\xB0\x95\x0D\x0C\x97\xAFvB0f{\x0C\xB76*{/\x0B\xBB\xC4\xB0\xAD{O"\xCBI\xE6\xD1M\x12\xF2W\x8F\xA95\x0C\xE5\x82D\xB9I\x0D(\xD84\xD01\x8AA\x87?t\xA3\x0D\x19B\x98@\x99<4U4\x84\x16D\x89U{\xA7\x1B\xEF-\x94=\x95\xC4:\xD4rn\x0A\xB6\xCB\x95/\x12/\xFF!\xA2\x0D:\x8D\x90\x17<\xD0\xD6\xCD\xFB\x9A\xA6\xD2\x85wx*\x04\x93\x8F\x06R\x1B\x1E.\xE1\x92\xFE\xA3[/g\xB2\xED\x1A\xE5@79\xDC`sk\xA9T\xF4\xCE\x1D\xD01\xF6\x15\xAF4\xF9\xA4>Y\xE1\xC1\xE5m^\xA5\xC1\xF8\x12\xD6?ar\xCF50\xA5M\xEE\x8D\x06\x81\xE4\x9A\xDEe\x89gd\xBD\xF5\xC0[\xD3\x94\xB7\xD0c`\x83\x8C\x93N\x103[\x81\x1Fl\x86\xAAc\xEF\xDC^w9\xDD>\x9E\xA8\xBA\x02R\x18T\xCC\xF3+\xA1\xFB@r=X\x19\xCD\xA7\xA4\xC7\x8Dq\xFA\x03\xA9\x83^\xD5\x96W\xB0\xE2S\xD5\x9E\x8FQ*\xCFt8]\x96\xDFx\xBD2\xE4\xB1\x9B_\x87l\x1F\x83\xC9~\xCA\x12y\xDE\x11\xB4\x0A\xE3\xD67\xBC\xB5\x0A\xF9\xB1wXg7\xED\x89\x9B\xF0\x92\xD6\xEC\x0B\xDF\x81C\xE4/\x1C\j\xC1\xEBk\xDC\x9C[3\x08(\xCBP2\xC8+\xD2\xA1\xB5H\xF2\xEF\x16\xD9V!\xDB\x8F\xFD\xD8\x15<\xABq\x1E\x96'\x97\\xDE\x90\x02\xF9V\xCD\x15t\x07Dy~/;G\xCC\xF2\xE89\xB6t\xA1\xFC\x9AW\x8E\xA0vycj,\x83\xE4\x1D\xAF\xC1\x92\x8B\x8F\xD5\xEA\xA0\xF6\x8C\x17\x94\xEB\x0B\x14\xEC\xF56J\xFD\x00`Y\xC8qF\x1D\xFA\xAF\xAAU3_\xBA\xF6\\xA7\xD9\xD1\xFD\x1B\x8DJ$\xEA\xF4\xD8r\xB08\x0DYwf\xCC\x01sb#\xE0^\x98\xE3\xFF\x94\xE1\x01_\xBF'x\xF7\x97\x8APy\xDC%\x95*}3\xE8\xE5\x81\xF4w&=\xA2\xB8)\x8F\xB5q\xA1\xCB\xC3\x91\x03\xA1\x8Cf\xFD+\x7FG\xCB\xA8\x17\x02\x16\xF5\x91+H\xAF\x9A\xE4V\xA7\x04\xE2\xD4O;\x04\x1Evz5\xCAy\xC1\xA3\xFE-e\xE7\x83\x09\xA1R\\xC3H\xD9}\x9F/0ua_\xF8W\x13M%\xDE\x975]\xC8\xC9\x04'\xF1\x14\x9C\x91\xC1_\x01\x9D\xC6E\x91\x92UZy\xE8\xA8\xC8/\xA4\x1B*\xCE\xA1,\xED/{(\xA2r\x92O\x15\xA2\x8E\xD8U\x83+C\xBD'\xD9\xF3\xF5:h\xDD\xCB\x01>\xFB\x0C|\xAC\xBA\xA3\xCFB\xA73\xB6\x8F\x94\xCD\xB4i\xCDQ\xE1\xE0d\x0E\xEF\x9AN\x8D\xE0\xE0A\xE0\x1E\xAA\xC9w\x17\xFD\x1A\xA3\xF5H\x17\xAD\xEE"\xC1\x02+\xFA\xDB\xB7\xD5\x98\xE0\x11\x1C9\xB2\x86C\x88\xC7\x05w*\xC9S\xA6\xB0Fe\xBD\xE6\xDEi\xE1(\xDDl\x99\x12\xF1\xFC\x80P\x10uJ~?*A\x17\xA8\xDB\xF5M4r\x18\x87\x18_/ftp\xD3\xFEo\x93\x14\xFE2\x89\x8F\xEDs*\x1DAi\x88\x1D\xE3\xDD\xC4\xB5\x18\xB7\x16\xD9\x99\xD3\xF8\xA7.\xE8@\xA4\x03\x06\xBA!\xECtjI\xAE+jL\xC3v\xB0\xEC`\xA7\x1C\xC3\xBC\xF1Q\x17\xCE\x98\x16\xF5\xDC\\xF3\x03;\xB1\xDC(,\xC2\xD6\xF5\xA7\x7FBC7\x037|\xCF\x08{a\xBF\xF8+\xCF\x14\xF20l\xF1\x85\xA6\xDE\xDC\x87\xBCy\xA1\xDA~<W\x04!\xFC5)\xB0\xB0n\x19\xC3w\xA0n\xAF\xA3\xBD\xBEp\xE6q\xC2\x03a\xA9bt\xA6t@\xAFq\xEB\x02\x1BL\xB2\xC3\xE9I\xE2,u\x14'\x00)h,\xB9\xD2\x9B\xB3\xA5\xF4\x7F*D!\x95\x9D5\x80*\x9B\x15\x97\xA7 3az\xC8\xE9A\xDA}\xFE\xD8\x84J\xDE\x7F\xA1\xDE=\x8C\xCAZGk\xC8\xB7\xFB\xA52-[\xB9\xA0\x95i\xA6V*j\xA4-6j~\xFA\x9A4\xCF\xF2\xCD\x00\xA4\x0BY:L\xBE\x91\xFA73\xEB\xF3,\xBD\xBA\x90z:\xF5:;|\xFC\x02-\x06\x8A\x10\xDD\xB2N\x92\x88\x14\xC9\xAB&\xECY\xA1\xE3\x02o$\x9B\xE2\xBF\xADT\xFB@\x17G\xBD\xDA\xA3\xCD\xD70\x92\x08\xE1kdz\x97:\x95=\xC7\xB8\xCAlD[.9\xD3]\xE4\xE0\xEA9r0\x82\x1A\x88\x9A\x98iJt\x1D\xCC\xFC-\xD2\xA0H8]\xF3\x89&U\x19S:\xBA\xFB#{\xA9Xr\xFF\x96(w\xA3\xC1\xEDb\x87}S\x09J\x08%\x84\xA4|\x98\xA3}\x8B\xF6\x1DW\xC8I\x9A\xB8\xC8\xD1\xEB\xE22\x1C\x80L\xC2x\xA2lp{\xC2\xEE\xCD\xDD\xEEqmz\x02l\xC5:\xA4N\xE0\xE2\x9E\xDD=g\xFB\xAB\xB8\xC3\x9F\xCD\xF6(\x0B\x93\xB3\x12\xB6*"5Hs9\xF7\x0F\x07G\x12\xE3`S\xC7\xEBf\xA4\x05\x1ER\x07Yf\xB0\xEE\x98\x9E/WW\xF9\x82Y\x07C\xE2\x84\xD1\xF4\xF1\xE8d\xC4\xD2\xAD\xC2\xDE\x81P\xD7\x04oZ?tW\x03k\x08\xB7\xD2\x9C\xEDo\xD8\xC4\\xDA\xF6\x1Bn\xE6\x96\xF4\x9Cl\x93\x0E0\x911\xB7\xF0\xC0\xBAlos>A\x8De)\xF06\xDD\x9D \x00\xDC1\xF9\x0F3\x1E]'\xFD\xAB\xC4\x02\xAC\x84-\x13\xA9\xFE`\xE5\x8E\x90[\xA1\xBA\x1El@\xAD\x9D\x15\xEAK\2\x869L\xCF\x18\xD4\x9F\xF1s\x1DW`N\xAFZ\xCCg\x83WV\xF7\xF8z/\xAE4\xEBL\x17\xF08\xE6\xA0\xEE\\xA1mI$[\xD5\xE2\xD8\xA1\xB0\xFC\x81G\x14\x005\xC3\xAC\xA6_'i\xBB\xB3.ww\xCF\xD2\xC1[\xB9\x0Eu2\x18K\x91.\x7F\x863\xDFV\xBF\xA1\x0B5\x96w\x10\xAC\x1F\x85\xFD\x08(A\xF0\xA4\xFB\x8C\x1F\x06\xC1tn\xB0\xF1L\xE8\xF6\xAC\x99I+v\x00zD\xA1\\xC5q\xCB\x1D\xAB{\xEF\x0FN\x84\xAE\x95\xEA\x81\xFCu^\xB40?+\xE7\xA1\xC1P\x91\xBC\x93y\xF7\x97\x84\x17y\xB7k\xEB\x85\xD2\xD5\xEB\xD6(\x1F\x03\xB4\x89of\xCA\xE1\xD9\xC4\x83\x89g\xAF\xBB\xC3\x0E\x08\xA0U:\x9E\xD5X\xBE\xD5\xC5UT\x02\x8D_\xEE\xC3j\xB6\x88q\xD4\xE9\xD3\xB7\xEFx\x1ADn+\x08{\xB4_\xFA\xB5\x8A\xA9\xBC\xF5\x07\xB2\x004\x96\xAB\x98\x18\x0A\x08\xA3k\\xABZ\xBBo\xA9\x1D\x92~-j\xF8\x85\xDE\xC0\xFC?\x05J\xCC!\xF8%\x04\xEA\\xB1\x03*y\xB1\xC4\x10\xAA\xB1\xB9l\xEF\x08=\xE4\x88\xFF\xFCF\x86p\xD4\x058\xB1O\x9C\xE5\xA4[ v\xB6\x1A\x85\\xA5\xF3Pq\xCFQF\x1F?\x90Y\x8E\x7F\xD7a*B\xE6)\xF1Cf.\xB4\xE8\x04\x9A\x12\xA3\x067?\xE2\xF1\xC9\x0F\x97T\xF5I\xBC\xFA\x8B\xF0\xA5+\x1F\xF5\xA9\x9D\x1B\x0Cqn\x07n\x87199\x9C\x06Kd;\xBA"\xBA%K~\xFBP\x8C\xDC9\x15q\x9C}\x04\xA7`ap\xB8\xE9\x90\x8B\xF4\xA9\x1DCk\x9A\xB3v\xD0\xB8fL\xEF3\xE5\x1A}\xB0\x09\xFDs\x126\xABx\x99\x11\x07\x08\x15\x0A\x94\xC7:\x12\xD6\x1A\xFB52\xB8lt\xB5\xAF\xC9\x9D\xEE\xA6Q{\xBF\xD3k\xEC\xC4\xC6\x95|\x93\x16\x01\xD5\xCE\x05E\xACo\x0D\xBEx\xD2z~\xAEf-6aq\x07_X\x1B\x83+WD\x0EyV\x84\x10\xE8\xC6Qn%\xDDa\xD2}r\xD1%z?H\xC1e\xFA\xD4@\xCD\xF8\xB2K\xA3\xE8\x0B\x0E\xEF\x8C\x9A\x16!Q|\xA7\xC4\x01\xE1\x0A=\xC3^I4e\x19\xF4\xBC@\x83\x19w\xF2!Gzb\x1BIp\xEE\xD9\xBDJD\xDC\xB8\xAF*\xF1\xEB\xD4i\xC3{\xD6\xF7\xC3\x06k\xD3\x89\xFA=\xFA5f\x83\xE3\x00\x86\x96\xC5\xD8\x8DE\xDE\x86\x8C\xC0\x1E\xCE\xBF\xB3Hd\xD4\xFB\x15Pj\x8C\xFCAs\xBA\x98I\xEC\xE3i\x84Q\x81\xDA2\x83\xFE\xAC\xF6tV\xDA\xD4c\xEB\x13\x90r\xDD\x87\xD1E\x1D\xE6\x83\xB6|\x941\xF0\x89\x03\xAAyJ\x8C@\x90\x09\x10F\xA5\x1E\x8DK\xC9\x8F\x82~\xF6\x8E\xAB\x88\xF2\xBB\x8A\xAF\x18\xDD3\xA8\xDF\xF2&\xB4\x90\x8A\xF4\xD6\x17\x0Cc\x0D\xB5lXCve\xDD\x07\x05K\xFC\x18\x80;\x0C\xF9\x94\\xB8\xA3\xF7A\xEE\xC4n\xEDF\xC2s\xF7\x1AC"#P5\x05\xE0D\xA5\xC7\xCF\x86'2\x06Z\xB1G\x95\xB5\x8F\xCD\xA6.\x1A\xAF\xD6\xDE\xDFo\x13`;\xCB+\x80\xEA\xA2pH;k\xCB\xDC\xEB\xFEOQ\xB7\xF5\xBA%\xF3\xC8\x13\xA6\xA50\x16\xAD9\xCC\xD8\xEEKt\x80\xF8\xB4\x8F$\xA9\x09\xA1XY>\x0F\x19\xC1\xD8\x83\xAB]\xA7\xA3D\xB9\xEF\x96\xAC\xF7H\xBE\x9BI\xA8G\xC3!\xFE\xA2\x93a\xDC\x1E\x8B\xC8vD\x00\xFC\xAD{\x8FBf\xEF\x14|\xC8\xC7\x9F\x9D\x92o\x06\x85\xC1Ng\xDC\xB4\xC5\x1EMC\x1C\x0C\xC4\xFE\xAE\xE5\xE1e\x8B\x0Ac \x8E&\xFEGn\xDFP#{c9\xD4\xFAh,4u~\x08'\xD7\xC6V\xD3\x16]\x8B\x0B\x06\xFC\xD5=:\xD8\x15\x04{9x\x0Es\xB8bV\x9F\x96s\xD1D\xA1\xE5\x8A\x11\xA5\xB9Qt\xF0\x00\x0Aa\xCF\x00\xA7\xFC\x8B#/\xA1^\xAB\xF6Z\xB09\xA6\xF5h|_X\xDA\x0C\xAD\x8E[;\x93y2\xA8\x15\xB7\\xA74\xB5=\x87\x88\xD7\xF6\xFA\xD2+VO\xB2\x99k\xD7\x99\xE9_%\xFF\x99F\xA5L\x06\xA1P.FY\xE7\xF0\x98i\xC2\xA4\xD8\xC5v\x98Q\x9FuR\x8A5M\x9A\xC6\x19\x1F\xA3~V\xAF\x9D\xB3W\x0A \xF0W\x01e\xAEB\x80\x18\xA3\xDF\xA3+-\xC6>\xB0\xAC\xF1f0\xD1\xBF\xF70\x0E\x0CU}I\x920\xC4\xBBY\x11\x0AQ9\xFE~\xFB\xEC\xD4\x01\x93t\x1DmHwO1~H\x95\x8B\x1E\x85\x1DxH\xFFQGQ\xEE\x18\xD5\xB1\xD1\x8E)\xE7\x7F\x96&M\xBEo+\x8A\xF2\x8E\x9CX\xA7\x0Ft\x07\x99\xA8Eb\xE2\xE0\xE3\x81\xE4\xFC\xC0R\xCA0\x833x\xA1\xED\x97\xEB\xFE\xBE\x02\x1Dc\xC0}\xDB\x03\(\x05\x13S\xFE\x06\xD5\xD4\xBC\x8AX+\x8C\x92t\xD8\xEEw\x05v\xA1\x13\xBE\x90$\x06\xB6^\x1DN\xCA\xB0`\xA9\x03\xC0\xB6\x82\xA9\xBE\x98\x7FH\xD3\x0A\x11*A\xEAg}G\x11\x87\xD1\xB0\xC8k\xF51\xFE\x80\xAAz\x94\xD4st\xD9G`pQ\x12\x8FKK\xBA\x90\xDE@\x0C \xBF~\x0A)\xA9\xAA\xA2L\x17\xFB\x0Cf\xB4/\xA1\x84\xE5\xEA\x87u\xA9C3\xB4\xBB$\xF7\x03~\xC9\xA8\xDE\xB4\xF6\xE06b\xEB\x0E\x03\x92\x80\xF0\xB40\x9Da\xF3\xD7\x1F\xE6\xEC\x84q\xF4\x02\xDE<\xDB]\xF5\xA5\xB5\x83\xBFx\xA6\x8DR\x8E,\x01R\x10.\x8D<\xCF\x1C\xFF\xEE\xE2y\xE2D\x02\x9A\x86B\x8F+\x8A;\xB8\xA3#\xC1{\xFAn\xC1\xFC'\xBE\xE5\xC0\xBAOn\xBA\x1A\xD1\x1ET\xA1I}\xBE:i\x01\xEC\xB4\x03U(\xB11\xF2f\xFA\x94\x1B\x80\x06\x18\xC6\xB9\xBC4;\xD7\x80\xBA)\xC5\xA3\xC3\x07\x95\xF0U1w\xF25\xA9\xE1\xCD\xAAu\x15\x8C\xC08\xCC^\xD8x\xB9\x19\x91\xFD\xA5\xFE\xD8'=$\xB8\xBD\x18\x99\xC0\xA8'\x04\xFD:\x11\x90\x08\x9D[x\xD6\xF7s\xA1\xE7\x9C\x93U\xCF\x0F#\x8A\xF4\xB8\xF7c\x19\xB1\xFE%5\xCBI\xF5\xBD\x8B\xAC8\xEEfzU\x95\xC6l\xF1pQ\xAA\xC05\x81V,\xA8\xE8\xE0T~\x7F\xA1}\x10f\xFBR\xD1\xA5\xE9\xC7\xC1o\xACA.\x81\x95\x8Cx\x8Fz\xF6\xD3\xB2\xC9\xDD'\xFD\x1C||f~\xEBD\xEA\xB2\x12:\xE8\xC2!\xA3\x7F\x9EmJ\x95.\xC4\xA6\xBB\x10\xAC1\xDC\x08s5a\x82\xA4k\xF3\xB9 \x0C\xA3\xB5\xC8\xE2\xB2xBs\x1D\xF0vG{Z\x85I\xEC\x8C\xCE\x98\x10$\x99\x16\x9A\x1Ba\xFD\x83\x96\xC4\xA8\xE3\x9F.\xDB\xFF\x0E\x83\xDD\x12\xB6\x92\xB4g\xA2q\xCE\x1D\xA6\xF1\x14\xDF2\xE2\x9D\xC2\xA7_RP\x01\x95\x99\x88\xE1\xF9OK\xC9\xED\x94\x99\xFA\x87Z\x8Eq\x877\xD6'\x0E\x82\x10\xCC\xE1\x98T\x17\x8Bwb\x07\x17\xE0\x92=\x027\xE9\xB6\xA27\xFE7zXo\x98ZL\x86k\x90DX\x8EY5"\x14\xFEt\xB2[\xD7<\x16L\xB8\xE9\x0C$L\x8A\xE1\xDF\x83\x1Fn\xCC\xDC\x89M\xE6\xB6\x84\x05\x9Au/Aw\xC5X\x99\xD2:\x83-\xF9\xEB'T%\xA3\xFD\xE4\xD7 Wa#\xB6\x12\xA4\x9B@\x07\xE4\x15\x19\xDBQ\xCFr\xE7\xF0\xE7\xDEf*\x04\xE3<\x9C\x12\x04\xB0{\xF6h\xF4\xE1\x9B-"\xD4\xA6k\xFD\x84\xA7:Z\xFC\xDE~\xDC\x808\x8Ad\xC0\x81\xBF@E\x04\x13]\xCD\x89\x1A\x0E\xDF\x93\xA1\xC3\x1A\xB4Cf\x19\xFFP\x92\xB6\x1C|\xE4\xCD\x07\xAD\xA8|V6\xB0\xCC\p\xED\x14\xD2t7cP\x90\xD0\xBD\x86@\xDB\xE0M\xCF\xB2\xE53\x19\xBB\xF9\xB9q\x15w\xC0\x95\xD4\xD5;}\x98\xA8\x84\xE2k\x87z0wcr4\xE2\xF0\xC6\xB1^6\x81\xF3\x16'[]\xCA\xCA\xCE\x1B\xB6K\x0A0\xCA\xE5It\xD5F\x9C\x99\xCB}\xE2\x8A\x1E\xC2$\x1A\xCB\x96\x999M\xBF\x18\x80\xCF\x0E\xE5\x9C\x92E\xF4\xF8>\x8F<+\xF8E\xA7|%\xAB\xD2\xD6\xFB\x81#\xFCd\x96\xC2\x1D\xD7\x0A\xC45\xC6\xB9:z\x12\xBCg\xB6\x07\xC8o\x13\x0C\xA7olL\x82V\xB1\xAB\xA0\x05\xDA\xCF\x0Ev\x18#\xC9Tv\xC1\x15[\xE8\xB5\xEA\x97\xB9g\xBAg.\x90\xB4-\xB6\xB4_\x12\xE8\x90t\x0F\x91O\xE2\xE4\xFA[\xD7d\xB6\xA7+\xA7\x854n\xFB\xDA\xBE%\x9B-`\x82\xFB\xC9No\xC0\xFBq\x15\x0A6\xEFKo\xD1\x0F\x81\xB0W\xC0\xD7\xD1@\xC9\xCD\xCE\x9E\xF1\x82\xF8\xFC\xD6\xA4[3\xAB\\xAE\xEE\x0C\xC3\xC3\x01\xF7\xB5.\x96\xE0\xC8\x9B\xA9N\x0Ba\x8F\xA4"\x8Fi\x01+`\x1D\xC8\xC4\xB1!u\xC9=c\xE6C\x8BM\x83Kj\xB3\xA8\xD2\xABy\\x193\xF4\xFE\xFD\x81\xC4\xC6\xEF&\xCFY&\xC4\x80\x85\xE8c\x0An\xAA\xB7\x9FN\x82"V\xBD\x9B\x0A4\x16\xCF\xF6\xD5\x85\x83,\xB2\xFF\xE2\x93\x0C\x0A0A\xA1\x10b*b\xD2\xD7!\xC8\x00\xAA\x8A\x908Y\x07\x94Z\x02\xAD\xA5\x1C\xEB\xDA\x12$\x9CeTh\x9E8q\xB0\xF3/\xC4\x1D\xE5\xA5\x0C\x95&\x87Lu'\x93\xE4_32U,B\x1B\x19\xB2)KDNX\x9DDM\x15#\xC4vT\xA5e\xA9[5\x0E'1\xC5\xD0\x90\xD8\xAE\x1D\xFBQB\xCE\xE4\xFEj\x03\xA1\xC6\xC8-'JN\xDE\x9D\x8D\x86\xCA\xC8vb\x86\xB7\x17V\xC4\x02\xEE"\x96\xC6\x05\xE5\xA6\x06\x9B\xDB|\xE5)\xF5\xE5\x81\xAB\x07v\x02\xB21\x8E\x027\x10\xF5\xD31&\xDC'l\xE2\x19\x9A\x88`'\xD2[*j1\xA7\xC5E\xB5\xA8=$\x09F\x93\xCB`\x88\xF6[T(\xB5f\x9E[\x15\x7F\x1B\x98S\x98\x92\xE8\xD9-C\xAD\xBCM\xA4\xEE\xF1U]\x86\x1D\xE2\x0FJ\x00\x81\xE6\x94\xAA\xF4?V6\x1D\xC86 \xCB\xF6\xE7\xDB}\xCA\xE1\xC1\xBE\xDC\xE6\xB9:h\x81D\x02I\xDE\xCB\xC0&\x89P\xF9\xD1g\x96#\\xFDn\xEE\xC7>\x19\xDE+\xFE\xA0B\xE1D?\x03G6\x02\xCAQ3*\xB1\x10P\x14\xFB\xF9j\xD7?^\xC8\xA9r\xF6\xE9\xF0\xEAH\xE2\x8B$`\xA6\xC0o\xDA\x0BS\xF1"\xCD\xA4\x93\xF1N\x08TW1r\x94\x09d\x7F\xFE\xAE\xA2\xB1s\x17\xAB\x95\x99Xa\x8E\xAE\xC9\xEB\xB9\x06\x88\xF7\xF3\x97F\xA6c\x82\xE4\xFF2\xFF\x0F&dsi\xDF e\x11\xCA6\x99p9\x8F\x8A\x92.\xB9;\xCA\xB0\x86\xEE0\x16\xFF\x08\x02+\xB7\xAF\xEE\x19\x0F\x02$q\xF6\x83\xC7\xF1\xCAE\xFD\xDB\xBB\xE9\x00O\A8\x0D\x00\xABi\xB5\xDA\xDF\xCC\xE7\xF5\x0D\xCF\x81\xFBN<\xF0_\xF7 +\x12\xE5\x7F\xB0\xA1\x9B\xA7\x0C\xAF4\x1D\xCC\xB6v\xDF<\x95t\xA2\xBA\xB2\xF0-\xF3\xE7\xA6\x98h}\xA3\x11\x8E\xB1h\x99\xC1\xE3w4>C\x9B\xF8\x965\x13h\x05\xF8:\xF4D\x0B$\xC3CVC\x139\xE3S\xD1\xE7\xAF\x86\xB6@\xB5\xCC\xB9\x15\xADo\x09\xEC\xBB\xAC/Xl\xCD\xCC\x96\xEF?c\xD0\x10\x9FY\xE6\x1A\xB6\xDD\x0F\xFAa\xF6lb\x1DG\x02\x07>~\x05\xB9\xFC\xCF]\x7F\x9D\xA8\x92\xA2\xCE\xD5d\x9F\xDA\xB1\xB5\x1F$Q\xCC\xE1\xC2\x0Dt\xC70k\xABmP\xDC&W<9\xCBd4\x84d<\xC3\xD90\xD30X@\xE3>X\xED\x97\xDF(:\xD6oy\xBC\x82\xEBo\x9A\xF0\xE6\xD6fp\x03B\x87(@\xD2\xC3?{f\xD4\xCAX\xD0\xB6\xB6\xB4\x0D\xD4\x15\x94\xACV\xE8\x9A\xD7P\x91L\x9A\xA3\x9F\xC4\xC9U\xA6\xAD\xD5\xFD\xB9\xC6wd-\xB0X\xC6\xB9\xED\x00\xE5\x1C\xA6\x80\x0A\xCB\x8D\xFC\x84~\xF4\xD4\xDA\x0Ck\x83\xAFI \x19B\xDE\xF7y\xFB\xD8y`c\x80]/\x00\x1BL\xDE)W\x03\x0A\xFF\xAE\xCF\x0C!|\xA3\x0F\xCAy\x0F\xF2\xFB\x8B\x7F_&\x8C\xBB\xFB\x8D\xD0\x06\x9E\xA3Qh\xF1\x1D=\xC75\x91J;4M\xD4\xE4_\xE4\xF1[\xE8\xB4e\x1F\xA3\x89~\xF6\x880\xD1\xB4\xE2`\x96\x07\xC5,3\xBEk12\xD3\xEF\x8C\x9E\x10\x901B\xA6\x92\x8FR\xBE\xCF\xE4\xD6\xA1q\x8F\x8E#'N\xD2\x9F\xFE\xC3q\x82.\xA3x\x14\xD4\xCB\x89\xA3#\xFCO\xF56\xF8\xFEL~\x1A1u\x8Fqx\xB88\xE8\x83\x9ER\xEF4\x10?\xFD\xE2\xCF\xC4F\xE6u\x88\xB4\xCF\xACi\xC1W\xBA{o \x83\x00\x83\xE3\xCA\xA6$\x82\xDDvll\xE0\xDF,\x0C\x01X\xCF\xD3$\xB0\x12\xF8\x08\x18\xA7#t#\x88|1\x91 \xE2B\xA0T\xDE\xB4\xD0\xC4\xF9\xA0*twX_-\xAB\x11\xB0$\x0FgV\xBF\xAE:(\x02"\x0B\x04k:\x96\xEF\xBF\xF1\xC3]\xCD\x12\x1D\xB3\xFD\xC5\x01/\x1E\x94\xFE\x85ID!\xE2\xD4\x06\xA2\x19Q;\xAE\x8E\xE9l\x8CD\xCC=\xD5(\x1C\x90\x92\xB6\xA9\x03\x85\xD4\xA8F\xBB\xDB\x80L\xC7\x0BG\xF3h\x1AZ\xFCI\x1B}\x06\xEB\x07L\xF4W\xF3~\x0A\xA5^\x7F\xCA[\xB7)X\xD5\xED\x8C\x91\x09\x15\xEDJS\xF7de\x07[\x9Cr\xA5\xEC\x14\x04\xAC\xD2p-\xFA\x93'c\x9F\xC5\xCE\x11\xEF\xF8u\x86i\x81\x8E\xEE(\xD4\x9C\xEB\xA8q\xCF\xB9:\xCA~53\x01\xA5\xD9\x1D\xA8qu*\x8F\x1D\x97\xAA\xC1\x05\x0C\xF0\xB7g\x93\xA9\x8A\x92\xB1F\x195\x90\x9C\x04\xE7V\xB9\x10\x84\x17\xD8i\xCEH\x10\xB4l\c7L\xE5\x9B*\xA8]?\x17\xBAO)\xCF\xFE\xB3y\x0B/y\x05\x0C\xA8\xD9^\xB2\xD5\x94\x8B\x05g\xED/?\x1Dl\xE0*\xB0R\x9F\xE6\x03\xA1\xC2\x03\x88\xA1\x08R\x83\xEE9\xD4A*\xF4\x17\x84\xC3\xA2\x80\xE3\xA9\xD0g[W39\xD7\xEA\xD7\x12\xF1I\x19L\x1A0K\xED^\x99\xB7\x90\x02\x08U\xD5G\xD1\x19\x98#{\x87\x1C\xDA4\x1AOP\xEE_,\xD8\x0F\xD6\xD8\x17\x0BC\xEB\\xA7Z\xAC_3\xBE\xF6\x06\x17\xAB~\xFEq\x0D\x09\x86\xA6\xA6\xCA\x06\x91D#\xFD\xB5>\xEA\xA2\x00\x8B*7S#A\xB4\xF7C\xDE\x8B\xD4\xE1\xFE\x81\xF9\x186r\x06\xED\x0E\x18\xEFC\xA2!\xE5;\xF7\x13\xC1\x92%\x04u[::T\xEE\x1F3\xF2'`\xCC@q\xB1\x1B\xD4\x86\xA0\xC5YO16\xBA\xDB]d\x93\x1C\x197\xE4\x0C\xB9\xB1V;L|\xA4M\x9F\xA1\xA3w\x9C\xB5b\x11R\xDE@\x0F(\x1D\xAC\xD1\xA3\x0E\xDD\xC0z\x0EB\x86\x88\xE0\xC8\x9B\x8A\xF93\x067?~\x9B\x8Ax&\xAD\x80p\x8A]p\xE9\xCA\xF3F\x86\xC0j\xBF\xEAM\xDC\xA2\xDB\x0D\xF1\x03\xA8hlx\xB0\x7F\xE2/\x0F \x80`\xD7\xD2\xC8\x18C~\xBA\x1D\xA9\x97\xDBqG\xDAd\xC5L\xF8\x18\x1D\xFB.zs%\xF4f_z\xEE3Yu\x7F\x13\xB7\xDB3\xC5G\xCC\x99$\x99P\xD6;\x15&\x97Z\x81$\xCC\x91o\x0Eo\xD5Y\x06\x01sr\xAD\xC6\xB4\x9A\x1C\xE2V\xAEF\x8F/oN\xA5\xBF\xD3ur\xFA\xFCb^\xF4\xF3\xFD\xB2\xF0k+\xED\x1B\xE4\xE1j\xE77\x9B[(5\x94s)Q\xF5\xAD6B3(2\xD5^\x11\xA8\x8BT\xF6;UQU\xC2\x8C\x1A\x89<\xB47\xD6\x9B\xE1\xE8\x08I~l\x96 q_6\xB5\x0Da\x08\xBF\x98\xFE\x12\xA0nk\x0E\xB4\xF3\x8DT\x9D\xF8GF\x10\xEE\xC8\x89\x8F\x0FN\xB8\xECs\x01\xCB\xF6\xB7\x87\xBFm\xC7-\xD39x\xF4\xB2\x81l\xCD\x9E\xBA\xAFp={7?\x90\xAD\xED\x8Aq\xFDs;\x03\x0F5\xD5N\xC9\xDBnN3P-V|A\x0A\xA7\xB8\xAD\xD6&5y\x16F\xE8\x89\xC3r\xB6\xB9\x11&\xCF\xB2 \xDB\x8Dz\xC3\x10\x8D\xD2\x1D\xF2oaQ[6\xC0.L\xD4F\x16\xE6\x02\x96\x10\x00+s\x0AvW\x83\x1B\xEA!"h\x9D\x81\xF0\x8D\xBD\x15\x19;ps\xF1\x13U\x99%\x9F\xAD\xE1c>\x93\xA1C\x96\x7F\xCB\xA8\x05\x0B\xE5\xDC\xB9|\x12\xD5\xF1\x0D\xA9\xBB7\xFC/\xCE\xE7Y\xC6q\x07\xD4\x08\xAB\xB26\x1A\x04=\x12@\x07\xB6\xF3.\x7F\xDB}N\x97qp\xBC@\x9Bx\xFA\x0C\xBA>\x91\xE0\x80\x8A\x01\xFA\xE1\x0B\xC4J/A\xA2\x13\x0E\xE6\xAE\xABjpN\x86\xA2\xB5\xB09\x14\x16\x98\xA9_n\xA1\xA1\xAE{o5\xA1""\xAF4x\xF9\xB7\xF3\xD2P\x8D\xB3@\xEFG\xBF\x9E \xE9 \xD3\xDC2\xEDnHf)\x06\x93f\xB0a\x0D\xA6#z\x1A\x0D\xCF\xB6\x1AW:Z-q%\xCEH\x0A\x93\xE2\xFF\xC9?\x86\x88j\x00G\xE80-\xFF\xDA'k\xAFK\xBF\x0D\x06\xA9\x1A6\xDA\x99\xA8\xD8GMV\x16b\xA6\xC8tn\x9B\x051\xF4\xAC\xC7\x1D\x89\xA9\xEA\x8D\xC4\xB4\xEC\x9F)\x1C\xE4\x10\x92S\xAE\xFD\x81~\xEF\xA3`\x1E\xB0o\x1A\xEB\x8B2\x07W\xCB\xE7}\x16y\x9F\x98\xB3\x8D{\x0B\x89R\xE8\xD9-\xE8^\x05\x00\xFD\x0B5\x84\x19W\x8A\xAE\xD8k7F\xAE\xD8t\xDEs\xCB{p\xA0\x19\xB3>\xF4\x103\xEF{\xE9\x9Dr\xEBp$\xCC\xDB\x19\xB0\x9C\xA9\xB9D:\x1F\xA1\xD6)\xDB\xCE\xBDKb\xF7\xF1r\x86\x8F\xBA\xD1\x941\x1B\x84\xF9\xCBX\xEA\x81\xE1cg\x13\xED\x11X\x7F\xD4%\x88Ry\x8C\xFE\xDA\x15 (\xD8\x9Fk\xAF,\xEB\xA0\x86\xF1g'\x93x\xA5h\xF0\xB9K\x8F\xC7\x98j\xD7\xDB\xF03"\x89\xDEy\xE8]x/2\x84\x94s\x87q3d\xA7M\x10\x9A\x80j#\x0Cu4\xA2?\xBB\xB8SvDHt\xAD%\xDF\x87a\xCD/\x03E\xCC\xED|5\x98\xD2\x8D\xBC\x91\xD8q\xDC\xCD\xBB\x1A\x94\xF4\xF6[N\x12\xCCB<\xCE>\xFF\x0D\x82\xA1\xA4\x84\x12P/"\x98\xF1\x07K\xDA\x9C\x0A\Q\x101\x8D\x82|/\xDD"J98\xF1\xD5y=\x9D\xD7\xFEv3\xA2-\xC7\xAAv\xBFH5\x0A8\xA1\x8E\xDF7\xB1X\x7F\xDA\xD9\xF3\xC40\xB7\xC2\xD4\x1E\xAF\xC6\\x05\x05_\x1E\xCF\x93\x0F\xCA\xF2\xFDn)\x9D\xB3\xE6\xC1 m\x07\xC20\x0C\xA8B\xA8Q\xB8\xB8\x91V#-\xDF@\xCC\xBD\xCCJhD\xECr\xA9$h\x0FW?\x16\x91\xF4\x8C]\xD3\x15\xAD\x10\xA4\xB5\xB9\xEB\xD9G-6\xD8\xF9\xBC\x82\x84/q/\xF8\xD0\x0A\x8C&\x14\xB3\x14\xD1#f\xE7\xA0%5V\xD1H\x00\xA0\x13\xFB\x9C\xE2\xA3~7Y+\x7F\xB96\xA2 \xDD\xEE\xDC\xF3\x17\xD1E\x8F\xC9\xCAy\x80Sv\xFC\xF6\xB6\xD4\x91\xC8/\xE8\x1Dj=\xA9\x01'1(\xC7\xB6\x18e\x09\xA8\x07T\xE9\x0Fd\xB5v\x8E\xC0\xFA\xCF\x98H+\x17c\xB5\x05\xE24\x04\xFE\x18\x13\x80E\x829.\x88\xFB\xC8vn\x1E\xD6\x92YF\xC5\xFD"\xF7\xC6]*\x1B\xD7{\x8B5A\x15$X\x02"\xA02\x8B\x99\xF1\xF3\xAF\xF7\x94'r)H\xABFJ_\xA6Vk|H\x8D\xD5\xC7}\xEB\x9B\x12\xFC\x8Cv\xC8\xFA\x8E\x8B(\xA3!\x8E\xBD\xADl\xC0\xBC\xF9\xCE\x1C\x81\x10\xE6\xE3\xFD\xFD\x1Cm\x1C\xC2*5]\x15{[\xC3B\xFDW\x9C\xB6\xC8]\x93P]\x07|\x96\x0D\xF1\xD0\x9F2\xE9\x9EM\xE2\x9A\x0A0d\x0C\x94\xFF.\xA3\x7F\xF6\xF6\xF8\xA1\x02f\xBE-\xE4\xB6\x15\xF6\x0B\xEANj\xAB\xE4*4\x8D\xC1\xF1,,s^6\x0F[\'\xE8\x0FAss\x0EER\x82\x1F\xEC\x83\x9A\xFAO\xC4Y\xA5Zy\xA5\x9B\xB0\x1C\xD6\x0A\xF1>\xB1\x05;\xC4\x8B\xF5?\x12\xD68\x09\xD6\x08\x03`\xD02\\xB3go\xAC&\xB5*\x12\x1A\x85\x10\xE4\x1B\xB8\x8D\xFB\x8E/\x93c0\xB1v\x82\x8C\x07\xE5;9\xE2\x0F\x09\xF3\x9E\xCE\xA1\xFB\xA5u\xF1\xA9x\x9B]\xAD?h\xC0\x01CfC\xC74\xB96\xAB\xD8S\x007\x91-\xD0\xFA\xF7\xEBq~\xF9=Q;\xEA\xDC,\xDF\x86~\xF7od_\x03\xA8\xB9\xDB\xCEK^2\x07\xE0\x08\x0FU\x11\xC6R\x8C\x8B\xD7\x04>\x0729/(\xD36\x09\xEB\xF5\x17\xE9\xD0\x0C\x89\xB7\xF4T^F\xD7G\xD5\xD1\xED\xA29\xBE\x98VO5\x96\x8B\xFB\xDD\x98\x7F\x1E`\x8F\xE0\xC4\xB0=1;F}\x98\xA6\xECx\xA1\xA5\x95\xD2\xE6&\x1B\x0B\x04\xB1\xFE\xFD\x98\xCE&\xDEw8\xD7L\x13\xA3\x0B\xB7\xDEm\x08\x02\xACKy\x95>`y\xC91\xA5\xA5\x0Ea\xA6\xAB\xAC\xDB\xC4\xAA\xFC\xBE\x9B3\x18\xFDs\xCFE\xFE\xA0\xD6_6\x10\x13;\x9A\xA6\xC4\xCC\xE7\x07\xAA\xC1b?\xC8\x90<\xF1\xA5T\xE9a\xC3=\x15\x0A\xE9\x08/+U\xBC\x80\xD9\x80\x9F\x042=\xBC\xAD?\xFD\x11\xEF\x99\x06\xA6\x88\x8F\x01\x85\xA1\xE5{\xB6S\xE5c=E\xDC\xCC\x0D\xF8\xDFeg zZ{\xF0\xBE\x91~d,\xEF\xCC\xF0\xBCRR%Q1r\xB5\xDF\x18 \xC5o\x85'\xB1o\xA3\xB9f\xAB\xD7z_n\x14\x0C\x14\xE0_[\x86\xC0\xC7\xCC\xC5|\xC1\x82\xBC\xE9\xD5\xF0j\xCF\x0B\x8B\xE18\x02\xC8\xA0\xED\x1D=m\xB1\x83\x1F\xC1\xFB\xE3\x02\xC3\xE3E\x8Eh\x1DL\xF5\xEC\xD6\x10\xC7\xA4%\x0E"a0\x85\xB8p\xFA@\x1A\xD0z\xF2\x9D&\xDE.\x81\x04\xDB9\x10\x07C\xD2\xEFP:w\x18\x14\xC0\xB7\x0F0\x00\x08%\xC8\x03\x88\xA5\x05q\xE9\xA4m\x88C\x0E\x08\xBE\xDC\xC6/'\xD7Z\xF3R\xED\xC9\x12\xC2\xB6\xFB\xF0\x07\x0B\xB9p\xEA\xBC\x9B\xC9"\x18k\xB9\xF8\x12\xA3t\x90\xEF\xE5\x83K\xDC\xF7h\x08\xCEc'\xA7U\x94g\xED\xCE\xCF\x83\xC4\xBB.\xA1KH]\x9ET\x9B\x02OZ/q8\xE8\xD2FB\xF7}\x8A\x93\x95R\x88\x00\xBD!W\xF2\xB3\xFC\xD7S(\xC5W\xA4\xE3\xD1\xE6\x86\xD0\x03\x81\x98\xAA\xDC\x05\x9D\x8D\xA3,\xC8\x80^\xE4H\x9A\x7F\xA5\xFF\x0C\x12\x99k\xDB\xA8\xF0\xC7\xD9\xE1\xD1i\x8D*r\x7F\xC3\xF5g\x947\x96\xF0\xED\x1Bn\x93q\x00id\xC4\xCCT\xB6\xB7\xE1\xC1#\xFA\xF1\x89\xCB,\xD9`\x0D\xE1EbX\xC8\x9B\xD6J\\x9CF\xBC\xD2\x92\x10*\xAA_9\x85\xCC\x96\x02U\x9F\xD8\xA2\xC1g\x02N\x92B\xD5\xF8A\xE0\xE7\xA1O$L\xF0\xD9d}\xC2\xDF\xF2\xB7\x06\xDD\x7F\xC9\xAC\x8A\x10f\x18Z\x97F0\xF7<\xA4\xA4\xDA\x03-\xF2\xC1\x87\xEC\xF8\xB7Ge\xA7\x9C/\xB4\xE9\x15l`\xAB\xF4\x1A\xA9\xDF\xC3\x9BJ\x0E\x9D\xFD\xC2\xB8d_\xCC}\x1A}\xE8\xAF\xEE;\xE9\xC4.\xCA\xD5\x9EGr\x0E\xCCR}\xC1\xB3{7#o.\xC6\xBD\xEE\xB0\xA6\xF3\x87A0W\xC6\x16(\xB2]&}G,\xA64\x17\xCB\x8Fm\x8A\xA3\x08\x94\xED\xDA\m\x8B*\xED\x8C)\x94~~\xCE\xFC\xAE\x96\x13\x13\xDA\xD93fp\x9A#c\xF3\x14\x15\xBAk\xBE\xF7\xA5\xB7\xDC\xCB]\xF5J\xEAN\xB1z\x05\xC9\x995W}}QAq\xFF\x88*\xA4\xB5`\x0E\xD5\xC3v0\xD7\xF0\x82\xFEk3\x02"\xA4\x1A\x05~\xA55\xBE\xDA\x97\xE5\x92\x9F\xE3\xE1s\xA4\xAAm\xA8c\xFC\x81F\xC3\xD8\xFD.\x94+"\x86\xB5\xEE\xDC\x02\x1D\xDA\xE9\xCA\xFE\xEF\xF3\x9F\xFF\xAD\x8A\xE4v\x10\x9E\xB3M\xAE\x09\x16|K\x1Fe\xDF\xF8\xA2\xFEu\x09|\xFE\x98#\xA4\xA2}K\x8F\xAEq\xF9\x86 ?N\xE3h\xAAcg\xACC\xD0\xD4\xE7\xD2\x09\xF8Y9\xF5\x959~\x17\xF4\x0D\x09o\xEA\xC1\xE8\xB4\xBE\xBE\xAF\xF6z\x06\xDB\xA7\x1D@3\x826\x8D\x83T\x0A\x9C-\xDA\x98W!\x82\xCF\x97\xC5\x88\xA1\xEC\xBE\xED\xA9i\x0De}VEe{d\x19\x89n[\xAB\xEF\xCBEQ\x1EY\xBB\x19\xFB\xB0\xFC\xCCj*\x00.\xB8\xA8T\xB2\xBB.\xF6\xD0A\xBF\xC9\xF9{\xE2b)\x03V5\xF9\xCB\xE3\x8F\xC1\x89Dr\xA9\x95!\xD3\xD9\xA7?\x10\x8C2\x01\x1Ek\x0B\x9A\xD6\x89\x936N\x7FH\xA4dKH\xC7\xE9\xB9YTe\xDD\x12>/B\xD8:_\x9C\xB5"\xB1\x864\xE2\xA1\xB5\xAC\x94\xBBS\x1B\x10\x07\xC4YL\x1Bb\x7F\xE7\x8F]\x1F\xF6\x06R\x85\xF9,x\xD3\xAF\x9C\x96`\x8A\x1B\x19\x1B\xE1\xB5\xF0\x19\xED\xA7\xB3~Yke\xCC\xC4\xD5\x11\xA6\x1E\xCA\xD43d\xCB\xCA\xFB\xE5\xB7\x94\x00-D\x8AK\xC7\x0F\xC2U\xE9\x16\xBD\x93\xFA\xDB,\xB4\xCB)V\x8A\x0F\x90\xFAiO-\xCF\x0D\xEFg~\xFF\xBE*\x8E6\xC8\xF5\xDE\x13\x13!W\xCA\xC6\x92h@\xD5\xDA}\xC2\x16U\xD6\xF7L\xE8\xD86 C\xD5~;\x08\xDE\xA2\xB4\xC7w\x1D\xA6OO\xEF\x9E\xC2\x89\x15\x0F\x0BJBD\xB8\xE2\xCF-g\xCC \xC6\xD0\x1E\xA3Z9\xEB7=-j\xA0\x02(D\x01~\xABI\x87\x02\xC1u\xB5\xD8}yo\xB6\xDC\xA5p\xD8Kap\xA5\x06W`\x82d\xB3\x9Fo\xB2)\x17Vb"\xBD\xB9\xF5-\x0A\xE1\x99[\xD7G4\xEE\x94.\x00\xAD\xB6x#w\xFC\xCD\xFC\xF6\xF3\x8A_\xC6\x963\x98\xD3\xE6\xB4?\x90\xCB\xC8\xAD-\x14\x7FtL\xE4\x0Fs\x92\x0E\xC9\x8C\xD8\xE4\xE0\x8A\xF7\xDB\x88\xBE7\xBB \x85\xDF\x80\xA1>3L\xED\xB2\xF7V\x0D\xC6\xF2\x0B9\x09\xA5\xE5\xB9\xF8\xB7<~g"\x1D\xA5\xD8kk\x83p\x0D\xA9\x05\xB8\xA0\xA0{\x03\xA4\x9DJ\x97+\xCE\xB0E\x00\x9BYX\x87\x94\x1E4\x04\xB4gp\xA6`\xEF\x0D\xE9\x82Qi\xD3i#\x12\x85\xEBD#\xD4\x10\x06\x0E\xBF\xAB\x14\x05o\xDC\xF4\xB4\xCF\x14\x9F\xD5\xFF\x9C\xA6\x0AB\xAC\x08\xF0\xBDoh\xE8\xCF\x11N\xF9\xDE;\xD1\x99\x84\xEF\xB1\x13\xCA&\xAF\x8A\xDA\xFB1y\xE31B\xB5\xAA\xC1\xF5\xCC\xC2\x0B\x9D\xF2\x18\x08J\x00\xD1\xE7\x92\xD4\xF3\xE4\xE9\xEE\xA5:\x9Dy\x1F\xCE*\xEE\x90V=\x9E\xF9\xF2\x99s:c\xCF\xB7\xDE\xD4?\xD7D\xDCI\x027\x0E\xEB\xCBD\xF6&7\xBC\x89\x9E\x8F\x9B\xCE\m\xCA\xA7J\x8B\xF3q3\xDB\x00\x06\xEFbf^Zh{]]\xC3\x9D\x81\xBC)rFQ\x95k\xA0,\xED\xFD3\xAF\x03\xAD\xE4\xD3+C\xB9k\xCEx\xCF\xA0\x95r\xB1\xB6Y\xDBP\xAA")F:\xFB\xBB\x1B\x0E{3\x9C\x90b\x9D\xC3\x93\x96\xCE4\x03CQ\x9B\xC9\xA5\xD0a\xF2\x09\xDC\xF6z\xDCj\x95IB\x1C0\x90\x9FUj-\xBD\xEB\xEC\xCA\x85\xAE\x0F\xEB!\xD9vH\x85\xCF\xDB\xFD\xF5\xB4\xC7\xD0\xF3\xE3;\x11\xBBp\x13\x0C\x90\x0E\x92\x83#3_\x07\x99S\xEA|\x98\x8E\xEE\x88\xCC\xABNl8(K\xE1#\xE7\xFC3\xBDp8\xC0\xBFLeB\xE0\x08T\xBD\xA6\x11\xB7\x00\xFE\x02E2B&hCs4\x7F\xFC\xCA\xEC\xA7\xBB\xE8(\x95\xE3s\xC3\x98V\xD4m*\xF0\xA8\xA0\x92G\x88Z\xA1\x98u\x05!\xF3\x1F\x86\xEA\xC9\x1E\x0B\xF9\xB8Pv9k\x83jXBaZ!\x1E\x8D\x9D,\x99\x8A\xD1\x8D\xB5+\x90\x99\xCA\xD4\x00\x7F%\x03\x83\x09\xCF8\x8E5|\x08\xFBk\xB3\xC9=\xE2\xF8\xDE\x07\xC0\xB5\xA03\xC6A\x8A\x16\x06|,9L\xC6)5P\x8C\xE1x\xD0\xC3\xCEwk\x09\xACv\xDB\xB4\xEC\xC2\x9B\xEE\xDDbV\xCA\x05g\xAB\x81<\xFD\x01\x19\xFC)2\xB3\xB9\x90\x0E0\xB7\xA0\x03\xBE>\xD9j\xF9R\x17;\x97V\xD5\x08\xDB\x18X\xEBu\x8F\xC9B\xF8\xD3\x09#\xD4,\x06\x88\xC2\x1E~J\xE1B0\xD8\xBB\xD52\xEEP \x14%\x98\xB3Ca\xB0hP\xC6,3\xA1U\xDB1\\x8Fw\x93\xDB#\x1C5\xB7\x1F\x8F\x0A\xA3\x12\xF33=~a$\x84\x0E\xBA\xAE\xF8K\xDF\xFCe\xFCs\xAE\xEB\xA7{\xC7\xC7\xB5\xEA!\x9E\x8C2\xA0\xDE\xDB\x11r\x82\xD1X\xF3\xFD\x96j:^]f/\xEB\x19c\xBE^L)\xC0\x14\xED\x00\xA6\x8B#i\xFE\xBB\xABei\xA9t\xE5\xCB\x93\x8D\xC0p\xCE\xE0\x19@l\xE1;\xF04\x05\x89\xB3\xDA\x11\x0B\x10\x15\xDDc\x90\xF6\xFA\x94d\x8AT\x8F\x18\xAE\xD0\xC6\xFD\xCB{\x16\x06H\xA7\x0F\x93B\xCFM\xE4\xF5k\xA6x"in\xAA\x9C\xC7\xC3*\x17\xB1\xEF,dp‹ê³9S&‹æ#y1\xF5\xE0L\xE1\x9D\xA5\x05\x82\xAAp\x8FP\x9E2\xB7\xC8\xD4\x8E\xED\xA1F\x8A\x9De\x07\x9BU\xAC\x1CF\xD1\x8F-\x98\xC00 \xC9\x19 \xF3,\xFF\xE0~l\xA9\xEF"\x81/u\xA1\xAA6\xF1\xEE)v\xC2\xB4\x93\x09\xC6\xAEG.I\xD6\xA1\xF9\xE1\xAC\x01K\xC6\x92\xE0\x9F\xDB\xE7@\x05=\x1F\xD7>\x05^\x103Ypy\xDF\xFE&W\x8B\xA4\xC1\xCA\x1C%\xD5A?t4\xD5;\xB0\xFFO+N\x18\xED\xF1\xA1b\xB2\xA0\x1BA\x8E\xFEo\xDA\xBE2\xAC7F\x0B\x0D\xF3c\xE5Yw\x94\xD9Mw\x0F#(\xBC\xF1\x01,\xA1\x84&\x19?\xE1\xD7\xBC\xCC\x1F\xB5A'A)*\xB0\x0Ekil\x8C\xF5c\x14\xBF\xDAU)\xF8L\xEDr\xACMI\xC8\xD9\xF7\xE3{\x84\xFCQ\x12\xBF\x9C\x81\x07\xEE\xDD\xD4\xCA\x99y\xA6\xBB6\x89\xD7\x83\xFA\xE6\xD0\xC8a\xC5\xFE\x8E\xB8C\x0Ac\x87\xB1\x93#\xB0\x03\x19\xC8\x0F\xAD7\xE6\xBB\xE1\x80\xCAqn\xCF\xB4\x16\x94\xD5\xC2\x07\xE0\xA7\xF4\xAEsq\x91C\xC4{\xEC@\xED\x10!\xE7.\xDF$\xE5\xC1\xF4\x96lJ>\xC3\xDDQP\xD3t\x13\x1F\xCC\x91\x92\xBE\xB9;\xE8A=\xF3`\x8F\xA6\x1A\x18\xA3\xC6K=\xC8\x9C\xC5\xE1\xCF\xD7i\xCD\xFE\x17By\x8B\xE5\xB6\x80\x90sP\x13\xF5H#Sz\x19\x85\x07N~\x1E\x90\x04\xB2\xCC}\xB7=\x9F\xE9\xE9\xD2\x84O\xD1\x05Wpf\xA9{\x02\xA0\x87\x103\x02|\xD0\xFC\x95\x9F\xAE\x86\xC4\xDC\xDBl\x9C\xF2t<\x18-\x08y\x92+\xA0j\xD6l\x0C\xB2}\x08>b\xFC<\xBA\xDA\xA4\xE3\xD7\x01S\xA4\xEE}\x96\x97a\x91\x10\xAD\xF8\xFC\xBEC~\xCA\x13\xAB\x8B\xE8=&\x02\xB3\x0D\x84^\xEA0\x06\xACw\x99\xF7m\x87:\xD5\x11g,\x0B\xF6\x82\xB5\xAF\x02\xBF\xC5{G\xABY\xCFi\xF0\xA4\xE8\xDFX%\xBD.r\xDE\x02\x10\xE3\xB6\x84]o\xBAM\xAB\xD9\xF3>=\xCD-\x04\xC0\xC4w\xD4'T\xC5\x1D`\xB3\xDA\xCC<\x0F\xD4\x8E|\xED\xFF/\x09\x12\xF1V`tW~KK\x9E(\xD6E\xE1\xEE$\x12\xA1\\x85q\xDF:\x8F\x80\xF6\xC2\x1F\x86\x0C\xBBA\xE9\xB0Ns\xE8\xED~]\xE6@\x86\xA9\xFF\x05qi\xCC\x03\x98\xB7hP\xE1)\x8A:e6\x95"H\xE8C\x17\x92KqUvq\x1C-o\x88\x0A\x11\xD3\x85\x1C\x8D\xC2\xD7V\xC1\xE4j\x07\x0C\xF1\xA7\x813\xA9\xB4\xA2\xE0\x12#j\xAD\xDA\x91\xC2\xCE\xE21A\x8D\x8DS\x0E\xBB\xB1r[\xB5\xCE^f\x9C\x1F\xB4\xB9H\xF0\xEC>\x9BP\xF6\xD8\x16\xDCs\x7F\x9C\xBC\xEE\xC3\x19\xF4\xE3\xA4\xC4gXz\xA7N\xF3&\x81\xBB\xD2,\x00\xF1\xF0\x80\xA9U\x06\xE0\xC4]nO\x1E\x93\xB4t.\x02\xB7QD\xCE\x0F\x1C\xA3\xE3 ^\xA2\xD9e\xD1\x18\xC5 \x88\x14b\x9BM\x9D\xD0\xE3\x00D\x01\x9Ay\xF0K\xE0\x7F\xB2+\xD6\x8Cl\xF0)8y\xD1\x07!\x0F\xA6\xB5\xA8.."\x0Bi\x91c\xB8\x0BTa\xC0\x16\x85\x94\x09\xB0\xDD\xB8{9\xFC\x9Br\x9E\x8EO\x98\xC9\xAD\xFC\xE7\x05\xEFP\xAE\x94\xAC\xF9mx\xD6\xC3v\xDEO\xB6\xC1 "\xDF~\xF9!\xD6\xDC\xA8\x15\xDF7UP\x03\x80\xA6\x86\xBC\xEC\x80)^k\xD85u\x8E\x0FF]\xEB\x15\xF9H\x8B.\xF0u\xDC[Vq\x05\xB2\xA0-`-\x8A)\x1Fc?\xF7\xD2[\xB8\x8BA\x11n\xFE\xC0\x88i\x1F\x80U;2\xED%\xA5e\x89\xAF\xB2^\xAB\xAA\x07\xF0\xC4\xB5\x15\xEC\x16\xFB?\x17\x89\x0E\x8E\xD1\xED\xE4\xB21\x9C\xDE\xA4Y\x1B\xEFu\xF8R\xD9\xABS7\xD45\xFC\xFE8\xF2\xD7}\xADS6\xA4*\x0FK\x11c5b\x04\xB6\xD8`\x8872\xF2osU\x92\x0F\x88wQ\x13\x83\xF6\x07\xA4\xEF\xA8\xE5\x97\xC5b\x06B3\x1B\x95?\\xC3\xAA\xEB\x85D\x16\xF7\x86A\xD4\xF1\x1E]x\xEE \xCF\x8F\xFB\x99\xE7\x1B\xA9\xD0\x1BI\x89w\x0C*\xBB\x8EB\xFB\x0C&\xB3\x05\x83\xFE\xD4'\xD1\x8E\x8D\xEB\x9CF\xF6\xEBD\x07\xA2\x80\xE32.[a\x0Ex)F\x80\x12\xD3I7\xE4\x99\xAF\xD2\xC8\x18T]\xC1j\xCF\x0FlZ\x18\x8B\xBB2\x97=\x06M<-;\x15\x95\xA1\xF9I\x15\x0Be\xF5\x9DF\xF4\x11Vb9\x16^P\x06\x8Db8\xB7\x9F\xD60jh\xFE\xCA\xB1\xBB\xC0\xF9t\xDAs\xD3\xCE\xA9q4r\xD2dZ[X\xC3\xF4\xB9\xDA\xE2\xF7\xA8b\xF8\xCFWu\x80\xDAy\x83\xC4\x0Eg\xF8\x7F\xA1"[\xD6is@CI^\xEE\x9B\xF2\x7F\x9F\xAB\xEE\xC2~\x18\x06P0\x0EUse\x00^\x8B:\xE5\xB36:w\x14P\x1Cg\xAC0\xD4*\xC9\xB7\x0C\xA54\xB9\x0E\x96\x9A\xC2\xCB\xEA\x14\xC71\xB8d\xB0Th\x15\x0F\x89\x87>\xAA\x16|}\x02s\xD4\x91)F\x0C\xDBu\xAF\x93\xF5\x8B\x1A\xC7\x7F\xFE\xCB\x958\xFA\x1E]\x8B;\x1D:[\xB3\x94\xE1\x04\x1D5\xA5\xA0\x09J\xEFB\xD7\x81x\xF4\xB6\x0DN\x01v\xC1#\xB0\xAFl-\xD4\x94}I\xE3\xE6\xFD(|\xF2\x8C\xCA\xB4\x9F\xCC\xB2\xC3r\x9Co\xCE\xF4\x83\x9CU\xB4\xFCR\x1BT\x83\xD75\xF3\xC9r\x01\xCC\xC6\x98\x80\x8F\x90\x16\xB9s\xE2\x8C\xA1\x95+\xE8\x08}\x05\xC2\xA3p_\xF6\x8B\x0F\x99k\\xB8\x14\xF6N\x90\x8C\xABU\xD8\x85~\x14"\x0E\x0AT\xFEJ\x16|G\xEBDhQ\xBCG\xAE\xA7\xDF\x90\x88F7\x1A\xA0\x8D}\x90\xF7;\x1F\x9D\x8A9\x09\x8A\x1C\x08\xDApg\xD2\x9C\x9B/\xAE\x00b1\x8BG\xFF\x0D\xBFs\xA6\xE0\x0C\xFB\xAA\xFD\xC6\xB31\xAC\xC4i\xC1\xECB(0\x96\xE6\x03\xB3 \xDE]\xC6\xBF\xB1T\x05"\xA2gi\x00\xD8\xD8\x0FM\xC0p\x9C\xD7`\x185\x9D\xB1]\xD7\x93\x0B\x12mW\xDD\xE8\xD7\x87R\x15\x05\xFA)\xEC\xB3\xEFl\xDF\x09\x9B9^d\xC9\x04e\xC4s(\xEF\xA7\xF0\x9D7\x1E\x0FSv^T\xB3\x88\xF49{\x82\xD9\xAB\xE3=\x99\xBF=\x13\xB3\xBC\xD8j\x1C\xFA\x85D'\x96\xB9\xF8\x0E\x9DBp\x075\x92\x8A\xDB\xB2\x04\xD3\xB4[\xD9h\xEF\xD7\x86!\xD7\x1B\xC2]@$\xC0\xF3\xA3+j`\xFB:\xF1\x01\xE1\xB6\xEB\xA5Yq\xA8\x98"|\xF2{\xF38\xE6\x93\xC3\xC0\x84N\x09\xC7\xFF\x98\xAA\x8A\xD3\xEE\x93\xA1\xCA=\xE2\xAC\x1F\x08\x1E\x1C\x88\x09\x84\x1C\xC6\x93\xC01\xC8U\x8D\xC5\x9B\xEC\xA3^Da\x8ECD\xC3\xFDrN\xD0a\x88\xB6+q\xA2\x8Ep?+D\xBE#\x9E}\xFD\xEE\xE4+\xCF\x0C%J\xD2\xE71d/QuPj\x9AAI\xB8\xAB:\x114;\xD2\xE8\x0F I5>\xC5j\xB1\xD8\x98x\xAC7\x11!\xF1\x94\x1B\x9D\x15L.\xD0M\x83\xBA\xB0!\xF7g\xE3N$n\x1F\xCF9\x94\xB4K[o\x92~b\xA9\x80\xBBk\xDC\xE7\x17B\xA03\xCA\x93\x9F\x04l\xDC2U\xF3\xD0\xF61\xF3\x05\x01B\xC8\xBD\x0E\x8D\xD4\x15\x13)\xD5\x91\x89\x06{\xF3\xD8\x0B0\x89\xF0X\xB92\x14\xCF;\x19W\x88\x16\xFBWU\xCF\x83\xC2\xBA\xF6\x8F\xF7/$\x94\x0A\xD8{\x99\xA4\xC1\xE2\xCBW1r\xFC\x03F\x12\x83e\xC3W\xCF\x02$\xD4\xC50L9\x1D\xC0\xCC\xCBq\xBC\xB3d\x162?*|\x11\x01\xBA\xD4\xFE\xA8\xA7\xC3\xA6\x8F]\x12\x17\x97\xAAW\xD0F\xB2\x86\x1CM\x1Dy\xF0\x83\xD0\xE9\x988\x94*o\x09\xFE\xAD\x86\x9D/\\xD4\xE7\xA0Z\xC9\x9B\xE4\x16m\xCBG|\x7F\x19\x03Aj\xB0F\xAFM\x04\x06\x03X\x88\x11\xC7 L\xA7&]'\xCDW\xF5\x03Y\x1C\xA6\xAC\xD0\xCE\x9F\xC9\x17n\xE2\xD8y\xAB\xAC\x03\x01:\xC561\xFD\xD4<\xF9\x02\xE6\xEC\x1F\x09\x97\xF6u\xD6qUAl\xF9H\xDB\xE6\x86_\xB3kx\x9B\xDB9D\x17\x88R\xB1C\x10\xCD\xC4\xCC\xF2\x89S\xF0@d\x93\xFF\x1E\x95K\x0B\xB8Vv\xC35\xA2S\xBC\xF0Cw\x94\x0F\x1AG}\xAB\x84\x81\xD3\xD8A\xEDS&\xE3(:\xB3\xAF\x18Q\xCAcG\xCB\x9F9E\xFB\x07\xF8\x92\xEF\xE4\xBA+[\x05\x18]\xD8\xF9\xC8\xD1\x8A\xFA\xC3!\xC0\xB9r'|\x9B\xC7\x81\x7F\x9A\x10<:xz\xDF\xFEmfv\xC0\x9F\x92\xCA\x9F\x95|\x8C\xB5\xCE\xA5\xC1\x9E\x82\xDE\x04tC\x8F!\xF5[\xEE\x86\xE0\xC6\xBF=<\xE7mF.\xC7\x89\xEF\xCD\xD8\x92P\xECz\xA7 \xAC\xC2\xA0~\x1A\xA2#\x18\xE8\xC8\x07X\xA3\xC5\xDA\x9D#5\x1D<\x00\x9F\x80'\xA9mxt\x0F\x00\x9B\xA8M\x8C\x0C'\xD0\xA2^\xC9%?\xDCK\xDEp\x08\x84\xE1\x12"\xFD\xB8\xC8\xA5\x7F\xACre\xF2'#\x08\x9B\x8E*\xC5\xD8\x08\xBC\xDE\x8F\xC7RH\xD9{\x10\x9B\x8DQ\xF8\x8F\xB2^\xF8\xBC;\xEA\xC0b\xE8W\xE4u\x8A\x86\xD8\x97*\xF0\x1C\xFE5=\x08l\xE4m]\xD4\xE4LQ\x82\x87\xE7\x07?Q>\xACk\x17[\xB3\x04\xDF\x0F\x8F\xC5\xFD\x1D;O|'Ui0\xB6\xAD4\xCBH\xE07/\xB6[\xBB\xECP\xA7\xF3g\x97\x83\xFDU\xCEb+\xF5Z\xB2D\x98\x02\xF2\x0E\xE4\xFEh\xC3\x19EfC^&\xAAM\xEAhu\xDAa\xBD!\x9Cz\x85,M\xF8t\xA8\xB6\xB3\xA0\xC6:\x0D\xC3G[\xB5\x0A\xEA\x16N)x\x8B_\x0E\xD4\xC4\xB3\xF8l\x054\xBFuC\xB1#'Lit{\x1E\x1B\x07\x1F\x13 \xBA8\xC0;\xF2\xDC\xA4\x10}\xC6\xE2\xB0\xB0U\x0C9\xC2\xE3\xF2\x10\xFD\x1DkK\xAB\xF9\x97c\xA1:r\xE9\xA9y&\xE7\xB2^\x94\xF9\xE6\xECg\xCE\xD8\xC3"\x95\xD8\x9A\xC0\xC8y\xFE5\\x18\xE4~\x9B\x12\x88=6\x95\xEFy\x17h\xFA!\xC8\x86\x91]&\xD1\xC6\x95(\xE6S,\xD0\x09$J\x97\xEER\x1F`\xEE\x13QA\x1AA\xD0\x13\xB6\xA8-_\x82U\x01\xF7\xD6\xB0\xFE%O\x1EV\xE38zffK\\x19\xB3\xD3\x9B'\xD9\x88\xE2\x18*\xD5\xF1-V\x9D\xA7\x96#\x05\x00\xA5\x95.\x08{\x00\xE3\x12\xDE,\x913\x84x\xF56h\xDD\x00{\xAE,\x8Eb\x0Fv\xBBnl\xB0\xE46g\xD2\xDC&\xE1\xEAx\x9E\xBE\xBD\x91\xE9\x82\xF62W\x10\xC5\xE0^\xCB\xEEF\xF4\xA9?3\x92\xDBH\x8D\x06\xA3\x0C\xC6\xB9\x80\xA8T\xF8\xDE\xE1\x88\x17pZ\xC0\xA4\x96\x19\x84y\x10\xCA\x1E\xBA\xD1c\xF0I.\xB9Ul\x7F\xC7\x90a\xF5\x06\x1E9\x9E\xD5\xE6\xFEd3_v\xB1\xF7Q@\x1F\x1C\x1Be\xA0If`\xB3v\x14\xA5\xED[\x94\xA5\xE7\x13?\x01\xF8\xC9\xEA\xE7'\xF7&\xE8A\x91\x1B\x89\x00\xC6cq\xF5\x8BR\xD0\xBB\x15\xF0\x17\xB0s\x9FA,\xA1h\xED\xB6b\x0D\xC9|}\xDD\xD2B\xAD\xCA]\xB3\xAC\x8F\x0ESxOh\xE4\xCF\xBF\x9A\xB8\x8F\x0E\xF6K\xC9&g\xFA:;\x81j\x81\xDF%\x81#`'\xC89\x01\x15.\x926^\xD8\x04\xFC\xB19\x822\xD4\x03d\x85C\xF9[\xDF.F$\x99eQcB\xCA]\xD9R\x9A\x7F\x11S\xFC\xAC\xB4>\xAE\xD8\xF4\x06A\x93\x92\xC4\xE1\xE6\xC8\xBDm=i\x8EPl\xEC\xDB\x8D/}\xD3\xF6\xE6_d\xD2\x11\x06T\xC9\x88\xE18(Z7\x1D\xBC$\xF5\x9D\x85\xA7\xB9\xF3\xEC\x9A\xD6\x89\xE9\xA3\x1A\x13N\xF3\x9Ap\x14\xD4\xC5\xDA\xA4\xB9\x17}\x19_y\x95\x9CvI\xC5\xD3\x9C`\xD6\x80\xE0I\xDA\x90\xF5)\x7F\xEC;\x16g\x11\x9F\xDDt\xCC\xAD\xBC6J\xD2D\xE5\xE7\xC3\xA3A\xF92\x0E\xD56_\x04\x1BY\xA1)\x0F\x0C\xC7\xD8\x92\xEBv\xE3\x87\x1D\x00\xC7m\xB5\x87\xC6j\xB0\x0C\xD2\x03\x98CVhqJ\xD77\xD2<\x19\x01\xD2\xDE\x1C\xDD\xFC%\x8B\x8D6\x99\x82\x15\xD4\xAF\xF3.\x83\x9D\x1C\xCA\xA8\xD22\xBB\x0E\xD8)\xE9\xAC\xBA\xFE\xA5\x97\xDC\xCF\xDF\x90\xB8/\xF4O\x98\x0F\xA3\xA7\xCB\x02\xFA 9\xB8\xDA\xB3\x00}\x13\x1FHr2H\xEBc>\xD0\xA2\x15\xC8\xDE-O\x8F \xFD\xDF\xF3\x10\xF6\xEDw\x95\xE3T\x8Ev\xF4w\xCA\xCF\xC8\xC20\x00\xB9\xD4\xE6\x1Dv\xC4\x08m\xB8\x0B\x98\xAF2<\x84\xAD!\xF5l^6\x8F\xAA\xBFNE\xD5\x8C299\x189b\x94g\xA6\xE8\xDCHC\xAB=6\xF5\xC0\xF5\xB4\xD7\x1D\xFA\x94\xA9\x80\x8C\x8C\x8Ao\xDD\x9AV\x8DGZ+"!\x02\x01=\x9A\xBBt\x18\xC6ro\xDC\xE5\x90Y\xAA\xF1J\x0A-#\xB1"a\xE9\xAB\xE0\x87\xBC\xC5\xEB\xAEh>U\xB8\xD3g\x12`>\x0F\xD6S\x14)\xC4\xA9;\x8Ej\x15\xBA\x94u\xEA\x940\x9A\x85l\xE7*\xA2t\xEEl\xFFK\xF8}5\xBB\xFD9\xBC\xD9\x1D\xF9iJ\xC43\xA7\x93\xCD&\xBF\xD9g4\xFA\xFD\xB4\xFA \xB9\xB3\xBA\xEC\xB7\xCA\xFCo)\xEC\xC4\x03\xEEj\x9F\xFD\x9EO\xA8\xC9S\xA5-\xF9go\x9C\xEA\x97\x05\xDFMa(\xA8\x0EQ@\xA0\x86\xAE1\x15\xE8~,\x82\xBB]\xB1\x0DR:\xD0\xD6\x93\x8E\xD6Bo\xE0\x01\x9A\xD1\xAB5\xDE'8\x9E\xEF\x18\x99\xD7\xF8~\x96\x80\xF1\xBF\xF2\x98\xEC\x8F-\xE1\xBE\xED\xB3u\xAE6K%^[W)\x1A\xAF\xA7\xA7\xE7i\xE1\x9FY\xAD\xD1\xBE\x8Ei\xC6\x93P\xC2\x94D2L^\x8C(\x02\xB8\xAA\xE8\x1B\x1F\"O\xF6[\x7F\xDE9+\xC6\xB2f\x80\x1A\xDA\x01O\xB5\x9E\x02\xCCnW\xCCgN(a~\xC8FG{5hi\x82\xA4\x81\xAF\xA0\xA6\x9A{2p|c\x9D[\xCD\xAF\x14\xFA\x9B\x1D\x14\xDB\x12\x1A\x0F\xBF\x969\xC7\xDF\x8A\xD7\xED\x8D\x81\xDAx\xD5\xCA\xCC,\xD8w#\xB3\x14j\xC5R\x9F\x09\x0B\xDA\x09\xBD\xDD\x98\xB9\xC71\xD9y\xFD\x1A\xA2T\xAE\x9EN\x07z\xA3\x86><\xE8I.\x87wK\xAEs/\x8B\x88:\xAD\xC2Z\x1B\xFA\xC1\xB4;TE\x00\x01|\xD7&5\x1C$\xAA\xFE\xCA\x9E\x0E\xA8\xEF\x87\xC4\x12\xE0\xDE\x0E0\xBE\xA9m\xD7\xB7\x93\x7Fs\xFC\x86\x96\x12oe\x8CZ\xBD\xB5\x844l|;F\x07\x0B\xC1\x03\x95aVX\xF9\xB3\xE4\xC4\xC7\xA8B\x08\xC8fH\xA0a\x94\xC2\x9E]\xA4\xE1\x19\x18\xC3\xFBN\xD2\x13\x82\xC5\xE1\xB8\\x00\xC9\xC37\xAF\xAA9\xE5\x10Y\x85\x8B\x0D+\x05\\x88Z#\xF7,\xFB \x7F\x9F\xF9\xB6\xB3\xBC\xFD=\x90\x897\xA7\x0E\xE9\x01\x14R\xD6\xC1\xE8\xC8\xDF H8\xF4\x1E\xE3i\xB0f\xEC{\x90\xE5XE\xB2\xDC0\xC5\xE9]\xDC%\xC7\x9B\x848Y\xD7\xDEMA7Yx\x91\xF9\x1D\xE1-%R\x7Fg\xB8R\x13Q\xD7\x05\x98*"\x05E#\x90\xC6\x96\xCBS\xE7V\x7F\xB1OMcC\xF9\x95\xED\xDEI\xC0\xE3\x18L\xF1\xAA\xE3\x8F/\xE9E\xA4\xEF\xD9l\x893\x12\xC9\xCF_\x8Eb#\xBEA\xD6t6\x80\x8E\x02"\xB3\xCC\x13\x89\xB0]\x09(\xD8\xC4\xFD1Kr`\x8CJck_\x81}\xA9{X\xD3b\x819\x05\xB96\xFC"\x01q\xBE_=\xCE<\x834\x8D\xDE\xDF,\xE7@{\x908\x15\xF6*\xDC\xA6\xB9!v\xAE\x7F*\x80\xD7.(t\x0D\xABS\xB8oL\xFF\x8E{P\xD5$\xF9\xF8Eu&q6"\x7F\xCC\x12\xD0;J\x15\xDF\xD0\xD1\xEAE? \x018_!\x8F\x12\x0F'\xDC\xAB)\x86JT8\xC5\x8FD\x0C\xCA\x06\xCB\x80uy\x1Fh\x96\xB0\xC1\xD7\xC7\x1E\x18\x0D\xD7\x80\x81\x0B\x0B\xA7A\xBD\x90_L\xEF\x0A_\x87\xC7\xF1\x1A\xDB\xDF\x9A\x8B\xD3\x94Z\xCFf\xBEj\xE9\x95\x10\x05\xF4\xAC\xE4t\x89\xF1R\x1D\x02l\x97=\x01Y\x01[\xC0\x17\xFF\xB0\x8B;=\xCA\xEE\xF7\xC0\xBAk\x8C\x10D!\x00\x94J\xE40\xBBi{g\x9Dk\x1C\x0F]\x9B\xE7\x96L\xF0\xF1\xCC\xBE\xA9p\x04\x0D\x0B\xD5VK\xBC\x09\xDF\x17\x8C\xECG~_s\xBA\x13w\xD9RR\xBD\x8A\xDAt\xC7\xA3\x07i\xF0\xA7\xA9\xB8\x98\xBE\x04\x13\x04\x1A\xFD\xEF\x0F\xEB\xA6W\xD6n\xFD0feE\xAC\x86\x0F\xC0\xEB\xDF"\xAC\x02\xB3\xE8\x08;c\xA1\x19MN\xDAX\xA1O\x078\xB5\xA6\xE3r\xCEC\x1C\xA8\x0B\x0F<\x16h2\xE8\x11B\xDE\xBA\xC6\xF2\x94\xFE6\xF3\xE8\x05S6D\xEF\xED8\x8C\xCC\xDA\xEA\x8F\xFF\x9Db\xA6\xB7\x1Bf+]QU\xC1\xB9f\x9B{\xFC\xBE\x93\x0B\xA4\x08\xBBR\xEE\xC79\xD8\xE6\xCE(@Z\xEEy\x0BR\xAD\xA4\xDF$1]h\xEA~\xDC\x10z\xB3\xCF\xF5\xFB\xB0\xC1HEDB\xF4\x03EMP\xB4\x0Al\xF2\x8A\xD8\xA5P\xA7J\xED\xC6\x92\x8C\xBD\x12\xDB\xD3\xDB]~A\xDDh\xD5\xC1\x91\xB4\x18X\xC3\xE2w|+\xDB\x13\xDC1\xC1\x10\xA6\x8E\xB2\xDB\xAB*\xAC\x0EB\x02/\xFE\x02)\x87p\xA2\x9Az\xF4#\x18\xF1\xE9\xC8\xF87F]\xD2\x197"=\xAD\xC7\x92r\xAD\x92\xC5"\x98\xD2\x14\xC25`\x17\x82'\xCAR\x7F\x8CXL\xEB\xE3\xC7\xBEX]\x17Y\xEB\x7FH\xF7\xCBTu\x19+j\xBC\x13H\x01\xF6a\xA5\xDE\xF4\xF6M\xAE\xA0\x07q\xE9\xD7\x11V-\xDDU\xFC\xA4}\xF7\xCB\xA6\x97\x90\xA3\xC6\xA8;a\xBD6\xFA\x10\x98\xA2n}\x98m\xDD\xC9\x98\xFD\x10\xA2^\xA6]\xC9\x82e2\xF0V\xB2\xC1%\x1E\xABd5\xE1\xF2}\x07\x83NZ-\xC6\xD3F\x86\xEE\x13\xF0\xD9\x9Dt@\x1Ev\x8B\xFE\x1A@\xDF\xDA\xDD~\xC8,\xF3\xF3\xDD\x82\x8185"\x1Fl)\x19\x10J\xEB\x92\xD8#\xFF#\xBC\xAC|\x93\x0Cm\xA9\xB2\x0E3nyK\x09wf\xA7\xBD,"9\x89>\x91"t\xFB\xE8DzV~\xD8\xCF\x0D\x0A\xEE\xB0\xE5\xAA\x8C\xAF\xAD<\xF3M\xD4\xFEYV\x8AV\x05\x87VzM\xF5\xDF\xC1\x03P\x8C\x02\x9A~\xBB\xCE\xCD\xCF\xD5\xFFB\xD2\x97\x13#\xA4\xA3\x9F\xA8'\x00P2j\x85\xF1t\xBC\x98k\xC1]\xD1\x95\x9F\x98\xAF\x80\x1A7X,\xAEpQ\xE4\x18P\xF2>]\xAA\x9CG\x11\x93R\xF8O\x15\xC9\xD0mZ\xBB\xFFxX5?'F&\xA2`6\xBB\x1B\x94\xB4\x8D\xA5q\xEDUg\x18\x0E\xC3\xC3\xE8\xEEn\x9A\xB9\xFF\xA4\xEC)>\xA6\x16\xAE&c3\x7F\xD3\xC6\x8B\\x1F\x0F\x7F\x93\xA8\xCA\xBEct-w r\xCC\x0D\x9D\x1EZ\x05\xAA\xC9\x19\x95I5\xFD0C{\xD34\xB9\xA5\xE4\xCD\xA5\x1E#\xE7.\y\xC4+\xE8}\xFC\xD4\xC3\x81Si\x05b\x8E\xFA\xF9\xA3o|\xB2\xABu\xF8\x10\xE9\xBF?\xD0;\x0C\Y\xAC\xBD\x10\xF1\xF5!]lx\xE6\xC7\xE0\x1E\xBE\xA5\xB0T\x1B\x0An\xFE6\xEA\xDA\ +\xFE\x83\xEC\xF3\x8D\xE6\xFD*\x0A\xDA\xB6\xFBI\x8C\xB0\x96Z\xF2E\x91a\xBF\x7Fb\x81m\xA8d:R\xAC\xE7\xFB9d\x9E\xCA02\xA9d\xF9\xD7\xB6\x97\xCD\xE0\xA2{\x1F\xFD\xEC\x89\x06\xB2\x10]\x8B\x0E\xC0?\xDE^&R\xEFC)?\xBE\xF4\x12\x0C\xD8\x9BX\xFE\xE4\x91%!\x1E&DT\x9BV/\x1Db\xF2[\x01\xA1bO\xB1~\x85\x09\xBB\x83\xDF\xBB\\x08W\xF1\x08\xA2\x82P\x97\xEDe\x0Ea8\x94\xF2\xE7]\xBC\x15\xD8v\xB6\xFD\xB3\xDDm\xD2}F\xB5P\xCA\xCC\x9CT\xA93\xB1\xC9\x030\xC8"\x1F=\xA3\x1F\x9C\xB4e\xD4\xABd\xBB}qt\xCD\xBE\x97\x84\x82Q\xF6\xBB\xFE\x97\xCC<\x1E'\xA0X2=\xB4\xEBN\x8F\xCF\xA4t\x01P\x11\xD2S\xE0\xE4[-\xDA\xD8\xA1\x91\x16ak\x97\xFF6\xB1x\xC4v\xE7}uK,\xB0\x1D&\xE9\x09\xF0]\xE6\xB5\x08l\x1F\x1FX\xBC\xA1\xB9\xAB\x12Qr#\xD53\xBD\xC1g\xA5\xE9\xEF\xB1@\x03\xC6\xE4\x18\xDD\x8B\xEFG\x0E\x07G\xEB\xBCv\xC7#\xC2\x87yW\x0B2X\x9Eh\x8Cys\xE7\x804P\x9E\x9A\xA2\xBAr\x84\xBBv}\xDE\xC5C\xCD\x8D\xD4\xEF\x7F$\x82\x97\x89\x12\x08{\xE46\xC8q\xC4~\x84\x12\xAA>W\x8AB8\xE9\x9AS\x1B\xF6a@\x18\xA6\x9F\x11J\xB2\xB6\xD8}B\xFB\x0D<\xE0\xD70\xF1\xF7\x1A\xE6\xB4\xA9\x00\xCA\xAF\x9A7\x99E\x0F\xA4\xA7t\xF2yp\x05\x1D0&\xF3\xD1t\xB4\x99o\xD8\xBF\xD9\xC0V">\x9D\x91\x0AZnH\x87#\x0Bs\xB95\xF7M\xE9\xEEnbg\xBC~b\x1C\xBB\x0FOi\x0C\x95\xA2\xC5\x87\x8B\xC7\x08\xD9\xCBa\x0E\xCC\x13\x89\xD0\x02\xF6b\x9B\xC0\xCC\xAF\xD2\x02\x0C\xAF\x803r\xF4\x0A\x98H\x1FH*\xC6XM\xDEM\x9CP\x89\xB1\x8Fj\x08=\xD9\xF9<~\x19b\xF3\x12\x06\x8BHzT\xE3\xBE\x1C\x9B\xB9wy\x07f\x17\xDB\x0B"\x8B\xE2?\xA9\xF8\x9C,Ke\x9FFW\xF3m"\xDEL\x0D\xE9\x17\x7F\xC5\x9B9\x9A\xAA\xB4d*@C\x91i\x86\x89\xD3\x9Bn\xE2,\x00R\xD2\xB2\xE4%\x96\x8D\xCA\xA3\x8B/\xABgS~\x02k\x90]\xC2\\xEDZw\xC7\xCA\xD2\xF0\x89\xCF\x0Dp)\x13\xBCz\x13T\xA2}\xE5\xE6\x97\x92\x11\x11R&\x9B\xBA\xE9\xAB5\xD5p\xE4k\xCB\xB4\xDD\xD0\xCC\xB1\xD9\xCAJ\x7F\x9E\xA6W\x99\x1E\xDA\xB0\x1E:p\x8B\x12\x8F\xD6\xF8\xA5\x01~\xCEy\xB08\x03,p/#\xAF\x9A\xFBQK\xE3\x85#\xE2\xFCx=z$\xC3\xBA/8c_\xB3hi\xD0Rm\xD0\xAD\x0F\xAE3r\xF4\x0F\x98b3\x0B\xF8sci\xA1h\xC2\xAAP\xD5\xB0=>\xEC8]\xD9<\x87\xD1\xB7Q\xD9\xF5\x9EV>\xAC,\x96\x8E\x9BIn\xF3\xF0\xC5\xED\xF2\xE4\xDCg\xAF\xDA\x9F\x1C\xDD\x8E7\xBE\xDB\x1Aj\xAB&\xEF\x92\xA0\xA2^+\x0Dv\x81\xA0\xCA\xE0f\xD4\x02j"\xE5q\xD8\xB7\x90vOM\x8F^\xC6@\xA7`9\x0B<{\x06I\xF7wL\xC6\xEF\xF1j\xBF$so\xF2\xA1\xE3\xED\x89j\xD9\xC0\x04\xB8z\xF2\xF6e{x\x95\x1B\x82\xA7\xC6@\xE82T\xFD\xCDF\xBAx\x86\xA9\xBC\x11\xDAD\x00^)c\xCA\xA2\xFC\xBE\x7F\x13o\xEDSSb\x95\xC2kf\x8F\xCA\xAB\x15\x1B]V\xB7\xA3\xE9\x8D{G\x03X\x93\xF3\xF8\x1C\xD8\xBBN\x0BV\xC7\xB7\x94P2^\xFA\xC3\x8Fb\xFA3\x08>G\x9BO\x9B\xACe\xF3B\xE07-\xDD\x99\x1D1{p(\xD7\x9D\x95N\xB7\xE75\x89\xA1\xE3l\x84\x1D\x9E\xC6f\x7F\xF5p3Z\x15\xCB\x84Qr\xD5\x16\x9B\x02\xD3\xE8\x14\x9F,\xF5\xB0 \x90\xA9\xF7\xA7\xCD\x83\xDDS\xE8%m\xF6\x0B\xC1!\xA5\xD8\xE6\xA5.b\xC9&\xDBJ&\x17\xF1v:z\xD4v\xDF\x09\xB1{\xC0\xC2\x85\x02\x1A4\xDF\xAFx\x02p\x9B\xC5\xF2\xDFs\xEB7\xD6\xF2\xBE\x9F\xD6\xA9u\xCC\xBE\x93-\x12\xCC\xB6\xC9\xB94\xE4\xABT,8"K\x15@\xED\x05\x98y\xCF\xE2R\xED\x80\x0F\xA0q\xB4+\xC2\xB2\x08\x91\xC6\x9B\x19\xA2\x96b\x092\x1E\xA8e^t\x10\xA3/\xA9X\x0Bs\xC0\#\xEB;\x00Ptn\xC8\x1A\xCA\xB2\xC2\xF9\xD1@G\xD4\x95\xD1\xC1n/\x1B\xCC\xA2\xC6\xB2Z\xA8\xE9\xF0\xF9\x13_W-\x92V\xD7\xD2dC<\xB1\xAE\x90"\xE9?+\xE87\xE6\xC9\x040,\xA2\xBD yv;2\xC1\xB8\x0EJ%\xD5\xBA\x8E\xC2G\x0C\x93\xCA\x9BO\xFA\x99\x02\xC1;\xC3\xC9\xA7G\x19\xA0h-\xCB\x01o\xF7[\xE8-\x8A\xFB\xC9\xF7:xf>\xEAc\xA2\x9AT\x82\x0FAjN\xE1Ta\xAF#%\xD8\x09\xA4\x94\xAB\x87\x06\x01%U]T\xE4\x7F\xF3\xE4)\x11\xCA\xFF\xCE\x04\xAA+Y\x0DW\xE5\xBF}\x8E\x83\xBB\x10-\x82\xD2\x11\xCC\xB4\x8F\x8E\x90\x94\xF3\xC0\x85\x9Dl\xF6,\xDFe_\x10\x0BG4\x83\xB9c&\xCB\x8F\xF0\xDB\xA1\xC64\x14v2~\xC9\xE7\xA2\xB0Y\x85\x18)^\xF1\xD1\xEEJ\x8C\x1BV!a-Mh\xE9\xC7\xE56nL=vf\x0D\x07\xCE3\xF0Bl:\xD7\x8EZ\xDE\xFC\xCDXf\xB7\x088\x01Fc\x7FQ\x18\xF3\xB3\x81[\xB68\xFB%\x8A1\xB0\xD5\x94\xC8\x8C\x0B\xFE\xF0)\x97\xDC\x83AQ\x12\xCDG\xFE\xD4\xD05\x91qM\xDE\xE5\x98\xD6\xCD\x90G\x89\x88\xE3}\xA4\x89#\xD2\xD4\xE4*\x97H\xCF\x03\x0D\xE6\xCB/\xC9DK\x09\xA4O\xC9.\x02$\x0Fi\xD1\xB6\x9F\xD7\x98-M\xE8\xD7O\xC9\xDA\xDFj\x12\x92&\xC6\x13\xEDo\xF3\xE6\xA2\x80\x10\x90S\xB6\xCE\x03\xE2\x91\x9E\x05a\xC3=\x18\xB7\xCC\x1C\xA4\x96w\xFERZ\xA0\x8C\x1F\x09x\xA1j*2\xF2\x93\xBD\x9An`\xEE@.\xFDN\xA4\x1F\xB8\xEE\xE7\x11\x0E\x11\x88\xFFZ\xF3P#9\x11\x97L\x14"\x975\xE4'9&\xE7\xE3q\xB3L\xCF\x1FcrcQ\x9B\xC0\xE1\x1D{}\x9E\x1F}c\x9E\x07\xC8\x82\xFE\xC2\x9CO\xCE@\xD3\xE8+\x05\x82\xD2\\xE1\xC1\xE6\xFF\xA5\x05\x0F\x9F\xA8G*\xC7\x8C$\x03u\x05i\x81oz\xDD\x17o\x01\xCF\x8B\xC3\xB4\xEA\x97d\xD9\x13\x99Uu\x98N\xC0|M\x10_'\x1A\x9AbQ\xC3\xEC\xB0\xB9\xE3\xB0\x03\xF3>\xFA\x08\x8B\x81\xDCt\xB9S\x15\xC4\xC5\x807\xCAP_\x10\x04\x17\x03\xB1*\xB2u\xC2\xC7.\xE45x/\xF5\xD9\x14h\xB4\xD3\xFEy\xB3\xDF\x09\x8E\x8B\x88\x9D\xC2\xA2\x82\x83\x95\xA7G\x1Do\x06\xAE?\xBC>~4\xF5\xE0\xAF\xA9\x80\xB1\x0EQ\xD5\xC0\xA2\x86=\xB0w\xBF\xD2\x88\x90|o\xC1f"\xD6\xCF\xA4u\xF90\xFC\xFC%\x0F\x11\x95\xDA\x9D\xCCu\xCA\x99M21k\xB9\x1AcV\xA5\x99\x86\x1A\xAD\x1F\xB8\xFCb\xBC\xB0X\xCF\x8C\xC7:\xC38\xD2\x1B\xAB\x0D\x1D1\x14Q@\xE8(\x07\xBD<7\x17P\xFB\xF1\x9D\xEB\x94\xDB\xAF_\x06\xB5M\x84\xED.\xD4\x97!q\x14\xD4\xA2\x8382\xFDZ]\x0E\x02k\x14V\xE9V~\xC7\x99\xED\xDC\xBA_\xC0\xBD*0\xC5\x10\xAC\x1F\xEE\xBA\xBA\x98\x1C\x0EE\xF4\xA5\xFA\xE49Tx\xB7\xB5b_\xAA2\xF0z&R\x04f+\xCB:Fkw'&\xDF\xBE%D\xA7&ha\xB4\x0D\xD4\x0C\xA4\xDB\xFF\x0Bt\xE9\xE7T>U\x99\xC0\x1E\x17\xBB\xE5}AN\xF1\x16H\xA8\xBD\xFFf\x97\x10W\x95X\xCE\xE2.x\xEF\x0B\xF7v(R\xFD\xA8\x0F=]t}cd7\xC5v\x82\xC8\xEE\xE5;\xE3\xC4\x88\xBF\xFEUK\xDA\xC7\x12\xD9\x9F\xDA\xB0\xE3]i\xF2\xE6\xC7\x1F\xD0\xF1\xFAO5\xDA{\xEC\x02f\xEA\xF3\x14g\xCA\xD8\xB1M\xAE\xE1\x98I\xA0\x87L)<2x\x1B\xE3f\x8E\xCD\x0AHWa\xB6b\x0E\x81P\x90\xC1\xF8K[\xF5i\xBF\xBE\x08M\xA97\xAC\x8D\x11\x16\x8D\x01\xADHZ\xF4\x8A\xED7\xEE\xECz\x95\xAC\x8F\xB4\xA1\xA5\xCA2J\xB5TS\xF5\xDB\xECyB/\xDE\xA8\xDEd6\xE0\xDE6\xBA\xF1d\xA9\xE7B?O\x87\xE3I\xB8\xE5\x03P[&\xC3\xBCk\xBA\x18;a\xCB\xDE\xC22\xD3.\xF1\xB5\xC5\x92@|`Y^G\x1F=m\xE2\x0D\xD8'\x18\xECn){+\xE6\x99)\x9E,>\xFC\xDA\xCB\xE0j\xBFc\xB9\x96\xF7\x88\x16eb#~\xB7\xCD8\x9E\xBE;\xB5\xB8\x0B\xE0\xC1\xC0\xC3\xF9S\x01x\xF9\x9BY\xA0\xE4\xACM\xEC7\x1DJ\xEDhxC/\xA2;\x85\xB2\xB7\x80,"\xCB\xE9\x04\x1Dr\x85\x1A\x01\x0F\xF2yw4\x1E\xF7\xB3\xAB#&\x18\x13\xBF\xEE'c\x00vn\x8D\xFD\xD5G\x0F\xE8+Zn\xC2 \x15\xA1\xBB\x0AbV\xCE\xB8\xE7\x00\x0B\x19\x92\x93\xA8\xBE\xDE;d\xDF\x00D\x10\xB9\x08\xEB\xAF\xA0P\xDB\xA8\xD3\xD6\xDA\x9A\x19\xA9\xD0\xBF\x0E\xC8=R;\xFC\xC9\xD8`x3\xEB}\x89\xDAgAv\xB5\xBB\xF1\x0A\xAE\x12\x85\x8A\x1D\x10\x8F\xE8\x8EfkX\x05:\xB6km\xEB\x14\x7FE"\x17\xC06E\xC3\xA7\xEA=\xB1F63%\x1B!\x15\xBD\x8E\xB8\xE7D\xDE\xEB\xA9\x80\xE7\x06\x04\x0A]\x0A\xFC\x98m\xE3Qk3H\xB7 \xF7@\x1Cu\x98\xA4\xCBL_\xD7\x0D\xF1e\xDB\xBB\xDE\xED\xBBr\x8F\xE2\xEF\xE9\x8B\xEE\x1E \x92\xB8\xF9\x83)\xC4\x0A\xD5\xB6\xB2\xAE!d\xF3M+\xB4=\x88\x9Fl\xEE\xE87x\xC4\x01\xB4\x1C\xB59.\xA1W\xD51\x04\x87\x02m-@^\x8DV5\x1Ee\xF4y\xF5\xC7!\xCE\x8Bp\x80\x1ABQ\xE1\xC7D\x87\xD84\xA8\xB1\x98\xD0[\xB4\xE2\xBBJB\xB6\xE4\xFF\x1Fxp\x09\x95\xA5e~\xF5\x9A\xE1\x91B\xE2>\x10[M\xF9\x92\xB5\x11`q\x84s\xC3t\x82%\x15\xC7\x89\xF3=2\xEB\x82\x01\x81\xB7\xCCx)2`\xC9y'kSv\xCEU\xAE\xF7\xC1\x16\x98\xC6\xEC\xD9\xAF\x1Ay\xEE?\x1AkD\xE2\x14\xA2\xA2#\xA1\xD9C'\x0BM\x1Ato\x1A\x19e\xFF\x82\xAE\xA1$\xEB]\xEDz\x1D9\x99l;G\xBD&\x0F^\x8B\x89p$\xB0\xE8(p\x90d\x96\x02\xE4\xC7\x02v\xE9\x0D\xA2\xBE\xE0\x979\xBB\xB3\xA9\x96\x1E:\x89\x15\xAB;\x94%W\xCC\x0F\x0Ev`\xA1d\xF0\xBDaM\xCA\x9D\xCC\x03\xFF\xEB\xF7\xE1f\xB7\x0B\x8F\xB6v?<\x13%Ld\x88y\xE5\xB7%\xA2\x83\x9A\xBE6!\xCD\x9E\x8F6\xE9ZE\xEE\xF9|\x15{\xBA\x00\x82\x97\f\x1C^\xE9\xF5\xC9\x14\x103\x967g\x14\xCB\xE0#j\xB6\xFDQ\x9Fz\xE1\xE8\x1E\xFF\x92\xB8\xD9\xE2\x14\xBD\x02Xq\xE7~a\xBDa\x9C\x82\x84\xA5\xA3\xAA\x13\xFA\xBA\xAC\x90.\x9F\xEB\xE1A^\xEE\xB5\xC4\x02\x0E+\xAF<\xF5\x8F\xBEe\xFC\xF1SC0\xA9*\xF75\xA8\xAD/.\x8BU\x96I\x90W\x98\x1B2\xC6~\xF4\xC79%s\x1F\x08\xCD\xE6\x86E\x02kHdd\x84\xBA\x0A?\xA0\xB6\x86\x1E\x1ET\xF6\xF0\x07v\x90^t\xAE\x9A\x967i\xF9\xAF\x820\xE4\xCA\x85e\x17\xF5\xE0\x16x\x1B\x87\x9A\x9D4D\xE2\xBE,\xF3TE\x0C\xE3\xA0\xA8\xBC\x09\xB3^T\xC5\xF1\x18\\xD4pR&I\x8CA\xFD\x0C\x9DU\xAEk\x13\xDB\x00i[\x0Br\x89[`F\x95\xE7\xB0\xFA\xB8\xDA\xA3\x061d\xE4)\xF1\x0E\xEAK\x80\xB3Ak\x98\x0A\x07+\xB13\x8A\xEC#_&\x0D\xEA\xCE\x07\xDF\xF9\x16\x01\xC9w\xEF\xEA\xEF\xBF\xAA\xAFq\xD2\xA2\xD9}\xA0\xAB(J\\x1A\xDF\xD5a\x8B\x87E\xFD\xD6\xEAs:Lq\xC4\x0A\xB5I\x9E\xCDE\xAB\x9F\x1B\xD0\xBE\x83\xB1a\xEF|\xBEb\xFB\x99i\x89\x82<'lB\x1E\xC1H?\xAEM\x96\x1CD\xEB26l\x13\xA1\x9Af\xCA56Ak\x0B\x9F\xB1R\x06\xA4;\xA3\xE1\xEB\x9F\xE7\x01\x9Di+\x10w\x87\x19\x94\x7F\x00\x98l8\xC9>5"\xEC\xC1ba\x95\xAA\xBD\x7Fm\x11\xEA\xB1\xCC\x99\xE2\xB1g\x8F\xA7\x02\xC4\x11\x8D{}.\xFB\xBCv6(7X^\xBBy\xB6\xF1SP\x83\xF6\x9F\xAB\x1B\xDAi\xB4\xC4\xEBeN\x91\xBAE\x96[z\x97\x1DD+\x98\xDC\x13\xA60:\xCF\x1C\x01\xC8k:\x1ED%?\x19)Z\xB5e\xE1\xEF\xB6\xBC\xD4\xCB\xC6\xAE8\xF6p&\x0Dp>{ni\x12\x0B\\xA2\xA8\xA8l$q\xB3\xA0'\xE6nbl\xD5iM\x8C\x81\x012\xE9\xA62*L\x94\xD5\x10M2\x10\x95}qd\xBB\x1F\xAF\xCA\x8F\x84y\xA3f`\xA0\xB0"5\xBCc\xF4gE\xD1-aT\xF0\x06\xA6\xCC!.j\xA9\xA0xuI\x9F\x19\x87\xF2;\xB9\x18\xCF"i\xBE\xAD\x0D\xFB\xDC\x1A\x12\xB5\x1B\xF4\xF6\xD8\x13\xA3\xAE\x0C0\xC9\xAE\xDC#&N\xE8\xEC\xD4S.\x11\xD3\x92\xA3\xE20|\xC4G\xC3\x96\x9C\xC9)\xA4\x94\x82r=[5,K\x00M?Ol\x9C*\xC6R\xA6M\xF6\xBE\x0CA\xE1\x90\xAC5y)\xFDpfN\xA0c\xF7P3\x92\x95A$"D\x1D\x86\xFF\x19\x8B\x95\x95\x18\xB8\xB3\x83$N\x867\x82\xF8\x8C\x86\x94\xF2\xFE\x99\x02p\xF7\x9F\x99\x1F\xA9p\x16\x96F\xE6~sd4\x1DUa\xBCs\xD3\x9C\xE4\xAF-\x85\xF0\xB1Xv\xA8\xACD\x9B]g\xCEQ_f\xA6kr\xD9\x92Pj\xD2\x9C$Vc\xCE\x03-\x0C\x9E\xB3t\xC3\xCA&\x17e\xEF\x13\xB6\xBB\x05\x0E8I\xB3\xA7\xBF\xDF\xB2\xB8\xA9\xD3\xF5\xDB\xE0\x9E\x03qU\xD3\xED5\x9E\xB3r\x90\xE5\x87\x03\x1A\xFB8\xCC\xD8\xDAW\x01\x90\xE8Eo\x09\x17|\x17\x96\x8B)\xC5\x8As\xEA\xDC\x95=\xC7_\x90\x01\xF8\x841`/Af5\x0D\xC2\xBB\x8E\xFA\xCD\x16\x10\xA96D\xAE.\xC0I\xF3\xA5;\x8D\xE3!\x16\xB8\xD1\x89\x0E\x09}\xF5\xA6X\xD0t\xFE:Xs\xF2t\xA2L\x18\x1BCb\x84\x0B\x15\xE0A\x80hZ\xDA`\xAC=k~\xCE\xD0/\xCED)\xB9em\x09>\xD2\x10\xD0\xF3Kg\xF1f}m_B\x1Ag\x1F+\x10`J,V4nO\x07\xBF\xA2\xE1\xF4\xFBeo\x8DPFO1\xDE\x02\xA3\x19a\x8D\xF4=\xBF\xEB\x1A?\xAD\xF7\x05\x1Bs\xEA\x92[\x82\xD5\xF2/\xB4\xFE\x92\xC2\x8Dn?\xA7\x8C\xC7\xD9\x8A\xAE|\xCE\xA7\x13\xCB{Z\xC7H\xFD\xA8\xB2jA\xB1c W\xBBL\xA2\xD6\xD1\xA5\x86\xB5\x09\xFD\x1AT\xEC\xE4?)6K.\x0F\xDE\xD8v\xB0\x9F\xFDDG2L\x8B\xEB<\xFC\x14\x92\xF3\xAB\xED\xC4>\xDE\xB3\xA7\x87\xE5\x8F)\xC8\x11\xD0+\xC1{;DV\xC6\xB8-\x07\xBAU<\x9D\x02\xBD\x16\xC5f\x96\x0AF\x81\xE4\xA1bj\xC2\xA6\x09U\xA9\x8B\x07B\xEB\xBF\xF2`7!w?\xD5T%\x1F_\x18\xDA\xD1I\xA0\x01]\xEB\x99\xAA~\x10\x8AO\xCA\xF53-2`\xE2\xF5\x83\xF7\xCDM\xB4%w~\xAA)\xF2\xF50\x0D\xF1\xD4Qk\xBA,$\xABoB\x9A@\x97k<\x02{=\x8A\x1C\x16_\xE0:JR\xB4\x1B\xE0\xF3\x16\xF8\xA9]\xE6\xDD-\x09@\xC4\x01\xA8\xA9\xB0X\xA1\x1D\x13iL\xCF\xDFyb\xC7XU\xBD\xA7v4\x86\x80!C\xB6\x8DS-\xA9\x86\xFC\xBA\x93\xEE\xF8\x1A\x12K\xFC\x9D\x11\xFDQX\xA0\xC2\x98\x04\xA4\xA3~\x924\xA4t\\xA8\x7F\xF9\xB4\xD7\xD4\xF4\x8E\xEE\xE4\xDB\xCC\x9EQQ[\xB64\xF7S P\xD9\xEC?\x1C\xC0G_| \x82\xC0i\xEF\xEB\x13i\xC1~\x08\x97\x15\xF36\xBA\xE1h\xC4My\xD2h\x94\xBE\x89\xF1XF\xA5\xB7I\xCC\x1F\xF1\xEA\xA1\xDC\xD9jrf\x9E*z\xCE\xCF\x99\xB5\xB6\xBER*\xD0\xCA\xD2B\x8B\xDE\xF4!\xD9\x8C\x0D\xDC\xF5\xB7\x18\xF5\xED\x16^,\xC3{Qd\xB7\xD5\x02\x1A\x92h\x02W\xB1\xE2\xF5\xD6\x14\xE9`?\x02\xBF\x0F\xC5B.\xFC>g\x13\xB3\xD0\xF3h\xD7s\x08\x0B\x8E\xBD\xBF4Ni\xFB\xA1\x0C\x13\x90\xF6^\x8Dx\xE7[r\x12\x80\x11\x12\x89976\xB6\xE4\x1A\x9C2\x19\xDB\xDC\x0Cn\xDF\xDA\x1F\x09\xC9\xF6\xF4\xEE\x87s\x83j@\xB9e\xA3\xC9\xD7\x04\xEA\x9F\xF1\xE2}\x8A\x82\xD4Q\x0A\x7F)\x8B\x8D\xF7\xC2\xB3\x01\xBA\xA9W\xC6\x98\xF8\xB3\xD0\xDD#\xCC\x08;\xDD\xFC\x03\xAE\xA9\x80.-\xEF>?\xC2\xDD\xC7\xE9o(}.-\\xEF\xDA\xF9|\xD5c'\x08\x06\xA7b\xF9\xA4`\x15\xD0\x10\x1E\x01\x92\xAA%8\xEC\x8D\xB4\xBB\xAF\xCD\xF0\xA9v:\xD9Ob\x1A\x14\x85\xFD\x91\xF2\xFB\xF4+\x15I\xB5\xB8\x0A\x11\x98\xB7gR3pfL\x8A\x95\x87\x93\x12\x82\xA8\xC6Z\xEABB\x9A +\x15\xF7bf\xEA\x1B\xEB\xB1\xBBP~8\xDF\xDFz\xA8\x8F\x15\x94[g\x8Aa\x83\x03}\x81\x11\xCB\xAD\xC7\x05\xC8\x99\xB4\xFD\xB2\xFC\xF3k\x9A-a\xCC\x95\xC2c\xDA\xC1\x82Nu]\x0D\xA1{{R\x99\xE7\x80\x12\x9D)\xB4,{c\x9D\xE3Z\xA0\xBF\xCF\xF6\xDD\xB2\x1A\xB6\x8E\x90\xB6\x03\x03\x99\xD6\xC5\xF3\x19\xEA\x1B\xEF\x9E55\xB4I\xDC\x9D\x8B\x9D\x99\xC7OE\x0E\xF8'\xA5gm\x0B\x8D\x8A\xFE\xD8\xE8\xE9r#7)_\x99.\x07\xE0\xB7\xE3\x87~H\xE9\x1C\x10\x88+\xD0\x19\xEB\xC9\x13\x93\xCBn\xDA\xE2\xE9\x17xo\x95\xDE\xD43\x18\x0CDc\xB6\xB2P\xF1\xD2\xD0)5\xF2\x86\xD3\x1Bp9\x0A[\xFD%\x07\xF5\xD1\xCDL\xEA\xABe\x0DI\xE2\xFAK\x1D*w+NF'\xD6\xB8F\xFF\xBB\x9E}\xA3\x89\xEB\x03\xBE\xD9\xE6N\xFF\xE7[\x17R6\x024\xCA\xF5\xEF\xFF\x0B\xFF\xAB#;\x01\xE9\xD1\x9D\x02\x85\xE1;\xC6t\xF5\x0F\xF0g\xC1\xEE$;`\x90\x84\xE2\x8C\x89\x13\x0F\x16\xC1\x19\xFC\xCD^\x9Am\xF6\xEB\xA0\xBB\xEC\xB6,}\x1DE\x1D\x93\xB2\xBC\x90\x92d\xFA\xAC\x1E-\xCD\x98\xD2\xC4\x85\x07\x0C\x0D\x01\x00\xA9\xAAa\x91H\xF3UXOy)hUJ\x88\xD2f\xD1-m\xBA\x9E\x02\x95\xF8R\xE3\x12k\x8FU\xF9>\xF7#\x7Ff\xCF\x03\x0EG=N\x91\x16\xD8\x1F\xC7\xC8\xAA\xB2\xE8\xD4+\xD5sW{\xC7\xFA\xCFb\x8D\x0Cey\x13?F^\x81\xCERN\xFCJ>MA2`\xC8q\x14lc\xA25\xDD\xF0\x1E\xA7\xE2|\x9F3u\xE4*\xEC\xC7\x01\xA2\xD1_\xC7\xF6\x8C\xAC\xBFj'6V{\xAA\xEC\x98\xFE\x91\xDC\xD7?\xE6<4\xA11\x9A|-\xC1\x1E\x1D\x98|\x8Ex\x0D\xAE\xDE\xE9:\x8C\x88T\x1D`YbI6\x15H$}\x0C\xC6\xAE\x0AS\x9B\xA5\x09\xDC\x9AQ\xA5\xFDb\x7F-F\xAAaVz\x16JX\xB1\x1CR\x92\x98\xCFt\x14\x00\xD3c`\xF9.3\xC4Ng\xE44\xB3<-VI\x82 g\x86\xC2N\x0C\x83f\x0C\xE5\xA8\xEDb\xCC\x0F\xDE\xE3\xB4l9*\xD0~\xF4\x0A\xFB\xA8\xF1\x9B%\x81\x18[&\xB5\xD5\xD9$F\xA1T{\xF4\x97S\x81A\xCFr\xD6\x82O\x81\xC0K\xB6\xB0\xC4L \xC7 \x0B\xB67?\xB7\x9FQ\xFD+v\xC4R\x1B\xB5Y\x0B\xC0t\x9D\xF5\xE3\x1A\x10\xAE`\xA6\x8E\x07\xD3\x9B\xC3\x001\xCBO 2\xC2z\xCB\x93O\x97\x92A\xA4\x80\x02|\xFB\xF1'\x87\xD9\x1D\xA3\xBF\xC2\xD7\xB4\x93\xE81a;hp!\xBD\xB7n\xA54\xDD\x9E\x8C\x8D\xB5\xE6\xD1\x13zHY\x1A\xDD?z\xA0\x8B\xF5\x04I\xC3\x80\xDA\xFF\xC4\xEApHI\xE2\xDF\\x90G8\xD4\xAC\xA7#\xF0h\x9B\xED>\x0B\x88J@\x86TNp\x9A\xFF1\x9E\xB8t*\xE9\x17\xBC~["\xADYcA\x97\xEFX!p\x95\xAA]\x03\xBB\x07\xBB@9=\x10\xC1\x89\xEBD\x999P\x16\xFB\xB1E\x0D\xBF\xC6\xCC\xA2\xCB\xB6\xC6e\xCF\x16\xEAa\x88\xD7\x1F9\xD2\xE2\x87zM\xBA=\x08\xB9\xE9\x83\x0E\xED\x98\xCF\x10u|\xD2\xEF\xF7\xB5\xDA\xD9\xCD\x0C\xBA\xB8\xD5@&\x90\xE9\xC0\xDEe%@\xA4\xCC\x9AE\xCE\x18\xB5\xC5\xDC\xAE\x13v\x17\xBD\x96\x188\x84\xA4\xDF\xA7\x98\x00\xD22U\xD2#UGm\x92S5np\x1CL\xEF\xE1\x9Ag\xF4\xE0\xD0\x03\xA2\xD5\x83\x81\x9C\xA6\xE7)\xA2\xFC\x07\xAD\xC8\xB9\x9F\xC6YX\x93\xD2\x84\xC1\x1B\x1E~\xEAe\xE5\n\\xF1iF>\xC3\x8486\xF8\xB1\x8D\xFF\xB6J\xD4\xA8l\xC1y\x8F\x06\xA0\xE9[h[c]\xAB\x16\xC6\xC3\xC7\x06d\xF1\x83\x09)bOi\x0A\x1B\xDB*Y\x0A\xE7\x023\xE9\xA8\x8B\x1B\xD5\xDD1\x07\x11COS\xD8|\xD90\xE0x\xB0E\x8Fl\x10\xC2\xD6\x9B\x8B\xDC{K$h\x9F\x85_`\xB6\x8E\x1A\xD4\xE0\x98Tu0\xE6\xCA\x8Ea\x81\x0Do1\x86\xD3\x85\xBF\x04\xC9*U\x92\x81\x1E\x9F\xC5(\x12\xEC@\xE6\x90A\x84V\x03RIF\xC5\xF87&\x1B{\x96\x19(\x7F"*\xBF\xE0\xEE\xBD\xFF\xE3\xA8\x14a\xF6\xE2}?\x11db\xC4\xAC\xD6\xB4\x02\xFE]p\xD4\x1B\x95\xE7\x05\xF9\xBF\x9FP~\xEF'\xDA(4\xBF\xD1\x0F\x13%\xAE\xFB@\xA1\xF5d\x99~\xD4\xD6\xE3U\xB7N\xBA\x90xv\xFAmC\x95\x8F\x13 (\xB4:\xBA\xA3\xF4\x0E\xEC\xEE'\xBD\xC6\xED\xA5\xDC\xB1\xBE\x8F\xFF\xF68\xA5\xADc\xE3~\xFE2W\xA5(hl8_\xC7\x14\xCE\xC2\xCB\x9F\xAEv\xDDs\x91\xB7p\x1F\x85\x85W\x98\x7F\xF5\xAB\x1A\x82AlRUG\xEB\xB0g\xF3x\xD3(Cc\x1E\xD4\xDF\xD1\x17|d\xCEy.\x8B\xB3\xC1x\x1D\xB8B\xC6\xF3t\xD4uo\x08\xD2OJ\xA0\xC4m\xC7\x90z\xAFe\xB0\xF87R\xE9\xDDK\xBAw\xEF1T\xF99?\xD8\x80\x1C\x0C\x0B\xC1M\x13\x04\xE7\xF77\x1Dox\x9E\xCEy\x0EW\x9F\xC7\xF3'\x87&\xE0\xF5G^\x13(t\xFB]M\x17=T\x96\xB9H\xAE\xD7s\xE5T\xE6\x96\xA3\xD4)!\xD0\x935&\xD4\xC4\xD5\xE7\xDC\xA2\x9B$\x03\x93\xCD\xEADh\x8D}\x94\xB0\xBFi\x18\x9A\xF8\xA1\x95\xC4\xF8\x9AP\xEF\x97\xA1\xAD\x7F\x059\xED\x19\x02u\xEC\x1E\xC6\xC2\xC6\x8F\x8FG\xEE\xF5\xD6\xB0\xF3\x03\xCE\x0A+\xA0\x02\xC4\xF7HW\x8Bl2\x11\xAB\x0D\xB4\xE5u\xBB@\x9E\xD4T\x14\x0E\x90N\x9A\xE8\x83\xA7t\x09\xFA8\x8C\x09BX=D\xDF\xE4\x1C\xC6N>s\x00t\xABU\x1F\\xA5\xD3S\x9E\xFE$\xACt%\xF9\xD4\xCC\xFE\xFAx\xEDm\x9B\xCBE{\xCB\xE84\x85\xEC\x94\xD7\xAC\xEB\xFE\x01\x13 \xEEK \x1F \xCF\xA4\xDD\xAA\x83\xB7fn\x8B\x11\xCD<\x0F\xAA\x95\x12\x03j$d$\xDF\xA3\xA8\x01\x1B1!K%\xFA0\xEC!\xD2|d\x10\xDC.\xA9\x85\xCFD\xED~lP~|{\xD2\x0A\x1B\xE5q\xA8\xE1#JPWF\xE6R\xDA\x1E\xEB\xF7\xA9T\xD3k\xEC\xBB\x9F\xA6\x1A\xF9\d\xCB\xAA\x0D;k^\xA1#\xA9\x8BP\xD8P9\x90t\xD2\xE8}\x0D\x96\xE15\xF6\xCE\xDFB\xBF3\x0B\x90ml\xD0E3\x8EY\xF4\x15_\x92\x89\xA8\x81\x84\xAF%Q\x86\x12?\xE1\xA5i~\x99e\x81U\x92W\xDD\xBA\xF9\x8BK\x92v\xDD\x8B\x18\x10\xA9\xAE\x8E\xAC{\x91\xB2a\xE3\xEE\x7F\x05\xA1GK\x1B\x8D\xEDB\x96\x86|D\x0E+%\x90\xC9\xA0k\x1Eo\xC8\xC9Yk\x8B\xDA\x93R\xF6,\xA0tI\xDA\x99\x09t\xF8\xE5\xAF\x92\x14\x17\xCD\xE5l\x1Ec\xCC\xF4\xACQA9\x7F\xA7\xFFxT6DpQ\x13\xF7\xB1\xD9|n\x92\xD7\xE4v\x84N[+\x8A\xDA\xD2\x8D\x06\xFF1\x1D-a!\x1A\xBA/fu\x17&\xB9\x1Dl\xC6o\xEFM6N-\xA3\xC6a\xFE\x17l\xD9y\xAEs\xAD\x0E@\xB6\xECx{K\xFB\xF9[8\xB3W\xF7\xA3B\x01\xC7\x1E\x9B\xFD\x90k\x8Ba\x0A"\xED\xBE\x92\x1C\x07\xF2\x0D$\xF0\xCC\xB27U\xBE\x11\xA3C@^J:NQ_\x8C\x1Bt\xEC\x0C\xD4d\xA1\xBB'\x80\xDB\xA5\xDD\xE9\xB8i\xE0\xC5\x89\x98\xEF\xF8\xB9\x1C\x1E#\xBD\xFE\xB8.sw\x95\xBAT\x19\xDE\x93@\xA0\xED\xC5A\x91\xC2\x15\x93g\xEDl\xFF*\xD0\xD3\xFB\xE8]v\xC1\x1C\x85\xD0W\xC5\x92;\xB9i\xAD\xBB:/[IO\xF9\x9C\x1D\xAELD\x19\x927\x9C\xB2\x0C\xC2\xDC\xD1E\x82\x0F\xE5\xDCu\xE2\xD1\xB7\xBC\xC1\x8D>\xAF>{B\xB048\x81QB\x1AI-~'\xA3\xBC\x02\xC3t\x05\x174\xA6\x98\xD9I\x01Q\xA9w\xFC\x9B,\x99\xE5\xABm\xCF\xD3\x00\x98\xFAe@\x93T7[\xAD\xED\xFB\xDD\x94\x8B4\xD3\x81\xBC\x86n\xCD<@ \x92\xE4(\x86(\x92\xEF\xBB\xDF\xCF\xBB\xE7\xFF\x05o\x16\xEA\x91g'%?\xF1\xE0\x17\xB2,\xDBNM\xD2\xA2\x97\xB9d\xFD\xB2\xB1!4\x84v\x9F]\x14J\xB6\xDA\x80\x1Erb\xFF\xFBe\x0D\xDA\xA5\x17g\xF2k\xD57\xD3\xAFQs\xC8,O\xF3\xF6\xF3\xE3!\x8190\x89N\x9A\xCE\xF2~\xF3\x80\xBB&\xC5\xBEb\x1Du\x95*\xCB.\xA0n"J:\xD46y\xC3v\x9B\xE1/vo\xEEC\xA1;\x9E\x03\xE0\xEA\x03\xF3!\xE2X\xC4zH \x1C\x18\x99\xA4\xF9\x86\xA6\xBFj\xE4\xB1\x82\xB5\xEA9[\xE6\x19\xB2\x99\x00\x86`\xE0\xF1~\x1C\x9A\xF2Xy\xAAt\xC0\xD3j\x0B\x0D3\xBA\x19\xB5p\x94\x00\xA3\x08\xA2\xDBk|b\x9BI\x1DplV\x9E\xE4\xA8\xAD\xE3\x1B\x13W\x89\xB4a@\xCA\xD4qyVB#P\xD5\xAD]\x8B\x1A\xED\x12\xDDp\x90$\x09l\x8C\xE8\x91's\xE7\xF4P\x0F\xBFK!<\x97\x828R\xA8\x16\xA3\xC4\x9E\xD1J_~\x86\x13Tc\xFC\x08\x08\x01\xD5\x91,\xB4P\x02\xA5\xBC/\xCB\xE7?i\xD7\xA6\xC8\x0E\xB9\x8B\xC9y\xF2k\x89\x9F$\x08\x15\x1A\xD4\xB7\x98z~?.K\xA6\x9D\xDD=\x9F`\xA8\x87\x83\xD0a\xC4\xACh\x96$\x96\x13\xEC\x14yj\xC8Ot\x8C\x7F8\x8Bu9e\xF7\x9E%\x9Fo}\xAB}\xD1]\xDB\xBA<\x09\xD7Ub\xCBO\xE79\xEB'\x0CU^b\xF8\x99\x85\xA4Er\x8B\xC2\xCF\x0F\x90\xE7\xAD^\xDEl\xE3\xFA\x1B\xE8\xF5\xC3L\xD2\xAE\xD2\x13\xC5\xC62\x08\xBEZ\xA3\x9C\x0B6\xF6\xE2{\x1E\xAB\xBC\xF0\xBE\xA5\xC9\xC2(\xC7\x830\xD0\x90\x8F\\x130m7w\xB7\x96\x810Y>\xF3\xA5\xF5f\xC4/ku\x0D\x1B\xE3\xBB\xD4\xE6\x19\x90\xB4\x16\xC0\xB0\x92SN\x7F\xA1\x1C'\x1F\xA7\x01\x99\xA7\xC0\xA56\xE4|ynT\xDFu\x09\xBB\xDBn\x1E\x04K\xDA\xB2\xC77\xC0\x17\xC4\xA75\x1C\x0F\xAB\x87\xAE\x1C\xF0k#D\xB1\xC8\x0E\xCE\xA7=\xC6u\xBB\x84\x9D\xF60\x96\x0C\xEC~?\x93\xA7\xC6GT\x0721f\xCD\xCC\xD1\xAAG\xDB\xBCwu\x8D+\x96\xAE\xDD\xE1\xB7\xD4\x90\xA6\x1B\xEE\xE8\xCBb\xEF\xBD]\x8C\x93]\xA2\xEF8\xF9\xD7\xB0\x8D\x80H\x8D\xCDc\xBA\xE9Ds\xB1p\x11\x10\xC8\xD1\x83\xFC\xF0\x91#y\x83mQH0\x90;J\x1E\x0F\xC7S4"\xE0\xFC\xA9Y\x8EJ\x16\x08L\x9E\xA2L\xEC\P\xB4\xD2uJ\x89X\xE2f%0\xD2k%:[\x9C~\x15\xF9{\xEB\xF1\xEE\xA3%\xF7\x8F<\xEEK\x81"T\xCB)Hf\xF5\xEE\x82w\xCF|*\xFA\xF7\x00p6\x06_\xF8e\xF7\x91\xE1\xD2\xCA\x85\x82\x05C\x95\xAE\xB0\xA4T\x94\x9C\x095\xF8[\xB7G\xE8\xEAd[\xF2OA\x02\xAA\xB5\xED\xEE\x1F\xD4\x94\x0Dz\xD6y\xFF"4\xBB\x0A\xF6\x94\xD2\xE3\xB5\x96C\xD3{\xB6\x84]\xE5R\x94T1~\x88o5\x05\xC5[\xBA\xC3\x0B7\xD2\xEC>\x87Uj\xBA\x8Fn4c\x99\x96\xD1\xAA/\x16*3b\xEE"+\xF6\xCA\xDBy\xA3\x96\x84Iu\xA1\xEAV\xF8\x97\x01\xDAE\xB3\xBC*\xF9\x060\xFFC,\x16\x86-\xB0\x99\xA092\x9C\xE6"\xC5x\xDE\x18}h\x01?M\xC9\x94\x8D\xD9\xB2Ye]\xD1W+\xE9=G\xA8qe\xC68\xE3\xB6\xD4\x97T#?\xA8\x1A$\x0EL{\xF5\xAEj\x99\xE49\xD6\xC19r\xDD\x123Q&\xE01\x1D\xFA\xF6\xA8\x075!\xC1\xE2\xFEor\xDA\xDC\x1A:\xCD\x99\x8D\xD2\x90;k\xF0\x9Fv\xF0\xCE\xB7\xB7\xDF\xB5y\x84\xAAl\x0C?a/\xA9&7d\xCB\x16\x96UA&\xB7\xA8%\xB7(N\x14\x96\xD0\x1Ep\x95\x06f\xFF\x06\xE1yV\xDC\x1A"\xA7xr\xFA75Pk\xEDG\xFB\xC6\xDD\xC7\xDB\x9B\xAD1\x83`Y\x1D\x1F\xF7\xCE\x01\xA2V\xCC~\xAA\xAA\xD2\x0D\xE1j\xB5\x81\x1D.H\xC7\xA0\xD9\xB1\xCB\xF9\x80S\xB5\xDF\x0E\xB9\xE2\xA8\xB0\x12D\x95\xB7%/>\x0EJ]\x8Dt\xF7\x1A\xC5\xDA\xCB\x1C\xD4\x81\xFD\x04\x0B\xC2D-<\xFE{(T\x8FR\xBF\x8A0\xBD\xEC\\xEC.#@\xC4\xB6\xA2\x85\x02Z %\x8E\xEB\x9D/O\xEE\x0B\xF7\x88\xCE\xB2\x8A7:\x83\xF2t\xB7FZ\xB5OP\x0AiO\xC7\x8D%^d\x08\xC3\x00\xFB\x98\xA2%\xD5\xF2\xCB\xDD=\xE4\xB7:\xB0d(\xA2M\xE4p\x19\xD0\xBEX\x09\xC2\x83\x1D\xB9GU3\x07\x0C\x0Ao\xE0\x99\x12\xF3\xD3\x0F\xB2\x1B\xB2\xD2\x1A?\xEC\xFEz\xD4\x8Bgr\x04=O\xFFW\xBF`\xC9(\xDC0_\x9E\xC3\xB8\xC0\x95a\x0Cu\xCD\x82\xE3q\xEE\xD9U\xEF\xA9)\xCD\x03\xFD\xC5Y\x0D\xE1\xD3"\x82\x9C\xE2\xB5\x04\xA0#\xC9i#fhd\xC9D\x1Em-\xD6?\xEB\x85\x1F_\x8E\xA7u\x8F\xAE=j\x87\x87?\x1C\xE2|\x07P\xEF\xFE_\x89\x9C\xEA\x9Fz\xF82\xC5C\xCCj\xCE\x1A\x8A\xF8\x01xXV\x16y\x12>\x13+\x0F\xDCzD\x1Au\xF0\xD7}%Ht\xC8\x8C\xF1/\x12<\x11\x8B\x08hw\xDC7o\xB1\xA7\xC1\xF4\x91\xBDIM\xF1\x18\xD4F\xF7\xB4si\xC2\xC9\x15h\x91\x88p\x83\xAAG\x9F\xC7\xC4\xB4o\xD5=\xC0TYg'\x87\x8EA\xCB_\xEE\xC0\xB2\x9A\xBB\x8A\x97 Y\xE7\xB7\xFF7\xBB\xD3\xE1G\xED{\xDFY\xED0\xE5\x01\xB9(\x93p\x00<\xD8o\x80$DW\xDB\xE6\xE7\x14\xEA\xC7E\xA5o\xBA\xD5\xD9>\xB7w?\xDF\xA5\xF1\xE4\xFE%wX\xAFx\xE5\xCE\x1B{\xAA+\xBF\xEB\xDA\xF4$o\x80\xEC\x95\xBD\x01\xB5f\x03J\xBF\xDA\x05\xDA\xDEkRB\xC0:\xADf\x94\x08\xBF\xE2Y\xF4\x02lw(\xA9"\x7F\x84\xD0\x92\xD6\x95\xFF0\x87\xD9[G0\xE6\x8E\xC8\xB5\xC8V N8\xB9\x0B\xB9\x9E\x99\xEF\xBE\x8A\xBCu\xA6P\x19\xC6{\xB5\xC8G7bw"\xFD\x8F\xFF#Z\xD7\x91\x17\x0D\x15\x9D{T\xCAh\x8C\x11x\xD0\xA7\xFCTr\xB4\xA8\xAB\xF6\xEC\xE3\xB2M\x8B\xCE\xDF\x99\x83e\xAB\x9D\xC4\xE7\x8DE5\xEA\xBD\xAE\x85Y\xD3s\xF4\xF2\x07&\xF1\xA3\xAFM\xD9\x95\xBBe\xBA\x0FI-\x17\x9D\x0E\xEF\xAFt3W>m\x1DP\xD3\xA5\xE6\xB7\xFDK"\xDF*w\xAE\x95\xE6\xC9\xE8\xD8\xD4\x8Ft\xA8\xB7b^l^Qd\xD9\x87\x84\xDC\x0A\xCF\xA5\xA3\xC0\xDE\x9E\x15\x07#t\xBFI\x7F\xF0\xBD\xB2\x82\x04\x09\x9D@%\xEA\xAC\xAA\xA1\x89\x18\xFB\x09\x01%\xB92t\xEC\xFA\xD8\xD2\x0C\xDD\xAD\xA8\x11T\xED?\xB9\x86\x85\x03Dn\xEB\xA1U\xCA\x87c\xE3\xE4\x8B5A\xFA\xC4\x9A\xF5\x0E\xB7\xE0M\xDCxs7\xE0\x9B/\xE8\xAD\x0E\xA0\x84y\xCE\x14\xEDG\xADeui\xCD+CS\xFA"\xAF\x93O\xC2\x9B\xA4\xF2\x10\x8BzD\x14),\xFF\xD1\xBF\x99|\xBF\xC0*\xC0#\xA0\xE3E\xCFm\x9F\x16b?\x14\x89\xAD\x97vy\x0Ef,+\x16\x12\xE3\x9DLb\x0A\xB6\xAA\xB5_\xF1\xCD\x05\x12\x9EG%h~\x07\xFA\xB3\x9F\x91^n0Z\xC1L\x04\xA9\xB5\x1E\x90\x1B\x7F0\xD2Y\x1E7u\xBDv\xBD6\xCB\xFEL=\xBD;\xC2\xA2m?\xC0~\x17\x8F\xE9w\x06\xCD\x0Bd\xCB\xF4\x02:\x09\xF0t\x06\x11\xC4\x13\xA1A\x08.\x7FX\xE9\xE4\xF4\xF6u\xCC\x8F\x83\xCA]\xA0x\xC7\x89\x08"\xDF\xE5\xEB<\xF1\x01aY\x99J$\xB6q\x19\x18\x9At\x14\xCE\x8F#(\xD1\xE9\xEF\x0E\x92t\x88\x02QgW\xC0\xF7\x9E\xBB\xC5\xC6U/>;\x9A\x029\xFE~\x88^\xBB\x8D\x00\x87y\xA8\xCE0\xCF\x84\xDE\xA0x=\xC51\x03.\xAB\x92{\xC0\xE9\xA7\x13\xD8\x04_\xCB \xBF&\x1B\xD0\x7F\xA6\xFCD\xE7\x9A\xD1\x03\xFD\x95\x98\x09Br\xCA\xBB\x14VI+29\x10\xB5\x8F]<&\x03g\xA2\xA6^\xF8\x96\x90\xC7.\x85\xA6\x82\x1D1\xEC\xD0\x97\x98\xBB]\xF0\xFD\xEB!_I\x84\\x06\xB4\xC3~C\xD6\x07\xDB\xCF\xC6\xDC\x16\x0B\xCB\xD6\xD6\x96\xA8Im\xB0\xCF`\xCF1\xE8\x18\xCD\xB3\x07)\x8F\x8C\xBAK: \x94\x17\x0AB\xD0?D\xCB\xF7\xDD\xE7Y\xC4\xE21_e\x0D?z`\x95@*Ji\x1C\x05vO\xCCH\x8B\xFD\x08\xBF:\xE9\x08`S\xDF\x93\xE43}\x1Aqd\x10\xE6b=.\x85\xD2D\x10\xB8\xED8O\xBD$\xBF\x0B\x02\xA7O\x860\xA1\x9B\xA2F\x9D\x03\x1C",j\xB4\x02\xAB]\xC69\xAB\xDB\xE0t\xF5\xF1\xFA\x80\xE5\x085@\xC3\x9F\xB6Y\x95\x7F.\x96\xAE)\xC8\xBF\xF1'\x9E\x1CY \x93\x96V+X\x80\xBD\xB9\x02'\x95\x90\xD3\xCA\x98}\x90\xA0\x90$3\xE8n\xFD\xE8\x03,\xE1z\x06\xA4\xECh\xEB\xB0\x02@\xA4\xEBGw%oY\xBFC\xFF\x805e\xB7\xA4Dj^\xBC,\xD8b\xF2\xFE\xF6\xBF\xAA\x17\xEB6c\x11x\xB3|\xBA\xDEv\xB5\xB4\x01D\x02w\xA0&\x89\xE5\xE6\x04\x05\x01$\xC5I4S\x1DG\xD7U\xE2\x04'l\xEE\xD8\xFF\xC4Q\xCC\x0A\xA1f\xA4\x8Ax\xFFVaA\xE0]\x9B\xD7g\xE5\x18\x04\x004\xC4\xD4\xA3\xCF\xBF\x18\xF6\x03]=\x85\x19\xBA\x84\xA9\xC8\xCE\x07\xD8\xFEv\xA2#\xAB\x91\x1F\xFB^\x8Dq\x97\xE7k\x18\xE9d\xD1z\xB7Fj\xA4Z\xED\xB2\x01\xC6\x15\x9F\x87\x9Fk\xD3\x9F>\xBC\x02C\xBC\\x93|\xE8Xi\x8C\xAE\x96\xAA\x08\xE1\x0Fs\x16\xD6\xEB\x83.\x91\xF78Q\xD8\xF8[\xE8\x02\xC0N\xEE\xF8\x1D\xDC\x12\xEC\x85\x112t\xEAe\xC8\xA0q6\xDD^\x8AP\x91\xC3\x1D\xB0f&\xF7H?\xC6\xCB_\xEC\x8E\xF3\xA65>\xEE/t\x0D\x1B,\xD2"\xA17\xA5\xF2\x97\x17&\xE3\xF9\xF2u\x95-\x10\xD0\x0DU\x82\x90q\xC4\xEF\x8D\x9A\x19\xD3\x05\xAC\x98F\xE8\xE3z\x9E\xDC\xFE\xB0Iw\x04C\xDF\x87\xA5Q\x1F%'\xBB\xCDRd\x89\xED\xE7,\x0F)\x1E\xB6\x04\x02\x0F\xF7\xFA\xA7\xDDE\xC9\xAF\xC24wf\xCD!\x90fK\x92\xBB\x1Ca\xC8\xCF\xE0/m\xDDk\xA3\xF0\xB6`N\x90\xC3\xA6\xC6\x87\xAB\xA1d\xE4R\xC2<\x01\x0C\xB3\xECG\xFC\x95&\x9192\xCA\xD7\x15\xDE\x16F7\x9D\x07\x82\x9B\x93!\x01p\x8C\x03\x96Y\xB9\xF0\x14X\xD9j\xB5\x84\xC4\x0B2\xFB\xE0`TJ\xD7S\xFB\xC6|\x88\xDD\xEC-\xBD3\x09\xC95lR\xF3{\x14\xFE\xAFE\xC0@@\xF1\x9DaA\x80\x86\x97\xE0ss\xD7q\xC6\x92E\xACY\xD8\xB8\xC2\x9B\xEC\xC8]\xA2\xAC\xF9\xD9UA\x7F\xE6&?F\x0B\x9D\x94\x19\xE1i\xBC\x8F\x8Ek\xBE\xD7\xFC\x0AJ\x96m\xA8t\x8B\xA0*\x91;a\xA6/w\xA2\xE1$\x9D\xB8]+pZ&\xFEJG\x9FP\xF8\x95r6\x0E\x0D\x92i.\xA2\xB96(!\xF7!\xBF\xC5q\x81\xEC3A\xA4B\xB5V\x8E\x16\x055\xDA\xA3\xD62\xE0`J%"\x88\x1C\xEA\xC5\x19\x012\xE5\xD3\xF0\xBB\xFA\xCC\xD6\xFC?\xB8\x9D\x11\xDB5\x88*\x99\xF7\xF6=\xCB\x1F\x9Bt\xE63A\x12\x0D\xDB\xFE\\xA5\x94\x8B\xB6VakW\xB4]*\x92-N\x8AT\xEDhnD\xD2Ke\x12\x1D'\xE7\x80\x83(\xF9\x1AB\xFF\xFD\xD5\xD0\x077\xA7\x93\xC9[\xB0\x92\xB7W\xABe\xB0{\xAFdE\x9A.9\x1C\xA8\x05<0\xBB\xD4\xC9\xDC\x03\xA0P\xD5\xA9\xDC\xC5!\x8C\x07+h=\x97\xE4#F\xDA[\xDD\xFDIL[\xE6\xF3\x13=6\xE5\xA3n\xB1\xEF\x1F\x7F\xF6\xB9\xBF\x9Ax)\x7F\x88\xA9\xC3\xBF\xF6\xCF\xD9\x18B[\xF2g\xF4\xEE\xE9:\x16\x00~)\xBD\xEB\xB5a+%x\x02\x9E\x1F\xB8\x98m\xFA\xE0\x8D:\xF9\x16\x0F\xD7\x97E\xFA\x15\x92\xD6+\xC4\xE3\xB0\xCB\xF9\xB5\x11\xC2\xBA\x92M\x1C\x02B\xAA\x12\xE8\x06\xCF\x9EL\x0Cg\x1D\xF5&`\xC0\x94\xA5\x05- `\xC2\xD3)\xBBpxTlD\xC3\x86\xEA\x9F=\xF6\x95\x97^96\xB4\xC1\x16\x92\x1B(}\x82<\x15*'L\xEB\x08\xCA?=\xF76a\x04\x00\xE2F\xCA\x01\xE58-\xBA\x056\xE9z\xF8\x1C\xBB\x8E\x86\xE6\xE7!\xA1/\x96FU+\x15\xC4J\x19\xC1@8\xCF\xAB\xAD%@u\xB9\xEE9_\x1F\x893m;\x92Q\x1A\xC3fX\x08\xBD\xF1\xEF\x13\xB2Q\x19\xF5\xE1\xC0o$]\xFA3\x0B8\xCA{\x1CR\x0C\x07\xE8e\x8A\xFA\x93'\xC7N\x01\xE3\xD9\xBAx\\xCC[~y\x91\xFA-\x09\xFC\xCE\x1F\x06T\x0E\xF9\xFEZ\x16.\xA3\xD8\xE9\xBB\xC8E\x9A\x97\x85j\x1A\xC6\xA6\x8F\x8Fa\xB0\x86\x81\xB0\xAD:\x0AO\x01\xAC\xD3\x82M\xE1\x05/5\xE9\x1F%\xCD\x17\xF4\x1D\xCA\xA8~\xB7\x04@\xCE\xC4\xED\xBE\x0A9\x94\xB2\xF7\x95p\xD6\x85\xFA\x18">'M\xAF\x11\xACQ\xA9I\x8C\x93\xB8I6N\xDC\xA2\x1A\xF9\x1CU"\x06\xDAl9\xA6\xE6K\xAF\xAE\x9D\x8C}\xB6a\xDBn\x9A\xAArAg\xC7JC\xAB\xCFi7O\xC4\x9DtK\x86x\x1E\x00\xEE\xB3\x95\xDF\xA8n\x07\x8Cz\xD4x\xED3\xE8\xAAq\xFE\xF7Y\xF7\xE1\xD5EJ\x81\x1E\xA39\xB7\xD7\xF6K\xDB\xF8h\xB1\xBAqM\xD3\xF0r3\x13\x1C\xE2 \x9C\xD6\x05\xBA\x9Dr\xCEdO\x80\xFE\x0A\xEA\xA6\x82g\x84$Y\x08(\x0A\xFD\xE1zL\x91ze'H\xF4\x08ca\xDB\xD6\x8FZ\xD1\x97\xD5\x95\x87;Q\x18\xD6&K{A\xCE}(\xE2\xA4h\xA5:b?\xD5\xE0(\xDFl\xDA\x9B\xEB\x0E\x16\xCEg]+k\x8559=\xAA4B0\x98\xE9b&&\O,s\xC1ED\xE5\xD4\xCA-\x10\xCD\x1C\x95J\x83\xFD\x9Fn\xEE\x87\xEB\x94\xEB\x15`tA\x19\x0D\xEE\x086\x09\x88{\x9C\xF8\xF4e2\x8D\xA4\x84P\x01\xE9\xBF"^\xAC\xC0\xCE\xE6\xC4\xAE\xA8q\xD2}\x96\x16\x04\x93\xAC\xE3\x19\xD4i\xB3I\x9Cm\x04\xC1(g\x1A\x00\xB6*\x15\xFB\x7FJ\xF8\x18\3\xFF3\xDF\xC15\xA9\xCA\x00\xC9Kp\xA63\x1A>\x86\x7F)\x11\xD2\xB4\xDE \xD6\x95\xB8\xD1\\xA4\x1CF\x159:\xE5\x0FIQ~\xB7xv\xB3\x1A;I\x11\x91\xAF\xEF\xFB)\xEA\x0B\x0Fxd+J\xDA\xE0\xB2\x7F8\x9F(\\xF3\x8CS\x17\x86\xDD6\x04\xA6\x93\xB3\xAE\x87\x0C\xB9\xCB\x10\xFF\x92<=@\x12O*\xC2\xBCF~\xF9\x95\x8C\xB6c\x15\x13\xF6+\xECc%\xDAXe\x05ty\xDA\x16\xDAs\xA8\x9E\x1C\x16\xB8\xF2\x1F2-\x9C\xD5B\xD0d~\xAAZ\xC1X(T\x9A\xC02O\xF8G\x97\x0CL\x95\x08\xD7\xCF\x0D\x00\x1FS%\x12}a\x87\x86\xE1\xEC\x03p\x1B.\xBA\xFBWh\x8C\xE3\xE6\x9C\xEC7S\xB7\xFF\x97\x078\xCE\x19N\xB0\xD3y\xEAu\xA6\xE3\xE5\x10\x09G\xB3\xAA\x8F\xDD\x17\xE3\x96\xB44\x9CJ\x9C{:\x1B\xB8\x99\x04=\x1E\xEA\xED|\x0A\x02K\x8D\xAC\x86\xE0\x1E\x9F\xF9\x93v$\xEA\x08\xCE\xE4,*O\x8D\xDD\x98\x9F\x80\xCC\xBC\xDC\xB99\xACI\xA0\x8D\x1D\xDB\xB7\xC9\x0A\xC2P\xAF&\xF4\x0E\xC2;4G\x19[m\xD8\xBA\xD7v\x8DA\xDAQ\x9B,:\xB3Xi\x91\xF3$\x9C\x99\xEAG\x1F,\xF1[\xC7H]1((\x18\xDCaw?\xD1\xED\xAC\xE6\x13\x04\x0E\x0C\xE9\x82\x87}0A5~\xFE9)8s\x18\x15\xF5\xB9z\xC4I$e\x14\xCB7b<\x09H?\xC1\xF7D\xFDJ\xE3\x18\x17\xE2\xDA\xC6\xB5\xB6\xFA\x1Dy\xD47GL\xF5\xFE\x16z\xD8\xA2\x18\x96k\xCD\xEF\xAC\xBE\xEC\x94\xB2\x17\xD5\x12dGQ\xE6\xFD/K\xCF\xEF\xC4wm\x0D\x19\xB7\xB0\xD0\xC2\x7Fy\x9D_h\xA7\xC4\x0B\xB6|\x8EI\xC6M\x1D\xF2\xA5\x7F\xFA\x15\xA4|\x93\x08\x99\x1D\x8Cj\xFBP\xF67\xD0 \xF5\x0C\xB3\xCF\xA9\xD8\xF4\xB1z9l\x08\xDA\xB2\x91M\xFBY`\x06\x0C]\x96#\x83\xD6\xD1\x96\x95y7xN\xDA\xAD\xFEy\xCC\x9B\xE2\xD7\xE9D\xB5d*?-OD?0\x87\x1E\xFE\xF4*kGM\xA5\x9E\x0B?\x05{\xF8\xFF\xC8Ur\xEB\xBC)\x0B/\x9C\xD4\xD2xR\xD1\xE5)$:q\xCF\xA5\x02\xEFg\xD8d\xD8\x0C\xA9~[el\xA1\x94^v\xC3F\xFD\x96e\xDE1\xFE.\\xA7\x17r%'aJ]\x0Fa\xBC\xDA\xA3D\x96>\xA7\xF8;\xF2Y\x00\xA0\xBB\xA8:\x19\xEB\xFBA|\x8E\x89\x0A\x9Cce\xC6\xB2\xAA\xBDX?\x86\x13M;1\xD5\x91\xCC\xCF\xADt\x86\xF6\x1F\xB9\xA9\xF5\xE6\xB2\x0A\xCC\x16uP\x0A\xF7\xD4#\xF4j_\xDE\x02\xABb7e\xD6\xF1\xC9BS\xA7C\xC5+\xA6\xFD\xEF\x09Y*J\xC3\xF8\xD7\x0B\xAB\x7F\x8C\xDC\xC9C\xEC\xA8\xBBM\x871:\xC6\x84\xB72k\x93\xBC\xF3\x96B;\xED\xA5\xF6\xA0\x89\xFA\x01\xEB`\xE7\x83\x06\x94\xC6Z\x87+\xE16\x8E\x98\xC7dn:9\x1A\xB2\x92}\x153\xC5\xDD\xB2J\xD3\xFF\xF5D\x07\xCD<\x9C\xE6\xCAj\xE2\xD7\xAC\x1E\x9C\x82,\xC0\xFB\xC43\x1BB\xBB2\x8E\xA4|}\x03)\xF1\x8F\xFFD\xEA\xD4\xFC\xCC\xAE\x85J\xAF\xC7\xA9\xDF\x1B\x03ZG\xC4O\xC0[Kl\xDF\x7FN\x8Fg\xB9\x01$\x9C\xCA,Ru"E&~\x1C\x18.J\x14\xF3\xAE\xF3\x98\x86\x811\xD3q\xB58\x04e\xB4\xE1\xF2\xF94\xB0\x84\xD2q\xAA\x85\xBE_q\xAA\xFE<\x97q\xACE\xAD4\xD1\x80;Z\x9A\x8B\xBFs\x13Y\xAD\x0D\x1E\x9Em\xDD\x1F\xA5\xC9\xA8p\xE3j\x97q\xC7F~\xF6\xE1\x7F\xAD\x87\x9A,\x8Bq\xADvA\xF3\xEA\xC4D\xDFB\x13\xEF\x92\xFF\x0D\xC0\x96[\xA4<9\xB4\xF2\x98#\xBA$\xAEa8$i\xE6\x97\xC0\xCC\x98\xF2\x87\xDB\x92\xB8\x13\xAE\xBC*\xB8\x0F\xF4P\xFE|P@\xDCA\xA8p\xF7\x1Cj'\xC21\xAB\x8AW \x04\xFE_g\xEE\x1E\xFC\x9C\xC2\x94\xDB\x81M\xF7#\xC3f\x11\xE5\xFF\xA0\xF4\xA1n\x82.\x08\xF2\xB9\x9C\x91\xC11[( \x8F\x88-(\xDE\xEE2\x9E\xEC\x09\xAC\x0E\\x18\xA8\xC3I\xF23\x01\xDC\xF4g\x14\xC9\xE0b'\x8C\xA2\xE2\x1Ev\xF3*;\xDE\xFB\x95?\x1C\xB8\xC8l\xC9C\xDC^\x84\xD3\x87+\x8087#\xDC\x99\xCF,t\x11\x82\x19\x86\xD1}W\xA4\xAE\xEA{\xB0\xA1Xyx\x02k\x81YP\x17\x87\xCAT\x04h\xB4\x7F\xC0\xD6\xC0\xB4\xD7y\x08!s\xB3\xA4\x98\xAB4|\xE3j\x8D\xE8\x95\xE4\xB0q\x8F\xA1\xDC\xE9\x18\x85\xE5X\x13k\x116c\xE9\xA4(\x153\xADi\xA8]\xAF\xD93\x88\x10\xCB4<\xDA\x9A\xD6D\x06a\xEE\x19g\x94\x03\xC0\x9D\x15\x88=\xE7uN\xF5,\x108\x8Ff%\x0FS\xFA\x87\xFD\xF5pG\xCB\xED\x0B\x89O\x1F\x06v\xA1\x91C\x8C\xBD\xE5\xC1e\xA3Sg\xCBk:\xFDA\xF4P\xF2\xB8\xB80\x8A\x0DC>\xB9\x0E\x8E\x87\x92\xD3dd\x81@7RC\xCFx\xFD\xCE_\xE0\xA4\xDF\x11\xB1\xEE\xA3\xACk5\x05(\xA4M\xEEn\xE9v\xC1\xC0\x80\x1B_\xCA\xFC7\xAEo\xAAM\xEB\xA6\xA9\x16\xA6\x00\xBF\x11\xCD\xE5\xBAv\x9E\xF4\xD5\xE4\xF6~\xF5\xDB\xE1\x19\x88\xF3\xBC7\xF4\x13\xF0e\x03\x857\x0E\xA1\x02\xBFy\xAF\xC8E\x9B\x1C*\xBDs\xC1\x17F\xE5P>\x1C\xFD!}t\x86\xBC\x14P\xB6F\xAB$\x19\x04z?o\xA8\xEC\xBF8\xDB\xE4\xE6\xCEa^\x0E\x9E\xAB=\xF0O\xCE\x89\xE5-XuN\xCA\xC7X\xD6\xDBb\x05\xFA\xD6\xF0\xC5E\xDA\xE7\xE6\x07\xCCd\x8FPz\x1D{\xB77\xBA<\x15\x95\xA7\x92\xE3\xEC\x92\xEA8\x7F\xDE<%'\x8D\x05\x8F\xD4|\xFD)\[^&\x9C\xCC\xE6r\x9F\xA4\xB1Y\x99\xB3E-\xCD%\xE3\x9D\xC2\xB7\xB9\xEC\xE0\xEB\xA5\x1B-\x90'\xC7\x11z??\xFB\xE3\xAB\x0C\xB7\xD2\xEB\xA8\x0B\xC8L \x02\xB8y!v-;@\x02\xA2\x84\xA4\x1F\x16f\xA0\xA1\xE9\xD2\xC0\xE3\xD94\x86r\x14\xFF\x050^\xCD\x02\x81\x13\x9A\xBA\x01\xAB\x18\x16\x917\xC7\xD9\x99\x13b\xE4f\xA79\xFEt\x06\x02?\x07\xD9\xA43?\xD78L(\xFD\xD6\xFC\xDBF[\x1F\x18\x04]\x97\xBE\x80\xD2|\xDD\xF5\xF5\xC3"\x8AL\x9EpS\xAF\xC7\xE5\x06\x1E\x066-\x11B\x14\x91\x18\x9D"\x1B0\xB0d\xFB\xCB\x8C)]9H3\x84\xAF\xEE\xEE\xAE\x0C\xF7\xC3\x8D\xB1\xF0\xD0\xD7\xD4'\xCB\xB1\xE8\x9F\xC2H\xD70\x96Id\x85\x90;\xC2)D\x99Q(\x83SL\xF6\xEF\x03\x17}}\xC5\xAF\x0A\xB8\xD7\x91{\x0C\x1E\xDB\x82\x13\xACS\xB9\xFD\xE5\xAAI\xC5\xC9H\xBBv:\xD8\x96o\xF3\xB4&\xAB\xFB\x01p\xA3\xF6B\xA2\x99\x0D\xE0)\xCC\x00~\x03}X\xCC\xB6x\x982)\xD3RT\xDD\xC1\xA2\x1D\xD4(\xF5\x0A\x1D\xEA\xD5\xF7k\x07\x98G\xECi\xB5\x8D\xE7\xC2v\x96S\xF6\x80:b\xE8\xF5\xD5\xA9V\xAFV\xAF\xA9j5\xF0\xFFn\xE0\x87w\x88\x1A\x19\xC5\x89\x0A\x8F\xA3\xDC\x7FY*\xBE\x08g\xCAk\xE5.\x12x\x89TF\xAB\xE3o\xE8\x9B\xE5\xF6\x0EANEn"\x96(\x9A>o_\xD3`S\xA6\xCE\x7F{\xE0\xCEWfM\xFC\x84>h\xBE\x15\xA5wt\x17\xB7J&k8zDZ\xC0\x12\x06\xB6\x0B\xEA\x10%m\xB8\xD6\xAF\xC4\x8E*\xBD\xC8\xDF.\xC3~=X\xC19\x8Bd\xC9\xE5\xEA\xE5v\xC6d\xAB\xFDam\xEF*\xF7)l\xC2I\x15\x14\x19\xB9 \xFBV\x8D\xA5\xE9\xD0\x0D{\xD4\x1E\xA9\xE2\xE1u\xEE\x88\xFBp\x19\xE2\x8F\x01\\xE2C] \xCDd\xF6\\x93z>\xA4]^A#=\xD3\x9B\x1B$Ds\xE2\xC1\x08\x99\xE6\xC0U\x8E\xC5\x80\x04T\x0B\xA8\xA4s\x05\xAC\x14\xE0\xAC\x1Ap\x13\xFD\xAC\xF4a\x14\xAD;\xF6P\xA65\xF5\xD1=o\x10\xDD\xC3\xCC\xCA\$\xC4(A=\xC7)\xFD\x8C\xDB\xF9\x92\x89}\xF6\xB9\xBF\x99\xB198\xBA\xF1\xD8\x9EJ\x15\xCBG\xACP\x9C\x8E\x9Aod\x15\xA6o\x81\xBA\xE1\x15\x0C\x95\xEA\x84_\xF0S\xD4\xE1\xE3!.G\x80\x1A}\x91\xD3(\xCA\xE5\xF6]<\xA2\xECT\x9A\xD3G\xC6\xC3dei\xF1\xD7w\x04\xEA\xD1=\xCC\x13\x82\xC7U\x8F\xF1`\xB9+K**\x867O\x8D\xA5\x99\x82UwQR]\xBB(\x95jK\x7F!m\xBC@\xA28\x1FP~K\x04\xC3\xFF\x80?k]\x9En\xC50Y\xA8\xF0d\xDC\xAF\xC6|\xE7\x1E\x83\xA4\x8B(j\xF5A\xC0If\xBF\xD7m\xEF\xC3\xDEd\xF1\xE8\xD2\x8FA%\xCF\x1Dn1l\xC6.\x01\xE9\x80,\x04\xC6\x13\x0C\xB3\x0A\xE9,jI<:\xBCv\x1B\xF9a\x1EI~\x0DqwpZ\xB0\xAA\x90\xE2\xAC\x1E\xD8\x85FZ,\x15\xF0\xB0\xAE\x95\x16@\xDF\x17_\xDF\x98\x12\xCAXB\xEB\x86pX\x03Q\x16\xE9"(>\x16s\x82\xF4|\xCD\xF6\xE4\xF5\xD9\xAAK`\xC8,#Db\x18]\xDE#\x060Jh\x9D\xF1\xD0\x80M{\x93\xF4\xF1\x03T.\xE8\xBA\xDF\x02\xD2K\x8C\xDA\xA2\x93\xC4\xAD\xE9\xA3\xA1\x0F\x1A\xA7\x87\xB7\x83\xB5+1\xE3d\xBA\xE2\xF3\x9B\x9E\xBB\x0E\xE6\x9D\xB1\x87\zv\xBA&\\x81\xFAbJ\xEB\x89\x01\x91\x1E\xC1\xA1\xB3\x16!\xA2\xBE\xF2\xD2\x1F%\xBE\xADi\xA2VP%\xEEk\xC0L\x83{\xAD\x99\xBD\x9C0y\xECM\x853\xD7tf%|\xBEo\x91\x880vy\xA5\x91\x99A\xA0\xC2q[\x95Eb\xF7\xF4\x84\x9FP\xA3U\xB6^9\xD29\xCC\xF04\xB3d\xBC\xA5S\x08!V\x0F\xA3\xBED\x07\x91R\x8C\xCE3}NCv\xC1\x91#t1\xABr)\xBE\x9A\xAE\x97\x88\x7F\x7FD\xD4\x1F\xC1\xE6i\xD97(_\x88M\x1F\xF9\x0B\xE4\xC0\xD9\xA6y\x1DI\xF4\xF6\xC6\xAA\x1A\x8BA\x08uT\xE5C7\x09\x813\xAF;\xF7\xC3\x16h]\x9F\xA6\x9A7\x7F\x8E\x09`\xBFl\xB6\xAF \xE6\xAA,+i\x9C\x845\x06hp\xA76\x1A\x8Bla\x17\x02\xB6\x9C\x95@\xCD\xB3\xB4\xE7\x06\xC1\xCD\xBD\xAD\xE5\x9Dz5\x91R\xFA4|\xC5;\xC1\xEC\xCC\xCF\xA8\x17\x84\x18\x1E\x10G\xE3\xDF\x1F\x90\xF3E}\xFB\xFB\x83\xF9\xCB\xC2>\xEB\x13\xD7\x0F\x83\xCA\r\xF5\x00\x1D\xAC6Dp\xC8$\xD6\x83W\xB6\x10\x1E\xD6\xCF\xD0d\xF9\xC9\xF6\x96\xB0\x04\xB8\xA6[\x83D\xDB\x1E\x86\x81\xEE\x11bY\xEC9\xAF\xED\x9E\xD9\x81\xD2\xE2\xC8\x1BHm\x09(\xF5\xDA\xCC\x10\xCC\x99\xED\xF8\xC4\xCA\x1D \x95\xA6Q\xCCq\xF5\x0C3B\x16\x90\x10M4^[\xAB\x13\xD1\xFDI\xE7&O\xEA\x91a\x17\xEF\x8F=\x9B\xD7wN\xAF-\x9Fm1i\x8F\xA8\xE0\x06\xAC\x8ER\xF4\x9E\x13\xCFx\x00%\xC2'R\x97~%O>\x00[\xFB\xCCTk\x86\x9E\xC7\xDB?\xD2\xDC\x19\xE0\x83\x91\x10\xD6\xB4\xC99G\x845\x12\xC20\xFF\x89\xAAU3\x19\x07\xF2\xAE\xDBlu\x9D>B\xC3\xE8\x1A1\x1CG\xB39@f\xEF\xE7\xD4\x94\xF8\xC6\x15o\x81\x01\xAAn\x00\x10\xCE\x80a\x1C\xDC#I:\xB4}\xB6\xF3j\xE3\x9E\xB6e\x98\xFF\xF9\xF8\x91w4\xF1\x8D-\xB8\xD9\x8C$\xC2\xCE\x16\xFD*P#\xE6\x9D\xE4V\x9416\x8A\x90Ys\x8F\xF21\xA7\x9B\x84\xBA\xB2\xF9\x8E\xA9u#\xDF\x80G\x8FF\xCEc\x9Ags\x11.T]xU7\xC9\xE3\x06yC\xED#q\x84\x0C3A\xCB\x81m\xE8/\xF1\xB2\xB8\x0B;\xEC\xE7\xB5\x03\x88\xB5=\xE1g\xE1\xAD\xCD&\xBC\x92\xAA6\xA0q\xF6\xB1\x026\xF5\x05\xB3\xFDh]N9\x10_2\xDA\x02\x91<\x04R\xCF\xC8\xB9p\xF4\x98\x9E\x11`\xE8m*\x0A{:?r\x94\xE6\xADu4\xF0\xB1\xEA\xCC\x1FZ\x09\xE6\xFBc7*\xB8\xAER\xA9_+\xE3\xDBt\xA9\x1F\xF1\xE5\xBF|\x84O\xA4v\x92I\x00W\xFDr\xDEA\xBC|\xDDk\x8F\xE4\x8D\x92<\xB2R@q85k\xE3^I_}f\x94\x87\xAB{q\xAA\xE3\xA5b(_\xD9@\xAB\xF7\xCE\xB7\x93\xA1\xC3\xB6\x0B\xC68\xD6N\xB4\xCD\xA7\xBD\xC6\xED\xAA$\xDA\xB3\x90\xE8\x03\xB0@d\xD1\xCB>\xC9\xC7<\xFAtde\xDB\x13\xF6WVz\xDC\x19\x15p\xB5\xB6uW(Xx \xD9t\xD4\x82\x1C\x7F>!\xAC\xC9\xC9\xD4a\x1B\x19\xD8@\x9A\xC5_U\xA0\xC3\x1D\xAAWk\x7F\x86\xB1\\xCBKK\x004\x9E\xB3\xDAX\xD6\x86\xBA\xA1\xD1\xB3\x1BO\xF7\xCF\xF5\xB7-,W\xA7X\x98c\xAA\xE2]\x01{%!\xA9\x96\x10\xA4a\xF2@z\x06{\xAB:a\xFD\xEB[\xFE\x16z\xE6ha\xA2\xA6\x1A}\xA2\xCFB\xD8\xDB\x9E8\x95\x9FAV\xAF\xE2\xAA\x0D\xA1\x06$\xBE[_&\xBC\x90\x13\xA7\x04\x1F\x8De\xAE\xABA\x8E\x8B\xF1L!\x19R\x9D\x15\xEF\xC2\xFBY\xCFuW\x9B\xDA\x8D\xA2\x11Lm\xD6\x0B+\x0C!\x0F%\x02\x17\xE2_\xD9F\xB8?\xA4\xA7\x97\x96\xD4\xE6$s\x8D\xAC\xFF\xB0h\xEA\xF2\x93\xEDR\x00QX7\xF1\xE7\xFC\x81\x13\xD3\x94\xF4\x99\x9E\xA3P\x0Fl\xD2\x17\x0E\xC4NM\xB7\x11\xC9\x0C'\xB7\x1F"\xEC\xE0\xB0\x83D@\xF1\x02l\x10Z\x8A\xA4\xB0E\x9C(\xC1\x932\xD7\xAF#\\xAF :"X\xA3\xC3P\x92\xB3\x8Bb\xFC\xE0\xC5\xFF\xB5\xD4\x1E\xCB\x98\xF1\x09\xE5:\x9DKc\xA9\xC69^\x0E\xD5\xEBE\xEE\x87?\x92\xC8\x9DA6\xF5Z;7\x0E\xF2vA\xB1c\xB6\xF9\xE1;\xCBb\xC4\xC0\xD2\xCA\xDAz\xF9\xED\xF2V\xA4-\x91\xE0\xF8\\x16\xA8\xC4$x\xCD\xC2E\x1B\x0B$\x86\xF1\x88\x94\xD0\xCF\xF6$\x04\x990\x00\x96\xE3G\xC2\xD6\xCE\xB6_\x09\xD4\xA5\xEF\xD6\xCC\xE1\xAD+\xA0r\x1B\x19\xFB\xA8\xBC\xCCu\xE8\xCB[.k\x05\xB6\x0DUM\xE5\xBD\xCC6\x88\xFC\x92]\xFAI;\xFD0~$AY\x97r\x9E\xFB \xB6\xC8\x04\xA9r\xAD?\x93\xBF\x11\x9C\x9A\xC2\xAB\xBC\xE3\x92K\x1B=\xFC\xAD\x07\x0A4\x12;c\xEF\]\x13\xA8\x12\x15\xE7\xE0\xC1\x1B$\x888r`\xAC\x83\xDD\xCE-\xAB_\x05\xD9c\x153\xB7\xF0I*\xDF5\xA3\x8E\xA7\xB7\xF8x&\x08b\xCE\xF8\x9B\x90Z\x94\x15\xBD\xF9\xD1\xCA;\xEC\x9E'\xC2mD@V\x073\xA4\xECq\xC1\x8C\xF8\x85\x06hE\x04\x19,\xF5Q\xF5\x14&\xAEL\x8E\xE3#\xA6up\xD8{\x92\x1A]\x94R\x16\x84\xA9n\xB6\xEB\x19b\xEE\x1B;c\xEE\x81B,\x17\xADS7z\x90e\x9C\xF8\xA8{\xE3\xA9h\xDB\xDD\x04\x9D4\x12\xC1KK\xD6\xBD\x1Ap\xCA\xE0\x1F]g\xE7\x98\xFF\xBDB\xDF\xDFj\xC1\x11i\xE6\xB8\xD7\x97g\x95\x03\xDDd\xA1w\x16\x9A\x86\x0D\xAC\xA5n\xDBI\xC5^c^\xEB\xE5\xC5\x9C\xD9\x8Edn\xA0.d!4D(\xCA\xD9\xBD\xA9\xDB\x03\xF9\xA7\xD9\x9C\xD5\x02\x88y@\xF2\xD7=\xB2&,\xD5\x9BfSr\xD8\x0D?\xCE@\xDE\x1E\xF7\xB5`\xEE\x1A\x81Q\xBC\xFB\x1C\xDA\xBA-\xBC\xC6\xEB\xB0\x02\x9A\x01b\xBF\xB0p\xB1c\x03\x1A'\x0625\x1E\xD5\x86\xF2\xF2\xBA\xDF\xC3\x97'\x9F\xD4\xF5zR\x07\x86)j\x19\xFA\x01\x98\xE5V\x18\xE3\xB6\xCC\xD8\xD4\x9F\x82<\xA3\x06\x0D8\x91\xE8\xA8\x92\xB6\x07uZ*@\x04\xD4\x8Bx\xCD\xC4o\xEF\xF9\xBA8A\x1Cg\xC1\x01\x9A\x94\x03\x95\xE59cnK\x1E\xBB\xE5g\xEBx\xBB\xF3\xE6\x04\xB4<\xA4p@Y\xFDJI\xCA\xAF\xC7\xA7\xA11d\xE3f@\x00\xC0\xF5\xB4\xEBvF3\x0E\x17Z\xD1\x1F~\xD8I[\xB5j\x7F s\xDB\xF0\x84/\x82\x846\x8FR\x9A\x9FD\xFC\x0Cv\x0C\xA6\xC7sy\xEF<\xFC\xF54\xD6m\xA0\xE9\xD4z\xF9\xE1\x04\xB7\x83\xFF\x19\xA5\x99\x00v\xE4[*&\x8F\x8D\xF3F\x06Ul)\xF1\xFE\x96\xDE2\xED\x09\x9D\xEEI_\x00\xAE\xC2\xAE\xBE\xD5\xEA\xEE\xF5mE`\xE5\xEE\xFA\xBA\xD1\x80\xFE\xA2QZ\x0B\x9E;\xA2\x91\x1BE\x85\xE5<\xA0\x0C\x90\x13*\xC4\xCA\xD9\x82.y|i\x0E\xC9\xD1e\x0E-^W\xF5\xB0\x0F\xA1Lm\xA7%K\xB9\xEA\x96'%\xA9n\x13\xF7W\xCB\xEF\xDDB\x80\xAE\x14\xC0\x9D\xCFTW.h1\x0B\xEC\xD2g\x03\xF1\xD3\x1A\xD7\xD2\x89\xD3\xD3\x8D\x8A3\xEE\x0A\xCCO\x84\xB3Q\xE7k\xCBY\xD1\xAD|\xBB\x92\xF5sh\xDF\xDB\xDB\xB2\xD49\x18sW\x90\xE6\x92j\xD4\xBC\xB4v@x\xBF\x8B8.4\xE0(\xB2\xDAG\xA0&Yg\x0C\xAB\x00C\x84?U\xFA\xCA\xCA\xB9]\x0EI\xEC\xEC\xBB\xC6\x82\xF2\x0B\x19]k\xCE\xB6\x14il\x06\x82\xD6a#\xDA\x7F\x08\x82W\x85\x88Z2\xE6\xB9\xAC\x89\xB5\xC4\x87j&\xEC8\xC5\xA3\x98\xD8\x9F|l\xF7\xD5\xA5\x1F\x91\xE2\x9F\xA9\x1E\xD4\x03K\xBFR\xC5\xB4\x98\xF9\x02\x9F\xD0\x09\xD1&\xD1\xD0kT\x0F\x11\xCF\xC6\xA6\xD8\x9Eb>\xBD\xFE\xA6H\xD9U\\x05\x14\x05\xFC\x03{MT\xDC8\xCF4\xAE\xD7\x91\xF2\xC4\xE8[\xDA\xBD#\xDA\xBA\xB8\x94\x9B\xD4\xC2\xAB\x92\xE8\x1B\x96\xE8f\xB9\xA2\xB9^\x0E\x90\xD5\xCB\xC4\xA6\xDA\xD5\x0F\x04F\xE8\x80\xE6\x0D\x97\xB7\x94\x85\xD2\xC1>;\x12\xF8\x9Al\x9F\xFA\xD6\xCE\xEA\x0F\xF2$\xD0\xEE\xFE\xDB\xE7\xB3(\xE0Co`,[NnX\x15\xB0\xBE`\xB9<\x01,\xA5\x8E7m\x17"gm\xE8\x8BH\x93\xD2[\xE1i\xF4?\x98!\x05p\xDA\xF5\x91\xAD\x18\x86\x0B\xC0\x1CG\xB9|)4\xC1\xCDyI\x1E\x84\xEBR$\x03\xB5\xEC\xF3\xC97\x9D\x02,X1\xE5\x8A\xB6_w"u\x84vB\xC7rV\x89\x17\x9F\x1F\xD1\xD8\x06\x12\x92\x1A)\xBE(\x09\x82y\x19\x8AH\xBB'v\x9FT\x97{\x87\xD5\x9B%\xCC\xCC\xC2\xB2\xBF\x09t\xE0\x0D\x13\xD5>;\xD1\xA8]_*\xCD\xD8%Ig\xB3\xA6\xEE%\xF8\x86\xD3\x86\xC9\x11P\xD9\xA2O;Q\x86\xB5\x91\xAC\xBE\xB0\x1E\x1D73\x92\x12m\x1B\xA3PX\xA2.*\x90I\xC0\xC7\xEC\x9FU\xA3N\x1A\x9E\xB0\x1A\xBF&\x8F\x157\x8DYT\xF6\xB6h\x82\xBF-\x8D\xFDx\xA9\xD3\x9C\xBC\x13d\xD2M\xD0\xE8&Q\x96\xBCb?\xFA\x06\9\x7F\xB7M\xED\xCF\x82\x89\x10n\xEB\x9A,\x84\xA6Q\x1F&(+d\xDD\xE5p\xBF\xAB\x06\xD1\x9A\x040V\x07/\x93\xC1P\xF7\xC5\x1A\x0B\xCC\xDC\xC7\x91\x93\xF92\xFC\xCA#\x8AK\x1F\xCA\xE0\xBCH\x02N\xA0\xC0=\xD2_j\xCF\x90\x1Es\xCC\xB8\x1BV\xF7\x8B~\x16x\xDCj\xDC'\xE9\xE4\x1E=\x04\xE9\xD9\x88\x90\x04>\xF4Vx\xD8P+&K\xE6b\x167u\xBF\xD2k\xA3\x17T9M=\xBEx\xD6|\xF90U\x06\xC0i."\xDC~\x7F\xEC\xA1\xD2\x96\xF7\x9D[\xB6\xFB\xFB/MB\xB2\x96n\x1B\x95O\xA1\x0A%L\x88L\x11\xD0Yw\xBC\xAA\xC9\x87\xEF\x83\x12g%\xB7\xBA\x1B\xD7?\x1E\x05\x08\xC9\xABl\xD9y\x9Ff\xF5\x8A%8&\x12\xF5=\x8C\xBD\x1F\x859\x0D\xC5\xB5\xF4\xB3\xA9L\x119\x12Z\x87\xD8\xE62"$E\xED\x89\xE8\x95n\xAD\xC7\x1A\xF0\x00\x9Dw\xCD#\xB5\xCE\xCE\xDB\x9CL\xAEj2\xF9\xE2\xA2GF]\xC6.\xFB\x18\x95\x0A$\x8E\xD2\x8A\xF1\xD8\xD2\xAFIG\xCDN\x7F&}:\x91\x83|\x90\xF5\x8F\x03q\xB7\xAC\x0Ba\x9E\xCC\x9E\xD3\x82\xE6f{7\xA3\xD6a\x12\x83\xB8\xCC\xDE,Zq\x0A\xF3\xE4\x0D\xFE\x95\x1C\xC7h\xA8\x9D\xA8\xFEmU\xAEC\xC18\x9C\xBD7J#\xD5wm"'\x90\x0BinW\xFAGa\xB5\xD7\x0CK\xA2>\x00a\xD0\xF7\xF6_:\xDB\x0B\xEA\xEBn\xB8\x95O\xE6\x8CGOO\xA8\x17 hc=\xD0\x13T\x98\xCB\xE4D\xFE\xEE!\xBF\xB2\xA8`@7\x00\xCBw\xDBC\x19\x8Ac\x9C\xD6\x9C\x83AW\xA6\x05\xD1\xEF\xABJY\xB54\x83w\x86\xA7}\x96\xC9\x1B\xB2n\xAC\xC66\x8A1\xC0O\x8F\xFD8\xD45\x048\x01\xE1\x1B\xEE\xA0\xB8\x8F\x0F\x90$_\xB2\xE3I*\xE5|\x09\xC7\xBC\xB7PI\xD5\x18\xA8\xD6\xACP\x8D\xE4\x8F\xCC\xEE\xAA\x07\x9E\xD3\x1A\xD5:\xE8\x9D\xC0m\xDD\xC8\xF0K\xE9\x07Yq\xCA\xB6\xC0{!4\xC3\xE1\x0E\xBE\x80\xD7\x84\x1Eo\x89e\x86\xE8\x89\xE6(\xE3\x87\xE8\xB5\x07\xE9+\xF8\x1A\xFFK>ok\x13\x99\x16\x95hQ6\xE5\xEF\xA66o_r\xF6\xF9?\xAB\xC8\x00\xB8\xA1m\xB2\x02I%\xFEw\xBB\xAB\x8Fe<%\x1Fpz\xEE\x8D\xB5\xD1N\x9D\\xAEU\xFD\xAB\xC4W\x8E\x16\xF0\xB9\x1A\x11cG\x8E{\x13\x1E\xC1\x91\x87FT\xF3\xE7\xB0\xBCZ \x1B''\xC3\xBFw\xE3\xA1\xF4H\xA5L\x97%\x1B\x13m\xD5Z\x82\xDA\x906\xBB\xA7\xB0\x18\xCD\xCA0zAocLx*B\xDBG\x08*\xC4A\xE3\xED\x03\xAE\xFC|M\x95k\xBFy\xA3\xC0\xCFO.^\xFD*\xE6hn\xC1\xC7\xBF\xA9\xCE\x1B\x1F\x94\x0A\x94\x95 \x1CF\x9D0+dy\xC4:\x86$\xF4\xD1\xAB\xE6\x0C\xB7m_\xA5\x97\xF1m\xEC\x19r[\xCBOdM\x80\xC0\xCB\xB7"\xE8\xDB0J\x15\xB5.\x85\xB2\xEB/\x97\xA1\xE1O-\xC1\xA1M\xC2\xE4-\x08wCZ`aH3\xC7\x88!,V\xAF3m\xCD\x8C\x7F\x05\xDC\xAF\xFD\xFB\xC0m\xE5Y(\xD2\x9C\xBB\xCE$\x96Y\xCE.D\xFA4\x1A\xBA\xA9}\x86\xF1\xEE\x988r\x91B\xB6\x142\x18\x8FE\x91\xBD9@\xF0r\xC1\xB1\x83\x8A\xE4\x0B\xA6\x10\x95\x86\xB8>\x17N\xF7wZ/=#\xE5\\xFD\xBD\x02\xB1<\x01\x07x\x97\xFE#\x02\x88 \x94\x9D\x15j;\x0A\x8ET\xDA.\x05N\xE9\x17\x08a\xC7\xBF\xDC<\xFA\x89\xB0r\xC1\x82\xBA\xF5\x83\xCD\x84\xDB\xE6\xCB\xC0wQC\xDF\x88\x00r\x14\x93~)\x89\xBD\xBC0\xC8\xBB\xEF\xD9\x0E\xD7\xE1\xEE\xE9\x83\xFC\x9C\xFA9\x91\xBC>\xFB\xA0\x87\xCB\xF4\xEA\xD0\xB8?\xD8n\xE0Uw\x93\x10\xD2\x1Av\xB3\x16Q%\x14\x92\x0E5\x94\xA8\xE4\xB6\xAD\x87\xF5p\x96\x9C\xAF\x92\xC2+Z\x006u\x81\xF2\xE5\xB7\xFB3P\xB9\xF4\xC3\xB2[\x1E\x1E\xC53@B\xD6f\xA2\xD9\x02\xAB\x9B\x0E\xD7\xD8\x88\x94\xE8*\xB4\x05\xFEC\xD6-\xAB\x80\x1E\xC8Xi\xF3\xBC\x80\x1E\x9C\x94#\xDB\xFA\xE8`\x99\xAA\xFE\xA6\xA5\x8E\xA0\xCD\xF4\xC0\x08\x15\xFC0\x171\xEE\x16\x89\xEB\xCD;\xFB\x8B\x12\x00Q\xCBe\xD8/\xA1a\x11\xA2\xAC\x91\xB9\x08%\xB8\xA9\xE1B\xBBW\xA1\xCD\x13\x9B\x82\x10#\x04\x80+\xED\x0A\x96\xBE\x89\x19\xD5\xFEo\xB6\xAF\x9B\x0C\xFB`"6G\x97^\x16\xD8\xEF\xBB\xEC\\xEF\x99\x08Cx0\x01l\>=\x1D\xD2\x12j\xB3\x18\xED\xC7k\xBD-#\xC4\x17\xEA\xB3\x07\x1DA\x9F\x7F3\xFC\xD9P\xEF\xA5\x05k%-\xDDJ?b\x09\xD7\x9A0$\xC3\x12>\x0A"O@Bz\xCE\x82t\x1B\x17\x16\xE4h\xB7\xA0\xCEb\xF9w\xFE\x89\xB0\xB97$#\x0E\x9F\xE0&\xEF/\xB3\x8D\xFF\x93\x8E\xD9\xEB\x07\xBD\xD0\xD5\xA4*\xE2\xF3[=\xB60\xEB\xC7\xA1\xE7SR\x00!\x9AF\x115\xBB\x9F>\xEA\xAF\xE1\xF7\xD0+\xE7\xDF\x84\x85\x1B\xC9\xCB\xBF\xFF\xAD3\xF2v\xF3\xA7\x05K\xE5\x16\xEE\x9AK\xCF\x83a\xEE\xB7N\xD6\x8BGE\x8C\xB7\xC4\x0F"\xA6q\xDD<\x95r\xF1\x09w\xD2O\xAD\xBB\xBC\x00&R\xDD\x08J\xA1\x90V\x14u`m\x968\x86\xD4\x0C\xBC\xB9\x06\x9F\xC1>\xAC{\x8B\x1E\xA0KF\xE3\x7FX\xD46<\xFDy,a\x07\xF58za\xFC\x85\x1B\x09\x0F\xDE\x0Cf\xB8,\x90\xC9\xC9\x0Dt\xAC\x93EvBui\x01\xF1\xAF\xD1>^\xA3\x93.=o\x17\xF9-\xAD\xC7o\xE1\x0Ck\x84s\xC1\xCF\xCA\x8B@\xDB*\x1C\x1C~y\xF3\xD5\xAA\xB5\x8Br\xEB2\xEF\xBAH\x97\xF0\x86\x08\xF5\xF6\x8E\xA6@\xFF\xC40\x04U\x8A@\x1E\xBE\xD4\xE7v\xA1p/rF\xC42'0\x81\xA9V\xAF\xD7\x07\x16\xA0\xC9\xD5qv\xC6\xE5\xFC\xAE1\x1E\x85'@>\xBF\xEF\xDC\x98:\x0A\x8E\xB0\x10-f>\xEA(\x1E#ck\xD1\x85\xA4\xE5C\xC70\xEC,\xBB\xD1\xF9\x94\xA5\x12\xA6\x86\x9D\xFC\x97\x8D\xAD\xA3\x05kk\xB9\x02\xA5\xC5/\xFAb\x82\x85\xDEC\xCDk\x9A*":\xF9/\x06K\xE0n\xEC9n\x8D\xE3lN\x18\xDF\xA1C\x9B\xB8\x99\x82Q\xF3\x8A\xF4a\xDE\x1A\xF7\xE3\x84\xAB\x94\xB4uG\x8E\x02#\xADX\xB9\xE0\xAA\x91x\xC8\xAA\xD8\xBC-DLEI\x81C\xEB\xC3\x9Du?\xC7FU\xBDs\xC2\xF2@7\xBE\xE0\x02\xD1\xBB\xC9\xE2\xE1Y\x10\x8BF\xED6\xCA\x93\xC8\xE5\x0A\xD5\x13:C\Up\x1C\xDC\xA3%2\x90\x82\xD4\x95_`\xE8\x94\x1A"!\x15\x1A[3\xAE\x1AH}\x06+\xFD\xA2\xD7\xDE\xA0;\xAC\xB0\xD9\x92\xADF\x92\xC8\\xA2\xB8S\x1E\xE9\xD2\xA2P{\xFB\xC7\xAFT?\xB1\x8Ap\xB2\xBBY\x10;\xAF\xAF\x1CEypH\xF1\x92\x95A\xCCa\x9A\x90\x06\x0F\x02\x02\xF8\x8B|\x95$\xA8\x07\x9E%\xC7\xFD&\x0F\xEB\xC2S\xD3m\x84W\xA8\xCFuM\xA3\xDF\xBA\xE2LI5\x18n\xAF\xFF\x0C\xB3\x90\x1D5\x96\xBE\x01\x96\x08\xB1[.l\xD6\xF5\x1Fo]\xDFsq\x8F\xA2H7\x13F\x0E\xF1s\x00\xF2"\x1A\x19\xCD\xE3\xC9\xAF\xB96\xE8\xD9\xA5\xFAp\xDA\xDD\xF5\xDF$\x88\x19\xA4\x8F\x1Cz\x96xwz\xAD\x10\xF2G\xFC\x7F\x02\xF2\xC80\x11\x18\x18(\x92u\xCA\xA7M\xF2=\xDE\x8E[GV\x9E\x0E\xDE!QsF\xCB@\xFBn\xAD\x1B!\xCD.\xF0"\xF1\xEBJy\xC9\xD9\xE0\x10!\xCD\xBFS\x16\xAB\x0C\xA0Z`\xB6\x8E\xBDb\xE0\xC7\xAE~\xF46\x9FG\xD2\xB4\xC4F\x0E\xB5"\xE9pPz\xD1/\x8D\x9F=\xAD\x95`d"\xC5\xA2\x7F\xFDH|\x0F\x0348O\xBA\xCC\x08&O)\xE3\x91\xEA\x1B\xFD\xED\x14\xCF\xEA\xA2\xCD\xBA\xA6H\x83\xDD\x1Cox\x0B\x9E\x86\x87xGbGX\xD7#M\xF6\xEAi\xAB\xAA\x9F\\xD6\xF7\xEC\x0F\x07\xDD\xCAz\x9F\x97d\xA1\xF5\x0C]\xF28N\xAF\xC8ifn\xF7\x97Dl\xC7\x8B\xCD\x1C\xB3Z\xAD\x15\xE4N\xB8\xCC\xB3\x8F\xB9Hx\x0F$\x075\x01c\x06\xA8\xE1E\xB0u`\xA3p\xF7\xCESt\x17Ff\xC3\x03\x9E/\x8F\x80O\xF8\xA9e\x83\xB6k\x01\x9A\x01\x17\x86\xF1p\xA4!\xB9\x12R\xC4s\xA0h\x84\x1AT\xCC\x029 [Z\xA6\xF1\xFDYt#`\xE7\x1C\xDD`\x9B\xEE*\xF3L(\xD2@L\x9F\xDD\x01\x1El\x02\xF9\x1E\xE3\x14^O\xEB3\xCD\x82\x1C1>p\xD8\x14\x95\xF5\x98\xDFk\xC8-\xF6\xC0'\x1Cy\x0A\x96\x9B\x13\x85\x0A\x86\xBD&;e\x9E8Y\x88\x9EbK\xFC\xAD\x1Bje\xA7~$\x9E\xB9(\xE0':\x91\xA0\xC8_\xA2\x86\x18W(\x8FI;o\x005\xB3\xAF\x8A\xEE \x8EX#\xCF\xC3\x81\xF5y%\xB6\x08Njx\xEE\xDE\xF4\xCD\xCD\x1E=\xAB\x9B\x127\xF4\xABG\x08\xEF[\xC0;=\xA8\xE4t\xF1\x03P5\xB8%\x1E\xACs\3\x14\xCF\xD7\x82 \xC6n[j\x07vK\xD7DU\xB0\xA7\x13k\x95\xEFe\x95@-)\x9B\x9F1\xA8\xFC]\x0E7F\x02\xF1eL\xDFv\xB2\xFF=\x89\xD0\x0B\xDC\x06\x899\x9F63\xF7\x12\xB36\x85\x11\x1A\xA0\x1A"\xE3K\xCC\x94\xB4h\xC1Y\xDC\xB1Hi\x10\xCB\xFE\xD8\xC4\xFEp.n\x1F}\xF5\xC4\xFFz\xCCJ\x1E\x9C\xE2\x08\x97w\x02\xD3\x9CS\x1C\xB2\xF4x\xEE`\xEE\xAB\xEE\x00]eHc\x03h:0\xEB\xF3\xDA\xE6\xF2\xDDN\xE5_\xA1\xCA\x98\xE9aE"\xDB\xB4\xDD\xF2\x11\x15\x8A\x0C\xB5\xDFK\x03\xFB\xCF\xA1\x19N\x91\x8F\xDB\xDF\xA6\x09X\xF6\xA4\x18\xB4\x07\xB1f\xE9\xC4\xCA\xA3C\xD7\xAC<\xEF\xB3\xDE$\xDF%t\xD7xb\x863X\x8D\xE2\x90/\xCD$\xCC\xBB\xC9\xA6\x8E\xD8\xEF\x93\x11Vf|\x06\xE3\xE4\x02\x8C\xAD\xF7\x91\x05\x98\x8D\x984O\x8E\x16\x11\xB1d\xE8\xC9\xA6\xF4uEW\xA6"".:\x94\x13\xD7\xC3P\x8D\xC8\x18&\xA0\x99\xF6q\xEF\xF9t\xC3{\x16\x05\x9D\xA1O\xA8\xBC5\xDD\xBD\x17nU\xFD\x19E\xED\x9F2\x9D\xAE\xD68\xD6\xEEl@PO\xF7#,\x0AI\x03\x14\xF8WW\xE6ye\xB9\xEBYv\x85\xD6\xFDM\xE4\xB5\x81$\x18i\xDF\x9E\xDA\x08\x91#\xFC\xA1.xS,\xC5Rj!LD\xA54I\x84\xDE/\x11\xAB\xB2R\x87+\xA1\x03\x08\xA0\xE5\x08\xC3\xA4j^\x97\xB1\xE2n=\xDC\xE3b\x0D\xE87\x0B<+\x0E~\xE7\xEE\xB8\xA1\xABk\xFB\x8D\xD8\xBF\xB49+\x17\xEE\xBAM\xE6R\x16\xCD\xD4\xF8\xEE\x83\x83\x03C\xCA\xB0\x94\xFAr\xCE\x05\xF0\xF9kgd\x13\xB0\xDD<\xD5l\x10\xA7\xCD\xA3\xD7wE\xF2]\xFF\x0F\xFD\xEF\x80\x91\xC86\xE4YnR'%\xFB\x02\xCAQ\xFB\xBA\x11\x0Fbj\x95\x88\xAEYnX\x88?\xCC\x1FM\xDE\x80\xB1\xD0s\x0Aw%\xB5/\x05\x00\xA5j}\xCBV\x13\xED\x01\xF1\x84bl\x83\x1B \xE19\x14\xBC,\xE9\xAFP\x1E\xD7uY\x0F\xFA*\x12\xDA2AV\x00x\xB5\xC6:\xBF\xFF4\x1F\x00e\x99%\xD4,\xFD\x13\x9D\xF3\x18Zv'\xC3n\x8B\xCA\xECQ\x11\xC2\xF1\x95\xCB\xC4\xB5\x82\xCD\x1CJ\xEFwS"\xD6?\x93\x91\x88\xC1g\xB4\xEC."+\xE0\x13t\xD3\x19\x93\xBB5[d\xB3\x19\x8CI\x0E\xE5\xC5\x12\xE0\xFF\xD2^k:\xBC\x8D\xB5V{t\xF0=\D\x84.\xDE\x86\xF8]\xF8\x0A\xA8\x15\x0A\x80\x8A\xB9\xF7\x8B\xCC\xD9\xF4QYL{bh4t\xC2\xA1U\x0Ah\xC2\x08\xE6FSzE\x18\x9C\x11\x85\x8Aiq\xBF \xD9<5\x12\xA82kcM\x06\xAB\x02\xCB\x08\xE3\xAF\x02\x8EC\xEC\x91\xEF\xF0\xD3\xD07?3&'\x88\xE3\x0A\x17g\xD6\xBD\xEA\x98\x89|\x8A\x05{m\x9B"`\x08\x92\x94\x87\x16\xF3u\x91J\xF6(\xC1\x8C\xEC\x07>\xBC@\x7FGu\x84W\x09#\x018\x14\xC8\x8A\x8BI\xF4\x0BS\x81(\x12c\x05\xCD\x83\xE5\x9D\xC6F*\xAC\xE0\xEEl\xC5\x10\xA6n%\x88\xAF\x91\x0B\xFF\x03y8\xEF\x93\xB5\x83^\xAC\xF0\x8C\x09S\xDF\x07\x1E\xAC\xCA\xF9;=\x82>#\x0B\x99\xC9\x0E^\xD9a6h\xC1CK\xE8\x1F\x90zu\xE7aM\xA3lBI\x0C?\x8DL\xADl[\xF8\xFFR\x86'\xDC9\x993\xD1h%\x0Ak#"\xDC\xF3\xD6\xF4\x02\xF0\x03\xF6\xC8F\xB2\x88O\xA3\xBD\x01\xBC\xE5\xF8\xC7?x>\x94\xDB\x88#\x07\x92\xA4\x0F\x82\x86\x04\x9C\xE7\xC6\x7F\x80\xB2\xE9\xAFN\xCC\x14\xE7\x02o\xDF\xB15c\xBC\x89\xDF\xA7\xE9\x8B\xA8l]\xBC\x12\xA9\x9BU7b\xA6\xD6v\xC5D\x8F8#P%on\x00o\xC1\xD0\xF6\xE7\x9E2\x0D\x0D\xD4%\x9E\x01\xEAX\x16\xEB\xF3\xBBYA\x99\xD60\xA3X%\xB4l\x12k\xE5\xBAo\xB2\x05p\xB4J3\xF5\x99r\x1Ee"I\x80\x9E\xDD\xB2\xF3N,\xFCn\x9B\xF6\x97j\xB2\xA2`\xF7E\x8E{\xD2\x84JU"]\xC8\xC2&\x00\xE9\x8B[\x99\x87\xAB\x8AQ\x8B9\x85\x9D#WmM\xD4\xEC\x00V\x93V\x9F\x8A\xCA\x98\xB5\x14\x9A\xBB\xD1\x8Ak\x8C\xF8\xDC"\xB3\xD6\xE1\xBC\x99\xA3\xC0\xF4\x11\xDA{B\x03\xE0F\x1C\xA2\xA9i9\x1C\xF7\x1D\x19m\x03\xE2\xC8H|\xBA\xE4=\x9CY\x17X\xA5\x92\x8Dc\x9A\xDB\xE7\x05F\x02<\x9F\x06\x0F\xA4e\x0E.Q\xE1+\x89\x91\xA9\xEC[\xBD\xDB\x00X\xF5\xC8\xBB\x93\xFA\x12\xA1\xF2&D\x98\x8D\x19+1\xEE\x9B\xE9z2Ro\x18'\xD8\x183;^]\x94Az\xF4\x94\xB8\xDB\x83\x8C\xA8b"\x81|\xDE\x9D\x00z\xC3=Y\xC7\x02|Z\x05\xD2\xBA'\xA9\x90#\xEE\xBCf\x15\\xE9\xDE\xA1\xB5\xC8&l\xC8x\xF5(\xEA\xACj`\x82\xC1\xC2\x925\x92\x07\xEA\xE1I\xDC\x92;3\xFDm\xC6\x83\x0A\xD1\x91\x83\xE0\x92\x97\xC0\x98N\x7F\x82;\xA7,\xA5\xDD\xFF\x99\xDF\x14\xD9\xBC\x93}\xE5\x01V\xF6${\xD6\xD7\xAC\xD5\xED&\xDBd\xA4\xB0L\x15}\xF6&V/\xCDVl"\xFA{\xB9R\xAC\xD5\xA2\x97\x85\x1C\x89\xA7\x1D\xA0\xF5\x7F\x93\xBA^\x0B\x02\x95b!?\xA6\xA8\xCCK\x8E=7\xFC\x1A)%2\xDA\xE8\xAFm\xF5I\xB0\xCA\x9Fx\x94*\xE8V\xEE\xAC\xAC\xA8xxm\xB7 7\x9C\xA2\x1A\x151\xD6\x01Q\xEF\xFC\x17%\xB0\x05\x1Cp\x92\x10\xECS\xE1\xDA\xDA\xFA\x0C\xB2\x90\xB1\x85o\x82B\xBB\x8Dn\xF4w3\xAD\xF9%\xAD\x90\x0A\x9E\xE6\x0B\x9C.\x93+c\xE5]r}\xDF\x84\xF8\xA18S{y\xC4f\xF9\x8FCsDRs\xD8\x9C\xA9\x94Q\x14\x04Z\xBD[\xB0\xA9\x16\xEB|\xAF,G\xB6\xE3\xA1K\x92F#%D\x8F\xCB\xB7\x8Cz)\x02\x0F\x95\x82\xBE\x7FS"f@Hy\x8F\xB6jf\x95,p\xDDd\x10EJ\x81\x84^\x95I\x0DK\x07N-Yb\x05\xD31\xC7\x9D\xFD*\x04;kKK\x00A\x027\xED6\xC9\xA2?\x1CSh\x11\xE1L\xC8NQy\xE5\xDCH\x81\xB24\x80\xF5l\xE0\xBD\x85P)j\xB1L@\xCB\xAEG\xB3\xFE\x9A\xCD{\x84\xD5\xC0\x96\xA6\x1B\xEA\xA5\x1D\x0A'\xC3f\xAF\x18\x05b\xD2\x12\xB4\xA5[Jl\xA7V\xFE\xDA\xA7\x97\xA7\xC7\xF9\x1E\xBC\xFD\xCB_u\xBA\xB9\x09X\xC6>\xB10C\x9A0n\xCC\xD4\xE5\xEF\xB3\x1C)\xF9\xD0\x0C\xE1\xF5\x89/\x9B\xCB\x1Ex\xF8e\xE8\xBBh$\x1E\xFD\x15\x94\xC8\x86yS\x9C({7\x0D&\x12\xA2Y\x1C\x86/'\xB7\xDD\x1D\xD8-\xA5-\xEF\xD3\xB7\xCD\x8F\x06\xB3[\xD5\xC3\x9E\xA6\xD7\x9E\x9DV\xA4ja\xA4Y\xCF\xAC\x07^\xCB\x95\xBB\xCF\x00~\xE7\x03m\xFD\xAE@\xC8\xD8\xA4@X\xAE10\x8E\x19\x9DV\x10\xB80\\xC9\xF3\x12\xBE\xA6R\x9E\xE8iC-N(\x9E\xAE>\xE0]\xDD\xF3\xF3\xF5a\xE3B.E7^\xEE`\x0F\x897n)*\x0C\x92\xD1+$bl'\xEA\x85\xF8\xD5\xB6\xD9k~\xDF\x15+\xAB}\xA0\x0C/\x1B\xB5\xC4(\x9D9X\xD3\xA9\xB7vG\xAB\xC5\xED&\x19\x00\xC4b\x1C\x949\xF5`;\xC9\x13\x95-\xD03'\xDE\xF3\xAE\x04uV\x03\x02L\x8D\x00\xC8\x85\xD6h\xBF\x01YJ\x02\x92\x85\x9A\x19`\x84\xF4 \x0A3\x06\x96m\xB3\xEED\x8D\x03\x95\x0B\x8C\x0C\xF2!3 o\x05\x81S\xC3`\x93\x86sv\x9D\xA3\xCC\x1D\xE6\x16\x0Bo\x8DE\xF8\xD2\xB3\x92\xC3;,\xAD2+o8\x86,\x96\xB3o\x92]\x0B\x17x|u\x0F\x98\x14\x10%p\x96\x8A\x19\xB7\xEC\x0BaJ\xDEq\x89\xA2g}\x1F*s\\xE5\xC8)\xF5\xCB\xF3\x85\xC9 \xCD\x96\xEC6\xF45\x87n\xF1\x98\xCA\\xD6\xCD\x1A\xB2w\xB7\xC6\xFBc`\x97\xC6Y}\xBA\xF7i5va\xBF\x06)v7\xD8\xE8\x01\xB0%\xFE\x99\xA4\xD1\xAF\xB1C\x91\xD9%\xD7\xD3\x90jf\xF8\xE4\xDC\xCB\xED\xD5K\x8F\x16x\x8D\xE36{}\xF8r+\x16sL\xFC:\xC7\xAB\xF5\xBC3W\xD6\x15\xA0\xF5\x90\xA9\xCA`A\xA0+\xF2B\x8F\x0D?\xB1j\xA7v\xA8_\x9A]\x0F#!EI\x8F\xB78\xDF\xC2*\xAC\xF0\xD5\x89\x92\x9E\xA1*1 \xB8\x0F\xFD \x03\xE7\x9A"\\xF7\x0E\xBC\xE5\xAE\xB5z\x84\xD1\xF1\x82z\xE0\xE2\xC9\xD2\xCED\xD0a\xDE.a\x01\xE9\xDF\x03\x91\x7FY\x17_\xD7\xA2\x1A:\xC9w!\xD8\xD7\xC5{m\xCA\xA8\xCA\x90A<\x18\x98\x98\xA20\x8E\x9A\x87.\xAC\xF7;\xE0\xF1\xD4\x13\xD1A\x12\xB5z\xE9\x10\xF6S7\x93/\xBEb\xC4\x85\xE0\x93\xC6\xD9+N\xBD/e\x91\x9C\xD5\x0A\x81\xA1\x07\xED\x9E\x9A"\xAB\x0DX\x86Uw\x02\xFD\xE6X\x0B\xCE\xC5\xEB\xB7a\xB6v\x96`\x1D\x02\xA0\x05\x83\x0D\x9C\x83\xB9/\xA3\xE0\xCE\xD8\xAB%\xF0\xE6i\xBF\7\x05\x0Ag\xDF\x8E\xF4\xD1\xD9\x0F\xDD\xE6\x93\xE2\x88\x1F\xA5v\xA9vT\xEB\x03\x96N\x85\x86N\xFA\xCF`\xC3}CR\xAC\xA8B\xD1\xD9\xA3Xn5\x0D1\xDF\x1E\xC3\xC4\xD4\xA9\x8CD\x1F]\x0B\xE7\x01\xC3\xB2oI\xEB^|3\xC24\x1F\x02\xD7\x1Ed\xE8\x99E\xD25y(|s\xADX\x13r\xEF \xD8c<\xF16rGR\x09\x8F\xFE5E\xF3\xA6\xE8i>g\x9D\xFE!\x95\x03|n3o\xD3f\xF0^\xDF\xC7\xD7\xB0HG#Vi\x0BQ\x8C(Y\xEE%d\xA75ha+\xE9\xC2\x03"|<\x90a\x86\xF6\x8B\x85!\x8A{Z\xC2,\xBF\x14!T\x0Eg\x12\xC1\x93\xD2\xF5\xE1\x9D&T\x156\xE6C\xD7m\xDE \x02\xEB,\xD7\x9F\xDA\xE5\xD39Om\xBBE\x94U\xB2\xB1\xF9+\x86\xCA\xC5_6j\x9C'\xA9U\x1E\xE0s\xFB\x16\x93<\x9E#\x1E\xE4(\x04N\xB1q*9[\x9E\xDD0\xFC\x8F\xE2\x94\x95\xBA\xA3\x0F\x8D\xB2n\xAE\x02\x93\xA5\xEEU\xC6JU\xB50\xED\x16\xCB\xD0\x92(p\xE7K\xD4\x13\x04q\xC0\xD5\x83\x19\xBD0B\xBB\xE4\xD3\xAD4\x04\x99\x16\xF4\xEC\xAA\x9A\xBC\x8Fp\x90e\xB3\x80O\x91\xF3v\xF5\xE3\xB3\xD0\xA3\xB3\x0C\x11\x0Bu\xD0(\x87\xE4b\xE7\x82\xFD\x18\xB00F\xB8\xA8~\x8E\xA8\x87\x02\xC3\xDA\xCE\xA9\x1C\x82V5\x89\xF1B6\xA2\x1FR\x15\xDC\xB0\xE3\xD5\xF2qDW\x05)\x13{\xCC,\xCC\xB29\xD9\xD1!\xF5\xB9`\xA3\x98]\xD20]\xDF\xFB\xD9\xC3\x07\xF4E\x98W\x98\xE4\x99\x03}\4!_\xDF\x0C\xE6\xBED\xBBp\x82\xE8?\xBA\xE5\x05S\xCA\x8A7Ha\x83\x00c#\xE38Bs\xF3L\xAD\xD9n\x1D\x9CT\xF9\x8C\xAD\x1C_W\xC2\xF0\xA7\xEFD\xE7d>\x9B\x13T\xEE\xFF*]\xB7h\xBDu8s#\xEBj\x0C\x99\xB6\x93\x81?2X\xCB\x02;\x1B\x88w?\xA6\xF1]\xF5\xBB\xCB\x92\x87\x82\x14\xE2\xA8\x8C\x95\x9B3&\xC4\x1C\xF0\xE5\xDF\xE0\xB1>\xE425"\x875\xCCP\x03\x05\xAE\xC1Y\xF0\xABIt\xCC.2wU\xCAC\xEF"\x0B\xE1\xE5\xD8\xD5\xBA\xFD\xBCj\xCA@\xE3_D\x8F\xFFm\xBE\xF0\xBC\xBD\x08[\x13\x83ZQ\xD1D\xC0\xFB\xBC\xE8\xF1\xA1\xEAMn\xEC\x1E\x063\xC3(l\x86\xD62\x99y\x0A\x98\x07\xD7\xBEI\x7Fw\xADB\xF5\x19\x1B\xCFOu\x9A\xAE\xB0\xDF\xE8\xF00\xB4\xB7\xC2\xE6\x9E\x1D?\xBDG\xD6YND8\xDF\xE8s\xED&\x06\xD3\xC8$\xE3\xA4HM\xAD[\x0EN\xCF\\xD5\x00\xF8\xD6,\\x84\x1E\xB7\xF5SO\x87\x90\xAA\x0E\xC2+\x02\x9A<\x95\x15p\x97\x09\xCAS\xDD\xCC\x0F(j\x94\x8Av\xD2Ew\\xC3,\xE4\xB3\x0Ch\x9B\x0C\xB6e\x02\xBC\xF57\xCE\xDCi\x9Byq\xB9\x07\xD2\xBA\xD9\xAE\x96]^8`\xA9D\x10\xD5)ON\xF5\xCE\xA4\xD6\xFC\xF08\xA9\xAE\x8F\x11Z\x91\xE3k\xB5%\xB7\x17pBW'\xFD`\;T\xA51y*\xDD\xBE:D\xEDg\x8C^-h\xD86jc\x9FQdz-\xA51n\x06\x07\x0E\xA5\xD8q\xA26\xD9\x92\x9E\xE8~^\xD25;\x0B\xF6\xB0{\x876\x0EdU\xA7h\xBA\xD6\x9EZ\xD7\x9E M\x03\x9A\xC0!`\x0D}\x13F6\xB9\xEF\xD4\x14BA\xAB\xA0Vv\xB0\xFF\x9C\xBEo\xA7\x17\xDC\xFC\x1F\x92H\xD7w\x8E\xF3$\xE0<\x9D\xBE\x03QE\xAC\x17\x1B\x10\x8C@\xB6?\xDA\xAD\xFD@\x91\x82\xF6q\xD9D2r!\xC3\xEE\x9E\xE1q\xC5b\xE6<\xC1\xE6X{\xB9&6\xC9|1\x1E\xC4#\x07z\x9A\xF3nY\x83\x0A\xC3\xE5\xA2\x81)s:\x7F\x09\x12\xFC\xBB\xDD4\x17q\x937K\x9A\xE6\x1D&\x88\x0C\x177g\xD5hy \x0B\xDA\xDF\xE7\x09]CO\x0Fh\xB6\x06\xC7\xDF\xE6\xDD\xFA\x10`\xFB-Z?%+kT\x17\xC3vii\xB2\xE9\xE6I\xD7E8R!eB\xF3\x06\xBD\xCEB\xA9\xB3\xD4m\xBA\xBE\x9B\x02\x9F\x0B\x91\xAAt\xFA\xC6\x00Q\xB1\x9B\xCC\xA0u\x07\xB9[Y.\x83(tpL\x92\x0C$\x80\xF9\x14\x10k9\xA1l\x1A\x12\xED\xD2\xF3\xFD\x06\xFB\xDD\xAE\\x12i?\xE6f/\x14o\x0F\xAA\x81u\xC1\xE5\xC7\x8Er\x8F\xF8j\xD6\xBE\x86KH4\x0Cn\x8D\x83\x03\x0B\xEEA\\x85-\x8E\xB0^\x85.\xDB?3*A>\xE3\x97\xCE\xB7\x0B\xCD\xA0\x96\x18\x84\x8D\xA3\xA9\x14\xAA\xB9\xB3*\xE9\x01_Q\xCC\xB4Fk\xAD0\xFD\xBC\x17\x9E\xA4e\x01p\xC6c\x95R8l[\x13\x87\x0A\xCA@\xE1H\xC5\xF9\x09W\xE6(w\xF7\x85\x00[\xA0\xB9\x09\x84\x87\xB2\x8C\xBB~\xCF\x8A{\x90\x96c \xD0{\x9D\xC9\x02\xA8bU\xC6\x854\x0E\xD5j\xDB\xCAD\x05?\xD2"\xCD\x9Aik\xA1J\x82\xF2\x84\xE8\xE5\xBB\x91s\x95\xAF\x97\x03\xB7rY\x99\x0B\xA6\x98\xE2g[y\xE5\xEB\xD2\xCD;7\x99\x09"\xB5\xF5w,@\x9D\xE2\x89\xD3\x16\x19\xF8y\xFFB\xD9\xBB\xA3)\xA9\x14\xA9\x99\x02R\xC1\x96\xA5\xE1\xDE<\xAAQ6\xEBo\xE2\x87&G\x99!\xEC0\x95}\xC7\xBC\x0C\x8A\x95\xBBu$\xBA\x84Rx\xC8";\x8F\x11\xF8\x86\x85]#\xED\xC6!=3_\x94\xEF\xD1}\x1C\xCC\xF1\xE8\x0E\x11\xBC\xE8\x80\xB9@2\xE6\x8F9\xF7\xB7+\xA2\x9C}o\xE0!\xAD\x9De?^LB\xD1-\xD8\xD8\x8D\x1E\x9F?\xC76\xD6=\xA7\xE2\xDDT\x1Ff\xE4JY$\xAE^\xDD%\xBC<$\x0C\xB4\x07r\x85u.\xF7\x81\xC8\xE9\x81mt\x91\x9B\x90\x945\xEA\xBD\xC8\xCF\x94>\xED\xBE!\xF3\x95m\xAD\xD8eiN\xF4x\xF2\x03>\xE4o\xF8\x99\x0D\x92\xB0\xD8K\xB3\xEA\xBD\xFF\x82\xE88po\xB1\x19EF\xDF\x05\xF4:\xF07}\Q\x0B\xC1]\xD2\xFF\x83\x1D:\x841#\x8B\xFE\xB8&\xF1\xB7-(\x19J\x90.\x07\xC3\xC8\x92:\x9Ec\x90\xF8\xBD\x1F\xF0o\xB3\x9A\xA1\x1A\xE3\x87\xF6_\xD6\xA3i\xE3gO\xED\xC3p[\xB8\x7F\xCD\x9C\xD0\xB7\xD5\xCEb\x9E\x0E3\xBF+\x86y\xB4\xE7\x90$\xA9\xBF\xC1us\x83v\xB4\xE1\x9C\x920@\xB6\xD2\x01\xF41\xAE\xA4-\x077%97h.=\xD9#\xF0\xFF\xF9\x12h\x81\xD1\xDAp\xE9(\xAC\xBD\x1D\x14D\xD9B\x8F\x8A\x91\xB4\xA0(\x92\xEC\x9B*',E\x9Ei\x97\xC8\x81\xB8\x92\xFD\xE5H\x1CB\Ud\xAD\xFF\xDE?-\xAA\x83\x19\xB4\xBF\x0A\xA3+\x93\xB9\xC3\xA9\x11!\xC2\xD2\xA9'%t\xB98\x08\xDF^m3\xD7\xEA\x19\xF13=.\xE11:\x93Kic\x9Cp\x88\x00=\xB7^\xE9y\x01\x16&\xEE\xC3\x8F? \x97\x07^kv\x9Bl\x88\x07Je$\xB5\xB4Jl2\x93\xB2\xF8\x10\x8AZ\xF9\x17\xED(L\xD1\x9A6\xAC\xF8\xA0\x0B\x07\xF0\xDD\x1BN$Bi+\x19C\xBB*\x94\xEE\xDC\x1E\x9B\xA3\xD2\xF3l\xF0\xB1\xEA\xCF\xE3\xD6\xF3\x1E\x8B\xDD\xF6\xB4\x8F/~\x9F;\xD7\x08v\xAE@\xBA4\x8A\xB6\x91q\x80\xEC8\x15\xA9\xA1\x91\xFF\x05\x0E\xFB\xBE\xBB\x1F\x92\xD9W\x91\xDB\xF5\xDB\xA0\x8F\xB9%Fc\xDF\xD1\xCE\xC8n\xE6#\x9DB\xCA\xF2\xC1\x92L\xFBn\x9C\x100\x0B\x06\x03\xFFm\x0D\x09\xEE\x8A\xBB\x871R49\xC3K\xEAe\xF1{`\x0E\xD5,\xD1rM\x1B:\x1D\xD6\xE5\x9C\xAA\xEF\xFE\x99+Y5\x08\xF3W\x16\xE1c>8\xC7<\xA71@\xEB\x169\x0AV*s\x1A\xCEWx1*\x7F\x9D\x91\xA9\xF6\xC0z\x94\x97%i\xEC\x81\xC1\xD2\x1C\x89\x9DU\xEF\x9B\x82W\x03\x1F\x0D\x90\x03ZoN]]\x1F\xB1\x8A\xB0\xD1\xA7\xBEQV~\x0B\x1A\xACr\xEF9\xA7\x03\xDA\xC5V/\xCB9"\x1E\x86\x9EI\x8C\xDF3\x99\x10y\xEB\xFF\x17\x94\x17f\xE9\xA1@\xD2\xA3\xF0#\xB7\xF8\xC0\xA67\xC7D;\x11i\xF6\xBA\xDB\xF7H\xD2\xE7\xC7\x8F\x1EXR\xCE\x9As\x02g\xE3\xA0H\xBB\xF0:\x9B\xD4\x8A]Fk\xBE\xDC\xB6\x9A\xF6\xCD\xC8 \xB6)\xA3\xA9\x03\xDC\xB6k[\x84\xB9=7\x99\xC7 \x80 \x86\x95\xE82\xC8>S\xAA\xFF+\x97\x18h\x001@\xE7!J\xFF(N\x1A\xFE.\xF2@\xD1\xF9\xE5\x0Da\x15\x8D\x0E\xD4.\x93\xCAC\x8E\x04\x07\x8E\xC6\xA0\x84U&9B+\x8A\x14P0\xDC\xE1\xC1si\xBF_s\x02\xDB\xF5\x97\xC5\xF6\\x970RiR\x03\xCC\xC9S$\x90\xCB<\x04\xB9\xC6\xC9KP\x85=\xE0&\xE6\xD6\x10*y\x80\xB3\xDA\xE97\xF8-c[bm\h\xCBj\xED\x02$\xBE\xFB\bj!\xFFE\xE4\xB3\x88\xCA\xDD\xCF\xCA=gG\xDA\x8A\xBB\x1A\xF6\x929\xD4\x880\xAD\xE3\xC2\xC3\xF4\x1F\xE36:\xDD \xCFc\x11\x91L\x8B\x95e\xDA\xA5~\xDA\x02\xB2\xAFAF\xA9F\xEA\xA7\xC4\x17\xB6\xC5$a9{\x0D\x93\x19{3:y#\x0F\xD6r\x12\xEB\xDA\xB4_\xF0\xBA\xB1\x15@\xAC\x89\xE9\xEEp\x88\x9E"\xA9\x9Ft\x10\x15\xF7\xE2A\x84\xCD7\xD2\x8E\xC84\xAA\xE6\x8C\x86\xFF\xB4\x8D\xB9Y\xC8\xA4E\x91\xA3\xDB\xAF\x1B%8\x84\x1F\xD0\xDDW\xB8\xC9\x9E\xCA\x0F\xD6s\xD8\x1C\xCB\xA7\xD2\xA3}p\x8F\xF7\xDF>\xE9\x91\xAB\xC2r#\xB7\x8C?\x11'\x80Q\x8Ao\x01\x82.a//h\x0B\xEE5\xE0\xA0\xCBpH\xE1\x9F2\xE5iGrK\xEB\x09\x19\xFBF\xA9,\x14\xCC\x90\x85~s\xF1'*?q\xE9\x0C``\xD9\xE4Z\xD1\x15\xC1q\xE6\x15\xD0(}\x982\x03\xB79c\x02\xE7\xAA\xEEV_a\x98C\xE2\xAD\xE3\xF7\xC8]\xF9\xC6#\x91(n\x0F<$\x9F\x9D#\x0D\x9E\x1A\x1B\x01\xA0(\xB2\x8A`S\xEC\x9AU\x16\x9C\xA3\x16\xEFq\xD9;\xAA1\xC1,\xA7\xA4\xE5\xDD\x82V\xA0A\xD9s\lx\x92\xD4*\\xDE\x8C\xAA\x88\x85\xAE\xF7\x92\x7F\xB4\x88\xBB\xA7$G\x87+\x04\x1E'\xEC\x04R\x0D\xE6(\xE2\x7F\xD6J <\xB4\x8Ch\xD6\xE4A$\xC8Lg"sk \x98\xFC\xD2\xA5\x01\xEC6\xDE\xB0daP\xBC\xEC\x08\xAE\xA8k\x84\x86RB^-kv\xB2\xA3\x09/q\x95&E\x9E\x91\xF7\x16)(\x80\x9F\xC1O\xD9\xEF0\xD7K\x92\x01b\x172\xD0\xA8;\xD9\xA2\xE8\x00\x14\xEE\xE9\xF3\x19<+~L\xED\x8D\xF0\x14\xBD\x18y\xBD^1\xE5\x11M\xFE\xF6\xB0\xF3\xAB1\x01\x80\x04\xFE\x88,?(\x1E\x81I9\x1C\x0F\xCB-,#\xD3\x82\x10H(\x93{\x99\xE5Z\xEA\x8CiLP\xC2\x1B\xC0\xB7p\xDDjs\xB2q-t3\xD9\x89\xE6j\x17\x11\xA4\xF4\x1Df\x15\x9D\xE2\x13\xB3+\xD0\xF9\xFE\xEEm\xD8\x0F\xED\x87\xD1'\xA0Az)a\xEC\x9DR\x91|\xFC\xBBz\xB9\xF2Z\xD4\xE1(\x00|2\xDC\x98\xDERA\xC4\xC6\xAA\xB5\xBF\x8F\x12\x9Ds\xD9\x7F6\x17H\x93}\x9A\xCB\xA0\xD3y\x94\xC8\x86m&y\xF1}S*\xD4M*\x95\xEA\xB4\xF6\x1E\x9Co\x80\xF5\x85\xEFs\xA8H\x0A\x90\xEF\xD6\xD5\xED+l\xB6@\x80\x8D`\xE07\x8C\xE5o1D\xF2\x04\xB5y\x9C\xD5\x89G%\xFB\xE8\xB6\xD8\x14\xFD\x0B\x84^\x11\x1F>N\x82k\xC9\x1E\xA5\x89\x0BP\xED\x19[\xFF?\xF6^|\x9E2\x1E\xE4\xC0\xA9UGC&\xD1T#V\x8B\xD0\xB2\xF4\x945$5\x02(\xC4uBj2\xF7\x7FT\x9D\\xCD\xC3\x8F\xD6\xD6\xC1x\xB2\xBB\x81\x03\xC2\xC7gj\xBCp\xAF\xEC\xB9QN\x9D\xEB\xF1\x03\x1B\xE0\xA9"\xF6\xED<|\x0C\x125\xE8/ks\xFB\xA4NA\x83\x86\x1C`\xA1\x0CIEwp\xA9#\x8Fn\xCA\xED\xC8\xF8\xDC\x0AK\xF2\x03N\x14\x8D\x92\xE2/\xD8\x07\xEA\xA1\xDE\xCE>!H>j)\xE2,\x8Am\xD0\xCF?\x0F\x8E7\xE8'\xD1d\x83\xD2\xE5\x96!\xA7r\x07\xD9"\xF1Z3\x0C\x01L\x16BJ/J\x0A\xE4\x89\xF7\xFB\x10\xE3\x1Bs\x1B\x899.[p\xFE\x95\xBCv\xC7\xA5)1A\x1D\xE1H\xDE\x89V\xC5|\x14\xF1\x81Q\xBC\xCA\x9F\xFD\xF3\xCA\x85Y\x0E\xC1\x15~@\x0Ex\x94\xFBbW\xB9S@\x17\x1FY\xBBc\xAC\x89\xE4\x89\xEE\x1C\xD3\x8B|'7\xAC\xD0\xA1d\x1FU,\xC7\xC0\xC0\xA6\x86\x9C\xC5\xA9\x81cvL\xA4v\\x90x\xDFQ\x92WW\x9A\xDE\xF6s\x0F\xDC\x83.p#\x09\xC7\xF3\xEBkc\xDF\x1A\xE0\xA3H\x09\xD7}\x7F"\x8D\x89c\xD1\x8A\xDA\xEB,\xE7*\x8B\x01\x88\xF8l\x06\xE1\xA9urX7X\xFAe\xD9;\x12\xBA+\xFE\x87\xFB\x96\xF0\xF7\xBE\xC3\x1A\xA7\xB1\xEC>DU\xE5\x1Co\xC7e\xB6t\xC4\x86\xD2\x99\x08\x0F\xBB\xAB\xB1\xD97\xA1n\xC5(El\xA2d\xF1kt$pA\x08\x06#\xA3z\xC8\x80D\x13\xC6?"yv\xD0\x84\xC0y\x01\x0A\x9E\x1Fb&\xAA\x1B\x9E*T\xBF\xA7\x83\xDB\xE6U\xB7\xE3\xE0\xC8\xBA\xDF\xFFm\xC4d\xE05\xBC\xC7\x89\xD9\xE9DL:\xC2&$\\xA1\xFF\x940/\x8E+\xBC'%\xD8\x032\xA8\x1Dx\x9C\xDB\xB0`-k\x1F\xB2\xC5\x0F\x0Ed.\xC1zu*\xE0\xACO\x0B\xE5um\xFC=\xB0\xDD\x039\x14jd\xFEa\xC9#*j\xF6?w"\x19\xC0b\xA9\x9D\xCFY\x146\xDA\xA6\x1D\x97\xCF\x80\x09\xF8,M\xAA>\x1A\x9D\xB2\x10\xDA/\x88N\xAC\x1D.\xBF\xF6\xBAS\x10.B]\xFD\xE0L\xAD\xFE\x8E\xB0\xA8z\xF0\xF5\xFCew\x81'D5i\x0F\xCAVu:\x00\xF8)\xAF\xFFO\xCB\x1C\xB4\xC28cT\xFBA\xF93-\xF0\xF9\x9Bb5\x852\xF4\x07\x87\xDA\x95\x072sF\x18\x05S\xD5Mkz\x00\x01\xB3U\xCFM\x8AI\x06\xB6\xE6\x0EV\xCCZ\xD0\xC4\x87\xEE\x1D1}e\xD4t\x923\xB5\x05\xAFf\xAE\xB0}\xC2\xBF\xB8\x92\x8Bx\xC1\x8D\xD8\xD5\xF3[r\xAC\xF1\xA52\xF9\xE6O\x09\xCE\xD7U+\xF3\xA5X\xAF(?\x1F\xEC\x11\x8D\xE1U\xE6\xFCP=\xB7B]ct\x99`\xBA\x02\x1B|\xB4PxYr\xAA\xAA\xD9\xEB\x88H\xC1> dq\xE0\x80\x9E)T?M%\x03\x89\xA2\xFE\xDE<\xF7\xA0\xE4{\xC8D\xA3G"PC\x92\xE2\x9B\xFCu\x82\xE4K\xEF\x1E\x0C\xB0&\x1D\x01\xEC\xA2\xDCUj \x8A\xBCy\x16\xDD3\xEAT\xF0\xAD\xE4\x97\xE3-\x1D\x88=:W\x12\x12I\xB9\x08MF\xFF\x86\x02\x01\x1Fw\xAB\x186\x97-\x9F\x8A\x184\xC3\x7F\xF9\xFA\xFA\xCA\xB7C\x85\xEC\x14\x0F**j\xAA\xD6\xDE\xCA\x8D\xFB2\x06\xB2\x0CC\xBD\x1C;W\x83t\xBA\xCA\xAF\xAC\xC0\xE3$\xF2\x00\x94\x0CZ0\x94\x0F\xA2*p\xA9\x8E%\xCC\x08D\xEF\xAE\xB8\xCB)=o\xEB[\xFC\xE8\x81UyP\xA2\x0B\xFB)\xF15\xDA\xA3p\xF3`\xE7\xF9\x85\x88z\xCC\xF2\xE5\xE2\xF9\xE7\xB7-\x8A\xFEU\xB5\x00\xBEU\x8F\x19\x9Fuy\xDFc\xB3\xAEQ\xCB\x9F\xC7\x1E\xBE\xF71_\xAE=\x07\xF3\xF3Xf\x91\x86\x94\xC3<#pL\x84\x1Bx3\xF7\xAA,\xDB&7\xDE\x0F7\x05\x1F\xCB\x15\xC4o;\xCEKFE\xD62\x7F-\x13?y\x1B\xA7\x9C\x1D\x9DU.#\x8EQr\x15\x1DC/\xF8a/m\x15H\x7F\x86\xB9\xF9\x0EC_Tc\x82R\x9B/\x9C\xA3xR\xD9\xCD\xCC\xB8\x1A\xFF\x07\xA4\xB6\xEE\x1C}\xB32\xA1|y\x81\x84\xC0\xB2\x81\xCD\xD6\xB1\x93(OW\xEC\x05\xBD,0s5\xD8\x9B\xD9%|b\x87\xE5\xC6\xA7\xEE\xFB\x12~\xD6\xA7]\xB6^\x0A\xF6\x06`\x09I\xFF\x92\x88)\xAA\xBA\xDE\x87\xAD\xCFk\xF5)\xBC\x08-\xBF$\x07O%?\xB8\xE3\xD3\x0A*d)q\xE0\x0D\x84\x9CJ!h\x10\xF1H:\xB1\xF0\xCD\x0B`O\x80\xA4,\xEC\xF3\x02+\x09\x8C2.R\xD4\xAF@\xC90K~,\x1F\xF0;I\x06\x103\x0D\x93El\xEE\x12\xE7\x1C\xC9\x1002M70\xABGs\xFFZ\x91\xB4\xC5\xB32\x8E\x98\xD5\xAD\xBCz\x00y\x1F\x98\xDEw+F\x80\x9F\xA7rf\xA0\x86,\xD0\x02T\xFB$\x0B\x90\x8A\xDE`\xA9\x16\x18#C\xD6\xA8\x95\xD4\xC5V\x9BoE\xDA\xA9x\xA7,N&,j\xE9\xF3\x84#FQ4\xD7\x0D\xA8\x82RKF\xB7\x93\xB0\x04+\xE4\xA3u04\xAB\x98\xAAK\xEA\x92v;\x0D\x96L6)\xCC\x81\xBB\xC5\xCD\xC09\xA0c\xFB\xB2B\x83\x90T\xD1Z\xA1\x8A\x8Fe\x19\xB8\xD2a\xB2[\xAE\xCA\xE4\xEA\xF9\xFB\xC7\xA6I\xCBL!SSZ\xAE\xF5_\xB5'\x8B\x96\x10r\x8F\xF6i&+\x89\xBE\xF9\x80m\x81\x85^4\xC3\x87\xEF\xCB_h\xF6\xE4\xD3\xAC\xA9\x06@\xE5\xAB\x92\x17\xF8>\x87\xF9\xEF\xEBC\x89\xA7uh\xE5\x8A\x92V\x09W\x14\xAB\xC0\xE9\xD1\xA8\x869iZ|\xED\xE6q\xD5\x89E\x8C\xC4\x09\xB1k\x91[\x1A]\xBBk\xF1\xC8\xAC\xF8OL?\x042\x8D\xBDsH\x9D~$\xA1\xB6\x11\x91\xB3;\xB0\xB1r\x17c\x0B\x1E\xA6\xB0\x00x\x0B\xC5\\xD9\x9F\xC3\xDF\x188\xC8#\xB7s\x95\xF5\xC7\x87\x0F\xB80sV2\xA9g\x8A\xBC\xE4\xA9U\xD2\x1AE\xEC]\x99\x833;\x1B2\xA2\x94,\xF3?\x15\xF6\xC2\xEB\xFF\x05\x93\x19\xF1\xA7t\x82\xA8\x13\xCC\x12\x88\xC1\x8A\xEEx\^p\xB5\xE3$\x8DV\x9F>\x01\x8F\x01\x9FQ\x08\xA0\xAE\x0C\x0E\x0F\xF5$\xA4\x17RI\xC0\xC9)\x16\x06R\xD8\xC1k\xAEiD\xAA\x0D3[\x1Ao\x1E1{\x14M\x81\xB9X4\xF8]\x9FW\xFC\xE0\x82\xC2\xC6B\x8F#\xAF\xD8\xCE\xE7\xA3p\xF8#\xC2.\xFAQ\xE1L\x96\xB9\\x98NY\xD5\xF2\x1D\xD3\xF3\xC3\xB12q8\x8B\xD4\x88|)C\xDC[\xE6\xA7\x9B\xB6\x12kXd\x01\xE4\x96\xD2\x92\xFC\xA0\x0DI\xAA\x8B\xCD\x0FP*e\xA3J%\xFF\xB7Z\x8E\xE8\xDEt\x9AqX\x9EcJS\xD1\x84\xB1\x15\x0F\x10\xE4\x9E\xD6\xA0\xF1\xC9rn\x89\x95\xA8\x91(\x08\x17hV\xEEL\x09\x0F#\xD6\x08\xB2.\x9C\xD0\x05\xA1\x10\xB3\xE7\xDC\x99Nf\xFE\xCF\xDB%\x08]\xB9D\xBB\x88\x1Cq\xA7\xFA\xD6\xC8\xFE4|\x07X\x05A\xE7P\x96\xC1\xEF\x84\xC2mHE\xA4\xED\x02\x02;FD\x08W\xD1{\x9F]u\xD0(hS\xB6;\x94\xB2\xC2\x13!`\xF5_\x00\x08B$.\x02\x94p";37~[\xFA\xEE\x86\xDD.\x12\xCA\xE0\x82fG\xE4\x14,DZ9\xF8H1W\x9Ax5&\xA18\x0Bl'^\xE5d\xB1\xE5J\xD1\xE5T\xE0%\x0A\xD5\xF9\xA2\xB4\x1B\x8B\xCF\x1DL\xF9Y\x96\xF5\xDA\x92\xCB\xB0/D\xC8\x18\xD8\x0B\x8B\x83\x7F\\xF9d\xE0T}{\xD5{\x16\x13n\x19b\xF8f*}\xE8\x9F\x9C\x85$~\xCD\xA1@"\x93\x1FQ\xA3\x08_K\x10\x85\xBBa\xAB\x8F\x92\xFB\x91\xAE\x9D\x0F\xB0\xD3\xA8\xA0\xA05K|\xC1\xADK\xD75u\x97\x82\x108Y\xB0^\x01\xE0\x87p5\xBBr\xE8\x8Ek\xCB\x1E\xCC\xE3\x83\xFA\xAB\xFEgW\xFC\xF3\x9BW\xEF \xFC\x9E\xB3\xDC\xC5\x11`\xAFG\x07\x88\xF9\x98+@\xAA\x91W\x19\xF0\xE8\xA4!ag\xD4\x8B\xDC\xA9\x19\x92l\xCE@w\x15JC\xFF\x0EeK\x1F\x08\x18\xD4\xA4\xFD\xB8\xF0\xDE\x02\xC2\x9A\xC3\x9Db\xF0\x03\xDBf\x1Br.\xC3\x01\xC2\xE1Y\xEA\xF2\x88\xAE_KwyY\xF0K]\x8E\xE9B\x17\x9F\xEB\xBE\xD2=\xB6\xD9\xC1h\x9E\xA1\xF9\xBB\xACS\x13]\xBA\xC9-\xDF\xA2*\xCD\xB6\x19@D\xF4\x1CNQ&\xB73zm&U\xC1\x12\x13\x02\x93\x13\xE32\x08t&&\xE8\xD3f\xD9\x9Fm\x92\xCB\xD1\xBFG\xB5S.\xA5R\xAD \xD5\xDFa\xDB\xD7\x11o\x8B:x\x80\xB9\x14\x12/\x95\xF9\x8FA\x81\xD5\x9E\x0C\xBC\xC3|g\x0F|\xD1*\x8C\xFA\x9E\xC4\x0E\\x94\xF8\xC4\xCB\xD4\x8CN\x07\xAA\x80\xEFg+\$\x97\xB2\xB2\x01v\x9C\xF5\x8F\x0FN\x84m\x84\xCB\xAD\xE3i\xD5\x01=\xE2)\xE9o,*\xF87\xCE\xE2\xD9\x12\xFB\xC0]U6\x81\x11\xC5~\xC9\x16\x15\xD94S\xFD<\x1F\xB1\x17\x8F\x0D\xAF\xC4\x1BvN-5\xBB\x1B\xD2<\xC8\xB7ua\x8C\xD3\x89(%\x93\x86\x97\xBAz\xE8`D}\xCD\xEBK\xD8\xE0j\x92j\xC8\\x12\x80Q\xA2\x8E\xBFK^\x92\x83\x97\xE4\xAA\x16\xF2\xCA\xD3\xE8\xAD\xFD\x1A:\xCB!a\x91\xA5=*\x82^\xCD\x159\xA5f\x18\x1D/*\\x93\x88\x06\x86\xD3\x07\xCE\x09\x1F\xD4!\xF94W\x1C\x03\i"\x0B\xCA\xB6qJs\xD5\x872\x86\xB0\x94%iPOGI\xE8hxjjj?aMb\x96\x01\x12\xDD\xA8\xB6\xF5\xEE\x07\xCC\xFB\x07\xEA2\x9C\xAF\x1F\xFA\xF18b\x0D\xB3\x8ATB\xF7"\xCC\x94\x84\xF5\xB5U\x8A?\x96\xCC\x7F\xE9\xF9\x17)?\x14b&\x1C\xEE4\x7F\xF7\xB0#\xF6]a\xF6c\x98\x86\xD4\xEE=\xB0\xC8=\xD1\x10\x016h\x9Ey\xCDP\xC6\xEDsJ+<\xAB!\xEC\xE6\x7F]y\xAD?\xE3\xD6\xB0\xC6\xF6\x08\xCA\x83\xD2s\xAA\xAD\x91\xCA\xC7\x9C\xB4\xDD\xEF\xF0t\xE2py26\x81U}\x0A\xB4\xF3\xDE*\xB2[\xCC\xF5\xFA$\x1C\xC3\x00F\x11&D)\x08wv'\x1D\x14M\xD3\xFC\x93\xF4\xCFq\x95\x1A\xC3\q\xD5O\xD9\xE00dv%.=\x8C\xAC\xA1\xAE\x0BwH\x08\x146\x0E\x0F\xB9j\xB3!\x9D0\xA4\xAF\xE2\xA2\x18Xz\xE9G5Fc\xEF&\xB1-[\xC7\xC1\x05\xBA\xD7\xA3\xB1/\xB1\x8B\x08\xC9\xC61\x05\x05\x9Eo5\x17\xD2\xFFb\xC5\x8B\xDAk\xC4f\x96\xCBY\x06'\x0B\x910F`\xB5\xF2C\x1D\x92\xA1\xA6\xD1pS\xCF\xA8\xB6\xC0\x9CQJ\xEB6\xD0\xB0\x8FN\x7F\xEB\xAE\xDB\xB9\xF9\xCEl\x14F\xD6\x97=\x05\xC6\xAFfy&\x02\xFB\xE2\x01\x93\xF2\xD5\xA3\xF3H\x8C\xCB\xD3\x94\x09\x05g\x01\x8B\x15H\x13\x16\xD6Ra\x8B5\x8D)=}\x1D4[\xCF\x043\xD8c\xAF,\xE3\xAB\xAD*\xEF\xEFp\x1B[~"\x95\xA1t\xC3ch\x0D\xA7\x94\xE5r\xD3\xDD\x8D\xDC\x037\x14\x0A\x99\xFBf\x06\xFF\xB4\xFF\xE8k\x03$j\xDCF7:3\x85\xB3\xE9\x1C\xB5u>\x81\x81\x85\xA3n\xD4R\xE1\xCB\xD7\xEE\xBE\xFBz\xFDp\xAE\xF6w\xFFO\xC7R\xE9[\xEB\xDF~$\xAE\xE84=2\xE5\xB2\xEC\x14\xE5\xAF\x93\x06\x08\xA1 \x18\x90\x85\xE8\xF9\x05\x0C\xE9-\xC7\xF3\x9B\x1C\xD5\xAB\xD13\xA0\x80\xDE\x06\xF5\x0E\xE3\xB8\xF6D1r\x16\xAB\xE9\xFD\x1A\xD16R\xEE\x19\x89\x80\xB9z#\x85\x97\x86(\x0F#\xE8a\x95\xBE\xF7\x89\xB0\xB0mc*\x05m-\xED\xE3\x8E\xD2\x0D'+\xE4>kcr\xF6\x80%(\x9F+>`}9\xA6e\xA4+|\xCB\xDF\x86\\xB6\x80\x89]\x82x\xF0\xCC\xDE\xD5\xD4JG"\x09'\xD3U\x06U\x84\xDE\x87\xD2Cn2\xCA?h\xE6@-\xA0\xC9y}\xA7Yu\x1A,\x10b\x8E$\x1E:\x196@\x8F\x0F\xDFB\x15\x88\x9E\xD4\xE1A>g\x18\xEA\x0F\x98\x1Bh\xF1\xD4\\xC9\x1B\x93}\xF6\xF5\x0C)\xEB]\xA5g\x85'\xD7u\x01\xF5\xC85\x19\x006\x19\xCB\xDF\x84\xEFlp\xDCE\x17\xEE9\xE1\x91\xF7\xF9(\xB1v\x8F\x8A\x87d\xF1\xB7\xBB\xEA\x9F\x93\x86\xF1\xE8\xAF\xC3\xF8r\xE6<\x85\xA6\xE4\xF0\xE6!\x93Om\xE9o\xD1C\x84Z\xC5\xC8\xFA9?(\xC6\xB9\x9Fu\x90\x9Do\x95\x9E\xD5\xEBS\xEA\xD8\xB7\xB8S?)\x00XS\xF3\x1B$\xFA\xA2\x86\xA5vz\x0EW\xBB%\x97W\x97\x98\xC7\xF3\xA05?\xB4k}\x0C>\xF6\x98\xE0\xDE\xC7\xBA<@\x0A\x81,\x19\xD2B\xCA}\xA9\xD2\xAC\x89\xEF\xC2\xF1\x10\xDA\xA6\xDBr\xCB\x16L Zn\xED\x0D:k\xB4\x04\xA2\x0D\xC8w\x16\xD7\x1F\xEB\xEC\x18\xFB\x08\xEE\xE0\x93m\xD9\xD77\xF9\\xC9\xB4\x9D\x88\x1EfW\x0F\xB6Etwv\xDB6\x7F\xD7\xD7\xF9\x8D6|^\x90?\x9B\x1A\xDFp:\xC4G\x0F\x1B\xDB\x8C\xE6\x8C\xE5\xAA x_\xABb\xA8\xD1NP\xC0\x18\xEE%\x90\x14\xA4 \x1E\x93\xC3H\x06\xA1\x1DB\x1B\x8F\x14B\x13d0C\xE2\x83\x91\xFB\xD3\xAE\xB0\x85\x9E\x08L\x05\x90\xA4\xD2\x17\x9F\x18\x9D\xFAU\x9C\xB8,\x08\x8E\x93\x13\x92\x01\x9BLxo\xE4l\xD3ogla(]\x96NG\xEA\x8A\xC3\xEC\x89e0\x8Cm\x90\xC5\x96\xE6\x1D\x92\xF7\x88\x7F*\x0F|hh\x11\xC80$%0\xC0(%\xD36Z\x9Bz,\xADk\xAD\xA1r\xF0\x9F\x87$\xDB\xAF\xAF\xD3\x02\xD3\xA3-\xEF\xC4\xAF\x00\xB8\x93\x0B\xA6G\xE7\xAB\xB1\x0E\xB07\xC9\xBA\xB7\x89\xE4"\xF9^\x0B8t\xC6w\x10PV3\xFC[\xFC\xB1[''\xA9\xEE\x0D\xCB>h\x9E0KTT\xE4\xF0S\xC4\x11r8-C\xD2P\xDA\xBF\xAB\xC2\x13\xDE\x06$Of0+\xADO\x93\xD7J\x07\xB8k'B\x88\x13\xBF\xF65[3\xB74\xEF\xB7\x9F\xA7\xFCRP$!\x7F=\xA6\xE1>B\xA4\xE9\x07oW\xA5\x16\xA8\xA0\xA0W\xC4\xBEz\xF7G\xB5\x96\x18\xBA\xE2\xD7F\xFF\x97\xF8\xB5\xC7\xC1\x95\x18\x83`\x0A\xA9^Hzb\x0F\xF0\xF0L\x17g\xA6\x05-\xAD\xE6\xF5Z\xA06\xBC\xCF:\x9E\x89B\xF7\xA1\xBFH\x972\xE3\x91\xA5Z\x8B\xE4v\x05\x91\xF0t\x90\x057\x87\x88%\xCD\x97\x7F\xC8W\xE3V\xDC\x8Fx\xBC\xF5\x96.\xFC\x95\x06\xBA?\xD6\x87\xDAU|2\xA2\x92\x80F\xDE\xC0\x91\xE2\xF0\xCE^`\xE8n+\xB6\xC5\xEB\x83\xCA\xA9\x96%\x7FE\xA0H\xCC\x8F\\xB0&5\x8Bs\xD1\xEB\x95\x8EpP\x9A\xF6isNl`\xCDL\xAC\x13\x00V\xE3\x06\xD1\xF8?}\xD5\x8D\xFE\xF8\xA8\x14y_F\xE5*\xD0\xF4\x199&\xA3\xD5\x97[\x9DL\x15\xF5\xC2\xD5\xBFd\x13Z]\xD5~CH7\xE6\xD9\xA6\x10\xF0\x02.^\xE2\x08C\xFD}*W\x1A\xA37\xF3\xC7\x94\xEA&\xA8e\xAFY\x06\x8Eg\x93Y\x0B\x09\x0F\x15\xB5\xBB+\xFB\x1F\x8Eh\x87\xB4b\xC03|@/6\xEF\xDB\xF2\xA6G\xAF{\xB4\x9E\xE7~5\xC5&54\xDA\xD4\xB9\x8E\x03a\x91\x154\xB3\xB4\xDFV`M\xC09\xA0\xD9u\xF4\xA7\xD4y ;\xD9\x877\xC4\xABE\x1Bc[~\x8Ez3)\x89\x0F=}\xE2\xB2\xDC:0\x15\x94\xF0\x06\x9A\x1D_a\x86Zou\xD9~\xB7\xF9\x92':\xDA\xE5\xAA\xF8\x11c5\x0F\xD0/PK\x99nD6.S\x0Aih$k\xF2\x89\xC6\x04\x0C[\xBC\x8A\xB1\x94\x81-\xEF\x00\xCE\xB1\xBB\xE2\xE37\xEELUN+\xF2z,\x0A\xA0\xA1nx\x10=.Xw\xDB\xC1\xDA\x8C\xC4\xE1+/\x90\xCCK\x90\x0B\xF5\xF4\x8Ap\xE8\xF5\x87\xC3\x0C\xABPqBL]\x94s\xC6\x17\xC9\xD9.O\xD7\xAF\xFF\xBE\x8B\xF6\xAD1\xB1-\x80\xA1S,\x7F\xB6\xB0\xF4*\xEB\xE7~\x1F6J\x0C\x13%\xCC\x0C)\xD2\x94\xCE\x93T@,\x81w&\\x11820cbZ"\xE4\xA0\x88\xB9\xD2\xB0Z!\x80I\xBF\xC0\xEE\xEE#\xD77pq\x08R\x8Elw\x88L\xA7\xD2\xAB+\xB4\xD1j\xEF=@\xEC\xEB\x1A\x92\xB5\x8A\x91\xDD\x04\xBFno\x982\xD8\xB6\xA9\x96E\x9F\xCE\x83\xEBX{\xC4\xA6f6\xE3\xA9\x80\xE1"\x83\xD9\xF63,\xB2\xF9\xBAZ\xC05$\xDB\x92\x7F\xFB\xBF\xCD\x00\x97\x87M\xD3\xBF;\x1D\x9A\xAD\x1B\x90-\xB9:son\xD6\xDF=\xFDs\xE7\x8B6Z6U\xB8q\xD6\xD9D\xB6\x18\xAFc\xE05\x0E\x1C\x0E\xE6\x01\xE8\xD5\x0C\x99\xAB%\x80\x93\x97\xB1<\xFC>\xF7!\xF3\xE0V0\x0D\xCB \xDB'*\xA8r\xBF(xp69\x1C\x7F\xEA\x1D\x02\x9F\x81\x0D`Q\xBEs\xEE\xF59\x19\x00\xAD\x04s\xAB3\xADC_\x0A\xF7k\xAD\xB1\xFC\x0E\x9F9\xE9;\xBB@&\xD7\xDB\xF1\xA8\xF2~\xBD3\x1C\x11wS\x03RB?\x10m\xFB\xA5\xA3\xCE\x89w\x18\xA0\x1A{?,f\x86\xE4\x1B\xB4\xA2:\xE3\x0E\xBF7\x0F\xF2aJ\x14z\x0E\xA9\x86\xE8\x112\xCA\x8D+\xE1G\xED[\xAA\xF0\xC07\x12\x0C\xDD0\xAF\xD9\x01\xE4\xCB\x7FU\xEF\x98\xF2\x13&X1\xE9|\x9E\xEC\x0D\x16D,\x08\x07\xBE\xA8\x09D\xB7\xB7\xA6\xEA\x1A\xBD>!\xCDV\x1D\x07B\xFA4\xCE\x1B\x15\xF8\xA4\x11\x01.\x1B\xEF&\xC6:\x03N*r\x1BD1\x8E'-\xA8\xC5I\xB5\xA9\xF1!b\x19#&\x1F\xE9"\xD9\x01\xB1e\xE8{\xD3x\xC2\x97\xAE\xB5\xFB\xBA\xA8\x13\xE5Fa\xB9\xDB\xF7\xA7x\x13\xB7\xD6\xF6^t\x11\x04\xE9XZE\x05P\x89\x8B\x8Do,a\x08\xA5ibJm2\xEF4\x15\x1F\x91y\x18\x87s\xDE3\x0BuW\xB0\x06\x13ro\xD1%\xB5u\x96\xDCft.;\xAD\xA1\x8E\x15\x9BL9\x1E\xB8\x84\xEF\x1Bv\x09?\xF7\xDCR\xDE\xA3/dL(\xD2\x95\xAA\x0C-\xBF\x8F\x81Jl\xBB\x04i$%\x09\xB85\xF3\xB8'\x90\x1DfW\x1CC\xDF\x90\xDC\xB3\xF3@\xAB\xEEL\xECIaN\xC2T\xDD\xD5\x8C\xB8\xA7[h\x0Dfz\xA8\x842\x04J\xFA[\x1D\xBBa\xB3u\x9C5\xED\xD9!\xE2\xB5\x1B\x98\xEA\xEA\x84\x05Y:d8\x12\x10\x12\xE4\xC7{\xE3[\xFC_\x0E-^\xB1JJ\x1D\xA4\xCD\xC2\x08\x94\xEA\xB5]\xC8}jx\xCD+\x9D\xFB\xF3\xD7z1\xAE?\xD5\xF4\x02\x0D6tBd\xF2\x87W\\xB7l\xA5y\xE4\xA6\x0D{d\xEA\x8A\xAE\x90\xCE*\x17<2R\xCC%\xA9\xA5\xE8x$A!\xFF\xBC:\xD4]5k\x83W@9\xAB2r1Z\x0F\x8A\xE6z\xB0F\xE2\x8B]\x92+fl\xC4\xC3\xA9\x1F\x1A\xA1\xFE\x04\x1D\xC1\x81 nQ'%\xA1\xE3M\x9B\xE3m3\x929U\x80\xB4-\x98\xF0\xDC\xC4j\xAE\xC6\x17\xA9\xE5r[\xB9\xA3\xB9\x166d"\x05\x84\xB8\xB9\x13#\xD3P6\xBEh\x03\xDD\xD54jH\xC1_\xAA]\x93\xAD_`\x1Bz}+%n#\xA7\xF8{q\xB2\xE7\x13\x8D\xAB\xEC\xCAIWH\xAE\x08\x0A\xAA\x8FH\xE77%\xF7]\x0F^,\xA13l\xB6\xD9\xEF\xEC\xD2\xA3o\xAD\x9E\xFD5\xBB)\xA9\x0C|~\x93\x12t^8K\xED[\xA3\xC0\xBCk\xF8\xBC\x1F|W\x00 l\x14U%\x10\x09\xD3/g\xC5\x081\xE8\xC3foo\xA1e\x9A \xC7\x00BAV\x0B\xD2\xAB\xB1>\xB6\xD4\x85\xFF\x09 u{0o\xA5,\xB35\xA6~\x98B\x94\xFE\x01\xCE\xA15S\x9C,\xBAh\x8D\x0E\xA2\x84#\xEB\xAFYA\xD6(\xDE\xCE\xF9\x86\xA8\xA9\x97\x00yÉô‰ÑÀÉ\xE0\xE99\x8B\x1A\x0CdL.\x0AF\xA4Z\x9A\x81\x8F\x9E\x99\xDF\xB1\xEC3\xE5\xEFZA\xDC\xA0([<\x98\xFD\xA5\xD2m\xBF\x10@\x85\xEEa\x82\x08\xBDo\xB3\xFA\xF2\x0E\xDB\x95\x9E\xA6.\xEEk\xBB\xC7\x96U%\xE1\x9D\x83\xADsp\xF7"\xF47\xF5k\xFE\x8B\xED\xFC~\xF7\x03d\xD8\xCB\xAE\xF9 \x8C\x80\xA9\x16\x99!j\xE0\xF5\x13\x96C\xCC"M\xF5&'^[]\x97\xD85f\xD7\xD8\x0E\N\x95\x05g7\xFA\xE3*\xBB\xF1{M\x08\xE8\xAA\xB0\x0A{\x05 \xBE\x84\xCF\xBF\\x1C\x9BJ\xEB\xDD\xA2\x12\xCB\x08\xDD\x949\xF2\x9C\xEFGF{|\xBA\xA0\x1EF\x07\xFEk\x1B\xA8\xBA4\x19z\xE4\x0F\xCF\xA1\x9A\x98\xD4l\x84\x9F\xAEW\xA8w\xFB\xED8\xA0>\x04\xAE\xBAOf\x08\xBE\xD9\xD8\xF2fC\x1E\xD2\xCF\xD0\x14i\x96\xB0L`\x0D\xB2x\x899L\xA1Y+\xF7;x\xACu\xD927BI\xB1\xF2:\x7F\x8B=\x07\xB3ZwU\x13\x96\x0F\x1DH\xD3M$\xD4\x81p\xB0\xDFUm\x82\xCA\xF9\xA1\x03\xC6\x92\x13\x85\xBB7?\x18y\xAE\xAD\xD8\xD7D\xA8\xE4\x1A\x1B,B\x86K{\xC9S\x13\xCD\x1C3<\xD09\x9D\xC1\x02\xE7\x89\x05\xAB+\xD1\u\xF6\xCA+s)\x15\xC8\x0E.\xF4\x97\xC3\x03\x97r\xCC\xC8\xFC\xC0\xA3\x19\xB1\x80\x95H\x92\xA5\xC3\xCF#\x8F\xD65\xF63\xB6\xCB4\x95\xF9\x17U\x06\xF2\xE2\x91\xA7G9\xFD\xAC\xA6\xE5s\xA5+\xDC\x0B\xCC\xC4@\xED%x\x9A\x19\xE5\x01A\x87\x13\x10\x00\xAB\x81\xB4\x90\xB3\xDAp$\xC3\x1FY\x18t\x88\xE3\xEA\xC2(\xC7X\xD32R\xF0O\xEAagP\x96\xD9\x81\xE7*;\x15iH\xD3\x16x\x8C\xBC\xD7\x81\x89\x8Cc\xC6:}H\xF52\x11\x02\xAB\xE1\x1Ci\x8A\x8F:\xDB\xE0m\x8C[\x18\xA7ew\x94\xE2\xF2\x93\xBC8\xC7\xBD\xFF\x05\x19\x97C\xA9=:P\xB4\xEF\xB0+\x04\xF6\x14@\xE9\xB5\xC0\xDE\xF8xL\xCC'\xC8\xD4\xBC\x07\xD3\xC9b\xE7+\xE6G\xE1\xF4_\x9E\xBF9$\x83\xE9\xCAd\x82\xDF\xB7\xD1S\xD1A\x8D\xA4\x8En(\xE7\xE0\xCF\xB7\x04Fw\x0E\xC7\x16Y\x1E\xDD]\xD0\x8A\xF4b\xB8\xB3\x91\xCC\xDB\xE7(\xE0\xB5$h\x9Atp\xB8\xAE\x94a\xB6\x1B\xA0\xCB0\xFF,X\xE4\xE8S\xB2}\xB5\xCB\x19\xD2J\xDC\xEC\x0C\xF2\x83\x8D\x84\x84\xEB\xA1\xD3?\x94V\x1D\xA7b\x17N]\x02\x90\x94\xA0@\xA5\x09\xBB\xA9\xB9&\x8Bi\xD52yD\x80y`#\x0F\xFAi>9.\xBAo\xCB\xCC\xEAO\xCCXK\xB6\xB7s\xB0.\xA8\xD1lZn\xC5\xD3\xE4\x14\xAE\xDF.\x19\x86\xD7w\x0D\xFD\xC3\xE1w5\xE8\x17\x94\xC9v\xDA\xF4\xEBb\xE8~D\x8F)\xBDTS!\xD9\xB5\xB5e\xC4\x0C\x89\x18s\xF4\x13\xB2K\xFEGs\xED\x9C!W{\xCD\xC7\x9A\xBE\x80\xD5t\xF0^\x93\x0F7\xB2.\xE1\\xED\xDCn\xB0\xC9\xC5E\x8D\xE2\x14\x13\xAC'\xFB\xD9\xE93\x91\xBA\x012\xEF}\xE0\xD6\xF0\x96+\x0Aa\x02+\x81\x06\xB9\x8C\xF7\xC2\xDC\xA2\x80\xE1\xB7\x0FJ\xBB\x91\xDB!R\xF2\xFE\xEB\x16\xAA\x1F\xCA\x8E\xF2L\xF2\x90\xEC7\xDD\xA2\xAD\xFA\xC9U\x1F\xAB\x80\x0D\xB5\xB2\xE1\xD6\xB4tJ\x8D\xA2[6\xF8\x05\x9B\x88\xF63!\x7F\xF1\x05"X%\xF3\x92D\x81\x9B\xA5\xC52w\xC8\x1A~\xFC\xFE\xCF\x99\NP\x9B\xBC\xCA\xEF\x0B\xBB\xC4;\xECy\x01F*\xA9\xDEm\xB0@+k\x1B\xF9\xAB:c%\x96\x89\xA1g\x11\xD6G\xA2r\xBB\xC0\xC2\xE0~}\xB6\\x9CZ\xDEq\xC9V\xE3\xB6\x917O\xBE\xBDAq\xE4\xA1\x1C>%\xB2\x8A\xAD\xF2\xFD\xAB\xD5\xF1\xF7\x00\xF0,po\x17\xD6\x0A\xCB\xBA};\xA8\x1D\x95\xE2~%\xEF\xA0\x16\x0Ec\x04\xEFv'"mS\xDE.\xFF\x9E\xF2\x7F\x10\xCDDK\xFC\xE3\xD7\xBB\x9A\x1Dy\xFC\x85\x0A\xF329;\xDF\xE8\x84\xBC\xDA\x18\x8C\xEF\xDC\xEF)\xFB\xD9;\xBD\xED1L\xA1\xDD8{\xDE\x9D4'\xB4\xEDP>\x11\xDB\x9BH\x04\xE1\xC3\x93Z1\xAB\xDD\xBA\x86\xEF\xFD\xABV\xA6\x90(\x0C\xB8\x11U\xFE16\xC0\x1F\x8A\x1AC9\x0B\x1E5k\x18p4\xF5\x13\xA4\xD4\x82dd\x8F^jW\xFF9)\xFA\x1A6\xEA\xF8\x8C\xF5L\xFAjTb\xD7I\x84\xAC\xB2_\xEA\xC5\x84\w\xE3\xFF}N\x00\xC0\xBC\x10\xC5_\x0DO\xA3.=I\x91\xDA6]\xBB\xC0\x03{\xA3\xB7\xB6\x13z8\xFF\xAF\xF4\xC7\xCC\xE1n\xA4]\xA1a\xC8\x9F\xE6~\xC31\xF7\xC4\x88\xDF=\x08\xA0\xCCA\xB0w9Jj^\xB9\xBAr\x07\x89\xC9\xDB\xF1\x04\xE0:\x9D\xCA\xAD\xD80Ta\x08\x92\x86\x0C\xD5\xECk\xED\xE5\x04\x9D\xB8\x17\xF4H\xEA\x0E\xB3b*\xF6\x89\xA3%K\xD49\xE9\xF4\x1A\xB0\xECz-'\x9B\xDAM\xA19\x18\xA1\xF2_a\x8Fb\xD8\xE5[D\x1D1\xF7\x81\xAD3<\xC9\xF4\xFE\x85\xE8\x81\x97s\xB8\xEB`F\xB9\x02\xCC\x0F\x8A\x90\xEATb\xDD#0\x8A/\xCE}\xE5\x17\xB5,\xCA\xBCW<\x86\x0C\xA1t\xD7\xB4q=$\xCB\xB7\x05Eu\xD1\xE4u\x9A\xB9\xBB\xC5\xDF\xB7S\xF1\xE7\xB7\x9D\x84B4@v\x01\x1F\x00\xD0\xDF\xDAH3;\xD4\xD7\xAB\x88\xB5\xB7\xE9q [@#,\x09t\x06\xE5\xE6\xE3\x1D\x8CbP\xD2i/#\x0C\x01fa\x9A\xFC\xCB5\x1A\x0E\xA6Y\x09/\x92\xFA\xE46l\x88@\xCE\xA9E\xF4WY'zG\x05\xBB\x0D\x82\x0A\xFBX\x1F\xADa\xCD\xD0\x93\x01\xCD\xFD\xB8\xBA}\xFCp\xD0\xC4\xA6\xA8\xEF\x07 \xEF\xB4\xF5\x97\xB4\xD2i\xA76\x89\x87\xFE\x84m\x1AhzPn\xDB\xB0\xD9@\xD4\xE8\x97\xA8\x8B\x8B\xC7\xA7\xDA%\xAE\xC5\x11`;\xDA\xA8s \\x80\x9D\xB6\xCD\xF9J-]Q\x93\xE0\xF12\x12\c\\xD6\x85\xBA\x1Ag\xECo\x0Ee\x0D\xCF\xBEg\x97\xB2\x8F+\x0D\x83\xFDb\x12R8\x8D\xB6IeK\x0CQ#\x91\xC38\x8E\x1B\xE2\xFCf\x83\x06\xEB\x04\xEA\xB3\x86\x8CE\x913#\x8DA\xC8\xDCW\x12t\x1Ar\xD73\x0Ee\xF0\xB0\xCCC\x82y`t\xCD\x84,\xC0\x90|L\x07\x01\xA2\x89\xC8\xD7~3\x02\x1F\x93\xBE\xB9\x80\xAC\xF6/u\xC4u\xEC[w\xA8\xC2\x13%\xFFo\xD9Y\xAB\x05\xBA\xEDDPu\xF7\x1D\xFC\xC7;\xA5\x02\x06\xC5zP\x05\xA8\x9F\x97+\x8Ba\xF5\x16\x0C\xB1\xCE\xFC\x86\xABs\x12\x035\x9D\x83\xFB\xBE\x95\xEC\xF5\x03\xFC\xD8i\xA5,g\xA7\x95\xF5\x8D\xCF?`R\xAD\x038"\x94&\x9B\x18),\\xE0\x14\xDFd\xCF\xBC\xBC\x9A\x0B\xEA&\xB5\xCA\x9E\xE6\x86\xD0_\xB5*K-8\x97\x80\xB2\x0D\x8B9te\x92\xD9\x12aBr\x82\xF8\xAE\x97z\x1D\xE7\x1A\x7F\xC3\x01\x16\xDD.`@\xE7\xD1\xAB\xB19:\x1D\xCARKj\xF4\x87\xC6\xD13\xAB\x91\xA2X\xB3m\x8E\x95\xD0\xAD\x94%\xEE_\x1B1\xEB(4\xBF!\xCE\xB5\xEF\x02\x8Eb\xEDL\xC4\xC4\xEF\x8FN\xAAe\x10\xAB\xCAZ)v`E\xBB\x9F\x1E\x1Bz\xCC\xE7\xF2\x89$^\xF0\x17\x8A\xD9\xBD\xFA\xE6L\x17\xFC\xEB\xF39q\x90\x18\x94\xBA\x8A\xC3qqUk\x8C\x8B\xB5k\xE53R\x1D\x84\xF9\xFE.8rGm\xB3\xB3\xF7\x9A\x7F\x9B\x08\xE2H\xC2\x95P\x1C\xC1t\xAA\xA2JI\xAA\xE3\x056\xB0[c\x15\xF6\xF8VO\x1E\x07\xE7zna\xB6\xC6\xD6\xF4\x19l\x8A^a\x0Ax[\x93+9\x85\x89\x19\x03\xB3\xE6\xB5\xF1\x00\x8D\x8Du\x93\xC1t\xD1\xFE\xCDn\x8Fz\xA7K\xBF5\x88\xD8\xE3\xA8{\xE1\xB69m\xE1\x0Epe/\xD5H\xC3\x9AC\x94\xDE$@\xFCQN=\x1B\xEAi\x9D\xEEv\x03\xB9\x15\xC8CJ\xA6\x04\xCE\xFB\x00\x97-\x03\x05\xE6\x0D\xDA\xA7\xCF%D2\x97\xA4h\xB2u\xD2Z`\xEA\xCD^\xE5t\xC1\xAD\xE7\xC4\xCB\xAB\xE6\x89\xFF\xC4\x1C\xAA\x80\xEB8\x97W\xE1+U{\xFF\x92k\x95\x8A\xF8\xAAed\x83.rp0\xC6S\x0E\x9B\x19.\xB4\x8D\x06\xA4\xB7m1\x9A\xC5|)\x0F7\x09\x08F\xF9\xE1\xFF\xBF\x09\xC7\xD8\xF8V\xC6I\xDC\xDFL|bP\x11\xB5d\xF5\xD3\x08X\xC5\xF6\x12\xC8\x01\xB3\x18\xC9*\xC26\x86W\x07\x0A6\x06\x150\xD9\xB6\xBC\xB8\x9C\xFB_\xB7\x1F-\xBD}\xE0nm\xF5\xC1\x1B\x97~sS\xA2 \x12\x98<\x8E\xCAag\x7FL\x80a+\xBA\xD6\xD9\xCD\xE6tCe\x92\xBE\x05\x19\xE5\xEF \xAFx\xE6\x99\x92zCt\xE2iH\xDC\xE1\xE6\xCD\xDC\x02L83\x00\xD5\xC0:\x88\xD6=\x07\xAB\x8E\xD7\xED4\xA9\x13\xBA\xE6\xAF\xB0\xAC\xB9\xFC\x97V%\xB8\x97\xB1\xC3\xBD\xB7\xFF\x1As9\xE7#\xEA\x16\xC3;\xC9v\xA6,\x81\xCE\x8Ay\xA8\x1D\xC6z\x93\xA3{\xBDoS"\xC4\xCB\x06\x9C+,J-gy\xE7l=\x157\xF5\xC7\x868#+\x9D\xE0\x96\xBF(\x85N=-\x83\x15\xB1I\x13\x04\x06\xD2Y\x14\xF8\x09\\xB0\x8A\xC1"\x09\xCC\xF8\x88\x88\xE2U\xD4X\xD83\xF5\x99\xE2\xE0\x1D\xE2\x0A9+\x98\xC11_\xE1n5\xDEe\xDC\xD3\xA2\xFA\x14\xCD\xCB\x87\x07\x86Q\x96F\x0B\x92%\x09\x07[0\x06\xD1g\x14\xF6hl\xE7\xBB\xCC\x1C.%g\x1D\x1A9\x80Xs\xF7\x10\x0F\xDE\xBDoi\xAD\x0D\xB9\xA5\x04QY\x08\xDC[\xB7\xDE7JbFK\xAF\xA6C\x0AJFv\xD4V\xC9f\x95`\xC7"\xE6\xE4\xB0?\x86\xF7\x0Bk\x09\xE2L\xAD\xD6\xA2\x84\xD8\xF7Ww\x0A\x8E\xD3\xF1\x0C\x82\xB0t\x9B0\x9A\xB1k\xE2Hg\xAC\xC1\xC2\x98\xFA\x18\xA1\xA3\xCF\x96\xAA\xD3\xA9\x8E\x08\x1E\x87C\xD0\x93\x87$d\x10o`X[M8\xF7\x80i\x05&\x02\x9DyH\x11\xF3*\xC4\xFD\x09\x84\x1CV%I\xC5\x99\x0E\x94c#\x92\xFB\x80\xCF\xDA\xD5\xACE\x8Ee\xC3\x86M\x12\x89?\xF6\xA9(\xB4\xB1\xDD\x0F\xDE\xEF\xC6\x0E{\xAEa\xC5BT|R\x08\x83w<\xB9O7\x00\x87\xA3\xBAOW\x82\x12\xD0\xA1\xBE\xB3}{\x03c<\x13\x85N'\xA6h\x81T\x9C\xE22\xF5P]\x98\xA9\xD8\xC3\xBF\xCFh\x97\xC2\xE9&\xA3\xB4n\x10&\xCD};\x98\xD1\xE0\xF5"L\xD8\xE8v\xEFX\x7F\xCF\xE6\xA8:\xB6a]\xDAH\xFF\xE4\xDAg\xA2\xF7\x9BT5\x1Fu\xF8\x95\x05\xBD+C\x09\xDC.\xE8"\x90\x8ED\xC8\xDA\xDCT\x18\xE8\xF5q\x09\x17\x9B\xD1'@\xDC\xD1\x15\xB7\x9A\xF87)oq\x8D\xC0w.\x9E\x8E\xAD\x19\x87\x1FXBf~\x01\xA3\x9F\x0B\xD1\xABG\xA7;Y\x9C\xB0\xE4\x8EK\x02\xF4\x02\xB6\xAC\x0E#L02\x91\xFE'uG=\xF9k\x87\xA9!\xA5/gb\x9B\x8A\xDF\x12?\x9C\xB7\x03\\xCB?w\x91\x00\xDB\xFD'\x1A\xD6\xB3\xE1s>\x92\xB8\xEF*\xAB\xC3n<\x1B%\xA7\xBA\xB3!\x9E\xD9\x01\x0A\xBF\xA3S\x84Pl4\xAA\xE9GeDL\xA0\x877\x15\x02$\xA1\x0ER\xB3\xE2\xF3\x83\x9B\xF5\xC1\x07\x85M{\xF7wCs+\x19\xC5s5\x8F\x04I\xE9E%\x14P\x85*\xC7\x85\xAA\x178\xE9O\xD9is\xC4~\xBB]n"\x1C4\xB9\xAC\xF4K\x01\x81Xz\x1E\x0Elqm\xE8\xE8\xD6f8C\xDC\xED\xCB\xAD\xDB*\xA9\xE2\x06\xF4\xCC\xD4\xC8O\xCC\xEB8\x84\xB1Y\xE9T\x8D\x82\x86\x1E\xC5\xD2\x847\xBCe\x8F\xE4\x03\xD6\x0F\xCF=w\xC1\x87\xD7u\xD9\xCC\x9E\x9C\xEE\xF72\xA0+\x8D\xCD\x1D\x8C\x95\xE3|}-\x08\xF3\x81c>\xE4A\x8AJ\xA2\x1A\x0AP\xAF\xD95\x16\x8D\xF8E\x0Aw\x90\xE4'\xEA\x03<\xBC\xEE\x1B#\x9A\xC7\x9C\xCD\xA4\x09)\x96\xDD\xB3\x0E\x11\x09\x86\xE7\xDA\x94\x09\xE0\x99\xFE\x99\x8B?\xDE\xFA,\xF6\x01\xC66\x8Dl\xBE^\xC3}+\xF4\xDC\x90\x9CI\xD1L\xD2A\x9A \xA0\xA0\x91G\xB9O\x964?\xCC\x8F\xA8\xB6~\xEFD8\x19\x96?f\x0Ce\xB3r\xF7\xBE\x9E\xBD\x0E\xAC\x85\xA5,Xp\xF98J\x1C\x12\x85\xC9\xC3\x03-\x0E@\x9B<6\xC2\x88\xA7\x82*\xEF$H5Ir\xB0\x93\xAE\x01\xDC\xBCs\x07\xCE;\xB0\xC1\x88\xDC\x08\x027x\xD0\xB4\xEE>\x94*\xB9\xEF\xF3\xAFJ\xDF\xC8\xF4\xF9|\x18\xCD\x93\x12\xB4\xE9*\\xB8+\xEC\xC7\xB1\x93;\x13\xC5U\x7F\x84@\v\x03\xFF\xC7'\x1Bb9N\xA5\x81 \x83b;W,-\xAE\xB4F\x02\x01\xEC\xF6^\xE9WhFvg\x11\xC8\xB8\xFE\x96?\x92\x04\x97\xDAL6q\xD6\xFF\xBA<\xE0|.C\x0E\x8Cwx\xE4\xB2\xE4x\xB6\xD6\xAD\xB7\xFBj\xE8\x9A\xB8\xA9\x92=\x07 \xC6\x83\x8F\xE6\xED*\xEBi\xE9\xAF\x98O\x81\xE0S/!\xC6\xDF\x92\x8E\xA8\xB6\x1E\xB4\xD4S\x12#\xA8J\x13\xE6\xD8T\xECv\xA2M\xD6\x0F\xB3\xCB\x89\xD9XCY\xDC\xB9J\x9B\xA2\xD0">\xCF\x1Ev.\xED\xD8\xFCR\xB4f\xDD\\x07\x7Fg\xD9\x03\x86\xCBY\x18Y!\xE2--\x0D\xFE\x07\xADc\x01\xAF \xE4\xF7}\\xB4\x1A\xDB\xA4E8\xACt\xFA*\xFF{\xE3x\xD7\xBCh&\xE9\xAF\xB3\xB6\x01\x0D\xE7n\x9D%\xEC\x0D\x0E\xEF5i\x13E\xC9t\xFAh\xA7E\xCF\x7F\x8E\x13\xB3[7\xE6$CuO\\xB5G\x93p\x0F\xC7\xCA\x0B\xE2\xF5\xE1\xAB\xB0\x0E\xD9\x95\x0D\x9B\xE7\x09!\xA6J\xA4\xD3\x99\xC5\xC3\xD0\xB3l\x8C\xE8:\x01\x87\xB2$\xB6\x9D!FH\x19\xA0\x00\x81\xB7;\x95\x95Qc\xBD\xB1+T\x93\xCD\x8C\xDB\x03B\x1Dd\xA2N\xD4\x04d\x10\xF5w\x0D\x08\x17\xE4_]\x04\xCA\xA4\x15\xAA\x81\xF7\xD1K\xB4\xF2\xE7\xD3\xE9\x93\x1Ao-\xBE\x92\xFDqXLp\xF8\xA3\xB0W\x02\xAC\xAF\xB3\xD6\xAE\xF2\xDC\x17\xBF\xA8S]%f\xB2l\x9A\xD2\xC5\xC7\xCA\xEA\x85\xE6\x95\x8F\x8D\xBCCq\xC5\x87s\x90\x05\xC0\xFD\xFC\xEDc\x1E%y\xD4\xFF}\xCF%\xC7]\xA7\xAD\x91\xF9\x0Ad\x1D5\xAD\x\xA1R2\x97k\x09E\xA1\xC6\x9F\x91\x1D\xADC\xED\xE2\xC4\xB8M\x93>\x8A'\x93b\x910\xECL\xA4\xCE\x1ADB\x1D\xDE\x15,\x19~_\xD0\xCD4^\xC8{\xCB\xC0m\xED\xE7\x90\x06L\x90\xCB\xB7%\xB7\xF5^]\xC7r\x1F|\xCB\xB1\xA6C\xA3\xE3\x8C\xDC\x9C)%\xB4o\x0D\x82\xC8w;\x04Qz\x16\xBF\xDFM\xF5\s\x9C3\x83\x19`(F\xBE\xAE\x1D\x0F\xE4o\xDC\x0Ay\x90Mj\x8A\x0C\x16?\x01\xD0P\xDE\x8AT.3\xDE6cD\xC8\xAE\xBA\xCD.\xD3\x0D\x01\xBE\xA5\x8F\x9B\x8Fa\xCC\xA0\x19\xBF\x98\x94\xAD\x85\xF4\x8Ca\xF4G\xD9\x1C\xDD\x8D\x0D\xA0\xE5\xE0\xAC,\xF7Y\xFD'\x0D\x87\xCC\xD0mS\xD8\xDE\xB3\xB2\x10\xD6\x0E4\x15\xC27\xB0\x1D\x01\x0Ado|\xF2\xF0\xEC\xC4\xBF\x0C\x1D>\xC4\xF7\x11\xAA\xE5\xEE\x85G\x87\xE6R\xB3\x90\x8F0\xAE\x8A\x81\xEA6#\xE5\xDD{7E\x9A\xF8j;\xE9\x08A\xF5\xB2\x9E=}hC\xCA\xD7l\xB0\xE4\xED\xADM\xCBg\xC4\xB5\x7F\xBA\xBA\x80O\xD5\xF2;z\x9C\x98\xED\xE9\xC6\x8D\xC2\x1C$\x9E\xC9\x8E[\xF1\xEAj\xE3?h\xEA\xE6MO\xBE|\xA4\xB2\xE2r0\xF6,Y\xB88>(\x1B@\x9B\x04\x01Q\x04^\xFB\xB3\xAC\x10\xFD\xED\x1B\xA5\xC3&l\xDD\xBF\xFD\x8A\x1C\x99\x06\xCB\xA3>\x9A\x8E5\x0D\xD5\xD0\xC8\x95Y$/\xCC\x14\xCF\xC2\xAFo\x97\x9A\x983\xFB\xEE\x94\x90\xC8\x18\x9C<\xBF\xDC\x8C\xA7E\x07\xFDR\xB3\xE4\xCF\xE1n\x08AF\xD5?\xCD\xA4\xE8H\x93\xC1\x08\x05h]\x06\xCB&\xDC\x81P\x16W\xC0=8\x1FE\xA4P\xEF\xB6\xDD\xC78\xB3h\xD0\xE5\xCF[\x0F\xF0\xF3\xE6\xAA\x9D\xAEt\x08\x1ES\xD87\x87\xB6\xFF\xE5\xB3\x13a\x8F\x0C\xFF\xCA\xAB\x0D0\x9B\xBE\xB1\xB2UQ3\xC4N@IOT0\xB1\xC5\xE7Kv3-i\x1D\x06y\x8A\xC6e\xB1\x89\x9B\x98\xFD\xD0*\x9C),\xD2_\xEE\xD0\xA2\xCE\xD4\xCD3\x19\xD1-H\x1E\xC9\x1B~{\xE09,"\xD5}\xECA\x9E\x97\x96\xCD\xE4\x92i\x12u^\xA9\xAF\xBE\xDE\xBAdJ.\x86R\xDB=\x8C\xB9i\xFDU\x90\x8E#\xC0\xDB\x10o\xDF\xDE\xC9\x12gcO\x96\xA7f\x9D\x83N\x91}\xF2\x9CHM8\x11\xAB\x1B\xAA\xD9M`\xD0\x0A\x93s\xCC\x14o\x7F\x9C\x90<\x1B#\xA7\xBD\xCA\x86l$-\xD6ZN\x83"j\xEE1+Vf\x04\x8Co\x04\x06\xB7\xE6d4u|`\x0Aa\xF7H\xD2\xDE\x85\xDA\xB70tO\xB4\xCF\x094\xA0\xE4\xEC\x8FB'\xCA\xFE\xBB\xC1,\xBF\xDB\xA2\x151\xADf\xAB\xEB\x1E\x99|\x11\x05L\x02.B\x87\xF4\xEC2&\xC2w\xA1{\xAB\x15v\xFA_\xF5\xE1\xA8\x1D\xC6\xDFH\x1Al$\x86,\x03\xA4\xF3\x01\xAB\x94\xF1CI\xA7\x07\x7F\x1EEN\xD3\x03\xCA\x8F\x1E\xE8\xFD\xF4\xA6S\xD3\xDD_\x18w4\xE0\xCF\xA7A\xCF\xDE8\xB1\xA5\x86T\xF7\xD1D\x8C\x88\xB9\xDD\x84a\xACa\xFF\xED\x98\xE0m\x08\xD9z\x83D\xD9X\x0A\xB6\xB3AG\x96\xDC\x8E@\x1E\xEA\xE7>y\x08\x14QKm&\xBD0.Mz\xC2\xAB\x1E\xD8\xE2\xCC\xEA\x9F\xB4SDRX<\xE6\xB9}\xFD\xCD_\x99\x1FF*\xBCm\x95\x84)y\xA9b\xB1=d3Ca\xB8\xE5<;x_I0\xEA\xD0S\xC6"\xF3\xDF\x8F\xE4\x88\x18\xD9\xD8\xAC\xE2\xDC\xDBn\x0E\xB9e\xC7J\xB5$5\x0E]H\xAD\x82\xB6_J\xE5\xFF#L\x08\xA1\xA3ox\x83\xA6/\x93\x8E\x97\xC1\x10\x8F\xEBe4\xD9\xDD%r\x8CAG\xA2\xDEQ\xE5D\xEC\xDD\xB3N\xCE\xBD\xC4\x8Db\x90i2\x1B\xA3\x8D\xD4\xF1p\x86\xDDP\xC7(\x96\xFF\xEA\xAANN@\x0E\x11\xD0\xF7z\x0FD\x06\xA1\xE2\x10\xE5c\x18\xE3n=\xF0W8X\x97\x95\xB4\xA5\xB4\xD5.\xFF[\xC1\x9DYju\x90\xC8dh\xCB~*J J|\x9A\xFB\x86\x85\xFDoR\xCB\x93\xF3%M\x8BR\xA0\x9C\x83\x9E_\x96\xA9*\xB8WN\x89r\x14t\xEB\xECt\xC6\x10\xA6\xA1`f\xF4~+\xA7UR\x87\x7F\x02\x1D\xF7V\xD3\xDB\xBB\xA9\x98yCl\xD7\xE7\x12\xAEt\xF9E\xC36-\xC5\xCE\xA7\xC6\xB1\xF1\xE5\x83\x91\xDB,\xC9\x11*\xEF%\x02^^\xC2D\xA3\x198P\xAE\xA5B\xC4Kj\x81\xB2\x15\xF7\x83o\xEF\x99!T1O@\xDD\x87\x90\xE6V!\x9Aa\x84\x82\x88'{\xC1W\xD7H-\x90\xF5s\xC5\x89_!\x81\x08\xC4\xE2(4\xE9\xF6\xFB\x9C\x7F\x95\x83\x87\xC7\xEAuZ\x04\x86\x8C\x03\x81\xA9\xAB-]\x96\xFA\x98\xCBx\xE6\xDCn-\x10\x920\x0F\x8C\x8A5 \x07\x04\x8C\x90\xC3L\x86\x86T\x87_\x12\x92\x1D|o\xE8\xCD\xFF\x97(\xA0\xDF\x8F3|8nf%N[m\x81\x01E\x1E\x89\x966_\x85U\x83Ir\xEB\x95m\xBCK\x99TU\xB3C\xC6v&l\xE0\xEC\x870\x13E2\x0C\x08\xBBVt\xE3\xFD\x10O?\x14\xC7c\xB8k\xD1\x09\x86r<\xE9Z\xEF\xAB\xF6\xC4\xA1\x87\x8D]\x86\xBE\x9B\x04\x7F\x0F\xC2\x89\x06\x06\x9E\x9BV\xC1x\xFB\x9E\xB5h\xC1\x00\xCA\x06\xEC\x1B[\x0F\xF3\xDF2\xE15>\x92\xDD\x9B\x95\xC9\xC6|\xC1\xCB\xECG\xFC\xE672\xD0\x17\xAA\x9E\xEC\xAF\x81t\x82\xD8LL\xDD/\xA3\x96\xB9\xB1q,\x84\x98\xCA\x09\xF6m\x88EgsH\xF5\x0E\xB0\xB9\xC3\xD1\x97(\x18\xAB\xFFV\xF3\xA7\xEB\xCB'Al(\x8E\x8D\x08=\xD1\xECo\x16T\xEC\x91\x15_5\xC5\xF1.\xCB\x80)\xDC\xBE\x9Fl\xDA}\x99W\xEBg\x1C\x8A\x84,\xB50\x87qo\x0E\xE8\x84\xCEN\x00%J\xA2Q\x12\\x99\xEF\x14\x8B\xDE\xA1\x17\x97\xC8\xF9\xD2=R\x01z\xC8\xD9C\x1C\x91:qYEf\xE4\xFDT\x92\xFAvc\xF1\x83\xF0R\x93\xC6\x00\x83\xA2N\x8C\x08\xEE6)\x07\x13dD!<\xF1\xDDU\x13\xA6\x81\xCFx\x10\xFA\x1D\x8B5\xF1.\x84 W\x1B\xEF\xA42\xF2\x00{\x03\x18\xDC\xF9>\x1F\x06\xE2z\xBB\xD2\x93\x144\x82\x1C\x15\x86)\x04\xF8=>\xB1\x8B\xAC\xBDc\x98m\xDF\xF8\x0D\xE9\xD7\xCC\xCA\xBA`l\xFCr`\xE4\x0Eg\xD0\xA4x\xECo\xDB\x82\x84d\xC2\xFEp\x9B\x9A\xA3\x01\x174\xC3o\xC8\xEA\xCB%e\xEEA\xC1B\xFBO@\xF6VK\x01d\xAB\xC0\xCA+T\x91\xC3 \x0E\x81X\xE5Z\x0A\x85\x1A\xC8\xB8~\x06\xD2\xE7\x04>\xBDE%~\x024\xE5\xF5\x10\xE0\xC2\xDD\xDB\x85peT|8\xBBh\xD6H\\xF0Z\x02\x85\xB3\xE5\xB9\xE0\xF4\xD9'dc\xB8Br\x8EZ\xAEWRJ\xC1\x85\x01\x0Fp\xC2\x18\x97L\xBFF\xC5%\xFC\xD7Z;\xF6\xC6\xF7z\x98\xBC\xBA7\x0FT>\x0F\x8A\x92\x05\x19$\xE4\xF8\x9ES\xA8\xE5\xBE\x9A\xD6\xA1\xB3\xD4\xF3\x02]\x147\x9B\xB1\x80B Fe\x98\xB8\xD0\xFD\x07\x02\x19\xE5Qsn}i\x17\xF6\xE739\x8ANA\x0D\xEB\x11\xBC\x9C)sU\xEA\x99\xEE\x80b\xB8I\xADOM\xF3\x83\xD1:\x83%\xA0\x02\xC3k\xD5!\xFE\xE6O|\x88\xE4\xAA7?\x8CL\xB2\x8C\x9A\x12\xE0\x9CZ7Sy\x03 i[One\xF1\x84b\x95J\xAE\x11\xC8X\x0B$&\xA3\x8E\x89\xE2\x02\xE24n7dYD*&\x95\xA3/\x06\xAB\xA1X\x90n\x81\xEF\x09\xE4\xDD%\x1C\xC2\xDC\xD6\xBF\xA0.y\\xEB\xC0\xF0\x88\x91\xF2\xBA\x9A\xE4\xFF\xE0\xE7\x87$\x81I\xEB\xAF}lG3\xD5gJ\x13\xFE\xB8\x16\xBF\xFD?y\xC6\xB10\xFA)b\x05\xC8\xA2~\xB3\x04\xE9\x1AGS1\xD6\xEE\x13x\x13\x89\xB3E\xBA\x93b\x86\xFE\xAB\xBAK\xF7\xFA\xA8\xBF`\xACN\xCC\xD1\xBB\xD6Pu\xBB\x146\xB3F\xE0\x87\xCFXs<\x99\x04\xCA\xB9\xD0\xF1\xAA\x9FS\x9D\xFE\xACu4\xC6X\xD4)\xDC\xE6\x09\xC5c\xB5\x1F\x0D\xE1\x9B\xBB\xF2\xE6\xDF\xA1E\xB6n+m;\x09\xEC\x11\xA4\xD8emN\xAA4\x0F\xC5"\xF0N\xD6\xB0\xF9T\xFA\x15\xD0\xC9\x06:\xC9\xD0\xCB\x04\xAB\xEC\xFC2\xFC\x15\x8Fwz.j\x9F\xD5H\xDC\xD0h\x81k\xAEw\x91\xFD\xDA\xC7\xCC\xD8\xFD~\xEAN\x04Q\xAA]\xDEO\xF8\xA7!\x02C\x1F\xB3M1\x1AtR\xC2\xE0\xD4\x9E\xCCM7\xA1\x9AR\xA8"\xFC\x9E\xBF\x00\xD4}\xE6\xC7\xB7\xEA\xCE\xCCfw\xA3g#\xEB\xD3\xB6Ev\xF0\xCB-d\xB6 \xC7\x9DR\x88\xBE\xD2U\x01\xA4\xDC\xD8\xDAq\x1D\xF3\xAFRt\x03\xA2\xCCS\xEA=.\x85\x88-\xD0\xEE*K/\xF0\x99z4\xBF\xAB\x7F\x09`0\x12!v\xD7\x04\xD9\xC8\xED\xB0O]\x92\xB5=\x89\x18H\xE9\x83b\xEE]j\x953u\xF3\x8F\x0C\xE1x\x8D\x8C\xAB\xC9"'\x12\xE9\xA5\xF76\xF3\xA9\x91\x15\x80qs?#\xA5\x17\x00\xAE\xAE\xE5Fs\x85\x1A\xBDe\x1CzA\x1E:\xF9\x98CU\x137\x9D\xD5g\x07\xC0B[\xF0\xFF-\x9Ai\x1EV5\x89:\xA0\x83>\xD6\xB8\xA1\x0B\xBB\xC4a\xD7\xB5:R\xC1\xBE\xB7pu\xA8\xCB~\x87L@\x8F)\xFD\xF7\xBAo\xD3u\x02\xFDpD\xDC)\x0F(\xC6b\x8D\x926fF8\x0B\xC3\xCD\xC1\xB1d\x03X\xCF\xAE\xD4K\x81\x8C\x89c\xB8\xFF\xFD\x13\x97\x01\x0AA\x97h\xA85\xF7\x07\xF7l:\xD5\x82\x89\x9Br\xE5;z\xFC\xE2\x13\x8C\xAA\x03S\xA8\xC57MT\xDC\xBE\xF9\xC3*\x87n\xFF\xDC\xB4\xCD##\xE2\xF87-)csnv\xA6NxN\xB5:\xDE\x84\x8D*\xD6m\x9BA\x8C`\xCBlB\x80\xA3\x90V\xB8\xFFV\xF8\x936\xE2\x8Dn'1\x02\xA2\xA3\xBC\x11\x1C8@\x1CL\xE6\x8A\xAD\x8B\xC4\x91^\x08\x0Cp|\xF2\xB8\x1B\xC6\xF71\xB1\xF5R,\x10\xFDk\xF4\xDC\x19UXW{\xA5\x09\x1A\x99\xD0\xE6u\x93\xFF~T\xC5q\x9C}\x0DO\xD0\x10G\xB2\xA1\xBD\xE0h\x9A/\xEA'\x1B>>1\x90\xF2\xFFq\xD1R\xC1\x9B}\xF2\xD5f\xC2\xC8\x10\xF1y\xF2-\xBB,|\xD2\xD5\xD2\xAE\x88\x1C\x81[\\xB45\x19\x06\x02\xC0\x17Y\xEC\xF7\xA6\xA7\x96k\x1Ct\x98a\x8DuA\xF0\x86_\x05\x7F4v-\x10)\xF8Jd\x16\x1FT\x88\xE7>\xF0\xFE\xEC\xF8*L\xEC#6Z\xDE,\xA1\x90\x88\x07\xE1\x84\x01\xA7^\xFB\xB4-\xF3\xC8x\xFA\x1D\xED\x98|\x95\x8D\xE7M\xF0h\x81\x8B\xCA4#\xDB1\x8E!\x97!9:\x0B\x0Bl\x1F13\x08N\x80\x19\xE65\xC4\x0C\x8E\xDE\x80#\xB1u\x1B\xBF"_\xC4;\x92gRH\xA5f\xA7*W\x1E\xBD\xF4\x1C\xAF\xDD\xB9\x06}\xC2\x1A\xC4\xB9\xE20\xE18 z\xEE\xD9=\xA1\x16c\xEF\xA2\xF2\xF2<\x13\x8F|\xD1\xEFT4\xA1\xC5|aAQ\xF0\x88\xEB\x06\xA5\x8F\xE8&\x99\x9D\x12\xAE\xE4\x90`\xE4b\xAE\x82u\x90\x97\xC1>/y\xE7g8\x89\x1AZS\xFCz\xDEb\x10<\xEC\x11\xF9\xF7\xBEC`o\x1C\x06O\xED\x98\xDF\xDF\x92\xF5\x9A\xA0\x97\x8A\xAF\xD0\xF9\xBD\xB3\xEC\xA8\x9A\x91\xA6!\x0BH\x02\x12\xB3T\xB7&\x18\xCD\xEB\x07\x18\xA9Z\xAB\xD64\xCD\xAF\x8BV\xC4\xEF\xD0+\xD2%"\x00\x13\xF6\x9F\xCE\x0D\x88Y\x03n\x0Du\xAE\x80\\x9F\xBF#\xD0~,\xAB\xA1\x9FX'\xD4\xAEPL+T\xFDi\xD2\xFF\xA56)M+\xD10\xF1Sm\xECp\xFE\xE6s\xA2j\xE5\xBErRqxq\xB6\x9B\xFCz\xE2\x90B\xEC\x83\xDC \xF0\x09!\xFF\xC1,\xF68\xAE\x8EfU6k\xAE\xB5\xDB\xD1K\xAA\x0Aq'\xF7]\x1C\xC4K\x17!#\xBBy\xDB\x13\xF2\xFB\xD0\xC4\xDB\xAA\x8B\xF8m\x9D\xFF:\x1D\xB1%\x15\x06l\xF4\xF82Uq\x14\xC3\xB1\xA7p9H\x8DP\x09UYc\xAF\xC9\x08\x0506\xD6B\x12\x14\x99a\x99\xE6\xA1?\xB3\x00\xED\xE4\xF3\xFD[\xF1\xB6\xE8\xC3\xF3\x14\xCC\xAD\xC3\x87\xA6\x89\x8C\x15\xE15\x84\xE3\xC1\x8DuU\xECc\xCB&\x85\x8Cl\x96 \xFD\x13\x1D\x87\x0F\x0E\xD0\xFE\xD4\xB8z\x8E\x93\x9D~Z\xD5A\xCE>\x09\xCDQ\x9D\xF4\x958p\x806\x16\xAA)\x0A(\xB8\x0D%\xCB8\xFDz\xB8\x88\x1D\xDF\xDF\x81\x17\xBE\xCA\xEB0\x98\xDE\xCA\xCE5p\xA6\x9B\xA4(\x92HL{\xCFc\xB1&\x85O&\xF4qJ\x0BA\xE8>\xC3hY\xE16gZTi\xA2\xFCPg\xB3\x9F\x14\x16\xC63\xF1\x9E\x1DM\x9C:\\xEC\x06n\x0B@\\x1F\xBCi\x05\xC0$2h\x95\xF1^s\x09\x03w\xED\xE6\xF7bU\xCD_M\x98\x1D#&\xDBk(\x88\xD4"Y\x13\x92\x80\xA0\x19\x95>^\xA7\xC6eQ\xC8~\xFF\x84\x98\xE9\x93<\xEC\xAF\x95\x97\xB8~\xF7o\x0C]!a\xD7\x13t\x068\xDE\x8E\xE7\x85Q)\x9CX#\xE8\xBAG\x9A8\x9D:nN\xCD!\x83\x1Bg\x954\xF5\x9E<\x8B\xD0G\x1A\x81\xD4;\x1CK[\xCB\xDE\xA6\xED$\xDC\xA0y\xCF)\x14Z\xD5\x9A\xB7vNa2|\xB3\xE1\xEDy\x0DkD\x00\xF9.q\xD1'\xEF\xAE\x9C\x00r\xFA\x07 \xC0C\xAC\x86L\xBF\xB9\x80\xC0\xFC\x17R\xF8\x01\x8Az\xC6i+}\x0E\x8E\xB7!o J\xC2x\x9C\x06EV\x92\x9C\xD6$\xB1(!oZ+\x8D;r\xD3\xBES\xFC\x0DG\x99\xF7\x0DgKL\x8C\xA9q\xD4\x8F\x98'lf\xC1\xCE~ \x1A\x06\x1B\xA02\xB3\xE8Uy\x0E\x01\x85\xE6\xF9\xDA'Jj\x8B\xBEe<\xF4.#\xBF\xF2\xAA\xC2\x8EN\x8Bk\x1D\x84e8\xD6\xB6\xC7\xEA\xE9\x00\x15}\x02;+x\x147\x7F\xCA\xA3hdv\x0Bg\xED\xDD\x05\xEAm\xC9\xF9\x89\xE98\xDE\x11\x14\xF87\x80d\xCEG\xA1\x96\xFFM\x983\x94\x1C\x9C&W#?\x177\x1D\xE2[\x8A\xDF[\xA4\xFF]2\xDB\xFC\xFD9\xBA\xE0]\xA4\xB8\xA6\xD9}\x80<\xE8\x93\8\x05?\xF4:\x9C\x0E\xFF\xE5d\xF5\x8C%m\xB6\xEEm!a\x87-\xD8\x8F3\x92\xE0\xA5\xD1\xDE\x0D\x0Ac\x85\xDB\xCA\xB3W+\x9E\x96\x83]w\xA0\xBD\xFA}\xD3K\x96\xBC\xDCa\xEF\xAC\x80;x\x0D\xD6,\xDB\xE2\x8C\xBC\x8F0jE\xC5\x01qX9\x04a\x11\x19\xD9Fe\xF9.\xF0\xAE\xEE\xE4i\xB7\x80\x85\x02s\xDF@\x9AY\xB6\xD5\x8F\xDE\xD8\x9Cw\xD6\xF0\xBCTmTH\xB5i@\x1D\x9C\xAA\xCA\xB8\x90L\x95\xA1\x0C\xAD\x92&H\x90\x1D\x0E\x80\x88\x9DI\xA2j\xD8D\x81\xFDf?\xC2\xCBi3\xE0\xBF\x83\xD3\xE7Y\x093o\xAA\x1A\x89\xC1\xD6\x88\xDE\xFD+\o~K\xF5\xE3\xF7\xB9\xDBR\xC5sV9\/6\xCF6\x8D+\x07\xE9B\xE0\xF3&@c\x16\xA9\xBD\xAE\x9E\xAD\x97\xAD\xF8Fcr\xF9HB7\x05\xD7\x9F\xF9\x1E\x99iI\x8D\xFF\x9A\xE6`\x0C\xA7r\xFA\x8CV\xF8ee\xC4\xED\xEA\x03\x8FV\x92\x89b8\x1C\xBC>\xF2q\xFF\x1D-^xx\x16\xB6\xFB\xA7\xD51\x93\xDC\x97V\xF0[\x1D\xDBB\\xCC2+\xD9\x08\x07\x05\xC8G_:;\xD1\x81 \xC8\xA7\x07\xF7"\xBF_\xCE\x02\xB86t\xE3\xE9\xE5\xBB\xEEgv\x8E\x8D\x98\x0D\xA3Bq\xE4\xDE\xB3\x85\xA2+D\x15\x07.k\xFA\xA8 \xE2\xA9\xD8tPkm \x04dK\x9A-T\xFA\x1A\x07\x8EV\x90?i2W\x88v&^ ZP\xFCh\xD9j)\x90\xAD\xE2\xC0\x07\xA4\x8Bs\x8A\x85\xD1\xB2\x153\xD2\xFF\x98Te\x87\xBC~\xE5\xF2n\xBE\xF0\x9C\x82\xD4a\x12L@}\x18e\x10i\xA3\x00U\xF9{&m\xD6\x91I.\xB8\x98\xEDg\xD9&\xC97\xE6n.H-\xF7\xC7\x06\xBB\xAD\xBAS\x7F\x1Fw`\xF8f\xC1\xAC\xEB\xC3Vu\x7F\xB0\xDDmYWW\x8E\xC0\xAA\x86\x85\xF8\xF4\xE8\xB8VM\x92[\xC8\xDB\x076\x90\x13\x8CD\xEC\x96\xC9\xBB\xC5\xA0\xFFR;q\xD9\xBB\x85\xFC2\x04\xFBt\x9Ab\x8E=\xE0\xDC\xA0\xF67\xDD\xA7\x99\xE6\xEE\xDC\xC9 %zy\x8E\xDB\x9F\x88\xFDo\xC4\xE0.\xDDXl\xF0\xE2\xB9#\xF2\xCD\xDC\xB0\xB2M\x06\x95ODUga\xEE\xEE\xA0\xFBP\xCF\xED\xDF\x8Bv\xA1VO\x93\x870l1\x96\x13\xE8\xEB\xA3\xEE\xF1\xDC\xFD\x06Hxg\xA7\xE2\xA7\x0D\x1F\x00&Q\xE1\xA7\xB3\x1C\xE1<\x89#\xBE\x08\x84\x943.\x0E\xE8\xE0,"\x98\x0E\xDD|h\xCE\xE3x{\xAE\xBB\x10\xC8?\x8C3\xBF\xC7\xAA\x076\xBF\x13\xFE_Ca\x98\x1C\xE6\xD2\xBB\x03\xF6L\xC6\xBF\x08h\xF4\xB5\x81V\x19\xC5\xE7\xBA\xA0\!C\xEA\x872\xBA\x7Fn\xDC\x89H\x84U\xABy\xB7\xD7\xC1\x8Ce\x01\xF9)R\x13+\x03U\xC2\xE3\xBA\xCF\x9F\xD6\xCB\xE2\x19\x82\xA3q\xF8p\xAA\xA7\xC6\xF3\xDFp\x8B\xCC\x15}s\xB4\xB4q~\x96\xF72^nI\x8C\xB3\xD4F\x14M\xC34\xAC+&\x8C/\xEE\xDD\xC1\xE2Y\xE1|{\xF8\xCB\x19i\xF3y\xC2\x851\xF5\xDD\x8CS\xD3\xC5\xE8\x84(\xF6\x0F\xDF}\x82\xE9\x1A\x0B\xAC\xACl\xD8\x0B/,\x04wc>\xB8\x1EX\xDA\xC7fF\x0B\x0F\xE4\x7F/0\xB8\xDD|\x8D}(\xC8\x18\x1F\xE5\xCCm#),7\x81]\x84\xBE\x12\x1E\xB4g\x91\x8B\xBB\xE4]\x9C\xA9\xB0\xBF\xC1_2m\xF3n\x0E\x9A\xC0\x01\xC1\xB3L\xE6\xD4\xD2\x11\xCC\xF7\\xD9\xD0\x0B\xFD\x89nU\x91\xD1\x8AO|\xA6\x99\x89\xF5\xB3\xBB\xF0t\x1FH\xD7D\x83\xA0Z\x8A\xB0AT\xF0\xAE\xE4\x1E=K\xBA\x88\x8E\xB0\xCC\x09\x8F\xB7Tw3W\x922\x8B\x0C\xEB\x18\x8F\xDA\xA1\xE18|e\xCA\x80\xFF\xFA\xBE\xABcpH\xB8V\xB7\xAD O\xA6"\x91\x12\xD7;\xB6v|\xD0\xA3\x8C\xEB\x91 \xA6~\xD3\x1FU\xDC>\x0C\xB9\xC4\x82\xF4\xFF\xA7_\x88\xC7(u\xAA>\xC6\xEA\x17\xAF\x8C\xAE\xA5\xB4~)\xC3\x03\xBD\xEB\xE8\xB7\xE4\xA5\xFD\x8A\xA8\xC8l~\xF8\x16Bk\x96\xA0A\xFA\xC1\x0E5v\x06H\x11\xB2\xC1y\xC0wm\x14\xBE;\xAA.='\xD2\xD1\xDE\xB9\x88\x1F5\xFD\xEC\x96C\x87\xE0\xED\xDF\xA1\x84\x95\x95|6\xE8\x04(\x86R\x14\xD9;\xC6\xB8\xF3\xCC\xF7|\x98\xAD\x98J\x93V\x8E\xDC\x932\xBE\xF2\xA5\xCDq|j\xD9\xEFG\xDB\x980\xD0\xE2\xF0\x92q\xB8x\xB7^\xF3\x92\xF6S\xBD1\x83\x9C\xE1\xAC/\xDA\x89 \x1C\xA3+.\x9B\xDA\x17\xEB:2\xAB\xB9f.S\x925\x81xp\x80A2\x18\xB4\xAB\xFC\xDC\xDF\xEF\x14&\xBB\x02\xFB6\x0F\xC6\xDD\x0C\x81\xD3)\xA2N\xFE>;\xB5W\x9CK\xD1\xA8}\xB0$\x0F\xF5\x14\xE5\xA4;(\xD6\xC8HP\x00:\x16\xC8\x1A\xB2\xB4\xBF\x09\x8B\x99\xF8#\xEC\xFCbZ\x9Bgl\x1B\xFDK\x86G|\x17\xA9\xD8\xFF^17K\x12\xAC\x9FM\x1E\x13\x89;\x90M\x8C\x8F\xD8\xC9\xDD\xCC\x10\x13\xA3A\x87\xD8\x84\xD5\xF3\x91\x93\xC7\xC2 \x13\x02\xB3\xC9\xAC\xD3\xCA\x00t&_\xE8\xA3\x1Az,\xF3\x09\xFD\x1A\x0C\xB3\x1C$\x0B\x879\xFA\xB9\x1DT\xC1\x04\xB9\x14nc\\x8E\xE0\xA6\xD4KT=\xBE\xBC0\x87\xFE\x85eh\xB6\xA7\xDE\xC1HC\xF5d6n\xBB\x11\xCB\xD7\xCA\xE96f\xCF\xAD\xD3EF\xD5c\x09hYLp\xE2\x0F\xD4\x9A1\x80\xEEd\xED\x8Fd\x8A\xEBS\x92`\x84\xE6E_]K\x18\x17\xE5\x09\x9EoR}\xF1\x9C\xFF\x1D\\xDFh\x92r\xAF\xD1\x9A\x92'\xAEx\xB6\xA8\x0F\x09l;\xEA\xF80N\xE1\x1A)\xBC\x84\xD9\xFE\x10\x8E\xEF\x1A\x15\xA3:\xD0;\xC3\xCAJ\xF8VA\xCB{\xA2\x82\x08\xA8\x83^HL\xCCp\xFB\xAE\x9D\xAA\x9E\xCD\xF2\xAA\x1Dd\xB1+\xAE\x06\xFE\xC6O\x99\xDF\x04?9:\x87\x83\x17\xE0\xDB\xF7 \xE1\x14\xE6\xB2X\xFFj2\x0F\xB4\x86\x12!\x0F\xD9\xA6p\x1B\xC5R`*\x99u\xE6\xCF\xEA\x8F\xA1\x02\xEA\x1D]5\xC5\xB8\xB6=\x14\xE4I9rP\xBD\x01\x8Eh\xD5\xB9\xE7\xA5\xF3\xB2\x08\x15\x16\x1A\x9E\x00d\x1AML\x99\xA4@\x18\xE8\x99Wq\x86\xA7\xEA\xEBs\x13\x95\x97&uV\xA9;\xACB\xB9\x1E\xA7\x0B\xF1:\x9D\x15.QW\x1C\x98\\xA1E0\xA72\xED\xDEk\xC9+\x02\xF7\x85\xEAu\xDE\xBF\xB0\x9C\x97\xBB|\x9A*\xBB\x10u\xE6\xE9\x18\x00!\xB4\xD8\x0DjQ~\xE9H\x9C\xBF\xFE\x8E\x07 &\xF5\xA5\xEF4j!\xF2\xBE\xD8\xD5\xC6\x99\xFC\x18d\xD6{\x85\xDBI\x0E?\xCE\xA9\x0Byx~\xADz\x0E*\x97\xA9\x9D6\xAC\xA5\x10\xCF)\x02.|zF\x99*\x8D\x9C\x1FY6{m\xE4\xB9?\x93\xF6sB\xF1\xF1a/y\xD4o\x98\x1D1\xBF\x8D,x\xDB\xFAQ\x90\x8F\xD5\x03h\xE6H\x91\xEE\xFEE\x8C*S(@1\x1B-\xCFS\xB8O\x0B\xBBSt\xEB\x97\xBC\F\xAB:\xDEJ7U.hl@\xD1\x19!\xC6\xD8W\xDC\xFA\xBEqd\xEB]=\xF6\x8B.\xBB\xB1\xCD%\xB4\x9F\xD2Y\x15\x9FW\x96:\xEDRN76K\xDA\xC8\x1B\xC4\xB6\xCF\xCB\xB1\x1DP\\x8EU\xF8\x9B\x03I],\xF3\xB8\x83\x89\xEFVa\xE1\x0Bw\x9Fx\x0D+\x9D\xE8\xFD\xF4\xA5\x04\xBC\x19\xCD\x13\xA4\xAD\x10\x0A6\xFE\xF9\xAA\x19\xCE\xEC\xF8\xB7\x08\x18\xF6\xF2\xA0A\xF1\xD2\x18o\x15\xAAgE\x9AK\x03\xCA]\xF3\x0BUFtw\x0A\x96\x8D\x12\x0A\x99\xF9\x0F\x96u\x0E\x10\xE8Y\x9B:\xAF/\x0F\x17s\xB5a\x9F\xBE\xBD\x9E\x94\xAC\xB7\x0B\x18\x15\x8B%uL\x96\x148\xB5.\xF8\xC84>\x91.\x15\x94\xA3\xD8\xE8\xD6A\x0F\x05b\xFD\xFB\x0F`o=#'\x7F~U\x80d\x95s\xE5cJ\x19\xE2Z\x17\x1B\x93\x96\xD7\xD0a\xA1\xCF`\x1CH\x92\x0D\xAB \xB5A\xF3\xA5\x0C{\xFC\xCDiqS\xD3\xB9]x1\xD3\x83\xA5\xA9"L\xF6M\xA9r\xEA\xBC\x9DE\x8Cs\xE0\x00a\xFB\xDEIH`\xE9w\xB8\x99\x05\x1D\xA98\xE1\xCD\xB0K\xF3\xF1\x9BT\x9DD\x0E{E\xEE\xEDG\x08\xF5\xD6q\xB3\xFD\x8B\xB4?\xEE\xFA\x90\xE0Hh\xD0>\xC2[(.H\xBC\xF3M\xC1\xB6\x99\x95Ro\x12\xCC:\xCDl\x06\x0A\xFD\xF4\xE1dX"\xE6"\x1C\xDBC\xECr\x9D\xB1L\xED\xE1\x84;8;\xF3Os\xCE\xE8\xEC\xF9\xD7\x9E\x97\xD0\xB5\x0C\x0C\xA6\x84\xA7\xC3\x132\xAA\x1B]\xC8b\xEF\x8B\xB3>\xE4\xD4\x9E\xAD\xD5~\xB3\xCD\xAB\x8DG\xF0\xFF\xFD\x09H;!R\xDD\x96M\xC2y\xE1\x9F\x1D\x8E\x95&i\x12V\x15s7j\xE7\xC7\x95\x1D\x803\x05P\xD1}\xEF\xEC\xCF\xD7z\xDB\x8D\x0B\x88\x17t\xBC\x1C\x96\xB7p\xE3\x0C\xB1\xEA\xF9\xA9\xD1\xAA\x06j\xEC\x9F\x13\xCCM\xE1\x06=q\xC0\xEA%\xC5\xFB\x96Vj\xF0S\xC1\xAF\xA3\x8B\xE6\x06V\xA1\xBE\x7F/&\xC1}\xC4\x16j`\x0C\x18\xF0\xFD\xFCN\xDC\xC6`\xE4\x7F\x1F\x93P\xD4\xD0\x0B\x92\xA9%C9\xEC\xEF\xA3\xD1\xD2\xEB\x84\xC8U\xE2\x06q\xEB\xB8\x0C8\xBBOj(4\x01@4\x05\xD8x\x12}dfl\x07\xCB\xDC\x82S\x87\xCC\x1Dlk>\xDD\xB8\xCF\x06\xEAS\\xF6\x96\"\x8C\x06|\xF80\xB1m\x8B\xCD\xC2\xFA\xA2`\x18|\xD6\x1E\xF9\xC1\xF4\xB3\xDF\x06\x8B\x07\xF0\x87\xCF\xA1t\xA3\x1F\xB4\xA0\xD6%F\xD5\xEB\x8B\x1F\xC7C\x81L\x07\x8AA\xEF\x1E\x1AKK\x87&\x0F\xE3p\x0Ei\xD75\xF7\x13r\x96\xA4.ZkI\xC9\xEA\x91r\xC5\xCB\xD6?\xCF\x91\x97sQ\xA61\x8E\xAC?r\xF5\x0BW\xEB\x0C\x9D\xED\xF2\xEA\xA6\xDB!@\xF1CX\xAES=&`\xF1\xD6\x92z\x136\xF4Z\xC0y\xF9\x1AU\xEF\xF4\xD9\xEF\xF7\xCC\xA0\xA2\x05gmd7A/\x13`\xC86a\xA4\x91\x12\xA8k\xEE\xC6$\xF3\xC3\xB2\x81c\x90\x19\xFD\x05*4@,p\xCF.\xCF\xF3\xC5\xBC \xAF\x0E\x0C\x1D\x12\xD1\xE32{\xB51\xB0"\xC3\xA5\xB7\xDF\xCB\xA5\x9Ac\x07\x03 9K\x90\xAF\x05P\xF9\xE2|\xB9\x0F*;\x81\xDB \x13-Md_\xAB2]o\xB3\xFF\x12G\xEB\xFD\xB1\xB9(\x15\x8C\xB0E\xD0_\x91\x0C\xC7v\x0C\xA26\x00\xB4\xD9\x0BP\xF3\x97\xCD\xF9\x19\xD7\xA9\x06t\xAB\xCD\xA2\x86\x93>\xF7\xFA0fsQa\xE61h\xE7Q\xA5\xCD\x86\xE1\x92\xC2\x0Dv\xC2d\x021\xAE\x11\x83c\x86\xB2\x1C\xBBN\xCF,\x0Bt:\x15\xA8%\xE4\xB514\x07\xA6a\xD2\x80c\xFC\xA4\x14D\x84\x01\xD0\xA4\x9Ff\x0A8/\xC6Qm\x99\xEC\x0A\x08\x09\xF9\xAF\xA7DB\xAB\xD0\x0FY^E\xC8\xB9\xC9oy\x80M\xB2\xBB.\xB9\xBD\x8D\xD2$\xB6#\xD4\xEB \x15\xAC\x06\x0C\xF6},>\xC0\x0E\x1F3\xEF\xB7\xE3\x9Ca\xD7fE\x85)\xF4h\x00x1\xE3\xF3\x9C\x0E\xC6C\xA1\x91g\x10\xC6\xFFM\x88\xEC\xC6\x00\x9Be\xCF\xA4\xAD\xD1\xA9kh\x1C\x92Z`<\xF7a\xD9\xB4\xA5g\xE4\xC5\xDB\xEE\xEF\xDA\xFB\x00?\xCE\x19T\xC0>"\xA8\xA2L!$J\xC9U\x97>\xC0]\xB1\xC7Pv\xF4\x9A\xABs\x0D\x85\x13\x8A~\x8D\xC3F+%\xCC\x96\x8A\x1E\x1C\xF4\xE52\xE1C\x86|@\x80\xE9\xC4\x9D\x83b\xEC\xA4\xA3\xE0&\xC06\x90\x8FB9T\xB7d\x11ql\x13\xDD\x16\xC9\xB1\x93tt\x82\xF12(\xB1|+\xDB6\xB7\xBC5%\x9B$\x04\xDE4\xF32SRI)\xA4V\x94\x9B\x17\xA9\x11\xB2\xEC\x84K(\xD2\xA7\xCC\x93q\x9D\xA6\x8D7.\xCC\x0Da\x92\x00\x19\x9A\xDFA8\xC5p0<\x7F\x0D\xF0:\xCE\xBF\x04\xBA\xF6\xFEE)\x02X\xDA\xC8\x84D@\x83r\xAF\xC6\xF5\xCF\xFDK\xC7\x13\xAC-*\xFF\x8C\x0Bg\x16\xB4\xC4\xBE\x8D\x12\x9Ca\x0F\x0FFR\xF1j\xD8\xCF!dd\xF7\xCDD\x9Fc`\xE1\xC6\x8C\xD4s>I\xFF+\x04\x83\xF0\x10Z\x923\xD2\x0CH6S\x12d\xFF\x9BO\xD4*z8\x1E\x1A1\xA6\xBD\xCCg\xC8\xA7l\xBC\xD2\x8C\x15\x02\x0C\x8D%\x07\x04.I\xBC\x12\xB6\xA2\x02\xCE\x01\xBC\xE0U\xC0I2n\xA3e\x80\xCD\x84\x01\x8AO\xBA^\xE0\xC3\x9B\xE2F7p\x17\x1C\x1D\xD2\xBF\x0D}:\x97\x19\xFA\x0F\x0F\x1D2\xDC\xAE\x0F\xD66.K1\xB0\x9C\xB8\x95\x8Dk\xF2e\xB5?S\x1D{.\x11\xCBTN\x08l$\xD2x\xFC\xB75\x05N\x11\xB9WB\x98\xA1d\x1A\xD3f\x18\x80\x01\xB3^ \xDB\x84s|i_\xE9\xB9\xCA\x9A\xEAH\x03\x86\xF3\x07\x9D\x83d\xDF/\xFD\xC4\xEF\xAA9]/\xA8g\xCE\xD9\xC3'\x8C'J\x13\xEF.\xFA?\x1C\x86\xA1\x09\x88\xB4`\x8E\xE0y&\xBC\x976^jwL\x0F\x88\xC3\x1E\x7F\xF2-\xB8GDF\xDEXaY\x9C\xF7P\xB4l9}\xC6\x18\xCCD+\x14\x8D]zfA\xC7[h/\xD8c\xF0H\xC7Y"\xD0\ka&\x0E\xDF.C\x1E\x1C\xD3\x0F\xAB52\x8B\xC0\x99@P\xC5\xBAV\xC0 o\xE00q\x88\x141\xB2q#\x15M2WQ\xB5GY\xCE\x15\x0A=\xCC2HP\x87\xADU*g#\xA9r\x95\xF2F\x12\xE9\x86\xF0"L\xB2\x83-\xF7\x0D\xD9kp\x0F?g`\x00\x94Anx\xC0J\xB3\xA0\x84\xE0\xC5\x03\xD4A\xC6;\x13\x13\x9F\xCAbX \x96b_\xD9\xDB\x99\xE3\x80\xFFlq\x9B{\xFF\xC0.\x1E\x8D;!\x9B:\x08\xCCF-\x9D\xA7\xB5\x90c9\x03\x85\x9F\xA5-\xBCl,\xE3\x0EtV1K\xBB\x8E\xE5\xEC\xE5\xBC'[\x91\x17\xC3\xD7\xDF\x0F\xB5\x83@\xE8C^(\xB9\xD4\xA2\xBF\xD3\x94#\x8F\x0AbG\x0Ct\x89\xB4\x17[\x0A\x1AK\xD4h\xA6\xE8\xACj\xA0\xC1T\xC0"\x0C\x1E@}\x1C\x16gQ=\x89\x19\xEA\xAA\xBB\x11\xD9\\xB1\xC6\x9Ej@\xDFR>i\xCF\x81 \x01+\xC6\xF02\xED\xC6\xC9\x8D3\xD1\xAE\x1C\x12\xB2._1\xA0\x14\xFF\xA6\xC4f\xC1\x9AiX\xFF,\x00x2d?\x8E)\x1E\xD5\x8F\xAC\xB5XCj\x7FWX\xE5'\xFC\xF2\xF3\xCBzx\x08\xB9\xF7$\x84\xA4\xA6I\xE91!4\xD5q<;\xA8\xB4\x1D\x13%c\xD5\x88b0+\x7F\xE6\xE2\xD6 G\x8Du\x82\xC1\x0B\xEE\xF8i\xCE\xF7D\xC96\x8B\x1Ew\xCE\xF6j\x90\xD5\x84E\x09\xA0\xC8\x95Z\xFC\x0A\xA1s\xCE-\xC6`+\xE3LU\x8F\x19\xB2\xC7\x93\xD6\x8E\xDC\xF5\xA6D\xD2\xEB\x06\xBAJ\x16`\xE4\xD7\xBCO*\xE8`\xFAw\xCBl\x98\xDB\\x87yyy\xFC\xC9\xD7\xB7,\x17\xC9x\x90\xC1\x04\xDA\xED\xF5ob3Qf\xD4\x0Bd\xF5\xE5\xC3\x1C\x83S\x89\xEB\xD2\x17:f\xEE\xCEj\xC0\x0A\xBB\xB8\xC7\xEA\x88\xEB\x06\x12\xC4\x07\xCD8\x9E\x1C\x1D\x7F\xCD\x17\xACm\xB7\xD8O\xCBk\x9Aq#\x1C\x8E\xC3[}\xA1\xFAG1\xEA\xDF.\xE7'\xACd\xB3<\x18M^p\x8D\xB2)F\xC8!-\xDB\xA8\x19Xd\x81\xEB\x1ABY"\xCD\x80\xFA\xF2\xD5\xA17\xDE\xB7\x186\x7F\x96\xEA/\x0C\x9A\xFA\xB5\xC5\xD8\xCD\x8C-\xAF=I\SU\x94\x93\xECO<{\x9B\x8F\xC34\x00\x13\x87\xB1\x17\xB9\x82\x8C\xD4\xAD\xA4&,\x8C\x7F\x0DCG\xF3*\xCC\xE1\x15\x01- \xCFJ\xCA\x13\x1B\x09\x19\xC6 3\xA7\xB4\x1C\x17\xF1,\xF6\xF8\xAA\xBC\xA3\x8F\xA7\xB5{|\x8CRA=\xC8Pn\x9F\xF8e\xBFaAW1\x10\xB0|\x95\x15\xE20\x08\x09\x1B\xE7\xAFUe\xBF\xE8\xA2\x7F\x1Fn\xAA\x05\x96\x83\xDF=\xEFK\xFE\xEA\x98:\xCB\xC0'\xB2D\xE9\x84\xCEs\x0A\xD9'\xE3xg\x05\xCA\xF7\x05_F\xC3\x07\xAD\xAE\xB7v\x91\xE3:\xFD\x9Et\x0A\x84G\xEB\x1F}\x1B\xC1E\x1A\xAE&\xD2\x17\xBB\x03'\xD17\xDB\xF2\x7F\x86n\x06^::\x8DX\xEA\xCA\xE4\xE7\xF3E\xEF\xBC\x10\xE9`q_\x1B\xD7\x0B\x14[\xA7\xB23q\x19I\xD0\x12\xD0\xED\x09B\xF1s\x801G\x92\x12u\x99MrC1xj\x13\xE0\x8A0\xAC\xF3*\x9E\x82\xD1\x1CM9>\xB2\x08\x8C\xA8o\x9B\x96R\x9B\x8A\xC4\xB0\x04\xD6\xBCU@Uq\xBA\xF2\xB8\xBE\xEC\x81\xD0aGr\xF1f}\xE7/\xE6\xAA\xF5\xC3\xD4\xC8t[\xB7\x9C:\xE9r\xAA\x07\xA3\x11$\x92\x96\x87U\xCF5\xB7\xBE\x1C>%?\xF6ec <-\xB7\x8D\xFA\x08\xDB\x19\xD1F\x06\xD3\xFC\xCBjTS\xFD\x85W\x93\x97\xFB\x0B:\xE0{7\x00\xDE\xB2\xEA\xD7\x9E\x8B,\x13I\x09\xB6\x89\x97\x85\xB8\x13\xB9us6\x10\xE7\xFD\xDE4Y\x17q\xF0\xEB\xA0|,\x8A\x1A_\xD6\x17T\xE0\x94hW\xAC\xF6\xD2\x03\xEA5\xC5\x1C\x9C\xAAz\xB9\x0Cfla\x80k\xA3\xB7\xE4\xA2=w\xDB\x8A\xDBV\x7F\x7F.\xB4\xFD\xD4\xC9\xA3\xBB\x0A\xCF\xE1_\x18\x8B\xDD\x08\xCF\xF2y\x1C\xBE\x18\x95\xA1\xE0\xE7~\xBA\x11\xA2`|\x8F<^\xD9\x05\xA9\xBE\xC4\xD4\xD7\x83A\x18)\xAA;\xFD\xE62\xD7\x19W\x14\x9E\xE1\xA4\xAA\xD9C\xCB4p\x87\x04\xA0\x0B\x92\x9Do\xCD\x84\xAD\xAFi\xCDi\xEF\xD6=\x84&/B@\xFA \x11\x0BO\xBD\xEC\xD23\xC8:h\\xFC\xEDL<\x8Bi\xD1\x9F%\x1B\xC1\xBA-.\xA8\x03\x06\xEA#\xB3\x0B\xA7\x94_\xADM\x09[O7V+\x9D'\xD8E\xA1\xB0-\xF2G\x91\x0E\x08P_\x03\xBF\x95\xD3\xBD*\xFFU\xBD\x19\x8A\xECw\xC3\xD7\xC5a(\xBA\xF3:\x122x\xF1\xAA\xE7e!v\xFE\xDF)\xE7\xA4\xC8\xE0\xAA\xEC\xEF\x86\xC1a\xEBV\xE4V\x82>C\xC1#\xBD\xD2\x0F=\x0F9E\xBD>18\xC1\x12}\xA2\xB9\xF1\x09t?\xF6mQ\x11\x95\xA5W\xA1H \xF3\xC1\x81\xFA>\xBB\xC0\x8A\x9BR\x9E\xAD\xAB\xB5\x9B\4\xD6j)i\xC4\x94\xE5\x02\x9DVB\xAC\xE9\xFD\x88\x9F\x01\xF9$\xC5:\xFD1O\x8D\xED1\x94\x17\x035\xFA\xC4Y\xC4\x1A\xB3\xEE\x8AY\xF1q\xFB\x89\x9C\x7FlO\x83mL\xFE\xC7\x06\x99-J\xCC1\xCE\xC7n\x11\x87V\xE0\x8D4/\x15Y \xED\xF0\x99x\xE1\x14p\xFE\xC6yP\xF2\xC3\xDFF\xAE$Px,(eq\xD3\xCD\xB3\x9FV<\x1F\xF0\xCAF\x91\xC1\xBF\xCE\xA7\x0F\xC6\x08\x8C\xCCd\x8E\xCE3h\xD8\x81"X\xEAT\xF1\xA9\x1E\x9D8\xBCG\xA4\xB1\x9B\x95G\x13<\xD2DN\x9C.j>\x99\xC8\xDF--g\xDCi\xC5\x8B\x0B\x83\xD0P\xFB\xCA\x8B\x7FB\xED\xC0\xC9\xB9\x1F\xC6\x11\xA0\xF6\x07\xE0\xAB|\x05\xD5`M}\x0C\xD2>\x87\x1E>6\xF0\x8C?[\xAAe\x1A\x1D;\xB5\xC2)\x95U\x8Ek\xECZ9}l\xC5eyD\xABG\xB3\x0Bn\x05\x91}6n.,-P2\x9E\xEF\xEF\xB8G2\x8B\x08\xCF\x1A\xD6k\x1B\xDEE\xFC\x13O\x135\x0B\xA6]x#\xDC\xA3\xC8\xBCz\x8E\xF1\xFF\xCE\x04\xFC{s3\x128\xF2\x94\x10C2\x1B(J\x8E\x84\x984a\xA4\xA8r\xB6\x8A;\x98\x11\x81_\xA5hx\xFB!;\xC96\x11\xC8[\x86\xA7\xA2F\x0B\xDA\x16\xDA\xF2_l!\xBE\xD7\xE2\xE5\xC4\xEF\xCF[=A\x8C\xF4\x9B\xF1\xE4\xB4\x9E#\xC5fA \xB5\xE94\xA5s\xCADR\x9Az\xCD\x19\x87\x0B\xBD\xD3\x1EP\x95\xD5t\xD7p\xAE\x80\xFC\x8C\x17`\xC6e\xA2Pk\x89\x99$\xFC\xF4[\xBB;\x8C\xE3\x8Fd\xD5\xFC\xA2\x19W\x8Az\xB5^#\xA1\xD1\x8F\x97`\xDEm\xCFf\xF9&\x05x\x8D\x1A\+V\x09\x19\xCB\xEE\xA6\x0E\x8Dt\x04\x0Bi\xD3\x0D\x00Q\x04Ay\xA4\xE5 B\xF9\xFFY\xD2/\x8E\x97\xF2o\x9E\xF5\xFB\xB4\xBB\x90-a\xA1m=>\xAD,\x02:\x8C\x96\x0D,g\xD9\x13\xB6\xB3\xA1\x9D\xE1\x82\x03\xEB\x0FJ|`mq\xE6\x01o\xE6}c\xFDq\x82\x14n\x03\xC3\xFA\xB4\xC4\x1BT\x9C\x8A\xC4\xD7,\xE4e*$y\xABt\xF0\xC8n\x82|\x0D\x18\xFA\xF2\x81\xD1M\xCD'\xA6A\xF5\xB0|l\xB6\xC1\xF4eV\x9F\xC0\xA9!\xA8l\xDC\xDC\x102 W\xE1\x02\xE7=\xF5\x89\xF9\xB6Y\xCDPZ\xB1\xD7\xAA\xFD\xD5\x04r\x95\x94jG\x03=\x0D$\xC7\xA8\x98-\x18\xB5\xE5\xC7\xB2\x17L\x14\x8F!\x04G\x0A\xA4\xD5k\xE7\x0B\xAC\a\x18:yI\x00W\xCBX\x88\xD9\x9A\xEA\xDCTt6\xE5:\xE6\xA4\xA8t\xC7\xC79\xC3\x9F\xF1\xE9\xDA\x03]s\x7F)=\x9C8k?\xB8\xB8a\x092\xEE\x04}\x92\x1E\xA52\xD6\x95:\x7F\x91\x85\xF1\xB2\x05WH\x81\xD07\xCDT(\x0A\xA9\x0D\x0F\x1B4y\x95\x9D\xDEM\x87\x19b\x8E\x95\xCAt\xE9]a\x18\xF6X\x9E\xF8\xB6y\xBC\x01\x9B\x86\x1A%\x969\x04\xA5\xAF2\xA7\xA2\x82"{\x17\x0B8Y\x0C!\xF9\x86\xC0\xACZ\x9B\xC5y\xF2\x0Fb\xEF\x8Ce\x03\xEA\xD0=\x1B(P-i\x8E/z'\xA8\x1B\xEBV6P\x17\xE9\xB8\x0ED\x8B[\x19\xCD\xC7<\x8D\xEC\x93\x8D/\xFA\xAF\xF7}\xFF\xEB!NM\x8B\xFD+\x1F\xE2\x9CM\xBBw>*\x101\xF7p\x80jH\xB1\xEBoa\xF5\xEF\xF4\9V\xBA\xC3\x04\x13U\xC4h(]\xBEb \x183\x99\xFB\xAC\xC2\x9C\xB8f\x1Ft\xE0\xCE\xD3\x85\x1E\xFF"x}Y\xCE8j\xC7\x91j\xBC\xA7l\x05\x85\xDE6\xF9Xt\xDC\xEA\xA6\xE6\xFA%\xE0\x05|\x87\xA2U\xFC$O\xE0\xA0\xB8\x9A\x97'\xD9Q`\xD4/U\xFFD\x1EtD\x86\xC5O\x8E\x97h>+=e\x9A6\xC8\x99}\x97\xA8\xB2M\x1C>\xF4\xAE\x8B\xA2\xDB\xD6-\xA4\x8D\x04m\x92AK\x0D/\xB5\x83\x18\xF2\xCF\x1A\xE4\xD0(\xAEhq;\xD6j\xC3\x0B\xC8/\x09\x8D\xE6s\x1E\x02p\x06\xC4\x94\x15\xF8|\xD6\xB3D\xF273\xEBu\x94c&\x1A\xCC\x09\xA5(\x05\xEE\xFB/\xC8\xC3\x94\xF0\xEA\xDC\xBD\x05\x97\xEFJzm\xE40tV\x02\x97a\x97\xB8\xF6`\xBF\xA8\xF9|\xDBLXg\x97\xEDL\x11\xEA\x14!fIO8\xC5l#a\xEF\xA5\xDA\x01]^\xEAj\xFB\xD6V\x19\xC4\x1B\xBAv%\x05\x0F\x01iV7\x94\xFBL\xE0$\xFD\x9A\xAD\x1B%\xE5vv\x12\x09\xB3\x0D\x15\xB5#",f\xD3>n\xA5\xFB\xADR\xBA;[-f\x14\xF3\xB4\x15uhd\x98>\x13\x92-tr\x9Ec\xA3C\x85\xF2l/\xC8\x0A\xBC+GUDab\x02D\x00\x00\xCB\xF7\x0A\xF3\x85\x9A\xE18Q1\x0F\x8E\xCD\x96\x9D\xA3\x08P\x8FIP\xAA\x15\xE4\x99\xC0\xA7\xC1\xAC^u\x08\xFFepB8Y\xD3\xAEtZkSC$\x1B"\x87I\x87\x9A\x92\x9E\xE9\x97\xAD_\x87\x83\x99+\xCD\x8F\xCB\x18\xCC\xBC\x7F#X\x0C\x85fm\x84\xF9\x9FLS_\x88\xFF\x01q+0\x1D\xEB\xD2,N\x1D\x1A\xB2\xB4\x98X\xDC\x83\xEE\x00}\xDC\xEA=\xD1;\x88\xE4\x81\x0B\x17LZ\xB4\x94\xEA\xBF\x96b`\xFB:2\xA2\x95\xDB\xA7s\x11p\\xEC\xC7\x9C\xFAt\x11\xB7j;\xA7UI\xE3e\xA4"\xD9m\x8FTE\xBFm\xF84\xA3!\x8B$\x11\xFCdxA\x90\x83VM\x81\x81\xD5\xA6\x12 \xFA\x1F\x08I\xC4\xBCW\xB9\xE8\xD9\x99/\xBD\xF0S\xADH\xD0\x8D\xE5\x83^7D\xBE\xF5\xDF\x90\xD3P\xF9\xE08$\x9C\xBB\xC5]<\xBB\xDD\xD1l\xBE\xAF\x0E\xFF\xC7\xE6\xBC\xBB\x83\xFE\xBB\x82t\xC3JE\xC0\xDE\x0Bk_2\xE0q,\xD0\x93\xD88\xB6\xF0\x980\xACY\xCDj\x85\xB2\xC1#\xBD\xDE\xE2:3\xF4C\x1DQ\xD0\x17\x84\xA2\xE6\xBD\xD5K\xCCWD\xA5\xD8%2\xAD\xAF\x14x\xD1\xB2Vs^i\xAB2\xDB>\xDE\x17\xEE/z\xCF\xFC\xFB\xAC\xF4\xC2\xFE\xD1\xA4\xF1;\xC0\x17\xC9j&\xAA\x94\x9Cy_?z\xDC\xEE\xA3\xC8\x12\x02+l\xCA\xD1J\xB6\xBFJ\x9E\xA5\x0ES8 \xFDT\x82\xC3\xAE\x0B\xFCZ\x98\x9D\x7F#Is{\xA57\x96\x07\xDD%\xAFZ\xCA\x8D\x9B\xF1a\xE2\x01\x7FW\xE8\x04\xA8\xFC2z.G\xAA#\x16/>\xB8\x0FG\x0Cov*N\xA3=`\x1B2X\x9C\x0B\x8F\x16\x19\xC1d\xC6\xFA\x87-3\xB6s\xAB\xF5\xA0@*Y\xB1i\x8EU\x1A\x92{\x16\x09\x1CZ\xE1\xB4\xEA\x94M\xE4zX')\xED)(\xED-6A\xA97+\xF5\xC5\x1F\xD6\xF6\xF4'\x1880\x98\xE6\x0C\x94\xB2\xDB\xF2\x16t\xE5b\xCEQ\xCA\xC8\xF5;\x86\x90\xF8Y\x8EP\xB0\xDD\x908\xC2\x7F\xF1\x93!k\xAA\xD7\xAE\xB6\xE3\xA7\xE1\xD6\xB5\x7F2-BD\x0Dj\xA2D\xA8\x82\x1D\xA2\xBC\xFA\xE7-\xE1\xD9\x8Dx\xFF\xF8\xFF\xD7\xCFK]\x03\x84D\x96\xA38<\x12d\xA7rV\xEC(&\x14\xB5#\x94mW\xBC\xBC\x0C\xA0AMCj7I\xB2\x83\xFA\xBD\xFBSNi\x92\x02@)\xB0\xB8\xE8\xFB\xA3\x83\x95\xBB\x95k\x9C\xBA\x9F\x8E\x97\x8BW\xED\xE4\x97{Q\x888yF\xD2\x1Do\xD1t\xB8\x84\x01\xA4\x95o\xA1\x8Ca6\xAF\xDBV\x0CAH>\x1F\x0F\x1Bf\x07\xD2\xC6\xEFK\xC1T>'p!\xD6\xE9\xD9\x91\x89\x11v\xB4=\x0E\xDE\xFB\xBF++i\x96\x05)q\x85\xD8\x09%R\xCF\x8BS\x1D\x8F\xD2w\xAD\xBA\xB4\xDE\x88\x95G\xEC6=\xA3`\x82k\x86\x86#w\xAC\x032&\xCF\x00X\x07oS\xC2N\xF7N\x84\x17\x19'\xB8\xFD\x14\xB1\xB3\xC6\xA1\xB0MN\xF0\x96\xE1e\x9F\x95\x01Z\xCC\xC30\x19Fy\xFD_\xEE!\xCE\xE1f\xE4\xE3\xBC@\xF8\xCA\x11\x0D\x1Fe\xE8XT\xBD\xC4(\xB5\x01\x94R\xAEt\xD0\x9E\x04\xE2\x93/ytA\xAB\xFD\xB6<\x0B\xC5\x84l\xD1\x1FYdAT\xD8\x0D-5\x1C'\xFC9u\x18\xEAMl\x0CA\xB8\x99!\x85\xEE\xEDX\xDD\x029\x85LH7\x7FJy\xE7\xBE\xFA\x8D\xB1\x17\x1F>\xD9\x85<*J\xC4\xAD\x89\x00\xB1\x196\x9D\xE2bn\xA2\xF1\x95^s\x0B\x13\x98\xFF\xD8\x06\xF7\xF8\xA2\x0F@m\xCD\x9E\xD6\xF6\x04Lc\x8F\xE4\x18\x00\x06\x1Eu\x97j\xA9W\xD9jnfi\x05_\xB9K\x1E\xB42\x99\xF3I\xEE\xCC\x9D\xED\xD3\xDC\x1C\xF0\xD19 E\xD5E\xCB\x886R\x8A \xBB#\xBF\xDEI\x0DFq\xE0\\xCByM$\x82\xF2\xC5\xD2\xCE\xD2W\x85\xF5\x04\xB7\xCA`\xCE\xCA\xAC\xCA0\x01V7\xE0\xAB\x13\x98\xAF\x16(x}$_\xFA\\xA1\x8F\xDB\xC8\xB5\xBC$\xFA\x1A\x09p\xA0(\xF4q\xC0\xC0\xDD\xB9x\x8B\xBF1y\xFBDp\x9C\xB1\xC8j\xC5jui\xD43\xF7i=\xF9>\xB2\x85\xF80\xC2\x84\x88\x125\xBAY\xBFh\x8D/\xCC\x19\xC1)\xC4\x0A\x9D\x82\xE1\x9E@\xABB\xD3\xD6;\xD9/\xEA\x1F\xBA\x86H\xAC\x802?i\xB9\x17\xDF\xF0\xAD\x8A\xF9h\xAF\xAB\xA9\xCBD\xB1\x15\xEB\x82^@\x89\xDC\xD2\xA0\xF9\xC1>gS\xCD\xEB\xA5\x1Am\xC6\x14\x0D\xCDr\xF62;*~!\xAA\xE7\xA2,)\x19\xED\xDE\xAC Y\x1E"\xFAT\xD7\x9D9\x0D\x19\x1D_\x08\xA4\x95\x92\x8F\x03[\xAD\x0A\x1F%\x12\xFB\x97\xB5~\xC1\xFB=\xFA.\xBD\xA7\xDB\x15r\x9C;\x9B\xA6T\xCBH\xBA\xB9C>o.X\x0C5\xE3\xECw\xD84\xBF\x95\x9A\xF6X\x1C\x84b\x9A\xC2<\xF4\xA1\xFA\xF8YB\x99\x9B\xFD\xE4\xA0\x13\x86\x9E\x97\x10\xD9B2\xC1+\xCB\xB5|\xD0\xBD\x82\x18\xB8I\x0B~\xDEq\xD5\xA5\xDFKo\x0D>m\xF9\x17\xE6\xFD\x93QFi\x89\x01\xA3~cD\x7Fo\xA4\x1F>&\xB0H\x1B\xF8_\x1F\xC7ywQ\x1A\x05\xAD=(w<\x91\x89\xDA\xA0\xE9D\x09R\x1F\xA8\xB3+\xD7\x9C#\x06jo]\xCC@\x06\xA4\x0D\xF8\xEBI\xC8\x80\x1F\xC7\xA1\xB8\xFEK\xDF>\xBF\xBD+At\xE6\xA3=\xFC}y\xA8\x81\xFA\xD6\xEA\x01\x02\xC6\x82\xF6\xC7wH\xDF\x06&\xA7\xE1\x97q \xDB\xC6\x0B.\x08\xB3\xFC\xCA\xBD\x9F\x04R\xB1\x199\xB0\xEF\xD4\xE8\xD6\xF8L\x8D'\x88\x0E\x03)o9\xC4\xFB\xFC\xDC\x03\xD5\xA9\xB6\x0A\xB9\x84B\xBA\x1A\xC0N6\x92\x10w\xED\x7F\x8A\xEF\xFF,\xBC\xAF\xC2=\xBE\xE6\x0B\x91\xFE\xFA\x97z\x9F\x87\x05\xDC\xCE\xD0AKi\xED\x14\xCD\xD6\x8B\x04\xC2\xEE\x0Ah\xC4\x1C\x9F\xC4\xAE\x0B\x09\xBF\x07\x95=@s\x11p\x0A\x0B\xA0\xB3R?@q\x9B\xB4H\xBD\x90|G\xFA\x86&t\xAE\xBD\xF5qq\x1A\x13\xB5\x8C\xEA\xADx,\x97\x18\x02f;4p\xDA\x97\xA02\xEB\xA7\xDCQ\x11\xBBYl\xCB4sG\xAD\x9A&\xA7jv\x0Ed\xA4\x13[[\xDE]g7\x1C[\xE9\xF9\xF0\x94\xDF\x16,\x8D\xC2\xF5\x10\x04\xF5\x9C\xCA\x84\xBA\xBDH9\x98\x9E\xE3D\xC5\xDD\x1B\xAD\x847\xBB;\xF4"/U\xA592&D\xBF\x1B\xDE\x8C\x962_\xA0\xDF\x0D{h\x00\x91\xD6\x8E\x90l7e\xF5\xA2\x10P\xDC\xD5\x1D\x93\xCD\x15\xD4\xF0a\xBC\xC5\xB6\x98|ugX\x0F\xFA\x80t\xBF\xDBl\xB6N\x96\x1D"\x0B\xB8\xE1 \x86\xD3E\xDE(\x8AJ"\x14\x90\xCF\x83\xC2U\xD1\xA0\x98db\xFDS \x13\x88\x11\x9B\xB8\xCB\xE8}\xF1\xEC\xBD\xEFw\xC1S\xB7\x1C6\xE9\xC6f\x1A\xA2\xC9\xF8\x1A\xDA\x09\xF8\xC4\x1D\\xC1\x85\xBB\x1D\x18\xDDs\xEDuE \x19\xED\xF3\xF3\xE57=\xB1\x91\xA0K\xA3\x8D\xCE\xDA]\xCC+\xAD\x94\xAF\xA24\x19B\x0CQ\xB2\xA4\xE7=4\xEA\x0B\x17\xA4U\xF7i\xAD\xADr\xC5\x0F\xBE\x80\xE36\x8B\x92$\x95\xD7\xBA\xE43\xE2\xE7\xD6j\x02k\xE6\xA3\xA92\xEC\xAF\x0Dv!\x0B\xBD\xFD\xAE\x0C\x19\x9DD\xDBZ\xEB\xB0\xF9SY|\xDB\xF8\xB6A\x8B\x1B\xEF \xDE\xB4\xDC\x15\x97\x0A:\x1F.\xF67=\x94{\xB8\x8A\x02\x0B\x1Cw\xE56\xDCKv\xD4\xBB\xC0Js\xB8\x9B)9\xCA{\x90ns\x86\xEE\xED\xC9\x0EU 7\x10\x9F\xD6b5\xA6\xDChd\xBF\xCE\xA9\xAE\xD61m\xBD\x97rR`\xFD}Y\x03\xFE\xAA\x14\xB1f\xF4$\x8A\xB6[\xCC\x99f\xFBcll\xF3*\x0C\xD9\xFB\x9B\xCDU0\xDD\x9EZ6\xA3g\xC6F\xA8B\xAD\\xAD8\xCD\xF8\xBF\xE8dm\xF8\x83\x09\xB1Y\xCAcu2\xAD\xCA\xA5j:\xAB!\x0EW\xCF\x0B\xCD\xE5\x1E\x86\xA5\xA7V\xEDp\xF3\xE7\xC3\x989\xBD\xBEH\xE5\x0A\x8A\x07\x1F\x83\xFF\x0A<6\xDE\xDC\x03}\xF5\xFD\x02U\xED\x02\xFFM\xE2m^l~t\x8E\xE6E|N7CP\xA0.Qb\xE1\xB13R\xFB9]g[\x13-]\xE3WB\x158\xC4\xF6\x04\x0B\xC7\x8Al\xA7\xFCL+\xD1.\x18,\x1B6\xD88\x02^Qn\xEB\xAE\xAEu\xE6\x0F\x93\x1B\xDF"\xB0\x83\xE3\xAA\xC3\x05\xCC\xFBH\x17m{\xBC\xB6[\x908]\x01d\x8A(\x9D~\x8A\xAC\x87c\xD3\x079O\xBCp,A\x8A)-\x1C\xB6x\xD3\xDC/a\xB5\xD2\xB0\x11\x02A3\xE0\xCA\xBF\xC1\x88\xC4\x1C\xBD\xB48vW\x0E\x1F\x16W+\xFB%\x83\x17 \xBF\x09#I8\xA3\xA9:\xEE\xC1\x95\x91\x98\xFE49\xFE\xA9\xD3\xB4W\xB0\xE4ma\xC3T \x87Y\xA0\xD3\x1FD\x06\x05\xB9\xC4\xFF*x\xEDy\xF3!2\xFC\xD0\x12\xC7g\x8E\xC7\x0F?\xA9\x9A\xE1b\x0B\xCDL#\x0CX\x0C\xA7\xB2\xE6\xC7\xF0\xC8$gr\xCA\xA3\xBB\xD4\x06\x133H'\xBD7\xAB\xB3\x85\xD9\x04J\x9D\xE2\x94M\xC5\xF0\xB7U\xEDG\xDC\xBC\x82\\x9C\x8Al?\xD2\xB5\x01\x9F\xA0(k\xDF~F\xA9\x18_\xF36VK\xDA\x92\x12~\xDA\xD0v(\xAEs\xF0\xC4\xD4\xEE\xF6\xB0yb\x0Ap\x99\x19\xA7M\x86a\xD4\x8C\xE2\xC6\x91\x85\x9B%\xE9S\x14B\x9B\xBF\x9F\x83\xC9\xEF\xD8\x0E\x0FK\x9F\xAB>\x0CE\xBC\xBBu\xA7\x00O\x17\xC1\x18\x97\xE1\x99\xEC\x92%\x0C\xA5\xDB\x8D\\x1F\x8C\xD1\x88\xC9\x9C&\xA5\xD5\xBF\x9Bq\x7F\xA7\x93\xA2\xAFM\x81\xE1n\xF8\xE3\x05\x98\xA5\xF5\x9E"-\x03\xF4{\x97W\x9A\x9F\xCB\xE8K*\x02\x98\xE6\xC4y\x0C\xF9\x00q\xC0\xE9\x8A\x91t\xD0\xF8\xEDYl\xDF~\x96FA\xA4\x1EZn,\xD96\xB5\xD7TCK\x86\x86\x89g\xAE\xBAM1\xE8`\xD3\x0A\x96\xFB\x14\xB2b@\xA2I\xF4\xF9M\xA0vi\x1C\xF81q\xA5yxmt\x03\xFD\xCD\x99\xB1z\xD6\x89\xEB\xB5\x18\xC9\xF2\x85\xFEn\x08\x9Bn\xA7\xDF\xA0\xAA\x86\xC4\x86h\x9F\x09]o\x10wdJ\x8D=\xCA\xECX\xBFj\x02'>FP\xEBi\x06:\x86\xB4\xF1\xD1#]a\x04\x7F\x89\x91\x00\xEF\xB5\x00\xF5\x04\x19\x1E\x19h\xC7,\x9EiE\x8F\xBB\xF8=X\xC9\x0A\xB9\x8B\xB9\xA6@\xEB\xE5\xE3p>\xD7\xF0\xFF9\x87\xB5\xEC\xD3\xB9\x09*D\xE7\xE6\x05\xF8J\xF8\x7FP\xBE8M\x04_7@\x82\xFF\xA5\xC1\x1Dojzd,\xB6\xC5\x90\x8D\xB3/\xEAi\xDE\x01\xC7\x09\xB7\x0D\x81q\xA9\xF4\xC6gs\xC3\xC3\x18\x0Co\xD5\x87X\x197\x06\xDB\x8B\xCD8\x87\xF6\xDA\xC6\x97T\x1E\x89j\x9FCl\x0E\xC8b\x96\xFE[\xCFMR\x05\x1A\xA3\xA4\xCA\x0D\xA8\xDF\xF8\x08\xC3j\xDE\xD95\xD1\xBB\x11`\xBD\x12s\xEE\x83\xA4bU\xA3\x0A\xE5\x8D\x80K#\x88y\x15\xB7\x9BaZ`\x19\xB1/\xF1\xFE}\xF0\xD1\xA5\xEBZ9h\xB3\x02\xFC5\x03\xD8\xED\x1C\x91\xD9\xB9\xC4\xA7\x9F\xA1\xDC\xAA\xA8o\x8CR\xBE\x03\xFF\xD4\xE8ix\xEF\xA7[\x02\xC6\x9F\xB3e\xD7\xA2\xEF\x12\xE7\xDCI#\x1AK\x9A\L\xBC N\xB5\x8B\x9D*\xAF\xDD\xC3x\xBD\x96N\x17'b\x12>\xC1E\xE7\xDA\x14\x85\xF4;Z\xDD\xEF\x7F\x88\xAC\x80\xF9\x05\xA9\xCE\x056-\xCDK\x91|\x04\xB4\x16$\xA8\xB8\xAAv\x06\xB3\xF2\xD2\x8E\xE2$c\xBD\x9E\x8D\xA0\xC9\x08 \xDCA(\xE2t\x99\x1AJ\x1F\xD8\x1D\x0CN\xE5\xF2\xB6\x01\xDD2\x05\xC4\xD9\xB2\x0E\xC2P\x85\x80\x9D\x8E[\x06\xC9\xAE\xC3\xC9|V\x12\xD7l.I\xE8j\xC7\xAE\xC2A\x87\xBE3\x14\x05\x8C8*\x1F\xF5V\x1B^\xB7\xEB\xA1=\x15?\xCE\xBB\xE4\xB3\x03ja\xF8\x1F\xF0\xD2t\xF8\x95\x13\xCF\x0F\xBB\x11\x14Z}#\x82j?D\xCB\x9Fp\xF6\xBE\x0FbEu\x9E\x93E\xC82\x81\xE8\xDE\xE7\x05\xC0\xE7/\x89+8\xE6]7i4&\x0D\x91\xC5\xADN/\x80\x17oe\xB4\xAA\x06\xC5\x86\x03\x9E\xAD\xCFG\xA9\xF4zv\x82E\xF7\xAB\xCE\xB3\xA0\xD6\x84\xD2\xAF\x91\x9Bm+\xD8\x9E0\xE1\xE9m\xAF<\xB2G\xE9\xAF\x0B\x85\xC9\xE3\xFD\x08\xDB/uyd\xE9\xBB\xFB\x16s\xCAo-\xB2\x89\x94\xA1\xE5js\xDE]\xBEYFsjM|\xA0\xD8\x1D\xA1E\xC5\x99\x16\x08x\xB1\x1F\xB5\x1D\x81\xD5\xF8a\x82\xAC\xD9\x06\x8E\xA2\xF3.\xC7\x15\x10\xE3\xCC\xCF\x8A(\x82\xF4VL\xAE\x9A6\xC6\xB9(\x99)\x1F)j\xF9\xE1z\xBB.v\xC7\xFD\xDFu\xB3\xF6&_qD\xA4\xE8lO\x94\x9D\xFBe\xA9\x81[\x1F\xC2\xF3M\xAC\x8D1\xEF/\x18z\x88\xA9Lau\xEC\xF6\x9B\x18F\xCA\xF0\x1FB\x19\xD9\xF60T]\xA4\xEE\xF5e\xB0\xA9\xE7\x03S\xD2\x96\xA7\xEFza\xFD\xC6hZ\xB0\x8D\x0D\x81\xF7\xA5c\xA1\xF2~\x0FVX\x11\x95\x0Ab\x16\x0F\x0BE\xB1s\x8A\xD2x\xF2;\x92x\x98\xF4w/,#\x87\x9B6f\x849I\x1E\x13S\xC8\x1C\xDE\x16\xC2d"W\x8F\x1Em\x94'\xDA\xB7>&\x98Yo\xA5\x8E\xDE$\xC8\x86\x9F\x04\xB8\xFA1@6XM\x9C\xA7\xE1tX\xCF\xD3'&33-/\x93[\xFAR\x9DQ\x0Ec\xFC\xD4:kZ<\x83S\xE5(\xC7i\xBA\xA7\xC3\x0D\xA1\x85"\x08j\x02\xA1J\x1F\xB0@\xF2VN4\x02\xEBO\x8C2\xB6kM*%\x082\x8EqkS\x8F\xD9\xDD\xAB\x87g\xCF\xC1\xECA=\x0F\xFD\x82pO\xAEK\xDDo\xCF\x0A\xB7\xA9\x07\x0F\xC7S\xF5v\x9B{?j\xE8\x08\xE3\xE7\xFCQ[\xB2\x82\x954\xDEM\xFE\x98\xF2\x13\xFE\xECS\x04jP\x96xC\xD8\xAD\xDC\xA7?%\xB9\x82\xD1r\xE8\x0B?\x00\x83\x12\xEE\x1F\xCC<\xF5\)>\xEA\x1BQ\xCD\x10)][H\x89\x90\x01\xF7\x91U\x04\xF9\xD5d\xD9#\xBC\xF8k\x928&\xDE\x7FMTnY\x1EJ0s\xE0qs\xA7\xB2_\xBA\x90\xD1T\xE7wo\x19A\xF9/\xD8\x0A \xE0\xEA\x11\xF3x6\xB6\x81\xBAD\xFBNA\x85\xDF.\x00\x03V|\x93\xE7)^H\x90\xF3\x93\xA7\x1F\x04\xA9t\xCE\xBB\x91B\x1F7\xDD5\x04J\x94\x8C\xF3eh\xBB\xC4\x1E\xEC\x19:-0\xFF\xFC\x10+I8\xB3\xD2(j\xC7\x9F\x889V\x9B\xCE\xF4,\xE2\x9Fl&\xB57t%XNbGg\x82\x06\x18\xDC}i\x91V\x82B\xEA\xE6\x80\xF6\xCC\x1D\x9E\xC6\xEE\xF4ee2\xC8\xB8\xC5\xCA\xFB\xE5K\xE8\xF0\x9A\x1Dm&\xEA D\x81(\xAFw3\xA5G\x84zK\x92|-\xD7\x16k)\xA9X\xD5U\x96T\xCD\xABF*\x11n\xF6\x10\x92\xB5\x02~\x03\xD7\xAFy\x7F\xFD\x8D\xF1\xE9\x14\x8A,\x13\xB4 \xDE\x84\xA7Y\x8A\xC3\xEC\xE2\x99m{\xE7g-\xE9\xA6k\x91(\xA8\xC2#\xA5\x7F\xB5\x0D\xD1\xD3\x84d\x19\xBB\x19\xE8z\xC3\xBD\xC4\xFD&\x18\x13\xFA\x86\xA1\x07%\x18\xCB\xF8\xFE\xFE\xD4\xF9\xA4\xBF$_\xB4x\xA4dZ\xBE\xB6\xF8\x19e\xDA\xCF\x9A\xEE|\xE7\xFC[\xB51\x07\xD5\xF6\xF47\xBB\x09\x9F\xE1d\xEB\x8E\xAF\xEC\xBF$O\x91+\xA5\x12B7\xB9s\xD4\xB8\x86ss\xA3!A6e\x143\xB6\xF3\xFBv\xC0&\xD2\xD7#|\x94%\x82%\xFE\xB8T\xD1S\xAD\x9C\xCA\x89\xB8\xB8\xA1\x94\x18\x1DzYX\xE8m\xFE2\xF06y\xE7\xF2\xC8\x10\xDB\xDC62\xA4"\xA2\xC0ao\x07\xFE\x08\xDEk+\xE7\xF1o\xE9\x8F\xC5v\x05\x17A@7\xBC\xFFv\xE2\xC4Q\xC1\xDF0a\x84e\x1C\xE3?\x96\x02\xD5wL\x9A\xF2\xF1\x96\xC5\xA9j\xE5\xDDa\x86r\xDAAk\xF2\x07\xACV\x8A\xFB\xA9X\x09^\xD7\x8B\x06*\xD7\x10\xCE3\xD1AokUo\xEBne\x0B\x11\xE5\x12\x92\x13"\xD8\x09\xAEh?\\xD7\x1B\x1F\xC7\x8Aj\xFE\x9AhI\xA2\x02\xB2\xF7y"\x8Fh\x95\x1Cx)\xCF\xF3dc:j\x00\x1E\xE1\xE3\x97=\xFB\x08\xCF\x8Cm\x81\xF7\x84\x1B\x03\xC5aV\xDD\x91\x9E\x14\xB7\xE0\x13\x06\x8DxnU#\xEC\x89\xB0\xEC@\x1Fe\xA0P\xC1\x08\x91\x1D""\xA1\xC6\xA7c\x1F#\x97Q\xEE\xB5\xB6:\xCC\x1D\xBA\xC0z9W%5\x1D\x13)_\xD5\x1D\xBE\xC1\xF7u\xA9\xA0ZI\x11\xF2A\x0DI\xBEmH4\xD7\xE8\x13o&#\xFD\x11\xD0,\xDE\xD0=\xC6\x18^\xB0'c\xE1\x8F.\xCD\x91W\xFBp\x98\xF3/\xA2\xDE\xF9\xD1\x19E5\xCC0\xB8c\x0E7^\xA2\x11\x0E\x04K\xA5\xE5\xB4\x12|<\xB7\x16Va`\x13\xAA\xC2\xBA\xE0\x92\xC0\xFF\x03)l\xED\x86\xB4K\xD5\xD3\xB8\xC0\x0Eru\x88\x98\xAF\x80\xA3\xDFu\xB47\xF7l\xA2L\xDF\x80\xB9\xCFjx\xF2qO\xEEf<\x97dS\xD2\xA8\x8F\x99\xEF\xA8\xF7{\x94\xF1\xB64}k\xBF7\x05\x89\xCF\xC2a\xE7\xFC'\xC0\x88[\x13\x9D\x8C\x9D\xA2K\xE1gJN\x19$F\xA2hf!r\xD6\x1C>W;\xAB\xF1fB\xF6\xF9"\xA5\x80\xBE\xF8\x1F4\xC6\x17T\xA3\xD6\xF1\xF1\x82\xFA\xE8q\xCF\xD2\x87~\xF5\xD4\xD1p\x98\x00#\xDB\xAD\xB3"vI\xF9H\x08\xD5\xC2\x88b\xD6K\xB3\x1EM\x82\x83\x18'{\xE5\xC9t%\xA4\xDB3?\xAE\x19\xEA`\x8E\x07=\x9B\x7F\xE3M\xD2\xD1\xFB\x06g\x88\xCD\xBF\x05\x13\x82@7\xE5\x00\x9A3&6|&s5\xAFx\xF9#\xE9\xA6\x01\xA1_d\x8A\xF5\xF2'\xF3\x1C\x93j>;\xDCe\x95\xE0\xB6\xCFS\xA3U\xF1\xB2K\xE2\xCB<\xE9\x89)'\xBC\x83\xCE/\xF4\x98\xC8\x90\x1A(\x10-\x94\xE4\xB7:\xFD=\x01G\x9F\xE8P\xFE\xC5\xC8S\xF1l_\x1B\xBEF.h\xA1\xE3\xC5\xC8\x8C\x11\x08\xEB\x0E\x0D)\xA4\xC8\xF4\x0A\xB7\xC5\x7F\xBE\xE6\xBF\x10\x9EA\xF7pc\xC2\x85\xC3V8\xA3\xFF\xA83')\x8F\xFA\x90\xD2j\xE9lq\x8E$\xB3\x84\xBD\xC8\xB1\xA1\xB9\xDD\xF1'Q\xDD\xB2\xD0Qh^l\xB0C9S\xDC\xD4jJ\xCC\x91\x03\xFC\x87\xF6\x9Cxf\xF5cN\xFFY\xC6\x091\xE9n\xA2Eg\xDD^0\x0F\xAB\x8A`\xAE\xD4\xAF\xF5z\xA0\x9E7u-\xE1\xF5H\xB9\xF2\x93\xB8"\xB8\xDA'TM\xC3\x08\x92\xD5\x96\xF6\xF9a\xA7\xD3\x0B\xC0\x80\xBE\x0AW1\xBD\xB8\xBFJ6kg\x10M\xF4\xF2\x1E\xAA\xF6\xE0N\xF0\xCF\xE0-#\xB7\xE12\x05\xD2v}v;YkSXa_+Ce\xDBs\xC5\x9D\xFF\xD8Q\x03\x1B\xBA//\xDD\x16\x86[QR\x1C\xCF"\x12#jW\xC2\xA5+\x1E\x9C\xE3\xD6\xBE+\x16\xA7\xCEY\x96\xF5\x09\xA5\x98\xF8ik\xEE\xE0u\xC8\xD5\xC6\xE4\xBC\xC0fi\x8B|\x14\x7F.%\xCCY\x04\x98\x0DWY!\x0C\x80\xDA\xBD'\xA4\xC9\x12\x11Q\x1F\xD0\xD6\xD6\x08F-'t\xF7\x08\xD7G{GT\xBAQ\xA4\xA8\xF1\xD0G:]\x8E2\x8D\x1F\xE8I&\x11"\x8B\xC7\x08=V\x08\xE9\x84\xB3\x8C\xDE\xDD\xF7\x1A4\xF91)\xB6\xF4D\xC3\x8Fv\x91\xAAp\x8D\x9E.\xFA\xD3W'\xB9\xAEOz\x02\xFD-\xA0\x9D\xD5d\x8161\xDD\xF3G5\xDDR\x82\xD2\xF4\x82\xD6X\xB7<(n\x07ly\xFB-\xD4nE\x19H2\xAB9\xC56\xF68\xEF\xE7$\x94\xE0\x1E\xD1~{\xB2\xDC\x8DP\xDB9\xD0\xD9\x8F\xE31\x99\xEF\xEFQ\x86\xCC\xE3\x93C\xDF\xA0\x8AI\xFAO\xA5A\x9Ez\x93|'\xAC\xD6\xA7\xC8\xEB\xE7\xAC\xA1\x1F\xD7\x05\xD9(*\xEA\xA2\xCD\xF4\x15\x90\xB8\xDD\xD5\x8C\xDD\x93\xA7\x13\x073\xD5\x9A//s\x97\x1E\xF2P;\x89\xED\xD9\x97\xF5\x82\x8Dl\x1C("\xDB\x95\xCFG\xCA\xBF\xDD\xD7\xDF\x84\xD8\xA58\x89\x81\xDEe\x9D\xD3XO\xD3~`&\xC3^\xEB\xE8\x95\xB1\x80\x06\xD5<_\x86t\xB4'<\xCF\x16\x81p\x89P\xB7C~\xB4\xF0\xB0\xD2\x82L\x98D\xC7\xA7V\xCE\x93=\x8D\x98:P\xB7U\xDD\x00\xB3\xD4m\xBDu\xB3\xDD\xDF\xB5\x0C;3\x95V\xA4\x1F\x93\xA1 \xC2\xFD\xF4\x81_\x9E\x9B\x05\x17\xF7y\x1Bw\xA5-\x12)\xBDQ[\xEA3\x84I"\x1D\x91\x98v\xD0\xF4C\xF4\xA4\xB0\xCE\xD1\x9B\x14\xD1\xF2\x03%\xC5?\xC6\x02\xA1m\x84\x9A\x9C\xAB\xAB\x9A\xC8\x02\xC5\x0F\xCB\xC4\x9C\x1A\xFB1\x19\x0C\xAAE\x9Cg\x9F\xF5?\xC8f/\x9CC\xFAvJ\xE4\xF5P\xFD\xDAH\x82\xF3C`\xBFZ\xCF\xB7U\xAEr\x80_\xEA\xA8\x8Er/\x93\x95;\x04-\xBB\x9DQ\xEA>\x89~\xCF\x84\o\x9B\xD0\xF5\xFE\x1D\xA0\x08\xB7\xBC\x8C\x8D\x85\xEFB\x17\xFF\x93S\xE1\xAE\x1F\x13+ !)\x9Dv\xFC\x0D.\xE4(\x9E\xDC\x93\x1EJ\xDD\x0DL\xEF\xB4\x9FwX\xA8\xFCg\xA7\xBA\x9C\xC6\xEC\x08\x02\x1B\\xE7\xA2\xAA\xAE\xC0d\xDC\xE6\xDC\xB7\x04\xC1e\x8E8\xDCz\x1F\x95\x07\xAC\x19|I\x00\xA7\x8D\xA5\x16\x88\xFC\x09\xF9\xB2\x81Je\xE1K\xD5\xD1\x1A~\xAD\xC6\x9A\x8C\xB2O vd\xC9k\xDD\x88\xAE\xFAg\xCD\xA7\x03\x01\xEE\xDB\xCC\xF2G\xDE\xB5\x0B2\xBB\x03a\xBB\xEA\x98\x91\x0E\x8Ao\xB5\xE4E\xAD\x99\xC9\x06\x95\xE6\xA8'\x0B\x0F\xE7N\x07s\xCC\xF4\x1B\x97\x97R\xCA\xAA\x96\x02o,)\xD0\x10\xBD\x14\xD6\xBD\xAF>1\xCB\x9Eo\xB9\xFB\\xA0\x8E\xF1\x85U\x12\xB3\xC8\x0A\x9F_\xCE\x19o\x0DJ\x16\xC6\xB9\xF8\xA6\xE9\x1D\x90\xC1\xD4\xC4\xE0\x80\xF2r%\xFA7\x0A\x98x\x1F\x02\xE3\xF9\x98\xC2R\x87\x8C\xE4[\xB4wU\xD8F\xB6s-\xE9\x94\xFC\xBD\x08y\xD3k$\x16G\xA9\xD3w\xF0(\xE4n\x89\xC1\xE8\x16h\xE4^=\x82\xA2\xD9\x87\x09\x9D\xC2\x88\xC2_\xCFf\xC6\xD0\x9D:\x8F\xC7x\xFAH\x06,\x01]\xE5\xEC\x08\x92\x13\xB6\xEA\x13\x17\x17HNG\xCD\xE6\xBA\xAD,\xCD\xB5v\x88\x91AY^\x1D;\xC8\xD5\xB9|X\xDF\xE7`s\x0D\xEF\x90\xE1\xA3\xC2S\xA8\x1CU\DZ\x9CP\xF6\x06A\xAD7\x9Eq\xDD\xE54\xFB9c\x93hR\xA4S\xAF\xB1\xDB\x17\xE6N\xA0\xC1\x86r\xBB\x9D}\x09c\x93\x86\x96\x99\x8D5\xA7\xD8\xC9\xFEx*\:\xEF)\x85\xC9\xE7\x1F\x9A%\x1AT\xDD\x11\x9E<\x05\xE5\x99_\x82q\xB7\xCD\xF7h\xF3\x84\xD2#3.l\x8E>G\xFC!\xD3\xEB\xFC)\xB6\x9D\xFF\xB3\xD2i\xB0\xBCyB$\xCE:\xC5\x05W\x832O[\xF7\x176\xA3M\xEB/\x93\xCDR\x834\xC2\x0C\xB3\x8C\xD5\x93\xDF\x90jJ6\xD1Bn\x9C\xB0\xFB\x14~\x95g\xD9\xA84\xAE\xAD\xB3\xD8^\xC0\xBA\xF0\x05wX0\xC5@C\x11\xEE\xE2\x95\x97c\xDE;!bd\x0F\xD3\xB8\x1Aa3\xF5\xDA\x8A\xD6\xC6J\x12\xF6\xE9\x18\xB4\xD7\x90\x02F\x11\xCC\xF8gZ$M\xA9\xBF\xA5\x05\x94\xC24\xF9)\x8E;\x91 \xAEw\xD5\x19\xE5\xFDE\xCEZy\x9DJ\xEE\x8F^&L\x84\xDE\xED\xDA\x14\xC3\xE8\xA0\xB7\x15g*\x9E\xECv*\x97\x03\x93\xDFr\xA9\x09\x18\x99~\x18h\x08AEor=tk\xE3\x14\xA0i5\xF3Aa\xBFC_\xED\x82\xFA\xBD\x15\x9F\x16\x91b\\x82\xF0\x84\xC8\xABb[T\x06O\xDF\xABy\xACB2\xA5\xB4xBt\xCDoG\xF4\x8BF~\xE9~\x95\x00\x0B\x04\x10\xA7\x1D2\xD2\x81\x01\xF2\x0F\xE6^\xCDtH\xCE\xCB\x98Q?\x98W&\xA2\xA1[,\xF7_s\x19gH\x9E@-\x969\xC7-\xE8\xEEv\x99\x800\xA5\xEE\xB9\xAE\x1A\xB68\xDD\x18_S\xBDl\x0E\xF4\x0B\x10\x88\xE0\xCAr=\x9A\x8C\xE6\x9AP\xDE\x1Enz\xD5\x8A\x02\x96\x88L\xB6Z\xFCG2\x05\x96%\x08N\xFC\x9F\x08\x97\x89\xE0A>\x19\x12\x14,\xB9\x07*\xE6p\xCDp\xDF5\x9EvP\xF2\x91\xA1\x98\xFF\xE0g\xB5\x7FV\x83"\x03r\x93Fmu\x9A\xC5F=K\xF1\xACXI!bI#\xBB\x1D\x09T\xD2\x00K\x8C\xEBq\x1A9.l\xD2\xD4\x81(\xAA\xAF\xBF309cz\xA7\xD3N\xF0\x88\x8A\xFA\xAAv\x84\xE1S\xB8o\xB6\x15\xA1\x07a\xAD\xF0\xE66\x07Dp\x90\xB24\x8DCSNm\xB3\x96\x1F\xD95\x99\xD3Cs*\x9E\xF8\xD2,\xF7\xAF\xDC\x7F\x7F\xED\xAC[E~v\x94\x01\xEB\xD0\x13q\xB8\x8F\x9C\xD2f\x0F\x8C\xCD\x8B\xFB\x86\x17\xDA\xB0\xB0\xFBl\xEF\xD6uc\xFFY\xA7\xBB0\x033iJ\x0DK\x1A\xBE#\xE9\x92U\x8EH!\x1ENa\x04\x9AE\xE2\xD9\xF1\x0C\x8F?\xB0\x0D\xD7\xD4\x02\x03\xCB\x89M$\xA7\x89\xF8\x99\xB2\xB0Bb\xDBFa\xE6]\xA5'T\xB4(\x8BN\xCB(\xAA\x8C4\x9B\xD0\x8B\xAC\xC2\xCA\x82j\xAD\x99\x06\xFF\x03\x1Eu\x9E\x83w\xBESnz\xBF\xC4\xA9\x86\xD59\xE9h$tv\x8B\x11\xA7\xDD7\xF3\xC4\xBB\x7FE\x80'\xE6\x8F\xA8\xD0\xBD\xBE6D\x8B7\x99h\xE9\xB8\xE5\x1A(\x8A\xFAz\xE1\x8C5E\x00\xD5Rz\xEA\xD0/\x94M\x0AxmE|6\xA6\xDB\xB8\xBA\xAA\x0F\x93\xB0\xC2\xCFj\xDB@`n\xC0W!pXTsb\xCA\xD5!\x1BH\x01!d\x9E\xB3v\xBE\xF4n,7\xA8\xE4&\xD9hG\xF9\x0F\xC4\x06eJ\xC3\xB68i\x89\x10\xA2q\x03\x87\xF4\xB5\xB4O\xC0l\xDE*V\x03\x84\xE8\x04U4\xA6p%\x8FF6\xC9<\xBD\x7F\xE5v\x0F@@\x91\xD0K=\x0A\xA0I2\x0EG\x01F\x05\x1Cz\x0F4\x87\x9B$\xB3\x90=\xBBL\xBCV\x9B\x0A\xC1\xD0\xCA\x0F\xFE@o\xDE\x91\xB5\xFE\xDB\xA0J\xE8\x9F.\x88[@\xA7\xEE\x06\xC9b\x0D\xC9c\xBA\x07\x07\xDD\xB7LZ3\x0As&\x02R\xAD\xC1\x08\x07\x12'A\xB3jMl\xD8\>\x1E\xBD\xDE\x9E\x9D\xF1Z}\x98\xA7 \xB8:@Lw\xF0\xD5\xE4#\x06\xC1\xE4d9\xA4o\xCAZ\x80\x85\xF7\xBE\xA5]\xE1rQ\xA9!4\xED\x0D\x93,\xBE\x98V\x8AS/\xACE\x04\xB8^%\xDC_\x8B\xD7\x183\x03\x1C\xA5\x85?\xC3\xFA\xBE\x9B\x8F\x05\x9Bo[\xF8l\x0C\xFF\xC6\xA3\xC2\xEA\x80sM2\x9Bw\xD3\xA9\xAD)\x01\xF8\x02\x91y\xDF\xA87\xBAr\xBA\xD2\xFE\x88\xE7\x9F\\xEF\xC1\xEF\x83\xD0\x88\xED+\xF7\x05K"\xC4\x8Az{eucx4l\xCA\x90\x82$zk\x8B\xB1?K\xCB\xF21\x17n\x8Bn\xE1\xADw\xF5\xFE\xDF\xF7\xCB\x9D\x84\x1Bq\xBB\t\xCFM\xD8\x8Bj\x8EB\xFA\xCD!\xE3\xF9\xA9\x91\xCB\xDA\x05\xD9\xC8Y\xE2)\xF3\xF8\xBC\x94\x05|\xB8\x14KUb^\xAD\xEFIa\x86\xF1\x0A\xA0#\xB2\xF5\xF4*\x10\xC5S\x-z\xEC\xC7\x99\xD5\x9DI\x97\xCD\x08\xE3/\xDD?\x90\xC6\xBD\x8F\x06n\x7F\xAC\xF7VL\xCA]\x96\x05\xA6N6#\xFB#\xA46\xFF\xCCR\xAF\x1F\x86\xF90\x9B\xF9\x10\xDA\xCA\xDB\xA2uJZ4\xBD\x15y\xB4\x1B1\xEF\x1Ey\xBC\x84\x90\x99\xDF\xF3\x92\x9B\x0C\xB3\x15\xFBej^\xD5\xCC\xEE\x06\x07?\xC3\x98'\xDB\xC5.\x93\x04\xC1N\xC5\xAD\x06\x06f[(\xE3\xB4<\x07\xECU\x0F\xF4iT\xBE\x8F,)@\xDC\xB0V!\xABh\xDF\xD5\xAA\xF0*T\xCF#\xD4\xB4\x92F\xB8\xEC6\xDA)\x19\x86\x80\xFF\xDA2\xA0"\x12z\x82\x0F\x08\xF0\x93\xF0\xAA\xA8\xE24\xB3\x95{o\xC2\xA6q\xAE\xA9v8E\xD3[\x12\x0E1\xC0N\xA0|V\xBC|\xD0\xC8\xD1\x9509\xFD2 \x9E\xB0\xAE\x92"B\xD0\xCB\xAB\xDD\x85\xEE-\xE0A7P}\xBE\xDB\x85\xCBvN\xE3z;\xB4\xA1>8\xA9\x85h\x09\xF9\x9F\xCF\xEA)\xA0\xB55\x0C\xDB\xA7Q\xF7\x0E\xE1@\x876R\xE8k8\xA7\xD6\xDF\xA4\xEEB\xF5\xB1\x19\xF2\xA2\xFD\x1Dc\x98\x16]C\x0C*\xB7\xFE\xD6J\xC2\x1B\x9F\x85\xAE\x04'\xC26\xE8j\x9FY\x14C\x7F_\xD0\x86IAv\xFC\xF1"\xB6\x988\x13;\xFC\xE4\xFCO\xEB\xF5U\xB3\xFB\x9F\x87P#0\x92\x08M\xC8+\xD2a\xE5%\xB1\xE7\x1A\xA1\xC6\x19_\xA6\x91,dn\xB4T\x8F\xC4\xC2n\xD4d\x15#\x1D\xE6O\xE9\xEF8\x12\x8F^\xE5r\xF7_rd,4\xE2\x12t\xA1\x9D\xAE^\xF2\xD8\x92\xE6\xD0b\x8A7j\x964\xE6\x94\xE0\x17p5Y\x94\xB2na\xD4\x0D\xFB\xE0\x11\xB7\xE9q\x06\xC9\xC3$\x19XF\x81\x04\xDB\xB3p\xB6Ty|\x0B\x85\xCB\xAD\xC8\x03\x86;\x9B\xF4\xFES\xD7\x13\x92\x0Dh8*\xC5a\x05\x09\x94[QN\xB3\x06\xAB\\xC1=\x1DC\xDA\x11`G\x89\x06u7\x9B"\xADA7\xE4n(1\x07\x8C=Dl\xD4{f\x0D\xB7\x07m\x9E\x97t\x05F=\x16Y\xA4\xF5d\xF2\xA1D\xBA\x85n\x14\xD6\x86\xBDC\xA9\xCB\x99\xD0\x8Bp\xE3`\xF4\xADE3\x1B\xAF\x94\xD8\x7F@\xC83\x97Dy\xA5)q^\x0F\xB9>\xC8\xEC?-G1\xF5\xD2Y=;N\xEBo\x9Bv\xF9Le/\x08\xD8O\xA3\xC3\xDEM\x04\xF1l\xC1\x12\x82\xAEH7^\xBD\xBDnp\xF0\xB0vp\xFE\x04c\xCA\xF9\xE1\x8C\xC1\x1A\xB3\x12\x0BN\xF6&\xC6\xD9\xA9T\xD9e\xB4\x0C\xCD\x83\xC0f\xE0_]\xD2TA2\xA2.9([\x90xxX\xD3y\xABba\xAA\xBE\xE5\xCEC\x7FL\x04X\xA5\xB6\x92\xB5\xB6\xF5>]'\xCF\xA0f\xCE\xCC\xDAv\x8D\xBF\x0E\xBC\x87\x91\xABsM\x80\xF8\xBB7/y^\x9B\xDD&2J0y\xD9\x12\xF2q5F\xCBEx\x9CN\xA5\xBC\x8A\x1Ep3?\x09\xFF\xC2\x04\x1C$\xA9(\x8Cn\xCF\xBCZr\xD0\x91\x96CWxk=\xA1\xE9\xC3\xF5\xBB\xF1]\xE0\x08\x9F.!]\xC5G\x02\xE4\xA0\x1C\xF1\xB2M\xC6;\xB0\x19\x87\x8Fr\xBE2p\xCC7\xC5O\xAD^\x0B\x0E}\x0F\xAE\xB0|#\xEA\x95\x11\x15>ipD.\x0B\x8B\xA9\xF6 i\xB5[R\x8F\xA7\x16w!\xD8*t[p<\x910\xB4ubW\xCE\xA1E\x1C\xF5n\xBC\xF7$$\x96\xEE\xA1\xFF\x9AN\xC2W&\x01\xEC`m\x1A7.\xBE"\x7F\x09r\xDA\xA5\xAB(.D\xD1L\x82\xFA\xCC\xE5na&\xC3b#\xBA\x88\x17\x7FU\xBA\xD3;\xAE\xC5f\x87\x03\xD1\xAB\xCB\x1Dh3\xD4\xEC\\xAC\xF7\x16\xD3D!D\x8CLqa\xBFl\x13\xDC\xFE\xCC\xFC\x86H\x98/5\x13\xC5\xCEx\x90QG~\xB4}l\xF3}@V\x99x\xF9\x98\xA0^p\x8FkB\x90\x9A@{I\x93\xBB\xCA\x14\xF8P\xDE\x98>\x12\xBD\xA4\x00`\xD2}\xAE>O\x18}\x14\xEE\xF3\xCF\xE6q\x94\x0E\x9C\xA9\xC1/\xE7\x11\x9BJ*\xC6&\x01\x11\x05'\xDCS\x16\x8B\xF7c\x9B}\x8B\xB0l\xF5\x8E\xD6\xDDu^B\xB0\x0Bv\xEF\x04\x96\xBA\x84m\x18\xF5\x89\xBF\xA1\x05\x9Aa\xDF2n,\x98\xEA-\xC99i\xFC\xB8\xBE\xCD\xD4\x80T hE\xBEm\xA2.MT\x19@\x1A\x18T\x1E\xA1R.\x95\xF50\xF2i\xB7\x0C\x96\x9C?Pi\x9F\x99d\x8Fy\x93\x16:\x19\xF9\xC6e\x83^\xB2b\x8C\xBCX_\xAC\xD6\xD8n\xA5\xD0\xD9\xBE\x04\xF8\xBE\xE4\xA8\xA7^\x95\xC9\xB8\xBC\xB7o\x07\xCE\xFE\xA6\xF5A{@J\xD2\xF7\x0E\xD4\xE1.I^\x81\x1D\xD0\x8E\x91\x92\xC7hK\xEEba\x84\xE6'M'\xD8k\xA0\x0BE\xA1E\xE9\x9F\x98\x92RD\x16\x8Air\xC5Z\x1E\xD0?\x83o\x9A\xF5\xCCF\xDEm\x8B\x959\xB8i\x93qk\x93\x86\xCA\xEF\x87\x8C\x8BAy\xE3\xAA\x0B\xFB\xA2\x9F\xE4G\xC3\x0F7\xD4\x0D\xD8\x1DB\xB6\xBD\x17G\xC6f-X>\x85\xF9\xCE\xA3F\xF2\xC6{\xD4\xAD\x7F\x97}\xA1\xF0\xBD\x1Ab\x85\xC4\x1CLR\xCF\xE57I\x87\xBB\xCB\x9E\x00\x10b\x0C-\xE7\xC6\xCE\xEF\xAA\x1D"\x0E\xE1\xF4.\xDA\x9C\xB3\xD0\xAE\x99\xC0p\xBE\xDBi\\x82y\xFCN\xC8\xB2\x19c3yN\xC7\x91\x82\xAD\x8D!fm\x0A\xAE\x88\xEADz\xC6sht6$\x99f\xD1\xCCs\xC2\x14\xD0xH\x06\x8E\xAC%\x00\x16\xB8\xB3\xBF3\x0F\xB0\xDC\xCD\xDB\xF9p\x14-\xA6\xF8\x81$\xEA\xB0\x1C\xD2\xA7\x8D\x7F\x8A\xE0s\x7F\xFA\x80f\xF5I\xFF3~\xCC\x03\xA7\xA5\xD6\xDE\xB2\x85\xBD\x9D\x8C\xBF\xA09t\x1D\xCFB\x87\xE1\x90l\xD4\x8D7wAI\x97\xBD\x95\x1E\xA3\xE7M\xBE\xAA\x00\xCE^\xD6T3\xC0-\xB5\xBE\xD9\xA6[\x0A\xF5t\xE4\xDE\x19O\xDD\xDC\xF7'\xE3a\xF2\xE3\x9Dq\xEC\xFD\x05\xECitC8\x8B\xF9\x1Ca\xAA\xF2\x84\xFF~T\xB3D\xF8\xBB\xADEF\xD04\xE8r>\xEB\xBD\x01\xB3\x80\xC6$'\x8C>\xC8`\x8F\x15\xC1\x7F\x82\x81\x84\xD67\xEA\xF2\x82\x97\x8AcY7+'\x7F\x84\xEAX\x06\xCF\x0CB3p'G\x9F\xFA\xC3\xA0uD\xDC\xD1\x8FJ\x9AD\xFD\x81\x90\xDE\xB9;r-\x9E\x05\xFBM\xBAS\xF5*\x855ey\x10\xE4\xF3\xA0\xCC\xB0xuw|\xA9\x1Es\xCF\x16,\xDE\x89^\xB7\x1DL\x88\xC3S\xD7\xC7vs\xE8\x08\xF5\xFF\xA6\x0Al\x14\xB5\x02Ck\xFF!&\x86hv#\x01\xEC\xB2\x8B\xB8N~\x9Cf$WvQ\xA3|\xF5\x09\x8D\xF7\x84\x8AZ\x8CQ\xC4j}\xF4k\xDA=\x80\x94\x1C\xE3\x82`\xCCBD\xF20P\xAB\xD1E\xA7\xD6\x0Bb\xF9\xBC\x80\xD6M|\xFB\xCD\xA5\x94\xF8\x11\x0Cd\xB9\xD8\xEE\x0A\x8Dl\xAA'\xCEf\xFDL8\xC6)\x9C\xA4e;\xBA\x13\xD1\xE7\xE2]\xC3\xF3\x07y}\xF2\xD3H\x99\x02\xA4\xD9*{7&\xDD\x9C\xC4]\x86\x81kE\xBC!{1\\xBAf\xD1t#\xC1]\x9F64l4\xD6f\xF4'|g\x07\x95\xB01\x81V\x1E\x0F\xD2\xC1?\xCE\xEFT\xF8/\xA9\xC4\xC6,\xB5[\x82\xD4\xC5\xE9\xC7y\xDC9<2\xFC\x0A\xC0\xE7\xEA\x0F\xE6u\xD1\xDF\x1C\xD72)\x9C)\x8A\x0C\x8F$v\x8Aqc)\x9B@\x9Cp\xD5\xC9\x14\xB9\xAF\xDA\xEB^\xF120.\xC9\x1E\x8E\xA3;H\x82_$\xE5z\x9A\x98\xF2u\xE43\x04\x9FM+\x90\x10\xD9\x19\xCBy_'\x15\xF5\x86=*>\xF6_j._\xA3\xAAr\x09B\x1F\x02\x97\x80\xAF\xE9\xFC\x91n)\xAA\x02S\x7F?*\x83\x1F\x0F\xB6\xCD\x06\x81)\xAFd\x1E\x8D\xABDR\xAE\x09\xE6\x9B\xF9\xCA\xF3r\x97\xE8\xE8\x09`\xF8\x1F\x05\xDC/+\xFF\x9D\x13["\x06\xEF \xB6\xDC;\x9E6zyb\x01B\x88\xCB\xDDS\xFE\xDCQ-\xE41\x1C\x90\xF0=\x95\xF8k\x84w_D\x9F\xF7\x9F\xB8 \x05x\xBB\x99\x11]v\x92\xC3\xD7\xD5\x16T\xB5\x13\xBE\xD8f\xF8\x9A\xA5\x96w\x1Dc<\xE7\xE5\xB0\x94(\xDF\xC30v\x14k\xDC6\xFEp\xCF\xDF\xA9go\xA5\x86\xC9\xA6\xB1,\xBB=\xE1\x95\xE3\x1C\xC0:\x01z\x04\xE2*p\xEC>\xA9\x88\x84\xD9\xB7\xB5\x8A0\x85\xC1Z{\xDA\xFD\xA8\x01\xC8b\xDB\xAF9\x0Aa\xA8\xBD\x87C\xA8ne6\xE9\x9CF\xAA\x80\xFD/\xE9Hs9\x80DG\xD4\xD1\xCCeZK\x05_\x159\x7F\xE5\xBD$\xA1\xDA"\xC1\xC8\x14;\xDFd\x99m\xE9\x11\x03\x0FN\xBB]\x1Bfc\xA6 %\x80\xCC\xBDc\xD2&\xFE\xD1\xB0;\x86\xD3\xF35o\xDB\x8C\x83\xA4\xDC\xB1\\x01{o\x10B\xC7?t\x1A\xFD\xE1\x90\xFAj\xF8r!\xE6\xB0\x1A\xD4\xEEfdw^\x12S\x05\x17\xD1[\xE1+#Y9\x11\xFF\x82r_<\xB7\xDF\xAF\x0B\xA3{\x13\xEB\xC6\x8F\xA0\x81\xBB\xDEO\xA1\x8C\xC0a\x1E\xFCZ\xA2Mk\xB2\x83\xE5\xCF\xF3\x0Ex\xFD\x19\xF3l,\x7F\xA4\xA40Z\xC2\x89\x16Y\x97\xFE@\xF7\xD1\xC9\xD5\xCF\x0D\x98\xB6\x00\x81W\xB2\x83\xE7\xD0\xDA\xBA\xA3=\xE5rT\x8F\x93\xE13&\xA9\xFD\xC8|\xFB\xB0X\x08\xAAT\xA9b\xB9I\xA5_|\x9D\xC2T\xD6\x0E0\xE5\xD8k\x0AT\xF1+\xD2\xE3'\x0CH\x86\x001\x09\x93\xFF#\xE2?\xA3\xECc,\xABqfi-x\x91\x90,\xFDT\x0F\\xC6\xCE\xB2\x80\xFE\x90\x19\xDCD\xA4'\xCF\x17\x9At\xC7K\xAC\x8F\xA7\x8A:E\xCA\x87\xB1\xAD\x13P!\xD3\x10\xA3\x90e#\xE9\xF1G@fp\x06@\xFC\xB9}\xDFaR\x7F\x16\x197t\x8A\xCE\x13n\xD4\x95\x0C"b\xB0\xF76\xDAk\x16\xB53\xCA\xC7ut\xCD/\x87\x1D\xCDZ\x95\xB9IFV\xD5 eK\xDC\x05\xDBwrr3@2\xB5r\x1D\x90\xB7\x0E=f2%\xF6\x0E:\xD5\x91\xDFF\x19\x9E\x82F.\x7F\xE4\xD9\x13\xBC\xBE)\\x03tZ\xC7\xCD\xD0\xBE\xF5,\xD3\xC6\xB2\xE1NX\xA3\xD3d\xC7D\xD4\x10Q\xED\x8A&\xFA}\xD4xP\xA5\xE4+\x06\xAE'1\xAD\x04\x919\x06\x95\x91\x08\xC3e\xE2CMS\xD4+\x12F\xAD\xA0K=\x12\xB2xO\xAAB?]\x1F\x1BUl\xC2\xE4\xE9o\x06J\x87\xCB\xE9\xB5u]N\x83l\xCFqj\xD2\x9C\xC0U\xD5v\x02\xA6\xCA\x97\xC0\xE5\x85\x06\x99\x09\x8C\xFEr&2\xAC5\xE3\xFC\xA2D\xF1x@ \x19\x1A&\x9A\xF3\xF7z\xFD\x80i\x0A\xA7\xE3\xCC<\xF3\xF2a$\xBB\xA8\x90\xA7\xB8#W\x91\x8E\xF0\xB9eJ4\x96\x82PZ\x8D\x03\x8D\x04\xF60\x86\xC1\xD9G0>\xDF5\xFD\x95\x8B\x81\x89\xCF\x01\x9FYc\xD7SB\xBA\xEC\xC7\x07\x02#\x95\x0B\xC0 :\xA34\xA0\xDA\xB6'\x94\xF6\x06\x00\xC9\x13b\x9F\xEDd\xA4\xA9\x9C\xC2\x9F\xB4\<\xD9F?@\xB4\x89PGV\xF9\x90\xD5n\xE7\x18\xBB\xD9\xA7\xFDy!\x9D\xA4i\xC1\x073X\xBB\xDC\xB2TPsV4'\xF7f\xD4\x8E!\x84\x0FE\x1DX\xD5,0\x18\x11G\xA4\x0D$\xDA\\xD2\xF17P~\xA9\xEF\x9Af\xE7\xE9ek\x09M\xB3.\x9B\xADM\x0A\xF2\xE9\x1F\xB0\xFC|r\xEF\xD5j)b\xA4uUw\xE5\xA9DD\x12\xE1\x93^6'\x97=1\x19ntV\xB0\xB4b)\x09H\x95\x00\xC0\xE5\xC4D\x1D0J;h\xE5\xE1\xF8\xDC\xC7\xB8\xBF\xC7\xD6o\x90\x84\x81\xBB\xFDT\x85\x07.\\x187`\x80\xA8\xC7\xC4\x99\x058\xC5\x87*\x1CU\x0A\x8ATPk+J\xB6\xEBD_mZ\xF4\xE6\x00\x88J\x07\x8D!\x1D\xF0\x96\x98\xD1?MY\x14\xD5\xC1\x7F\xEC\xC7;c\xDC=\xCC\xCE\xEB\xAD\xB8}r\1\xC2\x09\x08\x9Bo\xCA\xA2\x98\x8Fj\xC1`\xA0\xE0g\xB3\xB3cn\x9A\x95\xED\\x86\xB3\xECB\x93,\x91\x8E9\xE5%\x0AT\x0A\xA9[\xB73\x96\xCC>\x16\xC5\xBF\xE1\x02/\xA5\xCE\xFC\x9D\xF5y\xA3\xDD\xE2\x82\x0A\xE5&\x87\xEF\x83w\xF1\xE6\x09\xF3\xA2\x00.\x8E$\xE7y\x9B\x87-Q\xFC\xD0%6\xAF\xA3\xAC`F9n\xB83\x0D\x82\x1E\xCB\x8D\xCA\xCC(d\xB5S\x8D\xB75\x94\xC7\x01\xD8\x18^\xD7\xB0&\x02\xEE] \xA6\xDE\xE1\x8D\x9D\x8Cd\x96\xD8\xDF\xD1\xE6\xEF\x9B\xD6\xB5\xAA\xD1\x93\xB0Y(\x0A9o\xA9\xD5v%\x0AL\xDC\x19\x9E\xA2r\xDAC\xFFRE4\xEB84\x85)\xE4\x13\xBF\x8Bm63\xAFq\xA9:\xDC\x82\xCBV\x94\x85\x1C\x15%!\xC9a\xE12\xD5\x03]\xB6\x14\x909\xB4\x9C\x12\x186l\x1A\x19\xC8\xF2\xF0\xA4\x0AH\xE1Ok\xC7_\x8F\xF3\xDDj=\xCCl\xF7=\xDB\xCB\x92\xD6\xB50\x91,\xDC,*{O\xB3T\x1D\x90\xF9\xC6!w\x96[<\xA6\x0B\xBBi=\xEB\xA4\xF7r\xC0\x19\x93\xB7NY,\x03p\xF1m\x81\xAB\xC5\xCE\x05\x10^\xADy\xC7b:\xEA\x11r^\x8D=\xD2\xCB\xAExUG[\xC0WoZ\x88\xC9k&\x0D6O\xCD\x0A\x96\x1D\x87\xA62\xCB\xC7\x1Bc;\x9CM\x96L\x8Ci\x82\x8D\xBA\xFFN\xC2\xA75\xF4V\xCE\x98\xDB\xD0\x05\x88\xF1\x9EcY\xE7\xE7\xD0\xD7\x13\xC3\xA3\xAEA\xE2\x8B\xDCkD\x1B\xFD2\xE6\xA1\xFD\xB4\xF1\xD8\xC1<\x91*?T\xE1\xFF\xFB\xF7\xB8#tr\xDAG)\x93I\xB7e\xD8\x0F\xB46_\x11\x9B\xD5\xD9e\x0E\x1B\xFEh\x01A\xA1\x9C\x05 \xE6\x1B=(\xAD\x0B7\x89^\x10\xF8\xA3C\xD5\x80T9i\xFBf\xDE\xBD\xC7\x8DZ>\xD9\xD6\xCE\x07t\x01\xE4&\x9B6\x81\x05[Nv\x1B\xBEEFB'\xBA&\x8C\x8Bx4k\xA7\x1D?\x92\x18\x9B\xA6`L\x02\x0D\x9C/\x90j\x19\x99#["\xF6\x8BrE\xEB\xC0W\x0B\x8FFC\xC1\xE1:\x99\xF4\x1B\xA5\xE1gN?\xEC{\xA2\x83X\xBE"=\xEE/P\xC58\x90\xB3\x8B\xCF\xEA\xAE\xD3^y\x15\xE5\x84\x8Bd\xE2\xB1\xE2\xC4O\xF5od"\xEF\x0EV\x00&$\xD6{\x9C\x1B\x1E\xA7;"\xB4|O.\xB4 \xAE\x90\x16\xF7\x12\x1Ab\x82C\\x91E\xE8F.\x97\x8E3\xD2N \xA2\xA4\xE7\xA2 \x12Y\x01\xE1\xFA\x80g\xD1\xC7?n],)l\xD8\xA2\\xDAJDQ2d\x05\xB3S"\xD17\xAFCA2\x9Atz\xC8\xAD/\x9E\xCE6zz\xC6p\xAD\xF2o\x86\x1E_\xF4_\x12.\x13\xDB`\x82HZa\xE9\x1B\x8420\xE2\x8E \xBE}#H\x00-\xE6\\x0D\x01\xD2n\x94^\xA7n\xDE\x0A\xA0b@U\x11C\xDC\xF6\xF1E.\xB50-\x09q\x96\x1F\xEB\xE45\x95\xD4\xB2\xBC\x07\xF9\x1BO\xFB\xA2\xB5\x14\xF3\xA0n\xF8$\xE0h\x02?\xD4\x94\x02u,\xA1\x92\\x0Ehw\xC1q\xE3\xF4[\xE1\xD1w\x10yL\x1A#\xBC\xFC\xD16J\x13\xED\x92\x97Oz)\xFFIY\xE2\x1F\x07\xBFx\x18\xA2)\x02\xB2\xA1\x1CY\x95\x8B(\xC5\xB0k3\x1Di\x12\x95\x18\\x1E\x1C\x0E1Vj\x94\x04\x8A\xE8\x0B\x99\xAA\xDB4@\xE5!Wz\x9A\xC8\xF084\x1Cq\xBF\x0Fs\x8B\\xF6r\xFEH",\xDC,\xDD\xD3\xFB\xC2P:O\xC2\xE6\xAD\xDB^pS\x7FN\xB2\xB8A\x0Eq\x08\x0E\xA3\xFF\x0Cg\xF30\xF0'\x01^\xC2\x7F\x97\x85\x8CWPv\x19\x8F\xE4\xEE(\x91\xDF{\x16\x8B/n\xF4\xA2\x112\x86\xCA\xA0\xAAcg^\x98\x03\x03L`\xC1q\xF4~\xE0m\x1E-B\x09\x93)\xD4\xC5\xC0\x17S\xB2\xFAZ)=t\xC2\xBB\x90"\x87h\xA4\x1C\xD5\x06gK\xFD\x1CE\xE7\xAC\x16\x0F\x9D\xC3bW\x9D\x98E\x88I\x0D\xB6\xEA\x81Z\x17\x1B\xC9\xA9\x04\xB4\xEE\x83\xB0'\xB5\xF9@<\x88tI\x8D\xA3DC\x1E)h\x8E]\x81\xA0\x85\x17\x81\x9C<\xC3\xC8KD\x15h\xF6H\xAFFx\xB2\xB2\xE4\xC6\xEBj\x03R-\xA5\x90t\xFB\xF8\xA2\xF1\xD1\xD9D\xC1u\xF9wys#\x0FF\xB5\xB5r\xD4sA\x1E=\x02\xF7\xD2\x10\x88\xD1\x90\xCA\x96\xD2\x86#\x02\xAF\xE4\x01Na\xF0\x08\x10L\xD9h\xA36\xF7\xE1\x05F\x9F&\x9C\xA9\x83\x1C\xC3\xE3b\x14\xD9su\xB2\xA2\xE5\xA5\xC9\xEA\x1Dm\xDB\x97 1\xF1\x85\xF5\xF0\xD6dZ\x98\xF8e1`^\x1D\xD3\xA5\x99\xD2?\x1F\x1A?h\xF0|\x1FX\xC1I*XKL\xA3\x14\x90\x9A\xD0\xF0\x1B8\xFEi\xD9\xC1\xBA\xF2\x8C\xE1\xA2\x91\x1E\xA1\xE8\xB9\x1C%\xF7\xC0\xE7!\x12`\x80\xF5\x99\x9B\x0DPK\x98\x7F9|\x86{:$\x0Ar\xAE\x00+/N\xB4\x02U\x842\xE4\x0F\xD56|\x17\x18\xD6M[\xAF\x1CQ\xF1\x9B\xE7\x0Bnr\xC4\xFDa3\xB4\xF2tj;,\xDB\xBA\xC3J\x13\x1A\xA5w%\xC6\x1E\xD1\x87*N\xF1\xB2\xAD\xBC\x9B\x08zm\x07f2\x1C\x03lE\x1B\x0EF\xBFOm|\x1B\x13\xE5`]\x09$\x11\x042\x99\xADAl\x8EF\x98\xD2~\x8B\x08\xAA\x08\(t\xAA\x87\xCB\xB1v\x89CS\xEF\x0D-\x81d\x9F\x07\xD87O#\xDB]#\xCB\x0B2\xEC\x8Ac\xF0h\x88lz\xCE\x88y\xD6\xD4\xDB\xE2\xB9c\xF2H\xE6\xE1\x8B\x9A\x1F\xE4A\xE1\xDF)\x9E\x15N9\xFEa\xE6\x9A\x8F\xAD\xCA\x934h\xA3\x8D\x01\Q\x0DKp\x99\x88\xC1\x92\xAA\xDE\xE0\xCCP\xC0\xBCN\xD7\x8A`S\xA4w\x06\xE2'i1\xF5\xCDi\xE2\x04,\xA8\xCF\xE0\xC0\x93\x18\x1F\xEF\xBE\x96\xDD-\xFB\x0C\xFD\xB1u\xB3\xF8\x0F\x07\x81=\xDBVv\xCB"\xBC\xD1A:b"\xD6\xF8s\xB2d\x84\x8C\xA8\xC6\xDF\x00/\xC8:\xAA\xF2\xA8)]s\xF4v\xDD\x17I\x1DX\x88\x1B\x87\x19\xE0`\x8D\xB4l\xC9V\x14\25H\xF4;o\x9D\xE9\xCBJ\x03{\xBFr\xEC\xB5\x00\x8A-\xCD\xC2h\x9F\x0C\xE1 *\x0Dx\x8C\/=\xAD;\xC1H\xA6\xFE(_\xB4\xDA\xBB\\xD8_\xF29\xF9\xC5\xD7\x08A\x01E\x93\xA2\xDF}\xE1y\x00\x80\xF8\x91\x0B\xD3\xC2\xD8\xFB\xF2vmR\xA8\x0C\x00\xD73m\x01\x0E\xF9\xE2\xCD\xF8\xBC\xFF\x94;\xD46\xA6f\x11\xE7\xE2\xB8\x12\xE0y\x96\x13\xB5q\x0A\xEE\x13]\xF6\xE0\xCAQ\x14z\xEA\x09\xE6\xCE\x86\xA4\x17\x14\xF0\xDF\x02\x0D\x82\x0F\xA3u\xC1\xDF\x8A@\xD7/>\x89;Zf\xF0\xB5\x94\xA8+\xE0\x9C\xF4\xAF\xDC\x8D\xC4[\x80)d\xC9\xC4\x89\x96\x89n\x87\xE4\xB1\xA8\x9F\xDE\xA8\\xDEu\xF7\x9E\xB3\x91\x95\xC7\x82&\xC1\xCF\xFBW\x0Cj\x8F#ad\xFBW\xE8\x86\x91yf\xE7\x8A,\x02\x08\xFAo\xB9\xE9i\xE8:y\x08\xAD\x8DB\xE9\xBD\xF0i"\xC6Z\x0B\xADJ\xB7P\xB7\xE2\x12\xDAI\xA5\xC3\xE0\xC9\x97H\xD0\x8E\x8A\x9Cg\xE2:08YcY\x98\xCB&6\xC3\xED\x01\x9F: \xCF\x92\xC03;\xA7\x0B\xA5\x9F\xA6\xD4\xFC\xD8\x88\xF2\x9F\xE7J0\x86^\xB7<\xC6nz\xB6:\xCD\xDE\xC8\xDDf\x0B0\xA5H\xE5\xEB\x16\xCD}\xD2.6\x8D\x8Bd\x83l\x867i\xFC\xDB+\x9E\xCC\x02\xC2F\xE1?\x1D\xBE%\x1FM\x07\x1D\xE7\x97z\x1FLD\x8ER%\x87\x11s\xF7\xF6b\x8B\x82b\x09VG|\xC6\xE0\we\x19O\xA8\x18\xCD\x8D&\x93\xD2\xE8\xA9\xCD\x09\x82(G\xBE\x80\x8B\xCB\xB8+\x83\xD7z):\xEE\x9B\xCE+\xDB\x86\xDB+\x00\*\x13\x1Br\xFE\x1Ce\xE82w\x102\x03=J\xDBh\xE8\x84\xE0I\xB0!\x1A`Z\x15"\xFB.\xA7\xB0\xF8\xCD\xA7[@\x02\xCA\xB4Z\xA0\x0B\x09T\xA7)\xEC\xA97_\xC4c\xA1\x04\x80\x07\xD8\xFB,;\xDB\xD8Z\x88\x8E\xE0\xAD\xED0\xF5b\x85|\x09w\xA5N\xD6\xB7\xC9a\x0C\xA2\x90\xC3\x05\xF4J\x12\xE9\xC1\xBFI\xC4K\x0B9\x05\xD7\x18e\xE4\xC0&\xE0\x92\x1Bq\xBAd\x9E\xBFI\x03*\xEA\xE2\xD0\x92\xAD\x8F2\xEER{\x7F\x1E\x93\xFCfs\xE2\x84\x183\x92\x17aDN\x97\x09\xE4\x98\xFA\x0E\x88\x04\x11\xDBs\x16\x00\x98\x9CL\x08\x82\xF0~\xC3\xEA{\xC1\xC5\x15\x81}~\xE4\xFF]C\x9E\x91\x1B\x98\xCF\xF9\xFAe\xDB\xBDc|\xD6O\x9D<'\xCA\x9B\xB5\x8A\xC42\x88\xE5\xB1`S\xBD\xFF64"\xE5\xB4\x7F7\xB5\x08\xF5M\xCB\x9B\x88\x17\xAD\x85\xD30\x97\xB9\xB9\xD4\xCAiq\x96\xF8D\xDFCK{\xD87R\x95a\x10\x1F\xE8\x1B\xEF^n\xA8{\xD6\xC4\xADA\xAF\xB6\x1Ai\xD4\xDC\xE3\xB7\xB0\xD4\xCA\x02\xC2\x81\xF2\xA3\x12\x1CtuQrAC\xE8\xF7\xD9\x99\x95G\xACa\xEEC2\x7F]\xC6x\xDFj\xBE\x016n\xBD\xEC\xD1F\xF4EU\xF28m\x13\xD8\xF8\x16\xF8U\xA2P}]\xE3A_\xD7\xF5\x85&\x09\xBD\xD5T\xA7\xCCSN\xA6\x85\x1D\xF3Y\x14\xDF\xE7\x04\xF3\x10\x94\xEF\xDF\xE3\xE5j\xE3p\xE8\xB6\x89\x0C\xAA\xEB\xD6*\x82\x04ZuL\xC0\x9AFh\x09\xE0\xF2\x91\x1F\xDF\xB8`Ao\xAB\xCD\xB2X<\x0A\xD3l\xA6\x0C-\xA6V\x1A\x1F9\x1E"\xCC^) q\xDF)\xA27l\xC7\xBE\x9B9#\xCEWX\x84L\x13\xB1)\xF0\xEE\xBB\x04+%i\x95\xC9\x09\x15\x88Y\x07\x85(\xF2O\xFBf\x08\xFB+Kb\xEB\xF4\xC7Gn!\xC2\x81\xB6p\xE2\xF8;\xE7\xE6hI\xB0\xB1\xE4LN>\x9Ap;D/R\x10\x8E:h\xEA\xA9\x1F\xA5\x8F|\x1E'Cf7\xA5\xC1\xEA\xA1_\xB0\xEE*>].\xFC\xC7+%J\xFE\xBC\x8B\xB4S\xCF\xBF\x91\xBAc\xE4&\x8D\xBC%&z2\xEC\x1C\xEE"\x11\x851I\x8Dt\xB2\x80\x7FA\xC5\x1D\x03bzItg\xC0Z\xAF\x17\xAC\x97\x9F\xCDx\x81O\xC9\xF1\x99i\xC1\xF7f\x18QD\xCC\x04\x96A\xF4\xE4\x96_SLu\x17\xE9'\xB2\xBB\xE2(\x06\xBCa<\xA3\xD0\x17N\xC9\x17l\x177\x014+\x94h\x08\xCDv\xD2\x9A5Q\x1B+\xE5\x12\x1A|\x10\x93\x99\xC8\xB1\x97J\x96\xD4(0\xF7\xC4|B\xF2\xABH\xC8\xA0\xDE\xB5\x96\x02i\x8B\x88];i\xBB\x98\x85P\xB8s\xAA&\xA6\x83]\xE3J\x08G\x17\x8B\xD4Q\x16'\x0B\xB1\xE8L!\x1D1;c<\xFCA>\xCE\xC7>_Qu\xEC=\xEE^2\x827\x1F\x91\xBB\x17\xC7y\x18L5\xB7\xC2\x08\x037BH\x9F\xC4\xCA\xCD\xA3BQF\xC2\x0C\x9B[p%\xAE\xBC-\x03\x1D\x972&\x9E4w\x7Fd\xB5\x09\xEE\xA4-\xF8+k\xDB\xBFvO\xF2m\x0BcD\xD2?\xB71\x14\xD6\x84\xC6\xD3q\xF6\x88(t\xB9\xA1q\xE5W\xDA8\xF9\xA5\xE8\xCAR%\xEC\x08\xF5\xD4\xDB\x90\x8B/_\xB05\x0D\x08\xE8\xCC|-\xA2\xC9'4\xD9+\xCE\x9B.;\xD0\xF7\xB8\x94\xE2l\x1A*\x1D\x844\xF7\x89C\xDF\x09\xEA\x87\xF1c\x11\x09\x85MJ}z\x8F\x9E\xEF\xC8p\x96\xE2|\x09X\xD4\x90\xBC\xE38\xB5[\x9Ck\xD0^\xE0\xEA\xB6\x02\x9CQ^\xA2p\xCA\xDA%\x02\xE4y\x1Ayp\xC4\xFF\x9F=\x0E\x04\xBF\xC9\x80T&\xDB;\xE6\xCAL\x1A\xDD\x84\xE8\xD8\x89\x1B\x08\xEA\x81X\x08\x12\xC6K\xBD\xB0\xA4\x92#\x83B\xBE\xE4\x1D\xEBG\x85<5\x14\x8FaC7\xC7\x0D\xFC\x83\xF4\xBB\xE8\xA2\xED\xF9r\xB3\xEF\xC4\xCFP\x15\xC9.\xDF\xF05\xFF\x02U\xD1X@\xF7\xC9\xA0\xA7{\xC5J\x12"E\xF0\x067\xEBF\xAF?\x85p\xBDz/\x7F\x99\xB8\x0F\xE3\xBF\xC5F\xD9e\x1D\x81d\xC8\xB4\xBC\xD7\xE6\xC9\xC56O:\x8B\xAD\x0DM\x80\xE5\xFEh,\x1AR\xE4\xC4\xDB\xCC\x0B\x0BK\xAB*]\x9E\x14\xDF=\xF5Rn\xCCLi0\x89'\xF0\xC5\xBC\x01\x01\x87\xA3g\xE8D\xBC\x13\xD7\xCC\xAE\x19\xD0g\xEE)\x07\xD1\xA1`]M\xFA~\xE8\xF5!@Q]\xC5j\xF3\x01uY,\xEE2\x15vh\x14P\xA6\x1B\xC4;\xA2\x87\x89fA\xA3\xF3\xE7\x82[+Z|\x11\xCDF\xC7\x91F&c!\xDE\x11\x9F\xD0\x0F\xBF\x92\xB9\xFE\x05\xEC\xF2\xE2(\xED\xBC%\x16\x90\x06\x09H\x8F\xC2\xA5\xE7\xB6\x8D\xB8]\xC4\x07\xF0\x130\xF2\xF8\x09\x0F`\x89\xF2l\xD2\x0A\xAF\x84\xDAL\x9C\x92\xE1,\xEC\xFE\x18\x83<\xB9\x10y\xF1\xFC<\x09\xB4h\xAD\xF2\xCE)\xA7\x94\xA2\xB1\xA1\x9D`\xDC\xE1\xE3\x16\xA8\x1C\x05r\x12\xBC\xC3Y\x11.\xE7\x0A\xAC)\xE1\x16l^\xE8V\x03\xBF,|\xCA\x94\xC9K\x00\xE1\xE7\x8B\x19\xBEy\x09e\xD8:S\xC058\x09\xEA-\xAF\xC4\xC3\xF5\x83\xF7Q\xDE\x04\x10\xCE\xA43 \xAF`\x99\x8D\xD0\xC2[qg\xF6\xB3\xFA\x0D\x09Q\xD0\xBC\x9B\x9Ec\xDA\xA0\x9E\x97\xDE\x00\xD2\x0AV\xAC\xC1\x17\xDA\x86%4\xDA\xCEg\x07\xDC \xAB\xD1\x04\x7F\xC5\xA4\xA0\x81\xD7}\x82\x02\xEE\x94\x08\xF6\xCE\xB6\xFE\x93\xDB\x1E)\x09a\xD5\xE9m\xBE\x86\[s\xA2\xF4\xD8\xAF-\x07E\xE6Bm\xFB\xEF\x9F?\xBFCK\xE7\x8E\xF5mw\xEF\xFE\\xD4\xE3\xF3\x17\xD2hE\xC2\xEFFR\xD9\xD5\x0C\x8C\xA3\xB4\x02W\x01\x8A>*i8gunR&\xEDJ\x15\x8D\x19\xD8\xFE\xE1\xF0\xF2M|\xB4\xCD\xE3\xFBA>T\x0Ey"\x015J-\x98\xDAD5|\xE1\xC0\xA8I\xCFb\x86\xF3\x9B)8)T\xAF\xC2~;\xF9Q\xAC\x0B\x83 T\x91f1\xB6\x06\xA3\x15m\xCE\\xBA\xB4\x99G\x9A\x99^\xAB\xB9\xE2\x85\x18\x9F\xE5\xD5\xE1S\x00\xE8r\xA8B\x0EV\xAF\xC2\xE5\x06\xCF\xCE\x16;\xC9\xBAuF\x9E,\xEB\xAD\xF8\x9Ci\x00w\xCE`B\xD4\xF9(\x1AX#!!\xBA\xF1\xDA$\xA1\xFF2\x05-g'\xA8M\xBBRc4\xBD\xCC3\x95\xE1w\xAA\x15#\x15\xABf_8\x7F*\xFCNi!\x92\x8Cc\x9F\xE8\xDD\xE6\x9D\xAA\x9Cz\xD6p\xD6s\x8E<\x07\x0A\x19nl\x92e\xF5IMm\xA1\z\x05\xCD\xF0.\xFC\x10\xF4\x9A\x8E0\xBD\xE0%%\xFC\x15\xF9\xEDew\xE8\xAE\xB0\x9F\x80\xF5\xB1\xD7\xDB!\x8D\x926,\xD3m\xCA\xD4@\x0FU\xDA\xDB9K\x0F\x06\xFEG{@\xAE\x99\x1B\xFE\xBD\xC2\x06a\x11\xA7\xC1\xA4\xC6i\xDE_\xC7M\xCF\xF7\xDE:\x06\xEA\xCC\xE7\xA4#$t^S\x91\xD8\xD2s\xBF\x8A\xE1Z\x12\xA8I\x7F\x88)C^Vk\xBF\x19?Qi\x89\xDB\x1C!\x10\x19\x94\x82\xF58\xC9Q,\xFD\x89\xD3\x84w\x99\x88\xFC\xF8\xB4t\xE3\x05`\x06u\xD5\xEC\x8AB\xA0\xE6\x04G:=\xC9rX\xB8\xFF\xC5\xCD\?\xC4}V\xCD\xFC\xDAY\xBB\xD4\xE1!*6?\xB8D\x0Bm\x1B\x90H\x88\x8E\x856\x04`\xA2{\x14\x0B\x1Am\xF2\xBDom9\xF6\x16:\x05IU\x08\xA9\x0DH\x1D\xA44L\xEEP\x11\x02\xC6"~\xE6\xCCj\x85n\x00S\xC0Ge\x12\x1F\xB8`\x10\x88\xD5\xC5\x1A2\x99\x1C\x85D\x84\xCF\x1F0\xFA\x8A\x12\x19\xDD\xB6\xA6\x81\xD7:\xB6\xF11Q\x99\x01\x89\xCDP\x0F\x9D\xB8X\xFF\x0E\x8E\x08!\xC7\xB5\xA6\xE0\x1FnN\x16z|\xBF\xEF\x09sX\xB1\x8F0\xE2t\xA1\xFF\x04\xB1\xC3j|\x83\xD3\x9DC\xD9g!\x90A\x94A\x1B\xB6\x15\xFFR\x9EHH\xE5\x99\xC5\xE1\x07\xDA\xD1\x02f@\x00\x07\xA7\x1F\xE85\x0E\x00\xFC\xDDmYt\xFB\x87\x1E\xEA\xA6M\x8C\xEE\xA0\xD8v\xBE~\x1FY\x1A\xD2`p3Io\xB9\xA0d\xE53\xE1\xA65\xD8J\xC0J_\x99\xDBv\xD3\xE8\xF8\x90lf\xC9\x8A\xC13\x8A)j\xDE\xFE\xEC\xA4$\x13D\x91\xB6\xDB\xFD\xB8\x97\xBDD?\xA8\x0C\xE4\x0D:\x00\xEDY-\xA8{\xD4\x07l\x12o\xA7\x17\x84\x07\xEE\x0B\xECi\xDCD\xEC\xE5P\xD4\xB6\xB3\xFCI\x94\x96w\x89\x8E\xBB\x8A\xB2\xBA\x085\xAFP\x1C\xD9E\xD1\x95NQ\xD9\xB0\xFC\xE7\x88\x8C]\x13q\x18dl\xB6\x0BI\xC8\x1C\x82v\xCD\x02\xE7\x8F$\x99R\xE0.Z\xB9\xE8\xC3\xD9\x07\x81\xEC\xE6\xA4\x1C\x02\x87\x1F\x0E\xCE[\x07\xEF\xDF\x1F^\xED\xD7\x83\xF6\x9B\xA8\xBEV\xD0+\xE3\4\x19\x03A\x19\x90UJ\xDB\xBAR\xF6\x10\x93\x99\x19\xBA\xC1O\xFDqg^\xD1\x15f\xBC{\xDF\x99\x8C\xD8\xFD!\x81s7+\x8B\xE8a\xD5\xD0L\xE0\x81Z\xAD\x8F[p\x96\x86\x94*ak\xE8\xD5\x89\xE7\xBA\x19\xB9\xE3`vx\x94E|\xECf!\x9F\xC3\xDCkc\xA7h\x16\x15\xEA7\xD7\xDBs?\xFE\xB6!\xE5%\x03h\xD9\xF0\xE8\xC1\xAA\xBAP\x9C\x161(\xC4\xC4%L=\xD3\xA4\xE5\x8F\x90\xF3\x93\xD1\xE9k\xBD\x8D}\xC76\x0C\xA7\xBB\xF5\x028\xEE(\xF6\x92\xB3\xC5\xED;\x10o\xB8q!>\x01!\xF66\xBC\xF3m\xD6\xCEsr\xA7Ui\x00\xC4\x0D\xC1\x10\xA5\xF9n\x9F\xE3\x11I0\x11\x97x}DS\x82@\xD2I\x9B\x0B\x9A53\x00\x0EH\x0E*\xF3\xA0\x0Ct`\x8C4-n0\xDB\xD7D\xC42?\xCD\xFB\xC9\xA5([T9\x8E\x83J\x01~\x83\xDA\xF5|\x9B\xA5\xEF\xD2=\xE0\xA1\x14\x05B\xDEHm|\x90\xA9M\x15\x97\xF5\x07E\xCB\xBBc\xEA\xFD\xAF\xFB\xE4\xE9E3[UJ\x8Bc\xE9*}\xB0hfQH\x9D8\x92\x07`\xB9:\xC87\xFF\x04jF#\x89\x99\x1B\xD6W\xC0\xF5\xED\xE8!\x014\xDD\xBEB\x8FG\x1BBV\xC7Ds \xDE\xEC)\xBF\xC3\xC4SyA7F\xF4_\xAC4\xFE\xC0r2_t\xE9\xC6>\x1B\x8F\x0A\x01\x12\xF4\xC6Wn\xF4\xE3\xF2\x1B\x16\xB8\xAC\x0ES1\x1D~\xBB-\xC2\xCE$\x1D\x82{\x10W_\xD0\xD2\x7FQ\xE7FA\xE0\xF8\xD6q\xA2\x8F!\x9F\x05\x8FSg\x11=\xCAh\xD5\xB6\xF7\x91Y$\xF8d6\xD4&\xC7\x9C\xC6\xEA4\xB3\x95\xBD\xABJ\xC9\xCD\xDE\xED\xE1\xF5;\xF3r~\x9E\xC7\x82 =\x1B\xED\xC8\x0A\x99\x9F_\x90\xDC \x95\xED\xC9,\x88\x08\xCF\x04\xA3\x97\x06\xA8\xC7"\xAF\xAE\xBD\x8C@\xB2\xC7 \xA2\x03\x8D3\xEB\xD4hT\xB6\xB2\x81LZ\xEBH@\xE3\xB4Qe!'\xACU\xA8 2\xDB\x19\xE8\x89\xDF\xBF\xE2\xB7S\xAB\xF2\xBE\xE3\xBB'\xEAtZ$\xC6\xBE\x16n*\x1F\xFF4]\xCB\xE3d\xCD\x0F!\xD6\xF6\xD6|[\x9A\xB1\x8CI\xF3D\xBFV\x92\x88\x1Dx\xFA\xE5\xEB[\xA3(\xF6E\xE5}+bA\x93s\xEE\x14\x0AQ\xEB\xEF=b\x03,\xE3S\xC8=t\x1B\x07\x95 \xA5\xE7\xD8Q\xE2\xBE$\x01\xE4\xA6\x85\xC5\xA6\x8D\xDA\xDB\x9F\x97P\xFC[\xAE\xA4\x0C\xD7\x816\xCC5$x\xC4\xB1\xC3\x04H\x00tNi\x8EIT".\xC5\xB6\x99\x00\x86\xBF\xFBX\xEE'\xC1\x99@\xC9\xB8\x0Bs;\xC5\xE4A\x0C\x96\x96\x10i\x810X\xACu\xB1\xA9\x08\xD6\x1D0\x1F\xDFO\xAC\x98\xD0\x05j\xC7\xF2.\x9F\xA76\xDF\xB5\xF54\x8E\xFD\xD2Q\x1DOS E\x0D\xA4\x925a\xBA\xF5\x0FZkI\xD8\xF6\x05\xD0K\xE1<\x9FX\xA8j\xAC\?\xB9\xF6\xD7\xE4Ml\xB6\xD9T;\x84"\xB9\xE3\xDC\xA6+7\xCB\x88\xDC_\x96W\xAC\x1A/\xCB7\xC3\xE1\xAD\xA0\xC6\x0A\xB6g\xF1]\xD3Tp$[\xAF\xDA\xA6O\xF5\xB0H\xAB\xAB\x97\x0E\xCF^Li\xF1\xD0\xBF\x1A\xDB\xE0\xC8\xCC\x01\xB0\x09*i\xD4\xA0-/\x0Fb\xE1\x8B\xFB7\x01\xF9P\x8Fm\xFB\xEC!\x94\xC9\xCB8\xCD\xF7#|\xAF\xB3\xFAU\xD3Zzu\x1B\x19\xB1\xAF:\xF6\x03f\x7F\x81\xB3\xCD\xCDC\xA5e&\xBCau\x8B\x07\xEB\xECNn^Rmj\xDD\x0A\xC8OQ\x90\xB5\xB6\xE6\xEB\x12S<\xA5`:\x0C!\xD4\x1A\xF2]\xB4\xBF\x0A\x1C^&\xB5\xFA\xC4\x02\x0B\xFC\x82J\x10\xE0\xE7!\x11\xE0\xAC~X\xA0\xC2\x8DW\xCF\xFB\xC0~\xFCP\x7F(\xB5i#\x1F\x7F?\xB8\x04=\x0F\x1C\xF1\x92_\xF7\x07]\x87D\xF7\xFD\xC0\xC2\xF1_\x97`,\x8D\xF1\xE7A\x15\xCB\xE8\x80\x08+\xCE<\xC5\x91\xEC]Mp\xE7\xDCo\xB2Y\x11>\xA2M\xF8\x08[\xFA\xC6\x1E\xEC\xC1$\xA1\x85\x9E\xFE\x8C\xB3v\x1D\x0A\xBB\x11\xA0\x8C\xEB\x0E\xBCV\xE0_\x1C\xBEC\xB2\xBF\xE9\xEBj;\xC3\x9E\x00\xF5k\x08\x0F\x85\xB4\xEDW\x83I\xB5#i_\x85\xA5b\x0F\x0B\xBA\x98e\x9E*M}X\x8A\x1DP\x97\xED\xAB-\x0E4C\xCD\xA9\xFC>\xA4\xA1\xF4N\xAE\xE71\xA15\xCD\xE1\x84b\x84\xF3\xDD\xDC<\x16!\xAF\xC2\xBB\x93\x89\x15\x9A,\xD0\x00<\x93\x08\xAE\x7FF\x14\xB64\xDF1\x88B\xE5\xF5\xA9\xC7\\xD2<\x82\xA1\xBE\x05\x06\xCB\xA4+\x97wu\xCDN\xBB\xEC\x0D\xBC-G\x04b\x95\xB7\xB1hFPKA\xEE\xBA\xBD\xD5\x1D\xC2\xE1\x06\xC8\x0C\x03o\x1EY\x83>c\xD9_\xBFC\x10\x01/\xD0\x93\xE2\x043~\x01\xD3j9\x0A\xF1\xB5b\x06\xA9\xD0\xED\x90\x03b/\x16\x95+\xC4I\xC2\xAD\xD4\xD7\xAF\xB3\xCB\x80\xDB\xBDd\x98\xC8\xD9\xB8I\xEF\xB1?\xF3\xEA\x81\x99\xAA\x9EF\x09\xE3\xB9':Vi\xF3\xAD\x0A\x80\xF3\x0A\x1F;\xF9\xCD\xF7H\xFB\xBE\xF5\xDD\xFA\x0E\x0BrH]]\xB6\x0F\xA9\xCD3aZ\+\x80\x12\xC7\xB5Yb\xEB\xFC\x81\x85q\xA2\xC2\x0E\xB7\xAD\x9EM\xBA\x93\xEB\xA8\xFAJ\xCA\xE6\x03\x1DT\xA0\xFC\xCD&\x0E\xF7\xAEDV\xC7c\xF1\x84\x06C\xD4\x9A\xD4\x13O\x80\x93\x8D\x00\x85\x12\xA3\xC6$\x19qs~\xFC\xB7\x97\x0A\x11\xDD$=\xE3gk0u\x9E\x0DH\x9E\x0E\xE5\x03\x83\x1FsY\xD6\xB6\x15\xD4k\x82\xA0\xC8\x8AH\xED'\xE8\x92\x00\xEE\xF6\x1D\x14\xA3"\xEC\xFB\x7F}\xE2\xD8m|=\x04\x04\x9E\x91\x10\x09\x07\xD0\xB5\xEE\xB6y#%\xFF=\xF1\xBEq\xF2\x94\x0B1\x17`\x93\x95\xB0\xC6|C\x18\xC6>\x89M\xD0\x1Fr\xA9\xFF\x06\xA5\xD3\x99\xD8\x1Fc\xA5\xD3;b\x9A\x18Us\xB4\xEC\x1D;\xF3\x982O\xA2Vw\x12\xB6p \x8A\xBD\xA8H\x1D\x9489,\xDD\xBB\xE2\xB3Vu<\xC9\xA1\x12\xE0\x06\xC4\xE4 \xB7\xD21\xCF\xAE\xE3\x14s\xDA\xA5\x96\xB0F\xBB\xF3\xC5S\xEFaK\xF5\xFDU\x97\x15\x85z\x83\xCCC\xDD\xC9\xC4f\xA6\xD1\xF5\xC0\xBA~\xD0`9-\xC0\x9B\x99=\xC0DIC+I\x14\x17\xE6\xF3*\x91\x17\x9E\x8AXS\xC2 p\x0Cx\x8A\x07\x7F\x0A\xEA\xDB\xD0$SR0\xDB\x1C\x8B1\xF6\xDB\xF3\x972.Y\x04\xA8@\xF81\x1E\x9A\xE12y\x1Ae\xBD\xB3\x0Ca\x86++\xFD\xEE\xC5\x8D4CFg\xCB\xDB\xBC\xD4#IW\xEF\x8C\x9D\x05\xDFof\xF7s@w\xE0\xFA\xDA\x86\xE6\xE6\x9A\xA4\xA7\x81m\x84~\xCB\xEA\xCA\xC1\xC7X\x1AD\x03\xF5\x8D\xD7%7li'^\x1F\x0A\xBEWesn\x9B\x00;\x91\x120gUU\x8A\xA2\xEB\x85\x04.\xD6v\x88G\xF5\xD1r\x0Aq\xE6t\x1D\x9AW\x18Q\xC5\x85%\xCF\xD6\xA2<\xCEu\x1A\xF0v\x12p\x8Aw\xAF;{\xDDZ+~Ym\xDD\x86\xFBg&\xD9\xE4\x92Rw\xC4\x0Coe\x04\xBE\xCC\xDF\x88~\x970\xA5T\xFA\xFFtq\xF1=\x99]\xBD\xE5\xF7\xBF\x15\x02\xF5:_\xAA\x10\xFC\x1D\x86^\xEC+\x1B\xD64\xDA\xA2\xE3)3F\xBD7b\xC4R\xFCd?[\xF4\xE1x0\x86{\xB7\xBD:\xE0\x1F\xB6\x08T\x14\x94\x1F\x1E\xCC}\xE2\x9F\xCF\xBB\xB6l\xD0\xCE\xE1\xCB5\xE2\xDB\xCB\xD1\xA5\xDA\xD3\xA7g:\xED\xB0\xE8\x90\x03\xE7\xA7\x00-\x0Bg\xC1\xB8\x1BEx`\x03\x9D\xF8.\x1D>l1\x9FH\x04\xBA\x01\xC2\xA6#@V\xB5\xCA\xFE+4,+\xB7iqY\x88M\xA5g\x11\x02\xA7r\x93$\xAFPq\x8D\x8E\xFD\x12\x14\xE7\x1Fe\xA55\x18\xEEBZi'?\x8F8\x82e5#\xC3*[H\xFAG\x14\x9C]\xA7L\x90\xB2\xFD\x94t\xFE\xEBC;\xF2D\xFC\x9C\x94V;\xFE\x88\xB3\xD3\x0D\x0C\xAF\xC1\x98\xFF\xE7\xB3\xA9\xAB\xA2z\xC7\x8E\x14+|\x0E\xDC\xBE\x05\xEF\x13\xA5\x89\x81\xF6\xB1\x12\xC1\xA58(\x8D\x8F\xA0n$\xBF\xDC$\xDF\xF7\x80\xE8\xA8\xDD\xF8\xED\x06\x0DA\x1C\xCEM@\x7F\x95\xA71X\xA8+\xAF\x9E\xA8U\xC0\x13\\xDB\x81\xE0\xE2\xDF\xA9C\x96\xA0v\x0A[\xE7\x00\xE1/'\x8B\xAE\x18\xD5\x8B\xBD\x8D\x0C\xDC\x16\x04\xE8\x82\x04\x90\x18^\xF7\x80|K\xB1\x02\xA6\x9B\x1C\x07A\xB0\x9F\xE4\x0D\xE5\x03z\xFD\xF8\xA8\x15\x8E\xA9\x85\x0Do\xD0:\x1Ek\x1C.\xE9\x90\xDE=)\xC6M?\x06\x0A\x036t\x1B\xA2\xED\xCDr\x12\x0A\xB6j\x91\xAFqI\x0C\x7FT\xFAN\xE50\xCA\x03\xA0]G\xC42\xDA\x08\xAF\xE0\x99WI.F\xAB\x13\x1C<\x18\xBF\xC2\xA4\x10\x04\xD2\xF9\x0A?\x18\xCF\x97\xB9\xB1\x83\x0C\xF8\xEE\x08\xA7\xF6<\xC2\xCAh\xBE\xC0!\xC5#G^\xC4/]\xAD\x0A\xAF\xC5\xB9\xDF\xBC!\x94DL\x96\x13{i\x99\xCD\x10\xBF\x92`\xE9\xCC8\xC6\xB2\xBE\xCA<\xDA\x02\x17|\xB1\xD9\xE5\x85mX\xE7|\x8C\x94"DQ\xB6\x9A\xD1\xFF\xD5_\x9A\x0C R\xFE\x8F\xAB\x8E"\xE8\x84\x91\x81\xD1\xA6x\xAB\x84\xC3\xC4\xBB\xEF\xFB\xC9\x8D\xA4D\x9Cp\xA9\xB5\xB4\x11~t\xD35\xEBM\xADs\xCB\xD8N\xAF\xD64\x14N\xB8\xE7\xC1~\xCF\xF7\xC2Vny4\xDDAH\xCF\xCA"\xFB%\xFF\x92\x91\x17`\x99\x9E\x168\x7F\xD3As\xF4\xB7\xC9`V\xB8U:pS|\xDB[\x18#W\x90\xC1\xD6\xC3N<\x10\x0A\xD5cs\xF4\x80\xEF\xFC\xCC4\xC4.\xA2;\xF5`\x17\x16\x15\x90\xED/\x1D\xD7\xC7U\xA4\x19\x05\xCD.\xB0\xFC\xD3\xCC5\xD7\xC626TZ\x90"\xF1\x84=\xD5n\x1B*\x12\x90\xEC2Fp\x80eC,\xE9\x8Fb\xF2\xCA\xF0\xEFq8.S\xB3)E?\xC2\x88\x159\x12\x0E\xA0\xA7\x86!\xB1}x\x06\xA5O\xEB\xAA_e\xEB\xA2x)\x12M\xF1\xC2\x83\xC4H\x09K\x85\xEE\x8F\x8C\\xFC\xE6\xA29\xA51\x9D*:fmd\x90\xF5\xD0~\x0E\xF6\xE2U[\x81\x0C\x09U=Z{R\x97^\xE4J\xA0\xCA\xC0\x90\x8C!V\xB0\x89\x9D[.c\xC1\x15Ag\x11\xE8S\xFC|(\xD4\x0A1i3Z\xF1^f\xC1\x10\x88\x0C\xC9^\xFA\xA7\xD7K\xE9\xFC\xDB\x19\xED\xB4\xF3>\xFE\x9Csr\xF8\x934HqK\xC5\xC2\x1DR\xE1tXe\xE7?\x9F\x85\xB9\x98\xE2v\x82z#\x1Fe\xA2S\xBC\xC0.\xB0f\xA8\xE9\x8B\x11P\xB9\xA4\xEB\xA4\x12i>\xA4\x1D\xDAY\xC7Q\xCEx\xA0\xCE\x8BcsO\x0E\x89\x0DF\xB8\x8EU\xA8\x04L\xB7m\x1C\x86\x82\xFE5\xE67\xE0\xFD\xE0\xE4\xEE\x9D\xEDJ I\xFA]\x0F\x19\xAC\xE73\xED\xB6\xD1\xA3\x8CrZ\xC0D\xD4\xC589U\x03\x02\x0E\xD3\xB5\xDF\xE1\xA3h\x94U\xA0w\xBC\xA3\x94WT\x1F\x0D\xCA\x9C\xB7\xF62\x99\xED\xC6\xFCju\xEA\xD1$I&\xF6\xEDO\x9E\x05\xE4\xFA\x9D\xF2\xFA\xA0|1\x18\x94,\x8D+}\x1C<7|\xBB\xB1\x99\xEF7\xE6\xE1\x9C!\xA8\xD8B\xF4\x8F\xE1W]\x7F\x9BG}\xD2;\x83\xD8\xF7\xD4\xBAb\xCD\xB6k\xFA\xCC\xE80\xDF#\x9D)?\x02\x1F8B\xA0g\xE1P\xB7\x11\x93\xB3\xBB\xBB\x9A\x86N9\xAF{\xA9$\xC7\x857B\xC5}\xE8\x1B\xC8\xDEF%S\xAA/a\xDF)\x8E\xED\xC3t\xBD~y\xB9\xCD\xBF\x7F\xD5\xC3\xA9\xB37\x99G\xBF\xA9e`\x82\xC8\xEF8\xD8d]\xF5\xED^C4\xDB\x92\xA415+\xFB\xF0\xB3\xB2\xFE\x19\xE50Ly3\xFE\x8D\xD2\x17\x7F\xD7|\xB3\xE0%Cz\x02\x8E\xCA!\xB1\x9B\x9C\xD6\xC7\x01)\xB6\xD2cv$\x97\xDF\xE5\xBB7\xE7\x0FybJq\xF2s\xAD\x83I\xE9\xFC\xDE\xA0\xA8\xB2\xCE\xD8w\xA2jZ\xAA\x99\xC1\xD0\xA3\xC3\x06\xF4`\xD3\xD3O\xA2)\x9FF\x9C\x00\xDC\xF4 \xC5h\xA8\xFC=\xD8\xAE\xBA\x83\xE2R,\x97\xDBZ\x02\xF9\xA7\xFE\x0E#Js\x00\x8A\xE8\x85\xCFk\xA1d\xB6x\L_\x00q:\x11\xEA\x19\xB6!\xD8\xF7\xC7~\xDD\xD9\xFF\xAD\x02\xC6tcx$*\xDC\xCCUZ\xCC_-\xE2EP\xD3W8#\xEF\x82\x12\x94\xA71\x04p\xF5\xA0\xDD\x94G\x159\xCE\xF6\xD3\xD9\x7F+\xEA\x01n\x8F\x87\x8D\xABIP3.)\x16\xBE\xB9_F\xEB\xA5\xAC\x8E\xDD\xCBr\xCC\xA8?H\xC2\xA9\xC9r\xFB(\x0E3\x99/khe&j\xE3\xB7#\xB1\xD8\xC7\x98\xAB\xF9\xFA\x09T\x9AD\x96\x0D^^\x07\xE2\xEC\xC8L>a;\x06\x89\xB1M\x01V\x1D\x0D\x1B&\xA4\x0Al*\x81\x1Ah\xA1I\xDBs\x05T\xAF(\xFF\xA2a\x08\xB6\xF3\xD4\xA0\xA9l\xAF\xF9\xAAq\xA3|]\xDBy\xFD\xED\xA4\xA6BrI%\xE5\xB8\xA6\xE5\xEE\x04\x8A+-\x11"\x90(\xDC\xD1\xA8\xD5[Wk\xDA\xD6\xD6\x11\xAD\x82\x15[\xD6Xrg1\x17\x8F\xD1\xA6\xB9\xED\\xB98\x02\xDDT\xC2AH\x06CV7\xC8k\xA5a\x86\xCF\x10\x19\xA4Og5\xE5R\x1D\xFA\x95\\x89P\xD0\xBCy\x9B-R\xEC\x04tQ\xEE6\x03\x04\x83;\x88\xEFhn\xE0\x86\xFE \x1A\xCE@\xC2$2R\G/UNx\x0Bbp\x7F\x1DlD\xBE\xF7\x9DL\xFDW\x1EYZ\x0A\xCEe\x98TdnJ\x14\x94.%\x00\xEA\xF0\xB16"%\xF4{8\x88\xB3H2\xE49\xCEgk\xD9f5\xE7U$\xF0\x9A]\x92\x8BFf1\x01\xAD\x00\xF1\x08K\x820\xD5\xC7h\x92\xF7\x82\x83q\x7F\x97\x0A\xAE\xC2\xF1[\xE8\xAF\xB25\xA5:>?J\xEE,\xB5\xC6\x89\x1C.\xA9Hn(n\x991\x9A\x850\xD1\xFE\xAE\x80\x16H\xC7\xE3\xAB\xAF\xDB\xB2\xFB\x96I\x1FB\xC2\xF3\xD8\xB3\xCDt\xA1l\x83\xE7's-\x0Dd\xB6\xA7\xBE\xA3\xAF\xCB\xC1\xF4\x97-\x97\xC8\x0B\x85h\xC8Q<4\xCC\xEE\x8D\x09\x02r\xCC\x00r\xB4b4\xB6q^\x10\xD7\xC5-a\xE6X\x15XA\xE4\xDB\xACU\xA1\xDE$\xD5\x12l\xDB\xEE\xA5\x9AG|\x85P\x8B^\xA1`\x9E\xAC\xF3\xC5\xB5\xDFXN\x1A\xCF\xBB\x9AK\x8Cg\x853\xB7\xE4\xBF\xC2\xD8\xECGy\x85\x9E\x84\x10\xF5KL\xA2\xF1R\x83\xA5e\x91\xC6\xC1j^z\xDB\x85z\xB5\x1F\xDB\xF9\xAD\xB2\x1D\x04t7K\xAE\x80\x0B\xDE\xD3\xA7\x9D\xE9uf\x8A \x89\xEE\x96\xDF\xE4eW\xEF\x8D\x12\x0Bb#\xB2\xBF\xF9o\x83\xCC\x8037\xB7fiX\xF2\xB1\xEC\x06!G0<\xD3\x99~\xF9\xF058\xE8\x19Z\xF5\x1Dv"K\x1C\x00\xAA/\x93\xBC\xDC\xB2,\x0BP\xDD\x0B\xC7\x08\xAD\xA8=\x0A\x8D\x09\xB3\x8B`\xA5\xA3\xB6\x96\x91\x80\x06\x85\xA8\xFB\xCBU\xF0|*AS\x14,\xC3\xB3\x09\x91:/\xD70(\x1C\xF4\xEDJY\xF3\xED8\x88\x9E\xEB\x00\xD9>\xA6s\x9E,\xC2\xEE\xE1C\xFA\x80P\x84~6T\x97 \xC4\xED\x98\x972=\x98^\xD0\xCB\xEAdU \xA4e8b\xBD\xE1uN\xB2T\x8E\xC8\x0E\xE7Y\x9A8\x8E\x17\xE9&\x89F)F\xDE\xE8\xFBq\xDB\xA06u\x03(\xF5\x98yb\xF6\xC2\x870\x14\xBC$\xDE1\xA1\x14r\x99\x8E\xC0&\xA0\x08>D-[j\xC2\xDCWJA+o\xCE\xECC\xB1S\x89!P0\xC9Yw\xD8[i\x12_\xF7\xC0\xF9\xD2\xD3+\x0A\xCE\xA6\xC3\x83\x1Dp\x14b\xB80\xA4\x89\xE4\x1E\xA8\x8F\xC0Gx\xA0\xF8\xC8H\xFD;?*S\x04\xC3\x80U\x12\xF2m\x88r\x97\x16\xA3*Q\x93A@\xE8\xF0j\xDB\xAA6\xD4{\x94\xCB=g\x1Bo\x92\x94:zzY\xD7U\x12\x9C\xCC\xC1`\x0C\x1F%\xA9\x1D\xD9\x01\xF8\xC9%\xCC\\x8E\xB2\xC7\xD3!.=\\xEE\x94H\xDFi\xAC\xFD`-{u\xE4\x95-,\xB0\xCBV2\xE5\xF4PV}X\xA8\x03\xE7\xB0\x1B\xA9\xEBC\xDF\x901\x95jP\xEA\xE7\xE3v\xD5=R\xCE-;\xB6e\xDEC\xA7\xC1\x1A}\x0F5\x95b\x0C\x8BnK]\xCF\xD4,0\x92\xD9H\x9AWX\xBA))V-\xC6\x15o=\x0BBip\x14O\x11f.\xEB\xE0\xC2\x06\x8A\xCA\xCF\xC0\xE0K\xE0\x05\xACD\xF7\x90\x06\x90\x88H-+\x8C?[\xA0L\xFA \xEE\xF13~9\xE6\x03S~y\x00Dl6\xE1\x11\xEB\x0F,\xA1\x9C\x99o\xB2(\x9Dly\xF7\xC8\x96D\xAE\xF4\xCE1\xF9\xCA4\x9B\x1F\xFC{N\xD1\xA4\xBD\x86%\xF0\xE4xC\x13dA\x14\xC3\x9D\x19m}\xD2\\xF34:\xC9o$\xABTs|\xDEM\xBE4}\x0E\xAC=b7\xF4\xF2\xC5Vj\xA8D\x82\x1A\xAC*\xA4\xE6W\xB4\x89GL/eG\x98{\x0B*E\xD9\xA9\xE7\x8F\x96\xA4\x10\x0D!j\x9F\xE2\xB3\x0B\x16_2\xCB\xB4\xBD\xFC\xF6)\x8B\xBA\xE8\xF1\x1B\xC9\x1C\xADu\xDB\x9C\xBD\xC92\xAB\xD0\xE7}\xD8@'\xA4\xF8%\xC8\x0E'7\x85\xD9\x9F\x8F\x85\xFBC\x86\x8E\xE1\xC3\xB9\x15e\x05\x0D\x9E.m\xF2\xB7\xD2\x9EX\xFB\xB2\xDE\xC5u\xF8/$Q\x92\xFA\x0Ca\xD5\x06\xAAg\x03`\xBF!\xA9\xC1\xD8\xE4Eh\xA8\xC6\x8C\xE4\x9D\xB4\xDE\x9E@\x1F\xBDOa\x9AuQ\xAE\xAE\xDE\x9E3u\x0Fn\x1B\xAA\xAF\xA6Wlw\xAAwD\x0CV9M\xB0\x93;~\xA2I\x85D#Y\xEFaD?|\x07q\xCD\xB3\x82\x91\xD4\xCC\xF6\xDE\xD5\x0E\x0ESi\xFFr\xF0i\xA0*\x15\xFB\xD4\xED.\x15-\x94r@osB \x175\\xF7\x8B\xD5\x19\x048\xA0\x81\xFE\x12S0N\x7F\xD9\xD9\xD4\xCF`'\x8C\xC0x_\x07\x0B\xAC\x8C\xDC\x891C\x0EW\x9Eg\xCA\x0D\xFC\x7F\xE7\xDB!\x06@]\xCE\xA4\xB7\xD47\xA0\x02y\xDA\x19\xF2+\xAF\xAD\xF8\x15\xED\x1F\x1DS\xFF\xEB%\xFB\xA1M\xFC\xC8\x8BmZn\xFE\xE1s\xE4n\xFB\xC1\x02oy\x11\xEE\xEE\xF9`\xBCu\xE0t\x80\xFE\xEA\xFF\x83V\xD6k\xC81\x95\x1A\x1E\x13\x0ES't\x8E\xD9U\xDD\xB9\xE87\x16\x95\xD2\xF3\x1C^\xC8I\x92^\x18\xBC\x10\xA7\x9A\xD25/\x9F\x8C<=\xF1f\xC8(\xECB\x14\x00\xDA-\xDD\xEE\x99"\xF2nT\xF8\xC9v\xB7\xCD8\xE20^\xD7\x96\xA7\x0A\xD4\xB9\xF0\x90/\x9E\xFE\xEE\xF0\xC3\xF4\xBC\xEDU\xDF'\x0D\xBC\x19>\x86\xC6\x82v6\x0D"\xEA\x1F]\xF2\x9F\xCE\xE4\xA45q6nO5X\xC0\x13\xD8RH\xD0\xA8&\xAE\xAF\xC1\x1E\xE9\x88O\x91rv\x9F\x0E;\x85\xFF\xC1\x8C\x0E\xA9$p\xB1\xCE\x0A\xEA%\x17\xBD\x18d\x0D\xC6ZCiZ6h\xD6\x09`\x089D\x7F\xAB*\xDAXs'h\xBD3l\x97s(%\xBC\xAA\x1BK\xC8\x12\xD7\xC4\x9C\x86\x90\xA8\xB9Z*\xFFPc3\xE7\C\xE3\xE1\xB8XKe\xE6\x1B\x18\xA0&\x09\xA1\xC4\xBFN\xAAo\xC4~\x0E\xFD\xC1\xEFg \x1F\x87\xF5Q\xAC\xB4\x80sa\xAE>\xF0QA5~\xF1\xB3\x97\x89'\xFF\xE0\xE0\x14\xE6\x04\x83\xF4\\xD1\xE3\x0D\\xFB\x8F\xBC\x89\x90\xAD(\xA8\xA9\xA8\xEBi\x80R\xA1\x1A\x12\x81(\x98\x03\x84X\xFB&\xD0Z\x08~\xB5\xE2\x94\x03!\xF1\xD4\xFD\xB7\xAC\xB1\xFBe|\xF3B\xA1\xEF$\x1Ad\xE9\xAF|a\xFD\xA5?\x1F\xCD~\x06C\x1F\x99\x00\x02b\x9D\xD6\xC1\xD1\x13\xF8a8*\x86D\x166,\x88\xF3\xC7\x1EW\xEEq\xAC^2\xEE\x07\xA8N}\x99\x9F\xB2\xF3\xCCA&\x807\xAFa*\x9A\xE0rs\xB9yv\xA1\x9C\xE0*\x9B\xDF\x8ECI\xA1\xAA\x1B\xE2\xA9\x98\xE4\xAE\xB6\xC6^\x1F\xA5\xFFR~\x92ht\xBB\xA5ft\xEB\x0Ep_L\xDDp\xECc\xFB\x07B\xC4\xBDP\xD0F\x0DXK\xF8\x01\xBB\xAC_\xC5\xB2\x04\xA6\xC9X!1qV\x00\x9A\xC1\x84\xA3`\xBC\xD0\xAC\xB7\x99R-\x8Dqf\xE8\x0E]e\x9E\xDFN\x1D\xE0\x1Bq@\xFF\xAD#<\xA9\xB17XS\xB8\x92\xD5S@\xB4\x82Ty"Lm-\xA3U\x86\xFF\x8CB\x8D\x8E\xDE\xCE\x80\x14k)\xC3+\x01%\xAF\xFF\xAF#\xAA\xFB\xB7!&\xD6\x87]z\xE3\x0E\xBCa\xF0\xA2\xBD\xE6\x9E\xC5 =c\xEF\x1E\xB3kv\xBF\x0CNF\x91\xAF\x15\x01\x9F\xBDd\xAB\x89\xC8\xE9\xAD\xF8\xC6D\xF8\xFEh\x0C\xCE8\xFE\x9B;>\x13\x81\xFE\xD4\x1D\xD3\x13Z\xF7\x14&;\xDD\xF1\xBB\x8A\xFC\xC2\xE3Ad\xDE\xB80\xB6\x1B\x16J4\x8FA\x82\xB8\x0A\x97z"\xBA\xD1\xCB5akz;\xEF\x89\xA6\x7F$\xEA\x9A<\xC5R+\x02?\xAD\xD2\x97\xF5\xD4\x07\x872S\x0Bo\xF2\xC1\x02'\x08Lg\x1C]\x0C\xFF\x7FlK\x1A\x1D\xE4\xF8yX\xAF\x19\x86\x04\xC1,\xE6V\xF7\xD8V_\xD6)\xB6\xE0,\xF7\xA4\xE03\xDErz,g\x80\x04\xDB#o\xEE\xD1\xD1\x07\xD7\xE4e\x97k\xA0\xDE\x1F\x11\xF3\xD3\x14\xE1=\xCEQt\x08\xBC\x0D\xF0\x99\xF1\x1Dw\xB5\x0CI\xF3\xB8\xC3uW\xD5\xFF\xF0?d\xB5\xEA\x7Fd\x8A\xB1l\x86\xE9\xB9\xC7Y\x0A\x09)\x89r\x0A\xF9W3f\x90\xCB\xCF\xC2\xFA\xA4_\xAC\xA8\x02\xBC\x1B\xDCR\xA0\x7F\x0D\xF0\x92\xD9\xBB\xD0L\'p\xC4\xAA(\xE5\xDC\x89\x0B\xA5J\xE1\x84\xF5M\x7F\x8FP\xEBe7\x1Fk\xDFD\xD1\xC7\xAF,\xBF\xAE\xDD*\xD2\x98\x8730\x8D0=\x87|\xBDU\xEAt\xC4\xC8yJ\x89\xE0\xB6\xC3\xBA\xC2v\xBB`\x03V~\xF2h^\xF0s\x9F\x8F\x92\xF4\xCCP"\x08k\xE8\xE6\xB3\xC5\x0Bxa\x08V\x86\xB1\xB3\xACU(z]\xAC\xCF\xD9\xFE\xA5\x03\xA2\x08y\x02\xE6\xC3\xEC\xD0\xE07\x95+%\xB2%D\x8A\xBB\x15V\xF8\xED\xAF\x1C\xFC\xB5PJ=\x0E\xE2Q\x80\xD8\x96\x9DU\x0E\x00\xF1\xFA\x89\xDB\x07e\xEC\x98\xAF\xF1p\xD4yW\x07\x98\xC0J\x8B$8\xB9\xEE\xA7\x17\xB1\xD6\x80\xB4E\xF0vE\x01\xFE\xF3\x0B6\xEA)I\x17S\xAD\x89\xFD\xEC\x13f\xD3\xEE\x06`\xB3DG\x12\xBB\x07\x92\x85\x05\x93\xD9\xB9x~}Z4*\xC8+\xEF\xF8\x8E\xFA\xDA8\xD6`^\x81x\xFA\xC8+\xEA\xB9\x09\xFEkS\x92\x1D\xAC"\x837\xFE}\x06mu\x86b\xEF\xE6\xC5\xB3H\xCC\x08\x82\xEF \xC2\x05\xD6\x0CH2So)\xD2X\xE3\xE7ov^\x01%\x0D\xC5\x8AN\x02,\xF6\xF1:\x93\x8C\x83GH\x94\xBC'\xFC\x0Dc\x99C\xB0\xB2Af\x7F\xC7yh\x98\xCC\xD1d\xAB\x02\xF4XC\x8D\x19\xFF\x93\x8F\x9A_\xA1\xA3\x0C^\x1B\xF7\xA1T\x12\x9E;\x92\xB7[\x98M\xD8\xDC\xE1\x8D*\xD8\x15h\xBF\x99Z\x95\xB2t\xEEv-\x16u\xA94h\xDBQ\xF0\xF7\xB1\xB7\xD1&\xAD!\x80\xA5\x91\x94\xF8\xBC-\xDD\x92O~\x11\xAAI@\xC3\xE0\x9D$\xAA\x19\x19\xD6\xADe\x94[\x9Bl\x03\xE5]Q\xE4d\\xE2\xCB\xF5;\xC9\x9D\xFA\xE0|\xA9;!\xA8%\xBD\x00\x1C\xB2\xB4\x1E\x1D[\xFF\xF5>\x87\xE2[xu\xC4\xE1\x0FLL\x8D-\x9A\xD4\xA7PoU\x8F%x\xBC\x9D\x05\x0Aj!u\x88\x8D\xF3\xA1\x8A\xAB\xDD\x84x\x95\xB0\xD2\xB1\xDB\xDE6`@\xBA \x1C,\xAD\xB0\xEBsKO\xD5+s\xB4>\x9D\xB4\xEB&\xFB\x87\xF2\xEB\x15j\xC4z\x9B\xC0\x041`\xA5@PkB\xE7]\%\xA7\x95n\x99NY\xE2\xCF\x995b`A\x01!E5\xFF\x0B\xC9k\xE6\xC3\xA7\xAE\x02\xF3\xB8\xCD\xE0\x8A\x19\xC7\x83\x14Y8\xB4\xFB\xCBK\x9A\x17U\x9E\xABC\x8A\xEA\x92x\x12\x12\x0B\x9A26`\xAE\x9E\x7F\xBBtm\x9Bm6?LY\x0E\xA5\x8D\xE1x\xB6\x1B+\xD8\x18-\x8F\xDC\xB7\x9B)\x9Cmb|Y%p\xA0\xA37\xB9\xC2\x12\x19\xBFE\xFEMr\xFE\x02\xB7y\x96\xB5\xE0' AY\xE7$\xA0\xB2@>p\xA4:;u\xE4$I<{\xA4\xB9\xB9(\xFE0\xFA\xF1~\xA5\xDEg\x96\xEF\x8A\x9FZ\xAB`\x10\xF32\xA4\x15\x03x\x83\xB2h4\x17<\x83C\xF8\x8Fa_\x0F\xDE\xE0=\x01G\xC3\x06\xB8\xB0>\x17\x7F\xC9\x120\x82\x95f&\xDD5\xFB\x98\x10\xF7\xF9\xF9\x02O\x03l\x10`\xBC\x84\x86\xAE\xD6\x81\x7F\xBA,N\xF9\xD5\xE2\xEFc\xE7\xFB\xD9\xC8\xD6\xF5u\xC1\x8Cs\x95\x97([R\x18:\x9Evi\xDDt\xEE\x1Do\x8AqN^R\x11e\xF2c*fO\x1B\xCF[\x9C\xEB[\xBCN\x9C\x14\xC3\x96\x1BH\x08\xAA\xACo\xDA\x83\x16rUB\xCF%\xD6?\xEA\xB4#0.\x91U\x10\xC3\x10g\xEB/\xC4\xA0}\xFA\x10\xAB\xFE5\x01z/\x85\xD8X\x95\xE8\xB6\x93|\xB5\x81\xAA^\x97:B\x92\xA4Z-\x9B\xFF.\x82b\xEA\x83\x88X\x00tg\xB1,Uc\x1C\xC1m\xBA\xFB\x87\xAE\x91\x8E\\x821\x12yQ\xD1\xEE\x8F\xFB@\x98\xCC\xB4\xA7I\x11\xFE\xCF\xCA\xC1\xE8\xC8\xD2Q\xC6l3\x10\x81\xE7\xCEfw\xB6Bl&a\xE9\xEA=T\xD7\x8C/\x1C\xF6\xB2wU>$\xB8\xE0g|\xF8\xC1>\xC9B_\xFD\x18\xD2\xEF\x1B\x01\x18\xCD\x85Z\xCF\xD9\xBB\x89\xE1\xBF\x99\xF2\x9F@W;\xDD\x93\xBC\xED\x00\x81Zk\x88\xBDN6r\x87V6$K/\xF3\xF2\xBBE\x8D\x97\xBC\x00o\x02Oc\xE2\xC6\xDDh\xD0\xF3\xFDi\xEC\xC6\xEE\xC9\x18C\xA4\xF4\xBA*\x9CG\xEE\x10BXU\x12\xED\x0DwXQ2\xE5\xF9\x9A6O\x03Kp\x10X\x0E\xCA7\x007\xB72qJ\xA1\xD4\x92\xAA=\xAC\xF3[4x\x7F\xD0\x98\x0CE\x0B\xA5\xE7\xE3\xF1\x1B\x8AP\x86\x80\xFE\x93\xDF\xA6\x8A\xBBE\x06y*c\x1F\x11\x06\xED\x00\xBD^\xD8\xF1:\xBA|H\xED\xC0r\xFC\xB6\xCB\xC6d\x86\xB4\x11d\xD2v3\xEA\xA4-\x11\xCC\xF4\x92m\x88D\x8F\x926\xD8\x99\xC5\xA6\xB5\xF6\x89\xE96\xC8\xFD\xE2\xC0\xBBh\x0F\xE2\xA1\x10\xBE\xB8h\x19\xBA\xD9s\xE2k\xBF$\xF5\x04\xD7\x14\xA0.\xCC\x07_\xC1t\xF9\xFD*/\xAFm\x07\xD2>\x1C\xF5\xAAz\xD2\x94a'\x16\xFBXm\x80\x84J\xB7\xB7\xA4\xF6\x923\x1D|:s\x93QQ\x1A\xCEs\x94\x0D\xC9\xD8\x06\x82\xFC*\xDA\x84\xEF\xB4\x12\xC2A\xE3\xF0$,\xCB\xAF\xBE\xF2\x9CP\x0C\x97\x94;\xCF\xC7w\xA7t\xFF\xB4b\x81\x9DU\x83{[\xAF\x90\xD0Yvi\x0C?6\xB5\x8B;\xE9o,<\xE0H\xF4\x04\xF7\x92\xB6\x10DD2\x17\x061\x0D\xB3\xD6\xC7w3\x80a8\xA0\xF7O\xFB\x95\xB8\xCF\x98Z\x0A\xD0K\xC6\xF0p\x0C4\xA1\xC0jr\xE8d\xB5\xDC\xEE_u\xB9\x9E\xA2M5!\xE9\xE0s%O\x94\b\xAE\x821\xC1\xD2FXx\x9A\xF2\xC0\xA6\x809\x0Ck\xFA\xEE\x19\x11\x00~K\x9C\\xF6/\x8F)\x1B\x95&"\xC7\x12\xAE\xC9W\x87\x8C\xE0\xEBXsB\x9B*\xFA4\x8C\xAAAg\xDAb\xA4\xFF\x9F\x90\x1A\xBB0\x09\x0Cup\x97`\x7F\xE502\xDC@\xE0\x83Q.V\xF7{\xDES7\x80\xA6>H\xF7\xBA\xD3,Uq\x96\xBCv\x01\xA5c^g^\xD3Oq\x05\x90\xDA"\x96\xF7\xAC\x00\xD2!\xDEO\xA3\xEC\xDEo\\xF0"Z\xB5T\xC7\x0F\xCF\xA7\xCA\x8F\xE1m\x05YTV<\x175@\x89\x98+\xD1\xBF\xEA\xDC\xC7\xBEC\x81\xD6\x1D\xF9\xB1\xE2\xF1\xD9\xF5\x00j\x04$\x13\xAD\xC9\x0E\x16\xC4\x82VL\xF8\xA3\xFB?`V\xE3fR\xE1\xC5\x11\x12\xF7\x19\xEDV\x96F\xA6\xFC\xA6]h\x0B\x12R\x17z\x0BCJ\x1A\xBC\x8D\x03\xD7j\xB3'\x9FT\x01\x17\xB3-K\xED\xE6\xC4\xAD\xB6\xC5\xF0\x9C(x\xCC\x1B \xFE\x18\x98\x9D*\xB8W\xDB\x88\xD2>\xBF\xDA\xB2\x8E%\xC0;\x82\xCE\xAC\x0D\xCB\xAE\x83";\xA0\xAC\x8E\xF1\x00t6\xFF[2\xDA\x0E+(q&\xB5\xA1h\xAB\xB98\xC9\x84r(v\x1D\xF5\xF8J\x0C1\xE2T\x08\x07\x80\x15R\xCF\x8A\xEFqxEzM\xE4}\xA8\x93\x16\xA1m\x07,y\xF7mQ\x04f\xD9\xD1@\xC2\xC9\x8ASD\x18\xF7/\x0F\xE5\xECo\x995\xFD\xBC\xB3\xC2\xC3Vj;EX\xBFunI\x16y\x89\x9D\x90~b\xC9\xE8\x1B\x06\xE3\xDF&\xD6\xE5\xCD\xFE\x02\x97\xF7\xF9\x0C\xF5\xAA\x84z\xE3\xA5\^i\xBB)\xF8\x88\xC9\xB6m\x92\x12k\xE3\x1C\x90\xBA'\xD5\xDB\xD7\xCD\xA48W\x80\xC9\xBD4|7\xA2\xF3\x14\xCB\xE6\xA5\xCE\xAD\xA2\xC1\x0Crv{\xA9\xD0\xE9\x1C\xF5+u\xA6\x87\xA6F\xCFqX\xB6Ko\xDAG~\xE8\xF3p\xCAR\x7F\x17(\xA4\x8A\xA4N%\xFE+~\xFB\xF8{\xB01\x9A\xF2\xD7w\xF1+\xACk\xF6\x96u\x16p\xB1\x8B\xDD7\x9A\xA6\x1D\xBA\x0Be[\x14\x94\x85\x17\\x00\x1A\x1E"A\xE9\xEDS\xC6\xE3\xFEc\xA9\xED>K\x9Be]'v\x93f\x06\\x06\x02$\xC1\x96\xCC\x06\xDC\x1Dw;\x13\xC3rc\x0A\xA6\xA9\x84\x06/\xE6\x18\xC0h\xD3Q\xBD\xF8\xEF\x19\x1A\xE6\x03\xE2Z,\xBEL\x0D\x01\xB6D\xBF\x11j\xECX[^\xED\xA7\xA3\xF3\x8C{\x84\xD5]\xDB\xE9-\xD0us\xFDy\xA6\x1E8\xC43\xE3+TT!{xQ\xB2\x09\xE1\xF8n4\xA4\xC9\xB4\x0D\xD3'\xC6\x19\xD2\xB53\xC40\xF3\x17\xA9v\xD0\xB8z\xDE\x81\xCC\x103\x0B\xF6\x04\x9BZ\xE7\xD7\\x89H\xB7\xA8\x11+\xB1B\xCA^\xDE\xD6\x08\x0C"\xA1+\xEE\x1B\xAD]\xB9\xD9\xDD\xD5\x07\xA0i\xF7\xAE\xF2\xFE-\x8B'$\xBEQv{\xD8\x95\x05\x0B\x02C\xDA\x04\x02l\xD9$\x82CI\xD5t?\xA3\x98\xEEX\xFB\xF4 \xBBA\x075u\xED\xD8\xD1\xF3\xA7L(\x17%\x06!\xC5+#_P4V\\xFF\x0Et\xA7\x1E\x97g\xE8i\xDEG1\x92\xE4.@\x7F\x82\xD5&\xBE\xAC\x07\xCC2i7\xAC\xB15\xD5\xA4\xEF\xC1\x03-\x18\xBE\xEDE\xA0x\x01\x102,\xAF\x0C"\x15\xFDK\xFCS,C\x0B4\x7F$\xC1}8\xF7\xB2\x8E\xE7\x0Fk\x1E\xFF\xAA\xD6\xCB?fR\xD5m\xB9Yg%\x8DWO\xF30\xE56\xF3g\x88\xB5e\x1D\x7F:\x03\x1C\xAC]\xF4\xF8K\xD3\xBEbZ\x9D\xAA\x1C\x13\xF84\xAD\x93t3\x99H\xDEn~\xF3R\x00<\x9D\x9FO\xE0\xF4\x12\x80\xD8r\xF72\x02\xDAxx\xB5\x94\x18\xBB!=\x9F\x0C\xFC1#\xC3>S\xD1XE\xEC\xBBx\xA1b\xF3\x01fo\x00\xAE.\x04\xD4\x97I\xF3b\xD0\xD4$%\xF1\xCA\x90%h\x08\xDAy\xDA\x08]\x0F\xBFc\x94\x0Ec\xFF\xA0\xD8\xBF\x0A-c(\x9F\x9D\x80\x1F-\xDAZ\xB9\xB4\xCB\x96\xD7\xD6!\xBC9\xDAuJ6S2\x1B\x8D\xD5\x11\x1F\xFD\x95P\x83\x94\x7F\xD0@\xD0\xBA7(\xF399\xF4\xD9\xCC\xA5\x16\xE51\xCFL\xBB\xDAd\xD3\xCES\x06\x8A\xD5#\x8A*X\xBB!\xFFNE\xD6\xAC\xDF.\xA8\x91P\x15E\x8Fz\x96\x97s;\xABVa\xBF\xA7u\x19\xE4\x90\x9Fh\x85x\xF6Y*\xBB\x97\xF4\xD0L\xD8sF^\xC6\xBBC\x95\x0F8'\xCE\xBB\xDBr\xB4\x89\x19#\xBEtw(\xB0\x0D9\x81\xB2\x1B\xBC\xD9\xB8\xFE\xFAQBOZ\xFA\x8D\x0D\x1E*\x9FG\xD2\x11\x84 \xF5\xAD\x9C\x93[\xED`\xF3#\xBB\xBDKE\x01rB]\x91\xAB\xEDyW\x9C{\xF2\x8124\xEA%\xDBN\xD8\xFA\xFF\xAA\x14\xA9\xA7\x8E\xE8\x84\xD5\xD2;m\xEDA\xF1\xCB\x9A\x103/\xF8\xD6Y\x8F>\xBE\x8A-\xE9\xD8"\xB6\x7F\x0C^\xA8\xA0\x94\x91K~\x9E\xA93\xC3\x8BH\x82\xC4\x0C\xF0\x1A\xBB\xB0\xAEy\x18\xA7\x99H2\xBA\xAA\xA9\xED.\xFF\xE5\xAE\x11\xAD\xAF\x1Cc\xFB\xC62&\x1A\xF7$\x9AE\xF4\x18/0\x00\xB5\xB4G\x10\xB6\xA2\xCEYG+\xAC\x8A\x88\xE5\xE2\xAA!\x18\x15.r\x09\xFDz\x03T[\xA2\xBE\x8B\x80\xD2\xE7-\xED\xEB\x07rXB\x96AvX2D\xDBaTwvz/\xA2\xF2\x84\xDC<\xE4\xFB8\x93s\x0AMa\xF6t\x85\xC2/\xDD\xE4R\xCC\xE3\xE54u\xDC\x84\x81o.hQ\xC1aQ6\xA7\xBF\xFB)-\xA1a \xE0\xBB\x17[\xDC\xDCId\x0B\xBC\xB8\x12M\x1E`\xF8d\x85\xBE\xEA\x1E\x84\x8B\x89\x97\xE5\xDE\xC1\x8F\xF9P?D\x80\xF4\xBD\xD8D\x0E!\x9F\xE5\xBC\x0D\x93Y\xF3\xE4$\xD0\xC07\xAB\xBFxa}\xCA\xAE\xE6\xFA\xD9\xE6\x18\xF6\xAD\xA4\x9A\xB4I\x1EX\xB2G=\xAA16\xA9\x0FKW+t\xBA\xF8\xE4P.\xF8\xB9\xB6Yo\xE6\x07/\xB1-Y\x07#Hzo\xEF\xAA>Dg1\x89\xB5u\x09\xD1\xEF\x12\xBD\xC9U\x8C\x1Da\x813\xC0\xEE\xCAs\x9B\x9429G\x1D\xD1J\xCAw\xDD\x08\xD0$\x09\xDD\xBE\xF4\xA7(\xB6\xA4\xCD\x7F\xEF\xAD\xDF\xD0A\xB1\x94\x15Q\x9A\xF4X=}\x02\xBD\xB1\xD4\x1D\x80\x07\xF8E6nt3U+\x9D\x86PLuy]d\xBB\xA2\xB1v\xED\xCA\xD6\x06\xF6O.5(\x9A\xD7l\xE1k\x90\xE6_\xE1\x9BC\xD5\x00\xD0\xBB%9\x87\xCEx\xC3\xC2\x92\xC5$\xCC\xC9\x8B\xA7yl\x1B\x12\xD2\xBB\xFC.O=\xB5\xD9\xB5XOT\x18W@\x8D\x8B\xF9\xD9\xF9\xF8\xDD\x8Ce\xD8;c\xA9\xD9\x1C\xA9v-\xED.\xBC\x8B~\xEA\xC7\xD0&t\xC9\xE9\x97\xDBV\x14)\xD3\x09\x92(a\xB7\x0F]FH\xB7\xEF\xA1@\xD0&\x9D\x8D\x19jhU\x88\x84\x90\x01\xF3\xBF\x1F(T\x8F\xE0\x14\x878\x95\xAD\x01\xD2$\xFA{\x8B'\x17\xDB\xDA4O\xA1\x07\x0Bt\xA4AR\xAF\xC5T\xCA\xD2\xFB\x07|F!`0\xB7\x01\x9A\x8ExI\xD52\xC6\xD8O$\xD3\x83\xF8\xA3xfRP\xDFyC\xAFF\xE3\xCD\xA9\x90\xC7\xACma\x1B\x9A;\x11\xB9\xDC\x0F\x85\x86\x19]\x16w\xD2u\x05o\x9C\x81\xD0A\xDD1\xC0\x7Fplx\x17v9j\X\x85\x86\x045\xDC\x8C\xEE\xBE\x19U\x0Fz\xBB\xC4\x86\x91\xC1\p\x04\xCCF\x81\x17M\xF2\x9AE\xB8\xA2^N\xE9\x7F:\xC9\x0E\xFF\xCE\xE7R/\xA6h\x1F\xF3\xD3CP\xF1\xB3\x8F\x8D{1\xD4\xDBN\xAD\x07\xC0\xA1;m\x8B\x8A`\x8B\xEB\x1B\x87\xF0G\xDDQ\x05D\xBAF\xC6S\x17\x88\x1F\x95\xB7mY&7a6]FT\xC8\xAF\xA9\xA4\xB8\x11\xC9\x04\xB1\xFBs\xDE\xBC=[F{R\x8C\x1F`\x99zV\xF4C\xB9y7K\x0A\x96\xDFAw\x00\xCF\xEDgl\x98\xB69\xFBP\x14)\xE9j\xB8\xEAH\xF8e)\x0E\x09\xCCd\xC8v\x7F$(\xADN\xD4\xEF\xBAE\xFCt\xFC\x82\x0A\x0E\xEBESA\xD9W\xE2\x0F4T\x1C!\xA8]w\x82\xDE\x9F{\xAAm\x89)\x1D6\xAF\xA2\xB2\xA0\xAF\xCC^\xDB@\x80\x88\x1C\xE1\x00\x1D\xD0\xDA\xFDp\x0A\x18\x19_/\x85hp\x15\xC77%\xCA\x17WI\x07O\xF5\x8C\x91\xEA74"p\x0A\x16)\xFBx\xBD\xE2"\xA9\x90b\xC0Ha\x88\x83x\xD4l=\x0B\xC2\x11\xBB\x1C\x81G\x1C\x1E=)\xFF\xE1\x80x\xD17$}$\x1A\xEB\xAF\x12\xE1h\xF5[\x0E\x8054\x0D\xFC\xD5\x0C\xA3L\x0C#\xFD"\xF7\xEE\x01\xEB\xB6\x0922\x96\xCA^\xC9\x0A\xF3\x8F\xA1)\x91E\=\xE5\xBDtP\xA2d\xA9X>\xA0w4\x82\x84W1fK`\xACG\xE6\x83\xE8\x0CP\xA2J\x8A\xA4\xF2V\x8A\x97_\xCA\xA1~\x0B\x1B$~\xFA\xACb\xBC5\xDE=B\x15P\xD0(\x8A\xEB\xBE\x8A\x9A*R\x8C\x19\xEB3\x84H_o#w5{3\x8F\xE6\x1B]b\x04\xF8\xED\x86\x9F\x1CDq\x9E\x99\xBA%T\x17i\x0F\xF4D\x84:\x0B8\x7F\x8C\xBBb\xCD\x98\xE1\x9E3\xF5\xD4\x93\xCD\x14\xAD\xEB\xA7\x89\xC2\xE5\xDD\x00\xFF\xAAr\x9B\xC1\xF5\xA4\xA4\x0Fj\xAC{\xDB\xE8\xE3\x83\xDC\xBDn\xDD."\xE6\xF5\x07|\xD2\xCD\xD5\x1C\xB9\x0BZ\x01\xFDU\xEB\xD1FwJ9\xB8\xD2@\x92\x84\x89\xA3\xB1w\x8E\xE1I\xF1S\x00\x14\x1D<\m\xE9?\xFA\xB8Xz\x987\xB43P\x1C\xB7W\xEC\xD9\xEC\xF4L\x97Z?j\xC2\xDB-\x89~\x98\xED(;\xC7\x87\xC9\x8BC\xE4\x0E\xDC\x07\xE8\xB6N\xE9`\xF0\xA9\x14vA\xEE\xBE~U\xDB\x93\x9B\xCB\x86\xF9{[\x9C\x18\x9F\x83\xDD\xE8\x1AMGcQ\x05N\xEF\=\xE4\x08K\x17\x1Ap\x1D%\xF5'M\x98}\x95\x88\x06\xDB\x93g\xAA4r\x8BMTu\x9E&_\x0E}\xAE\xDD\x15J\x16\xE4u\xB1\xD8\x065_\xE5\xB8nv|\xF71[\xDE\xBA'Us\xB2P\x8C\x18\x09\x85\xB3\xD2\xDE\xC1\x162\xF9\xBC3\xFD\x18\xA5\xDEo\x11Q\xA9\x0F"Q\x06\xB3\xBE I\x8Be\x92\xD7\xC6\x96\xEFw\x82\xA2\x97\x0B\xE7fOzv\xC8\xBD\x95id\xFE\xDB\xABB\xA7\xB3j1\x84\xFF\xBDD\xD8;\xAC\x96\xBC\x03/\xDB\xC0\xA2\xAD"\x1D\x91\x0B\xC8~\xFC\xD4\x13k_\x0Es\x04\xB4\x7F*Y$\xCA|\x87{\xDE[\xB1\xF8\xFB\xADpg\xA7\x85T3\x1D]Pf\xD2\x83\x0AU\x8B\x82\xE5\xEB\x84b\xE7]\xE0\x0B\xE3)\xA0~~\xA3 1\x1E\xBA\xBF\xC9J\xE7\xD3\xE1\x01\xC7\xAA\x9D+6>t\xD6\x90\xB2\xB9\xA7n\x84Fr1pXdL\xC2\xF3\x8E\xF1\xB9\x90\xF4~\x81B\x18\xA9\xD5Ne:<\xFD\xA4@g\xAF\xC4t\xE9S\xB7P\xD4\x8A\xE7Guu\xB1\xA2\x8D]\xEE\xFE\xE7\x81l/\x91\x07\x13o\xDF\x0Ac\xDC\x00\xEB*iY\xB05\x07\xC9u\x95\xB9\xD6\xAAG\x19\x01\x19\x15.\x965\x1A<\xE4=\xE1\x91\x8989\xD1\xB3\xB8)@Z\xAA\xC8\xAC\xD6\xC3\xD8:={aK\xA9\x90\xAEO\x90\x05\xBE\x16\x0C\xEAi\x00NZ\x09\xB9r\x83\xA3Mm\xE7I\xADH\xDC\xDD\xD7RF\xA7\xD1U\xF2!\xCA\x091\x04,h\x0A\xE1N\xCA\xF6\xE0|\x8B^\xCE\xCEw\xDD\x87"\xE9r\x87\x14\x87Zt\xAEvR@\xBC\x0A\x0A\x87\xC0\xEF\x1F\xD1W\x15\xC9;cZ\x80\x84\xBB\x1DX\x8CF\xF0\xF6r\xEB\xAB|\xC1\xED8*\x1D\xC3zv\xFD\xB0\x1E\xAE\xE7\xD6\x14?\x16\xB4V\xC3$A\x9A\xF82x\x8C \x0D\xF9\xBCd\xDFg\xEE\xD5vr0m\xB9\x99\x0F\xC0\xD1\xE0\xB9\xFB\xCF\xDC\xC7%\x03\x89\xEB\xB0\x0F\xCC\x84k\xB6D\xC4A\x011\xD4\x14\xAFAS~v\xFF*b(\xCA\x9CU\xDE=\xA5Gi\xACyI\xA5c\xFD\x96\xF7Y\x0C1\x97\x7Fr\x8AS\xEF\x93KxSl%mO1\xD7N\x0C~\xF1&\xF8\xBA\xDD\xEB\x04R$\xC6\xA3S\xCAx\x13\xA0@6\x9D}\x08\xF9\xEC\xBE\x9E\x16\x10T\xBF\x19\xF1\xC9\x8C\xB2\xE1\xB9\'\xACP\xDD\xD8;\x81\x94\xDFg\xAA"\x16'h\x00\xE8Q^\xE7\xAC\xAEB\x81DP\xAE\xA6\xD9O\xCB\x0A\x0E\x12\xDBK\x0C\xA0o\x8D1:C\x7F\xD7ub\x10\xF8hv\x1D\xF6'(B\xD4a\x17r\x01\x196\xFF>`\x1B>\xD7\xFF\xBD\xA3\x9B/\x9B\x8DL\xD1\xC1*\xFEny\xE023G^\x90\x86\xFFE\xF7\xD8\x06\xA6\x08\x8E\x05H\xCF\x13==|\xA3\x80\xE2\x8Dr\xE1\xD4\x9F\xC9\xC2\xD6j\xBDt\xE2\x94\x82\xE2\x1AQ\x80\xCD>\x7F\x1F\xD4B=\xB1x\xB3\x9D\xE8p\xFC\xE2\xD8\x03\xA6Q\x11''\xC9\xD1\x04\x12\xB5\x87\xA5\x0F^?\x8C\\xE3@\x8C\xC5\xC1\x8B\x13\xD1@\x87I\xBB:\xA35\xD0\xA5\xEC\x02\x02\x09\x81\x84\xE5\xAD9\xB0\xE6\xA6\xAE\xB1gXxZ\xB2\x09\xD7&X\xF7A\xAE\xE13\xF0\x87\x91\xEA\x963\x17\xF2\x99\x9B\x84(\x16\x8E\x85\xFEV\x92\x1B\xEBg\xC6\xAB\x92\xBA\x9B}N\xEBG\x99\xB5\x86\xF6\xC1\x18,%\x1C\xE5D9\xCF\x8C\xEA2v"\xFBw\x07\xE8YQ\x97\x7F\xC9\x80iIV\xB7\xED\x17I\xD4H\x12\x14\xCCIx\xD4\xBE\xD7\xA3A\xE8h\xEBD\x07\x0F\x82\x91\x10"}\xF0\xB1\xB7\xAB\xEBvO\xDC\xB4\xA6\xA40'\xF0\xDB#]4e\x0A\xF3\xFC\xAC\x0D\xB8n\xEA\xC8\x999:\xB6\x8B\xC5\xF8\x13\xAE\xEC\x11\xF6p\xEFh#f\xA9\x94\xFE\xE5\xB2rs>\x8B\xB9i\x0C\x8C\xA4\xEF\x0Cd\x93\xD8\x96\x152\xE6\xB6\x9D\xEC\xA2,\x81\xB7\x1E_O9\x8AD\x18\xAD\xBA\x1C\x0D\xA8\xECQ\xF7\x1E\xE3\x8Dy$))\xE8]\x06v\xCB}\xD3P\xA3\xCDY\x9Ae\x13\x90\xF5\xC8\xF8\xC6\xB0\x01\xB8\x00\x80\xAD\x890\xEE\xE9\xA8\xA8\xAF.\xE5b>\xC2\xC3#Fvw\xDD\xA7@o\x0D\x85\xBC\xEB<\x02\x9A\xCB\x8DR\xE6\xEF;\xBA\xBE\x1EH\x97\x0F+O\xE9\xC7\xA3cQ\xC0\x95\xA2\xA88\x1E0WQP\x01l>\xE8\x89\x96{\xAA\xC6\xA5\x96J-Yr\x04\xAE\x9A\xE8d\xAFH\x89\x9F\x00m?\xF6b\xE4l\xA5\x8Bh\xC1\xB7\x19H*\xEB\xC5\x92f2\x07\x1B\x128\xEC\xEF\xD64\x18\xA3\xB1\x1Dl\x82\x99Nj\xBA=\x9D\x08\xA6?\x08A$\xE04\x89,\x1B\xA1rU/\x04\xCB#\xB4\xA1\xDC\xA4\xFF.\x85\xCAJ\x86\x90\xD4\x8C\x9FL\x8C\x00L#\x90:\xDE0Q\xDB\xA7n2\xD5\x99\xFA\xF0\xDB 1\xAA\xF3\x02vu\x80}\xE2\x1C\xECF\x96\x9E%\x1A\xD4\xF7U\x94t\xC3\xB8\x16\xE1\x95\xCB\x9A\x84=\xBF\x89\x98\xD2\x12`\xA1y\xE3\x19|(8\xDF c\x9A\xAC\xB7\x06\x0F\xD6\xB9\xDE\x11\x07+\x02\xBB\xA2\x06\xD9o\x98\xCC\x8E=!\xA1\xE2G\xC3\xE4\x80\xD3\xEE\x86\xBA\x81_s[\xE1wzG\xC4T\xCD\xCA\xBB\xBC\xBC\xD7\xBEn6\xD3\x15\xB3\x94\x91\x9E\xE8{\x0C\xBA\xA9\xF4\xD0P7n\x99\xA1 \xFB\xD1\x95\x1B\x1DG\x86\xE9[T\xB6\x0F\xF7\xF0n\x96\xBFHhy\xF5g\x0B{*\x13\xE3X\xE1\xF9j\xCBQ\x19\xE6A\x08\xF7\xBD\x9E\xBC\xA2\xC6\xE2\x7FW?\xE2w\x1C*l\xE6B\xF3\x83O\xD1\x15\x8Ex\xBE:H\xBC\x80\xD0\xEC\xE9\xCB]CU=64\xBB\xC0\x92\xC0d\xA3\x8C8a\x11\xE7\x12\x94y\xE5\xC6\x82'\xDE\xBBF\x99c\x08o\x07 \xB5\x84\xF7B\xB5\xC4\x89\x89\xEC\x0C\x80\xE0]\xA2\xA4\x081\xA4\x94\x99\x93\xB2\xCF\x09\x1C\xC2%x\xC4\x8Ab\xD8\xC4\xAC>\xEA\xF91:\x88:\xB5\x1D\xBC\xDA\xCC|\x1D\x18\xEA\xEDG\xAAn\x8F\xAB\xB6\x0A7\xFF\x12{n\x1B\xB6\x1Ct}\xF8\xEA{X\x0E\x8F\xBAG\xB5\xB6\xE5\xF2\xB8\xA0\x91\xDAf\xB2I\xCA\xA8\x9E\x1AT*\xDDa:\xC2\xCB\xA9\xFE\x8E\x92\x05#\xE26\x19\x96w\xC5073\xB6\x8A\xCFD~D\x91g\x84\x15<\x07\xD2\xC3\x8E\x96\xE3K\xC1\xFC~9\xD8\xC4\x82s\x19\xAD\xDA\x9D\xC8^~\x8A\x1Ch\xD8\xEEv:\x81%\xC3\xE82\xA7M\xD2\x1A\x81\xF1eB{\xD3\xD5\xA0\x88\xDDhP\xC5:F5\xE4\xFB\x17]6\xC9\xBD\x9FB\x12\xD1\xD5g\x9E\x8B\xDFKtR\xC3}C\xCB\x85\xE0\xB0\xBE\x05\x95\xDB\xA8Q\x86\xEB;_\xCEK_\x06\xDB\xB0\x08\xE2\x1B}\xC9Q\xB6\x09/\xE5\x0B(p\xAB\x9E\xD0G{2\xD1w\xA7\xDB\xD1\xE2\x98\x0A\xFF\xE3\x1D\x83`\x984+\x05\x09\x0E\x93\xB9\xCB\xC0\x0D\x84 \x1F~\xFB\xA0\xFFS\x02YZ\xBE\x0F\xBFk/\x98\xE3\x07\x14\xE7\xD1\xD4\xBE\x1C\xBB\xC7\x9CZ\xDCl\xCC\xB8O\xE0\xD0\x09\xEB\xEB\xE2Z+\xA0\xE6A\xA8\xB1Y\xAEHe\xB2\xA8\xC6x\xFA\x1D\xC5\xB3\xFEryV\xB6\xDD\x01\x8F\x9CIM\xF0\xF8\xA6yS\x7F\x97\x16\x1D`!\xD3lw\xE8\xCD\x192\x07\xFE\xC2\x8F\xC8\x9E)&NPj.\xE7op\x8A\xAE\x06V\xCA\xEE\xA8)P\xCA\x98Q\xB6\xE3\x03\x99\x8D\xEF\xB4\xACJ\xB6\xABI\xEE\x94\xEA\x9E\xC0\x9B\xFE\xEFOtJ\xC3\xFE[\xA0\x9Ch\x17}\xF9\x17\xC1\xC6s\xCC\xF9'\xC9\xCC\xC3\xE5\xD9\xAAS\x91\xE5\x0A\xB5,\x8F\xC0z\xEF\xF2\xCAYd\x95\xB3\xCF\xC0\x03\x07z9\x88\x1B\xC3\x0B\xBC\xE5\x0A\xF4U\x1C\xC2\x99q\xD8I,\x97/\xBATK$\xA6\xFE-\xA2\xDCn\x1F&z\xC3\xE9.X\x0A\xEF\x81\xAEc\xBA\x0C\xE8m/\xFD\x18\xB9\x16_\x83\x0A\xE4N\xB9\x9D\xABK\xA2\xED\xB1\xCA\xAD\x90\xC5\x11\x0F@\xDCy\x05$=\x81\xC2\x0ASD!\x90\x8E\x19\xE2Y\xF8F\xD8\x12?2!s\xCD\xB5\x1D\x0EW^@\xBD(\x10#\x09\x96:\x1B\x8162z\xF1\xAD\xA43\xBC)\xF6\xFETU\xAF\xD6\x8Cw\x85\x03r\xEC\xCF\xBE\x07\x8F(\x16L\xD7\xC5\xF7z\x88\xB3V"\x1F\x1F\x8Da\x92\xDEA\xFCwi\x13\x98?\x98w1\xFB`\x18\x95\x99\x81\x8F\x08\xD6\x9F+\xAC\xCA\x13d\xECc\x1B>\xAA\xA7%\xD2\xCA\xBDuIJ%]v\x87Dg U-{\x9E\xBD"-\xC7f \xD5\xE8\x1C\xC2\x094\xAE\xEC(\x82\x1E\xCB\x06\xA6*\xCFI\x00\xF3\x09`\xFE&\xE43\xDB\xD0\x91\x88\xD3\x09mC \x03@CC\xB8t\x06\x84\x7Fb\xCB$\x14\x11\xF1\x84\xB9Q^\x01_7\x07\xA4\x08Tj\x09\x8C\xC2\xDCP\xF7\xB0\xC7b\xC75\xC3\x1E\x18\x85^-\xB7\xC2\xF3\x9E^;M\xC4Fz\xB6\x0B\x13\x9F\xA9\xF7\xF7\x1F\xE9\x04\xD0\xD1\x00\xB8\x0D+\xF9A6#k\xB5\x17\xE6\xC5c0dx\xC3\x9A\xA4\xC6\xB4\xFF\xE5\x1A\\xE8\x7F\xDB\x9Dku\x1C\xE8qG73\xCB\e\xD4\x0C\x1E\x82/\xBC[\x0C`\x0A\xED\xDC\x1D\xC1\xA1\xCCG\x117V4+\xC1\xCF\x84\x0D8}\x0B\xEEQ\xFB\xAF\xC1tE\xE2V(\x81r\xBC3$\xD2\xB1\xA9\xE4\x05\xB7\xA2\xECWsy\x95\x92\xB0\xF6|^Y\x83\x9F\xAA5r\xCD\xF9\x94\xDB \xF9\xC7<\x05\x88\x0C\x1C\xA0\xA25'\xFC\xCA-^\xB9\x16\,\x8C0\xEA\xC2\xCE\xC7\xBD\x82R\xCF\xD36\x1C$\xB9\xBA\xBBwq\xD67^w~6\xC8F\x97\xC2S\xC9coS"\xB4\xF3K\x80\xAD\xD8\x86\xB1_\xDF\xFC\x11)\x92\x1Ae~\xABM\x80V\xB7\xB8/1\x0F\xDB\xE1\x0Bi]\xA9\xDC\x09\xB8\xFA\x9Ap\xEA\x91\xA4\x98*\xC6v\xCE\x12\xCF\x19\xB5\xE9\xE4?\xBF\x82^\xA9\xB2\xE2BJ6\xB1\xC8Dbcz\xEB"\x81\x1AQ#\xE2\xBE\x80\x993|7gRN\xECm\xC2\xCB\x8A\xE9^\xBF\x9D\xE3x\xED\xA7+ \xA3\xDD\x7F\xAE\xB8\x92\xC8\xE3X\k\x7F\x9C\xA77\x9C\xFC\xBC\x15Os\x1A\xB46\xDFP\xA3\x08+5\xA0\x89\xEFD\x0D\x8D\x1Am\x88\x85\xE3q\xC6zC\xC4x\x91>\xA1\x02i\xD9\x13j\x8B\\xBC\x0F\xDA\xB7\xDF\xFA\xD4'\xD0\x0C\x83\xB2\xBE\xDC,$gK`\xE9I\x83\xF1\xFAD\xCE\xCC\x80uYs\xA6Y\x833l?\x96@\xEC\x9FTF8U(G\xD4\xD9o\x9A\xEA\xBF\x12]+\x8F\x9B\xB2r]\xC2\xB7^\xA5p\x9AH\x01\xD7\x862-4!(\x12D\xC4 \xEAaf\x07q\x96\xCD]p\xD3p\xBC\xF5\xC1\x1E\xDB\xD1\xE3b\xED\xE7\xC3\x0C\xBF\x7F\x9F\xCF?\x1F\xDCR'\x95\xE2\xAA\xE4\xF3x\xAB3\x01=\x13\xEFp\xFE\x89\xA8I\x98\x09!\m\xDE\xB1\xB4\x1A9\x013\x8F"\x80\xDF \xDD\x88C\xA0U\xE2\xF0\x8A\xB8\xA1\x16&\xBB\x04\x02L\x89N\x8D\x86\xED\xF5\xD4\x1F\xA16\xE5\x01\xBC\xB1\xCF\xDFD\xE0g\xA82\xB3C\xB8\xF1\xEA_\x93\xDF`\x9D:\x87\x02"\xD2p\xD1\xFB\xF8\xA4i\x13X\x93\xB98q\x10;\xAE\x9A2\x84a\xCE\xAF\xE8#\xA8\x1C\xE5]\xEA\x05pxD\xB5Z\xCDH\x83hU\xC6U\x87TOp\xCFq#\xFEHt\xEE\x85;\xD4\xB16\xEC\xE7\xB4H\xEEv\xFD+\xFF<\xBB\xB6\xC7\x81-\x97\x80._a3t\x88\xEE\x82\x16\xB8&\x89\xC9h\x14\x83\xD4\xB5\xB5u\xEC{\x02\xFC\xA3\x98\xE2]B\xF2p\xFD\xDD%\xE4\xE3\xC5\xE1O\xCEQg\x0D\xFB\x9F\Q\xEF\x13\x09\xCF%\x81\xAC\x1C\xE8'5m\xC4\xB8\x82\xD7\xCA\x90z\x1E\xC0>W]Y\xEDC4\xBE\xA3\xDFI$ \x83\xCF\xBE6\xB6\xDA(qv\xE9\xDD2<\xE8\xA9e\x7FL\x8D\x86d\xDDd\x0C<\x93\x84MC\x0BO\xFFL\x12'y\xA6\xAEy\xB1\xE9\x9DJ\xEF\xA25\xCD\x16\xEBts\xADeB\xC5\x1C\xC4\xE2\x00\xCFw[M\x16\x0E0\xEA\xBE^(j\xFA#\x0D\xF3\xF1\x1D$_t\xED\x8B}T\xEE\xB9e\x15V\xC8n\xAF`\x9B1\xCB\x8D\xA7\xB6\xB9e\xC8\xDF\xE3f`\x82\xE8\xA8\xBD\xFD\xAE8\x0F\x1Df\xAD\xA3\xC3\x04*#\x08xp\x9F\xC2\xF7\xF6\xFA\xDC\x16~\x9C\x90\x82\xC3\xFA\xE6\x1E.\xFF6r\xF9,\xA5^\xDF~o\xEF\x01\xA9\x92p]\xBA\xFA+'f\xD3\xCF$c\x87\xAE5H\xD4\x83z\x86\x0F\xCF\xC76\xCF$\x91{\x90\xFE"d\xCFk\x01\x1E\x88\xC0\xB3\xB5\xB5\x0AY\xB5\xA6\x99q\x11A\xBD\xFD\xB3\x81\xF6\xDAx6r5\x83_\xFE\xD5\xEC\x09\xA4\xB6fO\xB9\x8EQ\xBF\x8AO\x80\x1F\xB6]:\xE9L\xC8\xC7\xF8\xC3\x09\x8D\xDB\xCBN\xBA\xAA,\x09j\x8D\xA7\xC3\x9D\xE5wuA\xD5\xB0\xF3\xEA\xFA\xECr\xD6\xCC\xC4y=\xD5\x17b\xE8\xA1\x0A03RW\xED},U\xA8?\x15>\x93\xCC\xFB\x0BX\x9D\x92$}\xEB\xAB\x0B\x11\xAF\xED\x01a\xB1\xD0s\x15\xC8\xCDJ\xA8D\xBC\xE8]\xDB]\x80\x01Y\xDDyxB\x18\x17v\x10\x8F\xB1\xD0\xD2\x09\xBC\x15\xE4\x96a\x18\xD9\xA4\x90vt\x95\x17\xDC\xAFq\x08\x10[H\xD7\xEF\x06\x0FytSCT\xA9\xBCdt\xB9h\x81{\xBF\xF8\xF6}\xD6\x7F\x15=uE\xB6\xE7~w\xAF@\x83\xC9\xCEo\xE9v\xD5\x13\xDCg0\xE8\x85\x08\x06\x7F-h\xF4\x91\x96S\x1C\x97\xDB`\xC89\x14w\xA7\xE2\xA4\xAC\x01X\xA6\xA3\x19\x17\xC7\xB1\x11\xCE\xD4\x1B\xFE\x970\xA2c$\xE1\xEB\x91\x92\xE1\xD5\xF4\xB67MkZP\xBA(\xDCd"& \x0E[\xA0\x10\xD2c#I\xB4\x1A\x1Dd\x9F\x84\xDB'G\xB0\xBE\x16~>X\xA6\xE2U\x17[\xCB\x8C\xD70\x91X\xE9\xD8J\xC1\x98\xE4W\xC6\x90\xA5\xCD\x9AhG&\xE1]BN'r\xA6\xCFIu\x9E'+J?\xE3\xB9\xEDhca^\x94+\xF4=\x01\x9BM)V\xD0\x1F:W\x0A\xFE\xDE,WY=\xE1Y\xE1e\xFA2\xAF!\xC6=\x88\xE0\xF2\xD5\x81:Bn\xEF\x14\xBA.\xF5uyf\xEFf\x9E\x9B`?&\xAA"L\x9E\xD7\xC4\xEE3\xDBXh3\xA4x\xB1$*\xC0\xA1v\xF8\xF8`v\xD7\xDE\xF8"\xBC7\xA0\xDE\x81\xE1\xEC\xD8\xF3>/~\xC2\xD8\xA7\xDAF\xB0_\xE4J\xDBN\xD9N \x017C\xA8'f\xD4\xBFU\xE0CUt\xBE\xE0\x9B\xB6\x135\xF51\x07=*\x15\x1B\xB7]\x1B6\x93\x9D\x94\x02];\xA8\xE7\x03\xBB\xAD\xAC\xBC\xBD\xD6\xCDR\xA8\xC6\xF0\xFC~\xFEI0w;\xEF]\xA8\x0F\xB4\x879\x07\x91W\x8C\xD7\xDB\xDER\xC4\x06\xE5\x00K\x05k<\x9AY\x1D\xE9\xEB\x0E\xC3\x9DH\x92\xFCm\xB1)\x0D>}\xED\xD6`0\x9C\xEAz\x11\xDA\xF0\x1C\xCC\x06&\xAD\xDDd\xF0\x157\x95\x93\xA8K\x0F\xA5\xEB\x8F\x09\x10\x03\xCC(L3\xD6\xA7\x07\xAF\xD9p\xE4\xED\x99L\xDB90V{\xA5\x06xu7ei\xE0D\xBB^v\xEE\xFF\xDB$\xC2\x0F4\xEB\xE7\xB9\xFA)\xB3\xB6m\xBEA\xA8\xC8\x03\x07\xE2\xC6#.M\x0A\x86}H\xD9 @\xD4zxc\xC5L\x0A\x02 c\xE1\x16ir\x94\xD9N\xA9/\x075\xAE\xED\xE0\xCA\x80\xA2\xF4\xD2\xEAPS>v\x1D\xE1\x07\x85\x98=\xD2w\xE45\xBE8\x0Fn\x9D\x01:\xB3\xCF\xAF\x1F\xEE<\x8F\x07\x95\xF3\xF2\x05\x17\xE4.Pt\x867|\xF0f_\xB9L\x03\xE9\x80{\x06\x92\x061fk+I\x14\x8A_)\xCF{#_\xA0\xB7Us\x18WZ\xFD\xC9_\xED:Lz\xD9\x07o<\x1E\x9B\x11\xF7\xCF\xDAX\x06\xDEb\x89\x86rX\x02h\xC4f9\xCF\x1B%\xB9\xF4\x91\x03\xF0F x\xB0>\xDE\x06\xCD\xC7\xC4\x7F \xD8\xE7*\xCB\xE7\xCF\xD9\xCB>\\x87\x85t\x8E\xD2K6\xD6\xCE\x0A\xB1\xDB\x8E\x15=d\x9A\xF8)\xA9\x1D\x1BaL\xC9C\xB4\x19\x85r\x14\x99\x18?\x85\x03\x92f\x8F\xF6\xB5\xF9\xD6\x18\xDD\xDF\x1C\x01\xFF\xD9I:\xFC\x0B/\xEAA \xBD\xAD\xAA\xA2\x9Dh\xAF\xCE\xB9\x0D\x01F\xC4\xFC\xCF\xE0W\x05\xB4\xC3\xAE<\x8C\x16\xCC\x11\x8FD\xEA\xD8\x0D\x99\x1C\x8B\xAA\xBA=\xAE7:\xE5\xC0\xA4\xFAH\x0A\x8B'(M\xB1i)\xB4>;\xF6nb1\x94r\xFDf\xD2h\x1EL\xA9~v\xB3%\x15\xBF\xE5\xE7&[\xF8u\xAET\xEEs]\xED:g\xCC\xEB\xD0\x15\xD6\xA1EpSp\x9EX=\xDA\x0B\xA5O\xEE@\xB8\xCD,\xC2\x9Du\xA9b@\xF96\xE6_D\x951\x1E\xBD\x15v\xD6\xA3\xA1,\xCA\x05\xA57\xE9\x92\x1B\x97d\xB2\xD6\xBA.\xD3\xF2K\xF6\xBDPw\x9B\x05y\xFAP\xBF^@\x00a\xEE$\x95\x0A\xE1\xD1\xB4\xF8\xFFH\xC1x\xFBU\xFF=v!m\x856\x09\xB8Z\xE8\xE6\xC4\\xE9j\xE0^\xA9\xE8K\xD4\x19\x99w\xD7Q\x07\xB3Xi\xD0QS\xF3\xD0v\x07\xBC\x1C/\x06\x08A\xD2i\xD3\xC2M\xAC%\x90.\x8A\x88\xEFN\x15~]e\xE8\x0A\xA8\x08\xE7\x149:\xEB\xA5\x15\xDE\xF4\x81n1\xB6\xD1\x9A\xFF!\xC2e\xAD\xAE<[\x96\xAA\xAB$\xD1\x86\xE9"\xEB5+\xB0]\xB9@\xBC\x1E\x89\x8Aai\x09\x7FE\x9A$4g\xBB\xF9\xCD\x06\x08\xB6\xA9\x0D\x93 \x97\xC4\xF9k\xCB\x7F\x01\xF9\xE2\xBDo\x00>&\x8E\xCE\xCB\x9F\xCB\xEB\xFE\xC8\xF0:O>m\xC4R\x1A\x12I\x92\xDA\xD2\xF0\x84b\x8A\x01g'\xAD\xB5\xA8XO\x09\x17\x83w\xE0\x9Co}m\x8D\xF6\xDE-\xE2$\xF6\xE1\xDC\xF2&,\xB9\x0A9q\xC83\x89\x15\x86\x1D\x15F\x00n\xCB\x8E\xEA\x1D*\xBCYg\x07\xCB'\x0Cm\x93\xFAQ7\x1B\xEC\xD3[\xDE\xDD\xC1\x0F\xD6\x18\xAA@\xE2\xF5\x0F\x17\xD5\x9B\x11K\xDF\xEE\xB0\x98\xD5\x1D\xDB\xCF\xC1^\x1C\xB30&^1\xE5\x9D\xAFO\x98\xD2{\xE6\xBC\xA2\x0FG\x8CZ\xCE\xE1\xCC\x94\xFF\x1B\x0E\xFF\x8D\x0B\x86\xF2\xFDZ\x17\x13{]\xD0{P\xB1b1V\x86\x12E\x07\xF4\x88\xEEj\x94\xF6\x9D\xF9\x9An\x85>\x1F-\xA3c\xEF\xDAC\xE3\xDE\xEC\xCA\xA9\x8E\x87\xC6\x92\x8BQ\x9FoK|\x89\x99iB\xF2\xA3\x03\xEC@q_\xFA\xE3E\xE1h\x94\x0C\x06\xBC)\xF7i\x16h\xD8\xE6\xB5_\x0DQ\x8B\xB6C\xBD\xEB\xE9\xA9\xF8\xA5\\x07\xE0\x8D\xD6\xBB=\xD0|\x18\x19|\xE9\x8E\x8A\x15\xB8/\xC2\x80\x1D\x0F>\xAC\xB0\x9F3\xD2\x80G\xEA\x9B\x8E\x07\xC9k K\xF3\x0B\xE2v\xFF\xA4U\xCE\x98\x12\xE4Wud\xAC\x9Dm\xA2\xDD\x1C\xE25Xh\xCD\x04\xC2\x997\xB5\x01"\xCE9\xCF\xAD\x86\xFE\x02#\xBC*\xF1\x04hq\xC9\xA8\xA6\xB0\x8AyR\x8B\xE01\x848\x9E\xB7o\xD9-\xE8\xC4\xAEB\x99J\x94]\x036\x89\x84\xB8(\xB0\x9E\x96V(\xA6\xE2P;t2\xDC{p\xF6\xD3I@\x9F\xA3\xBB1\xF6\x11]\xCB\xD9x\x82$xiz\x96\xDC\x09\xF7\xC3C\xF3zc3\xAF\xF2\x05\xFF\xD7b^}\x05B\xA2\xBC\xC6\xCD\x83\xF9p}\x06\xBC\xD2\x9D\x93\x88\x0E\xFCg\xA6\x9C\x9C\xE4@\x85\xF9!\xAB\x1B\xB3\x14\x80]\xE3C\x8B\xCF\xD1\xAA\x1A\xC5ft\x02!\xD0\x9A$\x85\xB9'&\xFF\xCA\x08"H/,nO\xBA\xF8T\xA0$\xCE\xEF\xCBl\x98\x02\x19\xB0\xDC\xA2\x06\xFE\xD4-t\xD4\xBA\xDB\x9F~\xC2A\xD5\xF8\xF4c\xAEmS.\xA7\xEA\x98"\xE83\xC7f\xD5\xCF^\xB4\x07\xC6ay\x11\x98\x9B\xE9\xB9\x08\x9C\x90b%\x19s.\xD1\xBF\x9B\xE7N\xAE\x13\x19\x9E\xCEZ\xCD\x0C4\xBE$\xA0\xB95\x1FVb\xB6\xB7\xE8\xA9\xC3 \x9D\x13\xF18\xC1\xFA/\x14\x84a\xBA\xB5G\x94\xA6\xBC\xF4\xF0\x82.\xB4\x97\xEA\xA1\xBA\xA6x\xDB0q\xDA4I\x13\x83\x01\xEC\xEE\xA8\xF9[\x1B-\xF4\xC7\x03\xEB\xB0\x85\x8C\x1D\xA3\xD6\xEB\xF2X\xFC\xB7E\x17\x82\x93\x1Bx\x18\xAB\xD6\xF5\x1A\xF6\x98\x9E[|\xB6.\x0C\xB7\xDC\xC0\x095+\xB9 \x11qa\x8Fr\x80\x15ki\x19\x09M\xC0\x90\x18\xD5\xEFGh\x811\xC9qd\xCD]\xEC]\xBC\xB2\x85\xAE\x00\xE9\x98\x9A\x92\xC3A\x1DC\x1C\xD0\x02\x01~N\xEC\xB5\xCC\xC0\xBD\x8E\x81y\x04\xB4{\xEBr\xF6U\xF6"\x8E,\x9Dwv\xD2\xC4\xEF8da\xA0\xAA\xEB\x0B\xF4\xA00\xA6u\xF9\xCF\xB2\x84~-\xF7\xD0g\xE0\xE3 \xB4\xE2\xC16\xB1\xEF#\xDB\x8B\xA4\xAAi\xA0\xE2\x00\xC2\x1C\xCF\xD3\x00#\x96\x9Ea\xCFT-\x0ED\x8D\xCD\xD3\xF0\xFBM\x18m\x83<\xFF\x95Zc\xEF\xD1>\xC0\xF2Lck,\x13A\xB4zP\xC3\x1F[\xBC\x9E\xBEg\xB2\xA5\x8B\x14\x9E;\xC8\x1CK\xE2\xC9\x99\xF1\xDC"d\xC1u\x7F\xB9\x02\xAAH\x94\xBBF\x94\xF8\x9D \xB9\x8C\xD3\x8E5U\x04\x101\x1AIj\xD1%{XU\xB9:\x1C\xA5\xDC\x05H\x0D\xD6r\xFDy\xBC@\xF0\xC1\xFA'\x8F\x94\xB9\xFE\xD3?\x82x)\x87 \x0A\x14\x14\xDA~=\xBF\xBD\x86\xFCrM\xA9u\x9E\x8F\xC5cS\xE7\x18\x041T-@\x1B\x02=x\x1Fp\x00\x86\x96r=\xCB\x89\xF9\x8F\x04\x9Bi\x1BY\xBB\xEF\xA4*\x8D\x92QtS\xEB\xE3\x9D \xED5\xAF\xCD\xCB|\x03\x10o\x04\xA4\x07 \xE7\xD8\x87~W\xA7\x0Bn\x8DA\xF1\xBC{L\xB0zl~Z\xB9\x8E\xEDC=\xA1\x83y\x85D\x0F\xDA8\xF7\x06\xEFE\x96\xC0\xB51\x92\x13\xDF*\x0C\xC7\x82\xAE\x19(\xBD\x7F\xDF(z\xA6)\x15\x8D\xAAe\x05\xB58\x8BLdX#\xC3\xFDs\xA9"G%\x1FQ\x0Bl)\xA3\xDB~\x9D(&:R\x00y\x9B\xEB\xB5\x97\x8EX\x80\x95\xB9U\xFDa\x00{\xD1B\xF9d\xFE\xDDHw\x90{\x97\x1BO \xFF\x0D\xCF\xD5V\xAA\xFD,\x9AY\x11\xF6L\x18vy\xBA~(Uy\x1E\xDE\xAD\x0F\xFF3I\xD2\x1AR\xCBR\x8D\xB5\xD7\x9E\x0A\xBF\xBB1\xF8&\x88X\x02\xCE\xAA\x18k\xB0\x1Ay)CJ>/]\xF0\xD9\xEADwb\x14\x15\x89{^N[\x1A\x08\xACh\x0A\x00\xFB\x97\xA2\xF3\xBB\x17S\x1DQS\x88\x0B\x17\x0Ax\x1A\x96\xA2\xB4!\x13\x19\xB7Ed\xB4\x94\x91\xCEb\xF1\x8A\xA0iv\xD7\xBA%cw`\xC3S\x1FJ\xA2#\xB8\xE2\xED\x9D\xE4~\xEEa"Hs\xCFk\xBE\x16\x83r\x06\xFB\xC6?p\xB9\x8B\xD7\x0B\xCB;@\xBA\x93p"\xC1\x91\xCB\x03\x7F\x07\xFC\xD0\x8F\xC0\x91<\xC6l]\xD6\xF8\x14@\x1D\xBA=\xD6\x17\x17\x1D\x02\xECLS\xDAo\xDF$\xF7^\x97\xEA\x84g\xAB=\xA0\xCF\xCC\xD4kw[\xFF\x93\xFF\x1D\xE8\xCB@O\xDB\xFFV\x7F\xB3\xB8\xED\xB1\x0E\x8D\x08|\x9A\x1E\xE3\xAC\xC3\xBA>\x9Ds\x02\x06{\xDD}\xCCD\xDB\xF5*|Q\x80\x13\xEBu\x15\x8E\xAB_\xB3\xB8\x1A\xA8\xD4\x9B+\x87\xF9\xD0\x98\xA7\x87L\xCFGE\xB7\xA8\x88\z\xBB\xAF\x01\xE5J\xDB\x91J\x95\xEC\x18]\xD5\xDFm\x0B\xE7\xA9M\x0Dr\x1F\xFD\xFE\x92\x82\xEE\xD96\x9C_\xE4\x8BA\x9A\xCA\xE7\xA5^\x1D>\xAEa\xDB\xC3\xFB\x1C)B;\x1C\x13\xB2\x10r-C\xB2\xD2\xCA\xCDV\xAF\x06P\xF6r\xFC'8\x0B\xDB\xF6\xBD\xBD\x01/&\xA5F\xC2\xC8\x08\xDE4\xBE\x15U% Z\x84\xC3\xB8&\x91\xD4y\xDA\xED\xFD\x02\xAA\xD2\x13b\xB3O\x18L\x9C\x9B\x92~Q5\xA7N\xA4\x05\xC0\x8E\x0A[a|\xD0\xCF\xC1\xDCrxsD\xA4\x8Bl*n\xA4\xAF?\xB5\xD6\xFE\xD7^\xF1\x0F\xF3'N^\x9E[Rb\xE0\xA0A'\xCD;\xA3(\x16\xD7\xC9\xE1\x1C%x\xDD\xAA;`\xFB\xDFh4C]H\xC9\x8FA\x03\xFDxB\xAE/\xFC^{N\xCD\xCB\xD3\xB9\xD1\xF1i\xA6\xBA\xD1+t\x9C\x01T-p\x86\xA2.\xA5A\xAC9\xC7\x89\xF2'\x98d\xC7k\xA7\xA1]\xC8\xA2`s\xF7\x17%\x90\xDD\x9Eh'\xFE\x94\xC5\xE2\xC38\xD3H\x89ha\xDF\xD55W\xB1O\x10\xBB~1<|\xB4\x86\xF5\xA4\x0E\xE8\xDD\xF1\xBEi\x046\x9B\xE5\xA4:sp\xE8BO\xF2u\xCF\xD6\x18\xF6p\xCE\xC4\x8E\x1FS\xDD\x0C\x13\xD0\x0F\xDC\xAB\x9A\xFE\xE6m\x10%\x86\x80\x8EQ\xC6P\x9D\xEB\xDB\x8DX\x1E[\xF0\xC2\xB5\x08jO\x17E\xF5*\x13B\xE7\xED\x8E\xB8\x84v%C6\x99q\xF8\x00\xEEuP\x13\xFA\xD5\xD3((\x90 Ln\xB2@h\xBCLW\xD7O\xE8\xC7iXx\x81J\xE4eg\x97\xF2j\xA0\xC9k\xA8\x09\x0B\x16\x92\xCD#9\xB6\xCF\xC1\xD8\xA7\x8B\xC2\xAF\xE7\xB9\x8A#6\xAC\xED\x1F\xFDnp\xB1?\xFB\xBB\x81\xB8:\x17\x00\xBE\x0Fi\xA4\xBCy\x03~\x14\xF0\xC2n8\x04\xCA\x11\xF5r\x86p\xD2_\x1B\x1D\xDEt\xDFX\xB8\xB8;\xB8\xF0ej/\x03\xF8\x1C2\x1B\xBB\x16\xC1Gt\xC5\xEB\x0DG\xB6}\x1D\xFED\x84\xDF\x85\xEB\xAC\x85h\x03\x7F(U\x19\x8F\x14\xBB\xFEv\x14\xC7\x00\xB97\xA9l]\xD3\xE2m\xAD\xFE\x04r$\xFC\x89\xC2\xE0lE\x14{\xF3\xE7\xE65\xCBe|\xBE\x92\x119\x9D\xE7\x96\xE7\xD6}\xBE\x11\xFDz\x9D\x89i\x03Aj{\xA0\xDB\xFD1\xAD*\xB0JeL\xFF\x07\xC1=\xEDly\x04\xCD3\x13\x9A\xAE*\x97\xEA/\xA4\xD7P\x94\x1B\xA9\xCCW\xDC\xCB\xAE\xBA\xE0"\xFB\x08\x92\xD3\x10Q\xB3\x16\x0D\xA9\xA2~\xFA= \x86\x80\xF0@\xB7\xBF\xB6#PO0\xAF\xFF\x09\xC1\x82o\xB0\x85I+\xF4\xBE\x0C\x19\xA1\xD3\x86b\xA4\xFA\xD2\xAA\xE88\xCA\x94z\xB4\xA0\xCD\xAC\xCAtOS\x0Fc\xE8\xDF\xEE\xE0wwh\xFF$\x04\x97N\xEB#\xC5\x08B\x1D#?^\xD0\x15-\xD0\xC1\xAD\x0E\xAF\xA9\xAF\xC2\xA8\xAD=\xB9\xF7\xCC\x96\x098N\xA6w\x0FG\x98\xB5\xE4\x11\x10\x89\xDB\xF7\xD0\xD2K\x80\x02\xBB\xC5\xAD\xA6a&u\xAD\x06\xF0H{\x07%\xE9\xE3;6\xA2\x0D\xE3\xB7'\x12\x1A;\x85\xA2-\xDBnB7\xBB\x04@\x0A\x90GN\xDB\x9A\xE6\x8FR|\x17x\xA03\x0D\xF2S\x0B\xBA'\xFEz\xF8\xF5O\xE4&6\x1A\xEC\xD7j\x89\x10dg\x01\x14\xC4\x87[\xA4\x02,d\x0Db+\xC2!Y(\x1Ch\xBE\xBC\xA6u7\x1F\x96\xCC?FhN\x8C\xA6O{\x1B\xFF\xF0\xB2\xB3\x1B\xFAe\xD1P\x7F#\xE190`\x96\xFE\xCC\xCC{\x0Ao\xF0\x9FN\V\xE1es\xAF\xBBDv\x90\x03\xBE\xBD\xD8o\xC0\x03\xDD\xA8\x1D:\x02\xCE)\x83\xC4\xF7y\x8CL\x1C{\xBCTp\x14\xFD\x8A\x06\x9F\xD9?\x1AD\xD22x\xAA\xD5\xDB\x8C\x02k\x1Fa\xA6\xEEf\x1E\xB0\xF8\\xCAl\xF4>\x0A`\xBD\x98\x95r\xD1\xF3I\xEE\x03\xF9X-sWC,\xD2\\xD2|\xAC\xF8\xDD\x1CgM\xB8W4\xB0\x1C\xEC\xA09\x0C\xA3E#\x8CX<\xA4\xD0d]l\xC5~\xA7s\xF7:\x04C|\x08\xDD\x83\xCF\xDD\x09f"\x03; \xFE2~\x0B\xA6\xA6\x83!x\x00\xE7\x9AG\x060\xB2\xC7\x1Bu\x14\x83\x0D\xED\x15\x87sC\xC4\xA3\xD5\x9D\xD5%\x8AF(]`XO\x1D1\xDAF\xC2U\x11{z\xEA\xF9\xBD\xBC3\xCALf\xB8\x17N\xC7h\xEE4\xEB\xDBu\xBE\xBB\xEF\xDD\x85\xED\xF6\xDB7\x0A\xFE\x01\xC2\xF5\xBA\xC1\x91@\xBE\x7F(Wm\x8D0r\x96\x04\xEC9h"Ue\xF3\xAD\x0Ap\x1Aj\x1By\x9F\x8B\x92\x8C\xD1\x04k\x8F\xFEj\xDB\xC8\xF2K\xB6\xF8\xC0Q\x01\xA8\x90\x028\xFB\xD6\xAC\x9APZ\xF0\x00&X\xE1\x88\x0DTn(\xC0\xBE\xACK\xA2xO\xD5^\x1C;K\xEC\xFB#\xF5\x90c\x1E\xE7\xF9\x97\xB8\xDB\xAD\x90\xA3V!\x9EL(\xBC\x14\xA8\x94\x04Jw\xA1(\xAF\x0E\xF5\xA4A.\xDF0:[\x16\x00\x0Di\x04\x8Ci\xC8B\xF9R[\xD1\x8B\xB0\xCC\x84\xDD\xDE\x87\xD5\xBAl\xBC\xFEm\xD8\xDB\x8Fpj\xF4>[\xD3Z\xB8\x02K\xC6\xA4M\x86\x83\x0C\xB3\xF7\xDA\x1EJ\x9D\x05NK\x0B\x87\xBBG@1_\x15\x97\xC6\xEDqJR\x96\x93Y\x8Ck\xAC\x96_\xC6\x9D\x7F\x88\x18\xC9t@\x90aw\xF2SM\xA3?\xEE\xC8Zz\xA2\xF3"\x0A#\x08\xD1\xCA\x99\x17\x93\xA9q\x1C\xB9\xEB\=\xBD\x03?\xE7\x06PB\xBBf\xED\x9F\xDD\xDE3T\x83\x1B\x91F\x0A\x88\x8B\xC3\xF3E\xFC\x80\xF0\xDE]\x8A\xC0\x03\xA1\xA7\xC8\xCDj\xD7EfT\x19#\xD6\xBF\xE91\xB8\xB1\xCCL\x1E!\x92F?x\xEEhy\x92uE\xAFw6%\xB6\x00\xB5\xBF\xD3\xC2\xC8\xCAM`\xC0\xC8~z\xE5C\x97\x01DEx\xEF\xB8\x0E\x09|\xA2\x0A\xA7\xAE\xFC\x0F>\xE7V\x10\xF5P[\\x06x(\xE4\x81\x84\xA5mc7+3j3^a\xAA5\xCC\xDCd\x902\xE0\xFC\xF4\x83z:KD\xBAF\xB7\xE6\xDDD\xC5\x84*\x1A\xB2-\x90\xB2\x02f\xA3\xC4\x91b)\x1D\xDD\xB0\x11R\x0B\xDD2ge;6[\x19\xB3\x87B\x90\xDE%f\xE6B\x97\x9E\xDC\xD9\xB6\x15\x1E\x07\xE1\xE6qu\xB5\xDF\xE5XF\xC6\xC8\xBB\xB52\xF6\xBC\xB5\xA0\xEBtN\xE6\xDA\xFA\x0C8\xB2\xC4\x09\xADe\x12*\x0D\xD7"r\xB2\xA7\xBA\xD0\xA5\x94\x84\xE6\xCB\xA7!\x99\xDA\x82\xEA^\x05\xF6\xF4]\xAD\x05\xB9\x92\xA7\xF9\x0C\xE3\xF4\xA2\x7F\x149x!\x83\x92U\x17\x83d\xC7v\xEAkQG\xF6\x09\x9Fh\x0D/\x8AK\xDD\xBEQ4\xF5?"\xF5\xAFm\xE4zz\x0DM=\xA7\x9C\xD2D\xE4\xC6\x96x@\xE1\x0A\x9Es\x9C\xBF\x95&\xFD\xE5\xFEv\x18a\x13O\xD2"\x0Af\xB6 \x814\x00\x1D\x89\x0D\x1F\xC4\xCC.f[u\xCC\x99V\xB4\x89(\xFB\x8F\x9E\xCD\x84\x0A4#\xCB\xE9\xFD#\xAD\xB1F\xA8N4\xD4\xD2\xDBy@'\x8E\xDD\x95\xE9bH<\xB7{C\x84,`1\xA9\xE0\x0C\x82\xC9\xE4Ea\xB8\xE6T\xAA\xF7})\x16\xDB\xEC\x95]>#\x83\xF8\xDA^\xDF(\xB5>P\x81a\x12\xF2\x156b\xA1g\xB7-\x96D\xC3\xFEP\x1F3\x82`\x8E#!.\xEB\xC5\x90\x93\x80\x95X\xBA\x19i\xE6\xC56\xFD\x9F\x0C`i\xA5n\xCE\x18\xF8qu\xC4\x82x\x9D\xE0\xBFGO\x8Du\x8FC\x93\xA1\xF7\xBB\xA5\x0DIK\xDB\x11H*\xA0!w\x0AK\x9A\x84\xDBZ.i\xCD\xEC\xC8\xF7\xD5m9\xBE\x9A(\x80\x15M\xE7\xF7\xF7\x11\x96\x01\x9Ch\x9Ei\xDC+\xC8\xBC#z\xAA\x85\x08\xF3\x89"\x7F3\xDD\xBB\xB2e\xAE\x93\x95Z\x88QI\x17S?H\x02\xEC\x03\x19[\x94\x92\xAF]x1R\xF8\x02\x9Fp\xA1&\xF4\xA7\xB7\xFE%C\x8F\x9EduA>\x16p\xA2:\xF8\xB75\x94\x83\x13\xF6R\xF6\x8B[:\x05D]\x17\x9D)T\xE7>G>\xBB?\x09F\x80\xBF\x087Z9cK\xA7\xF4\x80\x97\xDA\xB6\x02\xAC\x88,\xB3'\xBB\xF9\xE0:l\xC3\xDF\xDE;\xC4B3\x85\xCD\x1Dv=\xA9d\xA1\x92\x08 \xFA\x99F\xCD\x12\xEBE\xB2\xC5(\xC5\xE9\x15\xDAJ\x81\x88*\xFE\xF4\xE7\x92I\xF4T\x0E\xE9\xEC0\xBB\xA3\x0E\xBAn\x8F\xA8\xC6\x81\xAC\x1D\x80^\x9F\xC3\xC9\xA8\x93\xB6|\xAEg~\x95\xAF}2\x8DRg\xE7d\xB0<\x05\xD8\x81\xCB.\x96^\xD7h\xA5.\x89l\xEC-\xC2\xC3\x9A\x0C\xFA,D\xD8\xA47 ^\xDF\x9F\x86C\xA07\xD0\xD5ac\xA3F\xB3\x06\xC0\xB3 \x9C|\x7F\xDD\x0D\xCE\x9B\xB5\xE0$\xD5\x82\xD3|9\xBD\xD1\x91\x0F\xDDRc\x04$\xFEP\xF7\x084\xA8\xA9Kcj\xCB\x00\xF7\x12\x09\xE7r\x99\xBB\xA7\xD0W\x86\x1E\x09\x97\x88<\xD3\x13\x1D\xF6\xA0\x98\x08\x8B\xCBi\xAAV\x18\xF5\xDA\x94\x1E\xF9\x9B%*\xAD\x85\x92?#SO\xBCV\x95w\x1C\xE1C\xB8\x08\xB8\x0DV\xAF\xA5\xC5]\xD3\xF0\x8De\xCDu\x1A<\x1DK\xDEk\xE0\x9D\xD0\xB9b}\x09\xD8\x85\xB5{\x94E\xD2\xEC\xE5\xA6\xEE\x97\xB5\xD5|\xFBa\x8FspRQN\x11\x1Ce>\xD37|\xEF\x89\x108\xDF\x96Gg\xDAG\xB2Cv\x89d\xFC\x83J\x19\xF4a\xD3\\xB0\xA9\xCC\xD5e\xAE6\x9B\xAB\xCE\xC5\xB3u\x0B\x82\xA3[\xB4\x02\xC1\x9D\xF2\x8F\xA4\x02\xE9mC\xDF\xCC\xF2\xA8O(\xF9\x88e\xFF\xE4)\xA1\x17P\xB9s2\xFB\x0D\x1D#\xA0\x15 \xCF\x9Bd\x94\x08\x00:i]YU\x06\x80\xC7m\xE6\xCB\xD8\x19\xD5"&\xFF\xC1\xF5k\xFF0\xDEc8e\xFA\x08\xC70{\x84|O\xE6k\xD6S\xB0+\x80\x8E\xB6e\x19\x12\x92n\xC4C3M\x87vh\xD9\xB7#\xE3c\xA2\xDC@\x8A+\xF5]\xC6t\x96\xE7\x85\xFE[\xF9N\xCA\xCFt#,\xB8\xCE\xAF\xC7D\x82\xF8\xA4*v\x93\x02\xA5\xC0\x83\x8D\xF3\xE7\x10\xC9\x91h%\xEC\xE9\xF6\xB7?]\xAD)\xC1\xD2\xF3Ds\xD9P\xA1\x13n/\x01\xA4\xF1E\xAD\x8C:P\xC9EE*\xA7\x90\xC4\xFF\xC6\x81\xDB\xE0\xCE\xED\xE3R\x86V\x17\x95\x93\x9D#\x90\xA8|\xA7\xE5\x057\xC1\x99\xE7\xAC\x12,\xEF\xF6\xCD\xBD\xE6\x0D\x08|\xC6\x80\x11\x1Am\xCD\x94\x8BU\xE0\xEE\x8B\x0F/\x1B\xF51?\xC6\x82\xB6\x954\xB8\xA0l\xB2\xF7\xEES\xD7\x96\x850\x1F\xAD|J\xFAO\xB8\xFC\x1D\xBF\x09\x98\xD3|\x19{\xA0 \xB3\xED\x84\x0E\x87\x06m\x9E!9\xDF\xC0L\x14\xC7]\xC4\xD2\xB0\xDD\xC8\x17\xF6\x7F\xD0G\x1CQ8d\x1F\xF5\xC8r\x931U\x1B\xDCV\xD5\x97\x91\x00F)\xA2\xA6\xE1\x80\xE0\x07\x06\xDB\x0F\x1Dj\xFDg\xBA\xE0\x9A{\x1F\xCA9\x0C\xD0\x80\xC6e\xF1\xDA\xB9F\x8F\xDC\xCD\xA0\xAA\xFA\x00\xBF\x02\xA5\xF3\xC3\xDA\x921\x83\xD7$]\xD7\x8A\x95)n\x84\xC1f\xAC\x81'\xE0\x17\x1C\xDBG\x13\xFB\x1E\x14.X\x87\x91\xA7\x81Z\x8E\x96#\xB6\x14O<\xF7~\x11\xE5\xEA\x1ES\x08\x11\xC1\x89\x9F\xEC=B\xE6z\x13\xAAaF\xEB\x18\x90qs\xF9\xC9\xCD\xCA\x99"\xF1F~\x1EmU\xD2\xE0w\x04\x07\x0A\xD3;\x97\xD0Oe\x88\xA1a\xB9\xDB`\xB1q\xD4\xB1\x1B\xAC9\x09\xC5\xE7\x12\x12\xC58\e\x8B\xC6*W\x063UZ\xB2\x08\x86\x95.\xB9\xC5\xD8\xC2\xD1\x93k\xCD\x8C<\x91\xCA\x97\xFA2\x8A3\xD1zt\x17\xDB\xCFu\xF8\xE0S\xA5\x0E\xA6\xDC\xA1,{m\xE7\x0C*j\xF9a\x8CQ\xD6\xE3s\x9B\x95|\xC4\xF6\x14}3\x85\xD4\xC2\x99\xC2F\x1D`\xCAjV;\x97\xD0P"2\x1E\xC5\xCF\x80\xB9)g\x14\xF3\x88\x90\x117p?N1\xADAxj\xED\x1E\xC1#\x01\xBD\xFF!\x02\x83h\xF0u\xDA\xCA+\x1DM\x09\xEA\x94{V\xFC\xDC\x84\xD2\x999\xF6\xFE+\xCE\x0E\xEE\x8A\xFA\x1A\x00\xB36\x80\xEBe\xD5\xAD3CHe\xA2q\x1D\xEC\xC3\x17\xA2^k/\xCB\xB8\xDB\xB7\x1F<@\xD0\x93\xD0?\xE49\xFE^\xC7j\x09*x\x84<\x7F\xD0h\xAD\x0Dc\x16'\xE6c+\x87i\xCA\xD8\x01\xB5\x06 \xC6\x86f\x08\xE4\xD6\x94]\x8B+\x16\x81\x83\xCB\xFD\xFBC3\xAB\x822q\x0B\x05\x04\xCF(\x01\xC8S\xB0zm\x14\xA0\xD6=\x895\xFF`\x9C\xE3D5\xA8\x96"R\xDC$\xA2\x99=\x90h\xAF\xD0\xA68\x12s-\x7F\xEE\x0Dv\x8A/\xB2\xBD?\x87\xB4\xBD\xA3\x0D#\xE0k\x0C-\xD5'\xD4\x9F\xDBI\xAF\x81"0\xDE \x91\x8Fc\xD5\x9F>\xB7\x13\x916\x9B\xA4\xDF\xCAO6[*\xBE\x04`4#\xB9w\x01(\x15=,R\xC8\xFD\x11&\\xD2\xC1?\xBBK\x9C:T\x8E\xB8\xDC\x8A\xE5\xF6]\xD8\x18\xE4\xCB\xF3\x03\xCB$R~\x88\xBBn6\xEC*\xC2\x01\x16\x03\xF7%O\xF4[\xEC\xC3\x99\xF6>*2\x9B\xE7\xC2!\xDCUG\x10l\xFE1\xDD!\x82\x0Eo\xD4\xAF\xF3<\xA5\xFB\xD3\xC8\x1C\xCC\x10'\xF1\x10e\x85g\x8FOa \x87\xFA\xBCA\xA8'\x8EqX\xE9s<\xBEC-G:\xCD:\x17p\x1C\xE6xB\x0Ak\xD9(\x7FZ\xC1\xC0\xCC\xFDD\xA4\x02\xA8\x0E\x8F\xF1\xCBr\x83\xA5\xEA\x81<\x87\xEF\xE3K6P"x\xC1\x93M.<\xEB\xBD\xCA\x88\xCE\x8C\x82jE\xE9\xE9\x1F\xB7\xC6\xF1\xEA\x04\xF7\x04p\xDFo\x02\x02\x9DK\x1D\xF41vL\xE2I\xC3F_\x0C\xD4H\x9EPh\x00q\xCF\x0Cx\x9A\xF7\x9E\xDD\x99\x16^\x10\xF7\xB8\xAE8S\xEE\xF7E\xC1\x1F\xAC\x03e\xBEf\x9F\xEEa\x94cg\xC5\xC6\xE3pl\x0F\x1C8\x05\xB1\xCB\xE2\x8B\xCB\x9BP\xEC\x00\x9D\x9Fs\xD8\x06\x13\xEE?\xF6A\xEEO\xD2\x88,\xD6\xF4\xDAMW.)`\x1D\xA4a\x8F\xE4\xB1\xA4\xDE\x0Bb3d\xA8\xBF\xC3\x0F\xDA\xA1\x90\xC5\xF6\x11\xDBW\x0C\x83z\xA9Z\x1Fh\x91\xA8\xD9i\xB5\x87P\xC8+A{\xAB\xB2\xA3X8\xFBs\x9Di\xE1\xFE\xB2nF)\x0E\xA7b\xD8\xF4\x98\xB8t1\xC1\x9E\xDDp}"(\xF4'\x1D\x18A\x13t\xCC\xD6m\x83t\xA2\xD3\x9F\x1BQ\xED\xB4\x83\xA4\x7F;\xDC\x8A\x85!9\xA6E>\x9Ai;\x898\xD9^B\x96\xA5\xD2\xA3k\xEA\x9E\xC0\x93\xF9\x88\x86\xDB\xE0\x87\xE6>\x99\xA3\x1F\xA1{\xE7{*rq\xFE\x06\xA2\x06\xDB&W\xE1\xAF\xC0l\xE8\xD6;\xF5\xED\x8A\xA9\xA9?\x9D"qa\xADN\x9F\xEF\xBDr\xF7\xC5p\x93qY\x98!\x85y\x98\xC2\xB4\xCF\x0E'\xDEB5S_\xD8\x9A\x89\x09\xD5\x87Y\xE8+A\xF9\xD0'[Y\xF3\x8C\x82!D\x8A0\xA05\xF4\xCEI\xF0\xE1zf\x13\xA9B\xA0Lk\xDB\x0C\xD0/!\xA0\x95\xFD)\xC6+7\xA8\xA3\x15\x9B\xDB\xB2l\xFB\x04\x0D\x9A\xD9e\x0C\xF4\xAC\x80$\xD5dZ\x9E\xED\xD2\xEC\xD0\x84\x9Eu2\xCD\xD6\x06\xB4\xEEF\x8C\x00h\x0E\x82N*mwK\xFB\xFE\xB9(\x00Q\xA3A`\xAFJ\xD6\x9C\xD7\x0C\xD8\xEBJ\x03\x1F\x93\xB6\x12\x8F"[g`V\x93\xDAC~cM\x14\x8D\x9B\xF7\xD1\xD8\xA5\xAD\x15pj\xCF\x8E\x05Vr)\xFB/\xBBb\x01\x91\xA2\xD9Ruf\xCF\xD3\xBF\xA3\x03\xA0\xFFA\x8C!W\x19\x1B\x0F\x8BXZa$1\x11x\x87\x04\xFD\xEA|ED\xC13\x0F\xC3C\x98c\x0BZ\xFC\xAF\xFE\xEDD\x89\xDE\xD5t\xEE\xDE \xD1S\xD5\xF2\xC8\x0BnF\xA61\xB1\x8C\x06oS\xB9\x8D\x8B\x0CC\xADRW\x93{\x01\ \xAB\xA5H\x01\x00\xE1\xBB\xB8e\x1C\x8C=\xFFX\xA2M\xC0\xA2P|d\xAD\xA7\xBDCN\xC2\xDB\xE8\x9E4\x8B\xC6'\x01)/\xAE\x84\xEES\xB66\xB7\xBA\xA6~\xD7\x1E\xB14\xBF\x87E\x1F\x04\xBF\xB4;XY\xA8\xC5\x9D\x13\xD8\xAB\xBE\xF5\xCD\xD1\xDFt\x97\xBEe\xDF\x9Cue\x1EQ\xD4\xFFY\xF5_W\x04\x8CT\xF6\xAF\x14'\xACd\x0A\x0By\x1DS83\xCDK\x0AO\xCA\xDA\xE3\xA1\x83.\x03|\xAD\xAD|d[\xE6?\xF2a\xF9\xC1@\x8D\x0FT\x99&\xA3D\x89\x0AN\x8Cq\xAA\xF3Q\xFAT>\xCC\xA7M\xA9\x95\x1C\xF0\x8A:7\xF6H\xD6\x9F\xE7QH\xB2\xC2\x98\xC6\x17\xF9\xB7\xAC\x18\x03\x95\x07;]#\xB0\x1Dt7\xB4\xB3R.\x0F\x09\x8E\xE1\x89\xD5\xD0\x81\xA5\x89Wv\x8Ft\x0A\x83\x88e-\xFDl\x12\xAC\xA2\x9B]TVe\xC2\xF7:\xB9\xA7Z\xEBZx)\xD2\xBE\xC1\x81\xA8\x0B>\xD6X(\x8B\xD2\xC1\xB4)\x15(\x88\xD3\x92\x1D\x1Du\xB5)h\xFC \x87\x0F\xEB\xD6DQ!\x8EXb\xF3\x95\xF3\x90?t\xE6\x87\xF5\xAFZ\xF8\x0A\xC5\xF8\xACKJjeE\xB8\xCC|rB\x07\xE5?\x00\xCF\x04\x19\xA6\x0EO\xED\xE4B\xAE>U\xC1\xC2\xA8\xFA\xB1V*\xD6\xDB\x9E$\x91\x19\xBF\xE4\xD8\xDEM\x15\x0F\xA6\xD7\xB9\x0B\xE7`C\xCC9\xED\xA7&w\xDC\xC03LFe\\xD5\xD7j-\xAF\xBD\x10\x8B\xA5\x1Ck%\xCC_p\xEAK\x9F\xDB'\xBF\x96#\x06\xF0\x15b\xE3\xAD|\xFEE\xBE\xC2w\xA0\xA1\x13>O\xD6\x13w`V\x9Df\x0D?\x08\xD2\xC3\xAE\x82`\x1B\xCD\xFB\xBDt\x1Bu\x85\xDC6\x85\x0D\x15\x16\xB8N\x9D)\xF1\xF5\x13#~&c%\x8DQ\xC6rl\xB3P\xC1M'\xC1\x81\x0F\xE7\xD2\xD0h\x04I\xD1\xFF\x1C\xF3A\x1E\xF6EL\x12\xA8}\x87FM&\xFA\xEE\xE6\xD5\x85\xBD=\x9C\x90\x89\x03\xBCW\xBAa\x0E\x16\xD2\xA9Rh\x1A"0j\xEC\xC5\x12b/\xD7/\xFF\x98\xA9\x9D\xDE\xE7\x01I\xA5\x90\x0F\x90\xA9\x19\xF3\xCA\xD3*\x90\xBFX\xAF\xC2\xC3\xA5W#{\x06\xCA\xC7\x01\x9E\xD3\x06\xDE\xAE\xB98\x01\x85\xB6\x9C,\x1F\xBC\xB5\xF5$D\xFC\xC2\x1EC\xE1!\x9BM\x9B7\x8BP\xB4\x10;\x95t\x95\x1D\xB3yp\xE7\xD2\xA4\xCF\x84c\xFF\x9E\x1D\x01\x16\xE9\x01\xD9\xEA \x0CV\x82h\xCCR\x83\xA2\xB9\x1A\x85\xFF\xC9\xBA\x7F8\xD1\x1B\x1B\x9E\xA2\x0B\x95\xE7\xE9sgF\x82\x93\xF4\xCBb\xBA`U\xFC\xE3IU\x02!9!\x10s\xD8l\xBE\xFET U\x90\x99\x85<\x99I\xEDd\xC9J\xE1\x03\xB7M\xE6\xC3\xB9}\x96\xD9XDB]C\xDA\x15\x9D\x04\x14\xC35\xCE\x84A\x0D\xA3\xCAx\xD0\xFFCSq\x94\xBF+\xF3\xDE\xF2*\x06\x0FSl\x94\x87\xDD\xB1\x97J\x19U\xD3\xFF!y\xA7l\xD2\x83y[i\xC9<\xD2w\xD6\xC1\xDB\x8D\xA9\xC7B\x85\xEE\x82\x97\x11\xAF\xAFY\xF2\x8BzY\xEA\x9F\x08\xF2\x82/\xDFZ\xE6\x1E\xCA\xCD-\xBC\x9Fu\x0D\xFE\x9C\xA4\xE0\xDCd\x98\xEA\xF4'g\x1E}\x8E%\xEF\xB9\x8E\xE4\xF3\xA3\x97\xEB\xD9\xE0\xE1\x8E\xBDW\x95h\xD1\xE9Z7p\x8DyJ\x11Y\xBFG\xC2(q\xE3\xEC\xDF\xF6\xB6q\x86\xAC,\x93\xD1\x13\xA4\xEBG4\xBC\x0D}\x92\x8D%\x1C\xA8D\xF2*\xBB\x9F\xE0\xEB\xFB*\x0F\xC1\xAB\xBAY\x87\x07p\xFCh\xE98B\xCC\x17\x96l\xA2G\xDDT\xE93P\x86\xA8\xC1\x19s\x0A\x88Vc\x1Fd(\x86\xD6\xEELwQ\xE8\xCF&N\xF5\xAB\xBA\x94\xF7c\xD2\x15\x81\xD6\xB1\x88\x84\xAE\xD0.\x875\xF6N\x11.\xFE\xA8\x91\xD54\xE9dJ\x0B\xD6<\xB7\xDCb\xEF\xD4L\x09\xE9\x92\xA5s;G\x84\xE3\xABI\x1F\xBA\x1D\G\xB6\xA4A\xA5\xC3$(\x88\x92I\x8C\xF6p\xF2\xCB}\xEF\x9E\xFA\xFE\x84\xEED\x16\x19\xA2P\x8A^\xFB\x0BG\xBE\x0E\xA0\xF2%\xD1(AT"\xB7^\xF50~.7\xA4\x0C\x03\xCD\x90\xB6R\xA4W\x1C&M\x02\x9A\x1B\x01\xA5a\x9A\x8B9\xB9\xB0\x14\xCA\xBF\xB3~\x8E#\xDC\x14\xCD{2\xD2\xEAGE\xBC\xD4\xFB=-\x9F\x8C\xB6\xC3\xF7\xCE!#f\xD6Yj x*i8\xD2\xFC\xFD\xD4d\xA2\x0CU3{~\xA46\xA9\xB7\xD1\x02J\xCF.\xBB\x91PzPk\x15R\xF5\xF6k\x8C\xC6\x82,\x83\x02\xF9gB\xC0\x1Ah\xCD\*9\xFB\x03\xCD\xF0\xF5\x05\xDE(g\x97\x92v\xD9\x16\x84\x0BOQA"\xDF\x11\xAA\xC4\x9A\x18\x07\xE1Ym\xCE\x14\xFD\x8A\xF3yy\xBE\x9D\xF6m{\x97\x15\x0F\xBD\x07$2\xE6C!u\xD8\x12x\xE5~\x96\xAFp\x15Z=\xA7f\xF8\xBEr\xF9\x80\xB8r\x8B]\x1BJ\x11\xE4g\xAB\x04\xFD\xB1\xAA\xFEa\xCBC/X\x7F\xFD\x89\x99\xC0vI\x80\x99D\xAC\xC1\xA1\x1E\xFB\x12\xD7\x90\x810\xD6\x1A\xF5o\x1C#\xB0\xCBz;u\x06`\xE9\xBD\xB59\xA4\xA2\xAE\xE6'\x1Fe\x99\xD2:\xA8:\xD9Q\xB7JA\x94\x1D\xF13\xB4f6Q\xC0\x08H\xE3\xF6\x87Y\x82\x1A>\x07h\xC8\x83\xB8i\xAB&Z\xD9\xE4\xAE\xEF\x06\xA7\x89\x84ip3#s\xC1\xD8\x8E\xB8\x02Cg,\xCC\x0F`\xAF\xA2\xF5\xCF\xCB\x17 \xF2g\x1Ex\xC3\x91p\xA3m\x1B\x07:Z3\xDB4n=\x8F\xAF\xBC\x84\x96-\xDCcP\xB1\xDFO\xDE;\xE1l\x81\xB5\x1A\xAC\x849\x05\x11\x04ag\xD2nI\x89\xC5f\xA7F\x83\x1E\xADf\x13\x9E\xE4\x9F\xEE\xF3\xD9\xA7a\xEB \x1D{\x10\xE6\xEC5I\x9A\xCB\x19\xD0\xE1b,\x93q\x06\xD4\:q\xF05M\xFAD+\xDF\xEBa\x0F\xA0F\x85\x13\x8E\x86^-H{\x06\xEA@\xE1m\xA9\x1F\x92\xC5\xD0Qq^\x96\xA0\x8Ffi\x01\xF7\xCB\x12:\xE5\x08C\xA3y\x1C\xFFH_C\xDEx\xD4\xCE\xBF\x12\x93\x87\xB2[`\x8E\x9D\xE20\x80\xB2U:q\xED\xBA\x9E\xA2\x91\xD50\xA3]\xEB\xD4s)\xF8i\x95\xD0\H\xB9\xBE\xEA:+A\xAEZ\xE06\xEAgm\xC9\x92\x02e\xCB\x8FM\x12\xB2+\xC8\xBE3\x90\x1D\xF1\xAD\xBFM\xF0\x16\x82B\x1F\xFF\xAB)\x8D\x9C\xD6s\xFA\xD3\xBA\xBC\xA9\x8C`\x0E\x0Em\xA5\xB1\xA1\xF32\xAF\x9AYB\x1FZ\x1B\x0Dw4\xB3\xB7\xB2\xFFH\x1A\x9AF<\x9B<.\xC9y0\xCF\xE3s\x9B>$rbd_K\xE2\xF8(G^\x1C'p l\xB1\xFA\xC1S\xD3A=\x02\x19uW\x1A\xAF\xF0\xBA]\x9D\x10]T\xC2\x01j\xF8\xCE\x9C\xAC\xEEayR%\xE1:r\xEE\xDAzM\xD5Y_i9\x15G8\x9D\x83\xD0\xAD\xC1e\x1D\xA2\xCD\xFB\xFC\x9B\xD8\x14LY?SG[\xDE\xAE\xD2R\x9DK%\x11\xE0S\xEE\xB1\xBB\x09\x8E\xC2\x0CI\xA2\x07\xC5-Og\xC9N\x86\xFE\x01n\x05\xCF\xA63d\x02\x8D\xABo@ \x92\xD8\xB5\xB2 \x04\xF1\xE7QE+\xE1\xB6\xF0\xD2.IY9+\x0AKC\xD7,\x91iZG\xE2\xA6nl\x9DJ\xA1 \xDC\xF0/\xE7\x074\x09.\xAA\xA0\xC1_\x98\xBB\x01\xB0e\xD2\xEB\xDC\x83g\xD5\xC2\xE6=\xB7L\x13g\x86\xB4\x00\T\xDE=Z\x87g\xD7\x1Cb\x85\x9De7t\xA4\xBA\xBD\x90#0\xCE\x09\xC9\xBF\x81\x00?z\xCB\x92+6P}_l\xD7\x8E\xAD\x92\x04\xC8\xAF\xCF\x9B\x9E\x8A\xDD\x83\xF8\xF7\xCAK\xA8\xF0+&?=\xE3\x9E\xCCLb2\x93\xBFL\xC5;\xA4\xD2\xAD\xB5\xD8\xC2\x9E\x84,AcpQ\x92\x12\x83oD\x11\x12\xCEw\x1E\xBE\xB9'6\xE9{n\xDB\x9C\x07\xB4\x7F\xB4\x1D\xBE\xA2A;\x90\x8F\x9A\xEE\xB7z\xAA\xF3\x12\x19Qv\xFEQ\xE9\x08\xB2k\x8E\xC4]!\x11\xA3\x8E\xD5\x9F\xE2u\x1F7o\x99\xFB\xECA\xBE\x96Ag_\xE1\xA4\xBF\xB4\xF5E\x1F\x92\xF0\xBF\xE47*\xCBD\xBFp<\xD3N\x94~T\xCD\x99\x14l\xFC\xA9\xB3.:P\xC1\xFB\xCC\x14\xD0:=\xB8oN,sW\x94(\xB5U\x11\xE3J\xB7\xF7\xC3,P\xFA\x1F\xEF\xB1\x02x\x12\xCA\x13\xE8s_\xB5\x8A\xE4\xABG\x02\x12 W\xAE\xF5\x95\x8D\x83\xE9\xD9\x94\xB4\xA7$z\xA6\xAE\xB3\xD8.0\x13Y\xA3\xCB\x11\xD25\xAEh\xBF\x94\xB3G\xC7\xBA\xD0ka\xB1\xD5\xFB4\xFF\x1E\x0D\xFEd\xA5\xF2)8\xB1\xAF\x00\x07\xD3\xD1&_\xDDn=N\xEAu\x12\xB8\x9C\x8E\xB8\xA3f,\x1B\xA6H\x08\xC1\x01\xBB\x1D.\xB6Q\x80\xEF\x17\x1A\xC5\x1A\x0B\xD2p\xD7\xB3\xCCno\x9B\xE4\xF3X\xC4\xE7\xD5\xFB\xD0\x8C%1y\x08\x0F\xBA\x98M\xBF#jN{\xA6\x05J\xA0b,\x83\x1Bfn\x09M\x8C6%\x15\xD8!g\xF5\x19\x11\xFC\xD5\xD0v\xAD\xE1\x1D\x9F\x97\xC2\x06Wn\x99\xE8\xF8\xCE(\xEEd\xD8\xB3\xB9\xAC(\xA6\xE10\xF7\xE9Sgl\x97+j\x84A\xE9\x10\xA4G\xCD\xE6\x18\xD4x\xD8\xE2^\x18\xED\xF7X~\xD0R\x94\x0D7,f\xDC\x03\xDE\x19\xAFz\x8D\xF3\x8F)V\x9B\xEB|V\xDB8b\xD6\x0E\x91\xFB\x86\xE0>\xAFL\xFA\xB7\xF91l\x97\xF24\xB3\x80%`m\xA2\xB9\xA5\x8Ccu'\x11p6oVp4T\x1C\x0E\xFCF2\x84\x0DM\x18\x16\x80_\x94\xA7\xDA\x0AQ\x15uh\xA8\x11E\xDE9ds]^vt\xA0\xE6\x03\x8C\xCA\xB90_\xA1\xF3\xB1\xC3\xDA^\x0B~}!"v\xAA\xB9\x9F\xEF\xCD\xA4\x7F>\x88s\xB5I\xB1\xA2\xEA\xDA\x18\x8F\x08\xAFHi\xAC\x10G6\xC9\xEA\xC3)1\xB7\x96\xCC\xC8\x8FHL9BjM\xC4u3M$\x84\x1C\xAA\xF1\x10\xB9W\xB6\x83\x0C\xC0\x0Ck\x10!\x92\x98\xEFu\x06\xD2\xED\x86(+~\x13\xCBpmF\x1B\xCC\xE9r\xAAk{\xF8\x08|\x0F\xC3\x16A\x96U0^\x17a5yI$\x87*\xBB\xF3\xBD\xE4A@.\x17\xCFWb\xFA1\x98f\x1DuY\xDF 4h~\xB0\xA8f\xBD\xDA\xC1\x0E&t!\\xE0/\x02\xFA\xC9r\xF5\xE4{\xCD\xEE\xD8\xEE\xCDw\xE6\xCD\xB2\xEE\xE2\x8C\x1B\x9F\xADO^\xD6\xCC\x81\xC3V)<\xE4\x10\xB4N\x08\x91\xFF\xF0H\xDAx\xAF\xB7KBU\x12;4\x9E\x90\x0F\x99[\x04\xAE{5\xD3R\\x10JT\x85r\xAD\xA1&\x84\xA3)\xD7?L\x13\xCE\xDER\x19\xD9\x91\xE1p\x84\xF1\xDD\xF5\x1C\x84\xE6\x1B)[\xDBx\xFC\x0CVC\xDB\xA3ie\xB1\x82\xBD\xE3aS\xF6\xFE\xBF/Gt\x90\xE8\x8E\x0FR\x11A\x93p\x8B\xC7\x03\xB7\x9B\x9F\x8E\x92\xA7\xF9\xFF\xD2\xDE\x82\xD9F\xBDw\x91.\xB4\xDFm\x02\xC3\xD1\x8F\xDE+\xADQ\xF7\x15o5\xD8ZD\x09\xD3\xD7\x08<\xB1\xDC\xD5<\xAF\xF2\xC20\xB4\xFB(M\xF8\xFA\xF4\x0C\x8C=\xF7\x93\xEB"\xEA\xBB\x89\x7F\xA8\xA6_\x85\x1Dc-\x1C7\xB6^\xF4\xB6Q\xF3U\x86%s\x17X=I\x0Dp7\x8C\xC8\x835\xF0\xFDQX\x92M\x14L\xF7\x02\xEB\x92t\xB0\xA9\xA8KU\xC3F\xFA'\xF3e\x9E\x81m\xC6\x02P8\x83=Gi.H\x8C\x9C1JYv\x19\x8A%\xE4#\xAF\xE8\x89\xE5X\x0B\xCF\x18\xD1z\xC8\x94\xC2\xD1=\xEB\xCA\x97?\x08\x01\xE6\xB9\xD8\xFDG&\xEE\x96v"\xB6+\xAC\xE8S84\x89CQ-]\xEC\xFE\x0Ew\x0Be\xC0\xC4\xD4\x14\xC7B\x07&\xD0\x87\x87M\\x15\xF1\xF3\xA3\xD6\xC9\x98t\xD2\x8DI\x1E\x8EI\x0A\xCE\x02\x9C3\xD1\x0Fc \xAFdJ\xBA\xE1\xEF\xB2\xE1\x84\xE1o\xF0\x84\xAB\xBDj\xB7\xF2\x07m\x85\xC0\xA7\xB0'\xAC\x01\xE7\xAF\xD9\xC2\x0B"\x1D\x0D\x00\xAC\xF3(k\xDF\x9F\x11$E\xA1\xCC\xCAu@)\`\xDC\xDD\xDE#w\xB0\x15n\x025L"\xC2\xFE\xB0\x9F\xF01V\x84\xDC\x03m\xEDZ3\xA2#\xAB\x1E;\xF5\xCE\x0A)\xBC\x1B^\xF3'\x0A\xACC*y\xC9\x17\xE0\x83Z\x94\xE8\x17\x9Dl\x8DY\xD6\xAD\xC54iS\xDB\x09\x12\x02\xDB\x81\x04\xCCN\x98\xDC\xDF\xB4\xC0\x18\x9D\x8D\x118\x7FMF\x07\xA0\xC1\x87\xDA-aq\xCC\xDA\xE1\x02(\xB66I\xB4\xEC\x85\xF7\xDD\xDA\x87\xE4\xEF~i@=\x9F\xEBR\xBA\xF3r\xB0\xCD\xBF\xFB\x0C\x8D9V\xB1nz\xF7E7\xE4\xA3\x94Z?\x1C\x8BP\xAC\xCF|\x9E\xC8*\x96\xC6[V\x04_%pB\xFFi<\x13\xA2#\xF0\xFC\x82E\xFD\x81P\x12\xB4+1\xFF\xE8sF@Vd\xEF::\x96\xA7\xF9reeK\x05\xAA\xD4U\xD1(\xFBU\xD9\xF6aD\xE6\x90\xC3NE\x99\xDA\xDA\x9F\x80\x95\xA2^\xE0\x02\x97\xC0Z\x1E\x020\xFB;?'8\x84Q\xD4\xCA\xB5L\xACZ\x0B\x14\xC2\xA5\xCFG\xF1\xA3q\xB5\xEC=w\xAF\x93\x1C$\xBF\x0C\x0F\x0D0"\xCFe.\xFE\xFEg\x0FG|\xC4\x9A\xBF\x12\x8E\xFA\xFE\xF9\x1E\xB7 n\xAEY27\xDA\x88\x88\xF3h\xA1"C\xFD\x0A\xB83\x8A\xF1\xA2\xBE\x99\xF8+\x9F\xA6cL\xA3u\x92\xE1\x16~\x94\x95N,\xDF\x828Y}\xC1\x1E@\xAF\xAD.\xB4<=<\xABD\xD8\xD0\x16lU6\xB5\xE0O>\x00\x83\xED\x95\xFCT\xAFs\xDC\xB9\x95\xA1\x0E\xCC\xCB[$4\xEF\xE6d\xC9\xE1j\x9Dd\xDD;\x7F\xBBM\xD2;\xE3\x0AW\xE2xn\xBE\x02\x99H1b\x9E\x17\x18\xB5\x99\x9Fn\xA3\xB5\xE8\xD7\x94\x92E\xC7^r\x07\x84\xB8\x90=\xFD\xD1\xC8\xA6OP@v]!\x07\xF6\x9At\x94\xAAtX\x1C\x05\xBA\x7F\xF3\x0Fsq\xE9}#\xE1\x9C\xD5\xF0\xCD\xFF\xA5\x04+\x88\xB8h\xD8!_:h\x94-3U\x09\xF5\x1Au\xC7\xFAc\x95<\xEEb\x08 3u\x07\xBBB\x87\xB8G\xF2u'V\xAD\xB9\xDC\xDAJP\xA1 \xF0\x9F\xDEvA\xF9\xC6\x876-#\xC5\xD1\xCEu\xD6\x06\xC5\xA5\x07F[B\xB7]\xE1\xF2\xB5s\xFAX\xEE\xEFq\xCF2\x8F\xC4A\x14\x96 S]\xBD{t\xB0~'wM\x8BT8e\x93\x7F\x85\xE4\xF0\x1E\x0E\x8A2r_\x1A\x85\xE4\x80\x971\x17\r\x18Rq\xF4\xBB\x90\x12u\xCD\x85\x8F\xEB\x94\xF8\x9E\xE3\\xF0\xA9g\xBC~\x88\xC77/\x00\x1F\x90?\x12b\x98\xEE\xCF\xC8\xD2g\xDCm\xC9M\xDEeJg\xE0Q(\xBD\x88G\xD5\xC6\xB7K\xAF,\x08\x12\x1F\xC5BS\x06s\s]\xB5\xB9trhL\xDE\xC3M|\xFF\x17\x16\xCA\xF4\x87/\x85\xB8i\xE1\x0E\xD2\xAD\x08\xD9"\xC1\x94\xE7\xD8\xF9O\x89\xFCo\xE1%-\xB2\xD5\xA6\xB3\xC0D\x0F\xA6"\xC8B\xAD\xD5hwI\xF0hB\xBE:\xFB\xE5u\xC6\x18\xE6\xD6\x9A\xD6\xE9\x9B\xED\xA0\x9D*\x10\x12"b\xB9NV\x06\xD9_\xBA'\xFF\x9AR>v\xEE,\x8F\xEAGDW\x82\x0A\x7F\xB1\xED)\xA9Q\xC5\xDC=\xBF\xA3\xC4\x8E\xB7L\x1FA\xA1\xD6\x92*|\x8FU&c\x0E\xC9\xBB\x9A\xEAFx\xD8Q\xB4\xB9P\xF4\xFF\xF4\xB0\xFA\x12\xE8\x0E|\xC6}H\xD5\xFB\xE3\xC73\x05\x16\x15\xDF\xA7\x11WH\x8F\x92\x03[\xCD\x81\x83\x83\x89\xEC\xDD\x1F\xBFn\x19\xA9\x15\x0A\xFDAA\x03\xDF#^J\xE5\x8E\x8C\xD2\x93G#\xD7\x0Fq\0\x1E\xB0@\xE8#4\xAF5\xA8\x87\x18\xD7\xFC\xC2&\xF2>\xB6;R\x0AQH\x90xEQ\x0Bg\x9DC,\xDC\x88\xFC\xE0\x85\xA0\xFE\x8F\x7F\xC0\xA0\xB7\xDA\xE3\xF0\x04vS2\x92(\xE0q\x94\xEB\xD5\x18XP\x0E\x90s\xC1qJ\x1F\xBD\x8F\xE2\x00\x8Fp\x90\xCF|\x96\x1D\xCC#\xFA\x1D\xD3\xF6\xF8\x11\x9A\x14?\x9DSp\x95:\x80\xA9\xA1d\x94\x0Bp\x9E\x93\xAC\xA7\xF4\xB1L\xAD\xAC\xB4\xEF\xBC\x00\xA4\x17\xDC_`\xF7\xFBg\xD64)x\xD4\x18\xA4x\xEB\xBAu\x88\x8D2\xEB\xEF7rb\xF88\xDB>1\xA9\x90\xCF\x8D(B:{FLc\x9A\x90\x88\xD9=\x0D\xE9\x16\x1E\xAC\x0A\xB3tZI\xD0\x1D$\xFB;\xD92\x92\x9B\xA5p\x1C]4B\xD3\x03\x80\xB4-\xF6\xDB\x0F\xE0\x8E(a&\xED\xCF\x98Bw\xF5\xA9\xD1\xFF\xC3\xB4r\x0Du}:{\xFE\xD4\x96i\x95\xEE\x0F\x80!\xCD<]\xF1\xBE\x1Fy\x03\xB6\x04\xBC\x9BU9\xEC|\xF9\xDAv\x8A\x85\xBA\xE0\xD4\x9F\xA4\x1Ce\x1A\x1ET\x0A\x99\x94\xC4\x86\x06\xC3\xAB\xF0\xD6\xF5f\x89\x10\x0F\xF9\xBD*!+A\x8FX\x88\x95\x9FeG\xB8\xD0\xD0!\x96\xD2\x1FL\x10\x0A\x8D\xCDRKI#<\xC4\x8F..\x09\xBA\x06\xDESV\xA8#{\xAB7G\xAB\xD5\xEB\xEEH,?3\xD5\xBE\x9A\x89\x8BN\x01oX\xAC)p\xEDx\xE4\xBB\xB9\x0C&Z\x83k\xDE\xF9\x1D0\x8A\xDF\xAE\xBF-\x87M\x83\xC535\x05\xF5\xE2\x0Fm\x9C\x80l\x10%\x88\xB7|\x1C\xCE\xCE]S\xB8\x077)\x9A\x96\xDFi\x1A\xBD\xC7p\x99\x10\xE9W\xB7\x85\xDB\xCCd\xB9\xE6/\x8F\xB2]Ya\x1BZP\xCB\\xD8\xC7\xCE\xAFi\x8A\x06y\xD4\xB5\xE6h\x80dR\xCD\xD0\x14)\x1E\xDA\xEB\x18\xAA\x17\xDF\xA4_\x17\xB3\xCC\x8C\x96\xB9\x11BD\xEB\x14\x16g!6Av\xBB\xD9vs`/&\x03G\xD5\xC1\xCFf\x0B6\xE6\xFD'\x86\xC5&\x92\x1D\xF4*s\xDD\x0B4k0\xF1\xE1:z'\xB2\xCDS\xDB\xB2X\xFD-\xD8\xEB\x8B\x19\xD6*y\xA7\x8A |R\xACws\xB8\xE2\xDC\xEDf\xBD\xC3J0\xA1<{p\xA2\xA8>\xCB\xD3S>\x14\x87\xA5\xBC+3\x85\x8C2\x18v\xE25\x14\xD0\xD8c\x1CK\x95K\xD5\xD5\x1Cv\x11\xD8\xD9F*\xAA\x8E]~\x1Bv<\xC7&\xA2C\xD8\xA3{\xBC(\xC2\x04\x9D.\xE9j\x19\x8C\xA2X\x17\xFC\xB3O\xDBd!\x99\xB1\xCE\x83\xE7\xB9\xBC\x00Cb\x9B\x0C@@m\x83\x94*\x07@\xDA<\x18:Ue\xE3\x7F\x01\xEA<\xFA6\xBE\xAC\x99\x84|\xDF\xE9\x8D\xD7\xD6\x96\xC3P\xA8!n\xF7\x1FT9\xBE_\xF03\x1FL\xC2\xEF]\x1F\x96\xF6\x1F\xF3\xBC1\xF9\xCE*\xB3\xBB>\x18\xBC\x1B\x93\xA2\x91J\xD2\xF4\xA1^ZT\xECYA!\xD6\xF5\xB1Y\x13>\xA1bNm~dy\xCDOz\xAE\x15X\x8E\x9C\xCD\xE1\xB4b:\x96\xFE\xA8?\xCDN6~H_\x97\xD7X\x15m\xCA\xB5\xC6\x08\x96\xC8\xEEk\x08\x1AJD\x9B\xF0rfN\xB6\xAF\x7F\xB7\x82\x05$\xC4o\xF9\x10o\xDE\x05\xDB\xF3\x90\x96v\x9D-4Q\xCBlB\xD1\xAF\x06r\xD42\xEF\xBE\x9EG\xF6\x14\xE4\x91e\x05\x86E\x9D+YB\xFF\x04\xCB\xC9D\xEAy\xB5\xD7\xE5\xE4\x8C\x10\x02k\xA3\x8A\xD8I\xEDA~\xB0V\x9C\x0D\x8F@$\xF5\xA8\xACDU{\xBF\x98\xF6Y\xEEYo\x14\x01]\xB8V\xD4\xF3\xB7.\xBAG\x1B\xF7)\xE7\xE6B\xD5X\xA78\xCB'\xF0\x0A\xAE\xD8\xDE1y\xA5f\xD0\xA9\xD6\x97\xD5\xC0\xD6r\x82\xE5k"\xBE\xE6\x1EN\xF2\xC0\xB9\x80`\x81N\xA8\x8Fh\x8D5u\xBCDoh\xA2\x80\xA1\xCD>\xF2\xA5t\xE4\xFBs\xDFs\x1Fs|}\\xB1\xD8\x9C\x9Cp\x12/\x80\x09\xF7\x18\xFF\xC5zN7\xEDn\xDB\xD3\x99y+i\x8B1\x95\x08Q^g\xF2\xA9L\xC3+\xD1\xC2\xE3\x089\xBD&\x1E\xFC\xCFO8j\xE68\xC7\xCA\x1B\xEC\x08\xAD\x0C\x88A\xAEL0x\x1D\x89\x99\xA5\xDE"c9H\x92\x8Br\xE7\xA4\x7F\xD8mG\xBA"\xC7j\x86\xD5>\xC5\xA2\xA0\xA7\xE8=\x99=[g\xDDs.Su\x85\xF9\xDET\x81\x9E\xC7j\x0C\xF71\xB7\x97Q\xFA\xB4\xFA\x9C]\xA5\x02M8\xE1\xE2D#h\xED\xFCW\xB9\x95Z,hv\xF5\xB5\x862\xAF\xF7-\x04B1}\x9BY\x8C1|\xFD\xB4]o^K\xCC\x9B\x00\xEAydA\xC1\xF9\xEDY\xDA\xC4.\xFE[\xD5<\xF7b\xA1I\xC7\xDD\xFA\xFB\xCF\x9F\x7F\xDF\xB4\xE5)\x91\x0E\xA9\x90\xEC\xF9)\xDD\xA2\xD1,\x11oV\xAC\xC0@\xE3!\x03O\xFCr\x17\xE0(\x97Mp\x8B\xD9\xA6V\x8A\xB7\x8Bm\x16\xB8\x90H\xF73+\x97+2Er\xC8\xDA~Q(\x15\x85\xE5\xC5\xF1\xDF\x9D\xA3\x09\xEAH\xB47.\xCE\xE7\x89\xAE{\xBB)'\xE7+\xE7\x81;A\xA1]] \xCF\xA2\xA0\xCD\x9E\xE4q\x16\xB7\xA3\x04\xB7\xFC\xEF\xCE\xAF\x02zB#\xD0\xEC\xF1\xCF\xA7\xD2\xC2\xE7\x12\xE1\xBFq\xB7\xB5\x85%\x8E\x1E"\x99\x0F\x03\xE3E\xE2z\x0C\xF7B[\x1D&B\xB6\xA3\xBA\xDA\\xAF\x0F\xDF\xBF\xB1\x05\xC7d\x81PM\xE1\xFEF\x8B=\x86\xDE\x05+\xD2\xB0\xF3Y\xA7\x0D\xAF\x93\x98\xA3\x18\x84\xFDC\x8D\x9F\xD1\x9FO;!X\x0B\x98\xB1Jg\x0Dv\xFF\xAC\x97\xBC\x16\xA2\xA4\xC6\xF8\x98\xE9\xC2\xC5]w\xE3\xFAp\x9En\xC1\x04,L\x82D@\xCB\x00\x1C-\xCC\xE5\xFB\x03,f\xFD\x0Emd\xE1\xEEa\x0C\xB3\xA4\xC51U\xCD\xA2\xBB\x90\x0A\x8B\xD5\xEC\xEC\xA2m&\xE1\xF0\xA3\xC0\xEB\x86\xE9\x82\x8C\xE8\xDB\xA8/Hx\x0A>;\xE3N\xAF=\xFA^\x0D\xE1\xAD\x0E?\x84 \xDElg\xA3~}L\xF7\x87\xB8\xC32\xC9\x0Arw?\xBB"\x89Q\xBF~\xD1\x9BQ4\xE4x\xF5-\xDEY\x98\xAA\xE3\x96\x1B\xF7\xD0\x1CR6\xEA{3\xEC(\xC9W\xC6\x1C\x95\xE8\x9FXiVFJFZ\xA0\xAC\x963\x19\x88\xE1\xDD\xAE\x8B\xF6\xBA%\xA4\x903\x0A\xC7\xB1\x92\x10G\x99\x0B0\x1B\xF0\x81<}\xBE\xD1;\x1A.\x8C\xF2\x86M\x0D\xCClix\xB5\xC5q\xE4\xEC\xB1\xD3\xAE\xD0\xB2\x95}=\xABA\x9A\xB8PNN/\xDA\xE9\xFAb\x8B#\xA9)d\x80\xB5g\xAB\x17\xF6X\xD412\x0F\xB3s\x86P^\xFAM\x81T\x1C\xDC6\x10lU\xA0\Y\xE4G\x8Ei\xBF\xCD\x10\xF5n\xDD\~ir\xAF\x01\xE25\xBF.\xA9\xBA6\x0C\x19\xAA\xE5\xF4{\x16\\xFB\xA5>\xE8\xC2\x89\xC8\x8D\xD9"J\x05\x88\xE4\xB2\x08\xEDD\x99~x\xA3\xAE\x04\xDA\xB5\xDAA\x07\xCD\xA3\xEC\x11\x06\x80\x9F\xCD(YK\xC1>vbS\xF4\x1Fg3\xCFo\xEC\xE5\x94%\x8CT\xF7\xC2\xBFO\xAF\xE5\xD4\x90\xD6j\xA71W\x01R\x8B\xC1V\xF6\x1A14\xA5(\x9B2D&\xB7N_\xA48\x04;\xBA\x0B\x95\xEE\xCE\x18\xAD~\xC6\xF4\xB3\x13\x9A\x01e\xFEM\xF69\xC8\xE26\xE9U\x8C\xAC8=\xFBe5\x8E\x13\xCF\xF2\xB4\xBC\x82vN\xC9\x81U\x13t#U8\xEB\xE2\xFF\xB8\xD9 \x04Vh\xF8\xD9\xE0\xFD\x81\x81\\xEEjD\x84\x90\xFFz\xCD\x03\xA4\xCC\xCB\x94\xA4\x1C\x17BX\x9D\xAE\xCCM\x07\xDE\xC8\x83\xA9x\xB8!\x96\x00\xC3S`\x9C\xE7-\xC5\x90\xAA\xA7\xA28\xC0\xD3H":\x00G}\x8B\xA7\x04h\xEA\x18\xC7H\xF4\xEE\xE1\xFAk\x82J8k\xE0X\xB4$\xF83\xA2UT\xA5y\xBDD3;\x16\x8A\xE6\xCE{\xE8tL!— ¥tHjg\xB7\xC1\xE4\xD5\xA8\xC1\xC1\xEB\x85\xDC\xFC\xAD\x9E\x88\xA0>\x82'\x03\x0BO,B3W)$\x87\xA1\x068\xEA\x89\x01-\x80\xF2\xA7\xAC\x1FB\x7F\x09lt\xBEU\xCFloMI\xE4\xB0\xAD\x11%\x8E\xBB<\xCD\x7F#\xD5\x06\x89\xE6Z\xA7 i\x07\xE5\x19g\xD5\xF4#\x076\x89-4U\xF9\xB4\xD6r\xDE\xDC \xC8\xD1\xC5\x18\xB0\xA1\xBB\x91]\xFA\xF0F\xA1\S\xE3n>\x7F\xCD\xC8\xFF\x16\x1A\xAA\xAE\xB3E\x88g'\xD5\x99\x1F\xE1\xF6\x17>\xC9\x92\xA3\x9A\x85\xA4\x0B\xE1x\xCE]A\xE7\xF0\xCD \x12\x85\xC1\xE4\x7F\xD5\x10\xE8\xDB\x1A\xC7S\xF5\x13\xE9yl\xB0\x84v\xC8y\xF3\x08`}t\xB9?o\xCE\x16-\xA03H\x927/(\xDBw^v\xED\xB89"'\x98=\x99\xE5\xCFR\x8D\xB4\xCAN\xAD\xD0~\xB8\xA0\x98\xB7g\x91\xD3n\x90A\x849\xCC\xFE\x1C\xA0$]iZ(\xE51C\x7FV\x9A\x91~\x04_\x02\xD2\xFD\x11\xBF\xD4\xD9?Q\xE2\xDEM\xECNP\xC2}cRW\xEA\x84\xAC<\x87\x88\xACE4\xC8\x06\x8C\x17{u\xA2\xCB\xD1(\xBA\x0D\x9A\x83\x92\xE6{\xA0{s\xB9\\xD0\xA0\xD1js\xE0\xE6\xA4\xCC\x18o\xD6i\x8A\xC0$>\x98\xF6\x99i\xA0\x0A\x96\xAA\xBC\xD3y+\x9B-\x0E\xF2\xB9\xB3 \xA5\xA8y'\xFE&\x927#`\xBE\xFB\x96\x02\x0C\xBF\x03_\xCB%L\xCBfL~\x82\x15\x91\x90\xD3o\x14!\xCD\xD5$|K\x986MM\xD2\x14l\x8D\x8C\x1Fzqn\xA8m\xB0\x89\xBE>\xA7\xEF/\x05u\xF2\xF8"P\xE4\xD7\xAF\xF8\xAC\x7F\xF9>\x9E\xCF\xB8\xDD\xB4\xF7\x9AQ\x87&\x96\xD0\x99\xAF\xEA\x00\x0E\x0EC\x85h\xBD\xBC\xC8\xD0,p\xA2Ly\xE8\xD0\xDAYj>$\x99WP\x01\x93\x9A\xD1\xD1\x1E\x87v\x10[Y\xD0g\x87t\xDDG\xA7[C\xE1sJ\xD6\xF9\x8F\xAD\x1D\x0D\x0F\x8D\x10\xC6FE\x1F.h\x85d/\x8Bi\x85\xA7\x99[\xCD\x05b\xF8\xD7n\x80W\xD7\x98_z\x8C\xF5\xE7]\x0A\xB4\xDAIha\x89\xA8\x1CV^\x9F\xBAH)y\xE9\xB4\x01\xA6\xE0O\xC0\xA5\x8D\xC3\x15\xBD\xC2\x07Gf\x09\xE5\xD94 \xD9`=b\x0D\xC0\xE7\xE6\xAEc\x02\x19\x1C\xB5N\xE3\x01@\x8Eg\x06Ca\x99\xF2\x9EU\xADD\x06\xBC\xFE\xD1\x18\xA5\xEF5\xCA\xFAe\xE8&\xFFT\x9D\x9C\x8D\xE9\x01\xAF \x07Q\x1F\x8D\x0EZ\xB8\xC3\xE9v)\xF1}|0%\xEF\x92t\xCC\xF8\xA6.\xA9)\x043\xB2\xFF\xB8\x86\x1E\xC5\xA8\x97\x8F\xC5\xD7\xE5h\x86\x0E\xAC^\1\xD5,\x83$\xBB\x9EB\xC8\xB7\x09:\xA4\x91\xA1\xB6xr6+\xABo^\x83\x8B\x87;\x9E\x13m\x02\x1F\xB6}\xC3@RE\xBFLn\xDC\x17\xBB\xC7\xA9\x17\xA3\x87\x0AAx\xE0 \x05\xB2;@W!\xDA\x93p\x8B\x91\xF9\xA0\xAE\xE5\xD7q\x01\xA8*\xE0\xF7m\xCD3\xE0=4\x90\x1D\xDEa\x10\xE0\x05~\xFCS(V%.pf\x83\xCB\xD4\x1B\xA8\xB3\xA97\x0C\xCBY!\x8D\x891\xB9zB9\x7F\xD5@\x9F8iL\xAD\xEC1\xD4\x98\xBD\xB3\x85\xDC\x83\xEE\x94\x951w)p\xD2D@s\xE7-BI\xF0o'%\x07\xC6w\xC7/\xFE\x13q\xEBMC\xEBZe>\xD4\xB1Z\x97f(\xAD\xAA\xDALw*\xBA\xD1r\x90}\xEF\xE4\x13\x9B\x96\xCD\xC0\x11\xA3\xCD][E\xB4,\xFDQ\x05\xAE\xC1\xCF%\xF0b\xDF\xA8>\xEF/\x97\x99G\x91\x19\xB5x\x92\x13x\xEB_\x95\x9F\xFD\xBE\xA5>O\xC5\xFA\x9B#\xF5\xBE?\x97$\xF2u5K#\x04\\x8E\x04\xC4\x93\x80h\x19{G\xA1\xCB\xF3_\x7F9\xB9x\xD3\xA0\xEA\x0B\x0EH\x0F*\x89\xF8\xC5?b\xB7\xDDR\xC6\xFC\x08\xAC\x1DE\x0E\xDD[\x14[\xF2:Er\xFB/\x94\x1FZ`\xC1\xFB`\xC6\xA7\x98\xBBF<\xDA\x9E\xAF\xEC4\x1A\x04\xE6\x97\xB9\x96\xA3\xC6\xA2{m"\xB2\x9A_\xB4\xA3 \xE1\xC2\xAE\xE6\x94\x06\xAC>Bzs0xZ\x1B\xF7\xA4\x94\xB9\xFD\x15\x8A\xD5y"\x9B\x96@\x80\x12\x8F\xD6\xE8\xACD\x7F\x85<\x0DQ\x1A\xC2ExW\x99\xD9 q\xFFR\xF7\xFB\xD3j'\xB9\x1F\x06\x00\x87\xF9\x9C\x9F\x95\xA0\x10\xCFv}E\xDA:\xE2\x98\xF4\x954`\xBC\xFEU\x05\xC9X\x98{}\xE8=\xE0j\x9A\xAD\xCDb\xAE\xEF\xD8\x01\x155\xB6\x9E\xBE\x17b\x9D\x13)\xD5MC\xAD\x15\x03'K\xD9;M6x\xFF\xF4uMI|3U)E\xDAlv\xE2\x1C\xD8\xC8\x02\x14\xDF\xE6\xFB\xD5\x08\xAB\xD3j\xDAa\xE7\xF4\x1A\x0Abk\xC27L9\xD6(\x9B\xA1\x1D\x88\x89)\x90\x12liq\x12%\x91\x8DX\xBD\xDA=O\x9B\x99+W\xC4\x96\x15\x1D\xEF\xFEN\x10\xE4\xFF\xD1\xE4\xB9\x83\x0A\xBC\xAB\xFAxp\x84\xD4\xC8|\xBA\x0D/\xCB\xB0\x90\x18\x1C\x92_\xD1\xEC:\xBF\xD0k\x9D\xFC\xF4X\x1D\xA0\x10\xCF\xF0\xCC"\xDF \x1F6X\x92\x00\xB5&S;\xABCTJo\x04\x87\x0E\xCC\xDCyT\xA7r\x82\xD2\x864\xBD?\xB7L\xC4\xDD\x8D\xB7\x82\x04\x16O\x14(t\x98)\x07/\x8C3\x07\xA9\xEA\xDFk\x85\x10Z\x8E\x93\xE4k\x83C\xF2}\xDFcl\xBBY\xFA\xEBg\xDBU\x1EA\xD0P\x1D\x1E\x86\x88Xj\x11IG<7>O\xA5_\x8B\xC4!\xDAo\x9A\xE1\x99W\x94%(pJc\x18\xCD\x98.w@vg\x10\xF1\x0Fa\x81\xE7\x1E\xEBI\xFD]\xC6\xFE\xB1^\x8C\xF2n\xBC\x08\x18\xEE\xAEh\x89\xE3\xA2\xCC1\xE5\xD2Z\x93X\xFB)b=\x80\x11\xCC\xA2\x81F\x9E\xE5\x09\xCA/h>2dx\x1E\xBER\x1B\xA9e\xE5qoyVh\x1B\x94\x90\x8C-\xBD:G\x9C\xC2\xDD\xF3#\x9B\x96SF\xA6}NA\xE6\xC7\x8E\xB1\xEA\x15b\x10/\xAAKm\xCA\x95\x91\x95\xEC\xBBNV\x1C{X\xB2t\x8F\x9C\xF9\xCE%H\x14\xF5N\x9CsP(N\x95\x9BESS\x94m+\x98m\x9D\xF7]{\xA1\xAA\xC7\xBD 7i\xF4\x96A\xD0\x17\x9FVc\x11\xFF\xDCM\x0E\xE9o\x18\xE0\xB6\x91}d\xFB\xFF\x0E\xCB\xCD\xBB6S9\x12=\xC8<\xB4F\x08ONj\xAA\xA6\x9C\x1B\x91\xD0n\x0A@t\xF0\xFE\xC9\xB6\xE9\x81:\xC3\xFE_\x06\xCB\x98\x0E\xE0\xFC}\xD6\x99\xB3\x8E\x01\x1B\x12\x94\xD0]\xF6ask\\x8Bq\xE7\xBBV\xDA\xBD\x8F(t\x1C\xB5K\x973\x0F\x19\xBA1\x0E\xE8Aj\xE7\x9F\xA2`%\xDE\x9D\xBB\xBA\xCAg\xDD\x987a\x89\xA0=3\xCC~\xBE\xAF\x9Ef\xC6\x96I\x0B\xE1H \\xEC\xBB\xBF\xDB\xF8\x1A\xAE\xDF\xD3e d\xC6\x14\x9A\xE6|#\xC4\xE1\x80\x9A_\xA9l\xE2\xEF\x90\xE9\x01\xCA!\x1E\xE9N\xFD/\xB4f!\x8F\x99\xF7\xF2\x87\xDD/\x0B\xDBw\xA4$\xBF=\x9D\xB9-\xECD\xDD\xA8\xFCyb\xFC%\x1AV\xA5\xCE)l=\xE0\xFE_\xCD\x84K\xB4\xFFa\x81E\xA3\xBD\xDD\xCD\xF4\x11\xFE\xF4\x80zB\xCD\xADQ\xE0\xECW\x88\xE1b\xFF\xC5\xA4\xE1o\xDE6\xD9\xF6Wc\xF4\xC0`\x8E\x19\x7F\xF3\xE7a\xA1F\xBF\xB2\xDA\xA3\x93%E\x83\x9C\x0F\xF0\x95\xAC\xF0\xC0T\xFB&\x08\xEA\xC7]\x16\xC7\x7F\x05\xA1A\AC=\x8D1F\x94\xDA\xB3\x9B%\x0D$\xB5\x03\xB0\xBE\xE8*\xE8tf!\x1D\xC5kCc\xF8\xC9\x1E\xCE\xA2\xE8\x9F\xCCr\xB0\xC6\x8F]j\x11\x09\xCA\xA6q\x99\xFC,W\x10I\xA9\x04K\xEF\x1B\x96T\xAF\x08\xE4D6\xB9u\xA2\xF6\x135A\x8Dt\xB9\x0C\x04\xF1X(\xF1\xD9\xCB\xCClB\xCB(]\x8F_M&\x12\x84\xD8JV@\xB8\xF0\x8FB\xB3\xB4\x16D\xB2\x9DP\xE3q\xDF\xC7b5\x91a}\x02V\xF4_\xAF\x10\x0D\xB45\x1D\xC0>\xBB\xB4\x91\x99[\x7Fd`>\xACMX[\xBD\xB6d\xAC\x03\xF89\x19\xC2\xFD\x00\xBD\xE1#x v&Q\xDC2\x0F\xB8\xE3\xD4\xEAL\x16\x9F\x15\x9A!:\xFA\xD2Sr\xCE !\xD5\xB2\xB5 e\x1F\xB0\xEC\x98\xBEQQ\x84\xE4\xD4\xAC\xAB\xBF\x12D\xE0V\x90\xD3\x140/\x92\xC0\xDE\xEA\xC4\x88\x99sc\xE7\x8B\xC6\x04\x82\xF8_\xD2\x87\xA6YF\xAB\xC9\xE2\xF7\x04\xC0\x09\xD6\xC2\xFAy\x92\xEBc\x8F\x1E\xE7\xC5\xE7w\xEE*\xB3eu\xAD,\x1C\x8E|\x84\xFA\x9Ei\x96\x00\x8E\x04O`f\xFA\x86\xC5\xFEQ\xF0?%\x98\x111\x82\xB3\x17 \xDD!\xCFr\x16\xD3\xE5@\xB8\xEF\x8FV8\x89\\xFD\x14~\x91\\x18(m\xAD\x8D3\x9C\xC7\x04#\\xDDw\xF4\x0B\x17\x9B\xF9UI\xA1\x86\x9A\x92\xDD\x19z\x0Dn\xA72\xCF}Ng\xDF:\xF8\xA6W\x9B VS\xD7T@\xD5m\xFD\xAEv_~\xF4s\xE4J\xB2C\x81\xFAvY\xC0r7\xC3\xA1\x89\xACa&55\xD1.\x1BUy\xA4S\x0F\xDE\x05!b\Ah}'\x05\x94\xD6z\xF1\x93\xCF8\xEC+\xDFG\xCA\xD9#\xB9q\x9B6T\x15$\xAA\xCC7{\x02\xD1\x06\x14\xCE\x95\xDD\x7F@s\xE7\xB0I\x95#\x82\xA0\xD4\x07\x9FK\xFF\xC1MO\xBCcG2?{\xC2\xA2\xFE\x85\xF6\x8F<\xF2\xE9>\xCD\x91J\xEF!+\xF7\xB1\xB2d\xEE\xB0\xAE.\xA6l\x89\x1CJ\xBDi[Cx0\xFF!\x93!U#w\xD3],\xDA\x98\x8A[Z\xF2\xA3(\xA9c\xC2\xB5F\x98\xE2\x06\x941[\x01|Y\xE2\x0B\xD1\x19\xB9\xB5m\x13\xAB,+\xAC\x08\x82\x04\x89\x8E"\x84\xD0\xE1n\x9CK\xAB\xA9\xC6\xB1\xB7r\x1E\x90\x9F=\xF2R8\xFF\x83\xE0O\xD7\xF7\x82\x15\xE5\xC9\xCDKB`:\xFA\xA6w\x07\x0B.\x82\xB8\xFA\x01\xAD\x8F\x07\x1F\xFE\xCAj\x10\x9A\xD3-4|1\x05\x9F\xF3\xFCI\xBF\x06\xFC\x7F/\xB5\xB5\x91\xAA\x15H]?\x8E3<|(\xD6\xCC\xC6\x9CF\xD6\x1B\xD2G\x1A?\xBB\xB5\xB6\xC6\x1B\x02=\xA0^C7\xFBM\x19\xFA\xEBl\x001\xA9\xC2\x9Du]\x8D\xD7>\xCCkC`E||\x87\x86\xE4O\xEF\xAC\xBC \xD8\x9CN\x15\xD0H\x85\x9B\xBBdp\x9B\x1D\xEE<\xEC\x85\xAF\xD3\x1CVO\x16:\x12acw7 J\xC2\xC1\xCBV\xDA\x94S\x8BM4\xDD\xE2\x1Fu\x9C\x0B)\xC7\x86\xBF\xB8h?w\xBC5\xCB\x90%\xD7\xD5\xD8$O7\xF2;W\xDB\x0B\x87\xA6x\x86\xCC\xCAex\xFB\xFFjYv=\xE9#/\x12\x97\x05\x97?NK@\x95\xDC\xEC\xBF\xF1\x96\xBDX\x91B\xC2\x1C\x02\xCF3\x10\x04V\xBD\xA5\xCC\x0C\x1D\xAAQ\xAD\x81\x1Dp\xB5>\x99\x1F\xDA\x01!M\xA7\xF2\xF97!\xA2\xD8\xD9\xEA\xB4\xDD\x81%\x0E\x0AL\xAA\xAD\xA5\x00wX\x9D$w\xE2\xB5\xBCN\xA5\xCEr/>B\x824\x07\xA1\x82r\x05\x17\x17J1^\xE9\xF8\x86z\xF6y\xF2\x12T\xBA\x03\x9BZ\x95yjo\xECl2m\x00\xC4k\x85\xEA\x96:u\x944\xCET\x8A\x0D\xEB\xCD\xE9A\x08\xFF]\x04Y\xF3o\xF8K\x05\xF7"j\x0BE\\xFD\xF9\x0Dx\x05\x96\xD2\x9Dy\x1Be\xE2\x9Bm/>"NQ\x0E\x80\x89\xF3\x98\xFC.\x19\xCC\xB2\x15\xA6zr\x0D\xFA.\xFC\xFF.h\xF6\xD1\x1F\x82\x93 \xA98\x95\x00aU\xA64GC\xBCqa\x0Ft\x0B\x84\x90\xBA\xD8\xD3\xD1\xE5\x1A\x84?\xCB\x0EGK\xBF>%#\xAA*\xD4\xA2\xE3=\x883\xFC\xFF\xDD\xA1<\xE3\xA8~\x1A\x87\xE2\xB4L\x94\x15\x9E\xF74\x98\oe\xD9\xAE@Dr\xB7TLe\x85\xE5\xAB\xA9'>K\xAA\x97\xA8\xCCW*\xFF\xD3a\xCDi\x0E\xDB\x82\xD7?\xD8\x80G\x87\xCCI\x9C\xA1B\x82\xD0\xA9\xB4\xCD\xD0y#\xC7\xD0\xAC@]\x91\x80\xFDn\x866d\xDD\x8F\xDFG\x97F\x9E\xE4\x87^f\xF9s\xCB"\xF3i\xEB\x8D(+\xD1\x90XF\xDB\x13\xAB\x1E\xA7T\x8A\xF7\x13\xA5\xDA`\xD5\xA2\x8A\x0C\xC4\x06\x84.\x1B\x97\xDB:\xAE\x7F\x95\xF7A\xAE\xB8\x16w\x7F \xF3\x98&\x98\xD4C\xB8L\xF6$l\x0C*\xFB\x9E)\xBB\xB4\x10_\xD2\xDB\xA0\x1A\x0D\x85\xBD\x9D9D\xE1,\x1F\x1B[\x05\xD3\xE5\x10\xE8[s-\x10E\xB4w\xFA\x8F\xC3%\xC5SX\xAD(HZ\x00\xBE;\xE5G0\xB9c<\x00[\x1E\x0FQ\xAF\x98d\xB4\xBB\xA5\x92\xAF\x86%\xCB\x15\xEF\xB0k\x1E.O\x98\xE9{A\x87\x17\xBB\x9A*\x92\x03\xFD\xA3\x1D\xAC|\x18O~\x06G?V\xED\xF6\xFAo\x90\xDDYIH-\xEF\x85\x04\x1DN\xA1[\xE6\xE88\xF1\x09\xF9\xFF\x9Egf\x10\x15\xEE\xB8\xAA\xE2\x12D\xC9J\x00\x0F7\xFD\xE3\xFE]\x1D%X\xAB8\xAB\x8EuM\x0DV}\x8Ef\xBC!\x92\x9F9\x17\xFE>u\xC1U\x1D\x06$x\xA4\x05\xD0>^\x06\xA55\x1A\x9B\xCF\xCB\xE4\xF1YsN\x88PC\xFE\x0B\x06\xF0c\x0CH\xCA\xAA\xA37\x9B\xB0\xBA\x0B`>vKK\xF4&\xF2\x06\x9A\xA9L\x86\xFB6\xEFr\x14E{\x9B\x15f\x86\xE9\xBB\xDB6\x98\x8AYs<\x17P\xD5\xE6\xA4\x8C\x9A\xFE\x01d\x8C\x95\xBBL\xD9j@p\xF6\x95Elr\x92\x01\xF3zw+B\x88\xD2J\xF5\xE1h\x9C?X\x98E\x12h\x81lB|\xFD0\x1C\x00\xA9\xC5x\x84\xCDZ/2\x93\x89\xF9M\xE6\x8F\x90\x17\xA4zD\x9D\x1C\xFA\x08n\xC0\xEAw:\x01\xF2Z\xF8U\x9A\x155C\xF5\xD9\xC2\x1DoDQ~F:\x04c\x09\x94$\xB5\xC93\xDF\xDB\xCF\x957\xCE\x08\x87\x8BM\x1D\x85\x12\xC2\xFD4\x13\x98\xA0V\xBEe\xDC\xA2j\xE2\x06\xF3R\xF4\xAB\xE5x\xF1\x80\xF8n\xC2\xA0\xDF\xCA\xF6\xEF;\x91\xBC\xE0Fk[SP\x96\xACA\xF5\xFER\xC0\x08~N\xAEGv3\x8D\xFE\xAD\xBD\xC7\xCDF\xEC\xBD\xB65\xC8\x1A\x9D\x9F\x12\xF4\x83!$m\xE3\xBCW|\xBE\xF4\x99L\xA8\x08f\T\xAD\xA5\xBA\xE4\xB0|\xCFUY \x99h6>=>1\xE4\xF0\x0El\x8A\xB51;\x93Y-ld-\x97\x0D\xE3A\xEF{*l(\x97"\xAA\x95B\xB0\x9D\x0A\xA1\xC9\x9E?\x9C\xF7$\xC3+[w\xAA,\x9Bd\xE9l\xE5\x1D\x9C\xA8-\x0D\xD2\xE0\xD0}\xC1\xC2\x12\xEF\xAD\xCC\xF1<\x1A_\x9F\x9C\x0C\x96\xF6\x1F\x9E$\x8C*R$\x9A\x83\x9Bm\xEE_\xF3VO6/l^|Q]?JII\xF7\xB1\xC7\x83\xCB=\x97>MZ\x02}\xF9\xA8?\xB2\x8D\x18\xC1Ck\x88\x1E\xECdX\x98\xE5\xDB\xD2I\xD1h8\xEF\x82(T\x85\x07\x08\xC0\xD8Vza\xF2b\\x94\xB2\x01\x12\xEC%\xD4I\x04\x99A\xAFTN\xF6\xCD\x8B\xA53\xBB7\xB5\xAEz\xA7\xBFJ\x9B\xCA\x11\x7FbLr+\xD5\r\x98\x03f\xF5\x94\xEB\xB3\xE95\xF8\xAA\xA9\xDF\x19W|&t\xBA\xBDL\\x08\x06`\xD9\x17z-j\xAA\x0EA\xDE\x0E\x8B\x0E\x81?t;-"e\x10:\x93\xD4\xB6^/\xD4\xB2\xC3\x11\xA2!\xAF>\x055,Y\x94\xB1\xF9\xD1uN\xA9\xC5\`\xA4\xC5\xDC\xEF\xFB\xA7jy\xAFG\x04OZ\x8D!D\x09\B\x83\x99\x12\xE8\xB4\xCA\xAA^h_\xB8\xD7\x08\x0B<\x0E\xC0\x9B$\xE1\xE4v\x1E\x16\xFC\xAC\xBDU\x98\xBC\x10\xEF^\xD3\xA5\xE3L\x96\xF3P\x01\xE0a\x9E$\x03Y\x84\xDB>\xF4I\xC3\xD4\xC6\xFA\x95\xCB}\xD3F\xD3\x85\xC79 \x98\x0F \xFA\xEB\x8F\xF51)\xB0\x9F\x9EG,\x81mv\x18\xAE\x80\xBA\xE3\xD7\xCDM4K\x0C\xBFs"kE\xCEAe\x8F&H\x98\xE6G[\xE8\x84\xB5$\x94'\x0EpB\x98i\x03Jo\xBC\x0CZ\xBD\xDCF\xC0\x90\x9A\xFB\x9B\xBB+\xDB Hw[[\xAA\x06\x1C\x83\xD9\xE3{x2\\x85\xE0\x11\xF8\xD5dq\x13\x1E\xD3$<\xB03\xA7\xF4\x94\x1AF\x1A2h\x08\x91I\xEE{\xB1\xFC\x94\xED\x15\x06\xAF\x8F!\xCD\x05~3\xCCzD\x13l\x1A\xA8\xAF#\x97\xA7\x14T\xF5\x10\x8D\xD2\xEDtV\xE3\x9Bnlt\xDE\xB9b\xB7\xCA\xCA\xEBu.+\xDE7\x0FJ!\x86\xEF\x96\x0B\xF2\xDA\x91i\x07|\x89d\xBA\xA7\x99\x98\xA3\x145CAw\xE6\x96\x84\x8F\xFD\x99\xCD$\xB5}\xDD\xE8\xD6&\xF8(\x19f.\xE2\xF1\x09y\x02\xE07\xE4\xB5\xDD\xC7\x0D\xD1\xD2S\xD0eT\xFF\xF7\xCB\xD7\xA5\xB0a\x0A\x1B8\xA15]\x08\xB3\x8B$\xA5\xB7\xDC^\xF1\x8D\xDB\xB0\xF2\xED\xC3x]\x01\x9B\x9F4\xA9\x85\x1D\x0C\xCD\xB5\xE7g\x8F\xD7 \xBD\xC0m\x95\xF4~\xCB\xD2k\xC7h\x14XB\\xC9\x8D\xB2o\xC7R\xB7\xC3\xDC\xB4L\x0C\x8EB\xB3T~\x01\x00e\x17\xA2j!\xBB>\xC4\x00\xA2\xC0\x97\x02p\xAC\xE1|[\x1F\x9D%\xF2\xC0\xB0\xA11-z,\xFCZ\xAC.\xF9/-\xB4?K;\xF0\xB8\x8D\x1B\x82n\x1DW\x1A\xF6\xEA\xE1\xD2uy\xF9fW\xAD\x8F\xCA\xD6\xA5\xCE"\xC0\xDD],\xFE\xE6b\x879\x88w\x95\xF0\xD5\xA9\x89\x9A\x0A\xFA\x88\x03\xDF\xA9\xC45\xEB\xFD\xDA\xCF\x92\x139\xFA3\xCD\xCB\x8CY\xEBvI\z\x8C^\xDD\xFD\xE1\xD0Wc"\x09%\xEA\xBC\xCD8\xDE\xD1Z#\xF2a\xD2|\xE9\xF9:`\xC9\xE1\x17\x1BP\xCE\x82\xD3\x12E\xB3\xAF\xD14o/z?\xD8\x83\x99\x88\xA31"n\x9FI3H\x1C\xAC\xD0\xED\xF4\xB7J:\xEBi\xA27.sk\x98\x81\x1Bt\x19\x0E\xE5\xB8\x12\xE6\xE7b\xFE\xB2\xEB\xC1\xE0\x8E`\x1E\xDD\xFF\x8A:\xA9\x0D\xE5\x0E7W\x07\x16\xEA%\xB5\xDE*\xF4\x16F,\x91E\x915#\xFA\xD7\x90\xDA\x97S\xFAE\xCFV\x11\x9D\xA0a\xE6EU\xD2Z^\x01\x10\xCC \xF4\xBB\xE3\xB6\x9E\x0E''\xD1\x87\xE19\xDC\x9F\xE1k&\xB6\x0E\xEB\x87\x99lMK)^\xCF\xB5\xDF\x8C\xE2\x03\x87aa\x1Aw;\xE3\x0Fh\xF0\x9A\xB0\x9B\xF0\xE1\x14W\xD2'\x9DI\xDE\xCCX\xA8\x09\x7F\xBC\xA9\xB7K\xE8\x15\xEF{5\xA8\x050\x17X\xFA\xA9\x07\xF3\xE63\x80\xB8\xB9\xD0w\x87\xCC\x0E\xF3m7M\xB4 B\xE9\xEDy\x9F">\x17B\xFB\x91T\xCAC\xCB\xDF\x01;8\x02\x11\xA4\xBE)S\xD9\x14\xC6\xBD\xB3q\xF0\x15\xD7\x81\x97;U\xD9w\xFA_\xE7[~BXt\x1C\xD9j\xBD\xC1\xFE\xB1V@a\xB9\xD6M6x0\xDBv\xB5\xE6S<}\xB2\x07x\xC9bT\xB3\xFE\xB5\x9Ej+\x1D\xF0\x9E\xA0b/Lc\\xCB\x89\x84\xA6\xAE\xC9\xBF\xC3\x99i\xF7*l6\xA9Xq\xE8\x83\x87EL\xF3\xD6\xC8dr\xFE\xB0N\x96v/\xE3\x05\xD9mP{O\xE2\xBE\xE6V@O@<\xD4\x85\x9Ec\x0D\xA9\x1F\x8B\x01\xD1 \xB6\xDA\xBC\\x84H\x0E\x9C\xF1\x82a\xE5\xDFt\xF1<\xA4+O\x07@\xE7\x9C}\xE7\xC9Cn\xBD\xCD\xAE8\xBF\xD7\x14\xC3\x10\xE9\xE4\xA1oZ\x16\xA0\x00\x87\xF1\xC3\xAF\xA3\x89\xBF\xFE`&@-4\x17\x85]J\x8D[\x17U$Z\xCFW\x7F\x9D\xAA\xECMr\x03\x08\xD8\x96\xCBkr\xEA\xBFg\xAE{\xF6yvk\xDF\xA1j\xBE\xF2\xE2\xEA\xB8\xA8\x12\xFF\xD0$\x05\xC5\xC5 \x1E_\xA3\xD5\x0ELO\xCC(\xD3\xB8\xA6\x97\xCF\x0D\xE4j9\xADz\xA5\xC4\xF6\xD66%\xAC\xAD1\xF0((\xF7S0^M\xD2y\xD2UJ\xF3\x0D\x07P\xBBq\x03\xB7\x04\xDC\xEE\xB9/\x12 \xFEXT\x83\x16\xCC\xC0\xCE\xE2S\x1E\xBA\xAC9[:~\x1C\x03\x8Ds\xA9\xBC\xEA_\xB4\xA5\x9C\x09\x07\xCD\x10\xCC.*\x8B'\x08:L\x18y\xBE\xFE\x02 N[w\x99\xCE/\xF4o\x7F[-DwR%!\x81\xF5\x02=\xD5<\xEA\xD6\xEB\x99u\xE0\xEC\x82\x81\x06\x86\xD2\xB3\xC1d\xA0\xA9\x8A\xE3\xA8-M\xFF\xEB_\xA8\x0B\x95\x97\xC7\xF2\xA0mS'\xD8\xFE\x1C\xC4oz\x86u\xD8\xC1ap\xA0\xA5\xD9\xF9\x1F\xF7\xFDI\xC0\x7F\xC7\x19\xC0\x1C\xC4I\x81\x17C\xB7\xCD\xBD\x96\x81I\x94\x7F\xDB-\xEF;-/B \xC3ok\x95_\x90?1\xA5Q)^\xCDxH\x8A\xF0\xF7L\x08\x8C\x99\xA4\x94\x87W#\x83\x12\x87\xE5\x88\xC8\xD9?\xEB2;\x8A\x9A\x80\x12Jso\x11P\xB4R\\xA1\x02\xCAb\xEA\xAD.\xDE\x06`M6\xF7\x1DD\xADD\xE9\xDF\x90\xE6;\xF4\xD1R\x16\xC3\xD9Vn\xB8\xBD\xF3iHZ\xD9tO\x04\xEEq\x0B\xDC\xE0O\xD9\xCEt\x0C:\xDF\x19RjE:\x0Eo\x9C\xF7\x0A\x18\x17\\xF20\x1E\x0C\xD9&\xA4\x99E\x95T\xFCr\xDDNl\xE5\xAA\x11\x81\xA0+\x81\xCCVp#|\x00\xD4}l\xAB\x10\xE5\xC0\x8F\xB4'\xC5\xE18^\x00>0P\x03\x9C`~\x01\xE9+\x1Ch\x9B,1\x15g\x9B\xCD\xDAsn_y\x8C\xCF\xCC\xA4?\x04\x01\xD4O\xA4\xC1ph\xCC\xBA\xBBw\xE6P\xAA\xC1T\x99\xF0\x80\xDA\xBF\x12}\xB1\xC5\xF3\x8DJ\xA7\xEB\xC9OC\xB0\xA5\xF7\xAB\x86\x18q\x11\xDC\x98J\xADf_\x97\xA3\xC3,\xBBP\\xD1WL\xB8\x8F(\x13\xAD\xE2\x18\xF5\x1E&\\x16P\x8D\x01s\xFD\x1B\xB8#\x87>#";p\xB5\x93\x1C\xCB|x\xE3W\xE1\x88q],\x9C\xB4\x18\x90\xC3\x96=\xCF\xFC\x94\xD7\x0B\x8Fy\xDD\xF9\xE5\xC5\xF8\xAFY\x99\x9A\xAF\x0E\xAB\xEC\xB5\x05#\x04!\xCBZ\xA7\x86I\x9D\xB2\x88n\xC5%\xBC\xFB\x9F\xF0\x11{Y\x92\xB0J\x92\xC2\x19\x96X\x17\x15z\x09\x12"m\x9Fe\xA0E\xA8\x09H)\xCBa\x05H\xD1\xDDIV$\xAF\x1CU\xF4\x9B\xF5\xA9\x19\xEA\x0F\xF0\xEB\xB9\x89\xD0\xC4\xC4s\xAF\xC7t\xF1\x91\xEAl&\xEDW>*\xDF\x9B\xE5\x89\x94\xE6\xCFT\x93\x136\xDE[\x8F\x9EKz=\x9E%\x8C\xAF\xB8\xE1\xF0k-\xAD\x03\x05ax\xFF\xF7o\x1E\x12r\xE06\xE5\x9C\x13sH8X/\x0C\xD6\xAEQ\x84U\xB0\xEC(\xB9\x0B\xD3\xD4\xDD\xCB\x98"\xF9\xAB\x81\x00\x10\xA0\xEF\x14]\!\xD2\x88\xF4\xDA\xC7\x0E\x14\x83\x1Ew\xC8\xAB\xDF"u\xE9\x8A\xA2\xB1\xC1\xCE\xC8\x9B\U|\xB6\xDDHW0P\xA1\x10t\xADx\x0D\xD5<\xA0"\x82\x1C\xF1+Z\xD6\xD2\xEC}\xFDA\xE0ej\xE2D q\xD7\x92s?\xD7(Ki\xCE\x1FY\x92\xD7\xDA\xF5\x8EH{\xB1\xA0\x80\xEDO\xFD\xBC#\xD3\x18P\xAF\xAC\x810)J\xDC\x1EB\xE2\xAEr\xFD\xECOO\xF4I\xE4x\xBD\xF3\x0C\x89\xE0y\xBBe\xCC\xD4\xB8\x9B\xBA}\xF5*\xFE\xA3\xA5S\x9F\x17Gc\xD8=\xB3\xAFX<\x1D\xAE\xD0\x9CI\xE2&\x02\xEE\xEBM\xF9>\xFB2\x8C\xB7\xF0L\xAB\xA0p\x93\xB9=[\xD1\xE1\xB3M\xF3\xA08\xD2\x8E\xAD\xAB\x1D\x96$IY \xF9\x93H\x09%\xFE\x02\x81U]\xB9\xBD\x0D\xCCT\x95\xD1\xDB*\xA8\xDAa\xFFj-{\xCC\xF5\xCF\x91\xB79-uVaf\xE1\x10\x88\xDA\x0AOkL\x13n\xC0\xE8\xAF\xE7\xDCeo\x99\xE0\xA3\xCF\x01\xD3$\x80v\x0E\x14\xE5\xD0\x14\xC3A\x9A\xE64\x9C\xA39"\xA7\xBA!f\xA8jIM\xB1\xA8c\x9E|\x83\xCA\xFAq\xBB"\xD1+\x8B\xBA\x85\xFE\x98^\xA1\xFC|Q1\xE8\xCB"p\xB9=\xFC\xB5\x0FP\x1B.\x0E|*\\xED\x04\x92\xA8g]\x9CF|\xAA\xE4&Tz\x16\x8C.\xFAd\x8Dk\xE48\x1AV\xC3\x19\xFF\xBF\xAF~\xDA\x17>\xBBT\xE4\x10X\xF1C\xDD>f\xBF\xA4\xE3\xE9*/\x06\xCF\x07\x02\xE3\x90\\xA3\xAC\x94\x84N\x0E\x1C\x08\x12Y\xE6\xA9\x7Fx\xFA\xA3\xE9\x13\K\xFE\x9F\xED{j\xE4\x95\xEB\xBF\xF2\x98-\x04~\x98p\xBF%\xA8\x16\x0F\xBE\xD0B\x88\xD8\xDD)L\x97\xDA#\x92\x04\xEF\xE1\xDF#\xF5EI\x0C\xDC!q\xAE\x16\\x1D\xE2\x87;\xC3\xE0\xD5\xC7\xA30\xDD\x80\x1A\x81\x96\x0B\x0C\x92\x85\xFC\x0C\x0AG(\xAB'\xC6S\x9Dr\x16\x94\x89_h\xD9\xB3\x096\xE8x\x93oS\xCAQ]z\x91\x0D\xD8\x0C\xF9K\xB5|\xE5\x93f#\x18\x9F\xFCY\x06`z4f-@dzfq\xD5\xAD\x94\xFE\x19\xC4\xAAoyE0.}\xF1J\xA0\xB2\x11F\x9B`!\x03\xFD\xF3\xF7N\x93\x93\xD5_&:\x80E'H\x94\x83dL\xCE\xB2\x08:\x18P\x05i/\x99\x18Rn\xD8V\xA3GmS\xDD\xB0\xE3*;\x02\xAB\x8A\x99\xE3Gq\xB3\xDAK\x00\x17\x99\x12\xB6rp\x81+J\xD1\xD6\xFF4\xAD\xBC\xA2A\xBAZ\x03\x96\xA68\x0CS\xF7N\x8F\x81\xDD<\xE3K\xA0\x0E\x03="\x9F\xC8Z\x99\x02\x86zB/F\xCF\x05\q\x8CNI\xBE\xF0\xBAt\xF7\xAB\xC5\x84\x08c\x8D&\\xFD\xE4\xA3>\x06k\xCC\xA5\xAD\xBB\x8Dz.<\xC4\x17b\x16\xC5q\x9F\xD2l\xC7\xCC\xDE\xDDd\xBD\x89nN)\xC08\xED\xC7\xFAr\xC6\xE9\xCF\xA2\xA5\x17\x19\x14@\xE01\x04C\xC3}u\x16\xA2Ag\xE0\x0Eod\xEE\xFBF\xE25\x89\x97\xF1)\xAF1;\xBD\xD79\xB0\xC4\xD5\xD8\x80\x08rI\x94\xF7\x8E\xD4\xDB`\xDD\xFD\xCD\x11\xF4\xCC\x94\x02-\x85E\xC7b\x17\xFC\xF3\xD1;\xDC<\x91C*\xC8\xF6\x92\xC6\xC2\x18\xDCx\xD6\x05d\xB7)V\xAA\xEAA\x08'\x14\x15\xCBSRz\xFA*\x8B\x88i\xB7j`P\xDA\xCF\x01i\x1B\xF6{7\x13Lb\xA9\x90.\x05b\xFA\xFB\x01\x96\xFE\xFB\xE7\@_\xC36\xA32b\xB0\xE4\x8F\x88\xD0\x841dv\xE7\x83\xEB6\xEF\xAB\x80\xF8`\x1A\xF7\xD3\xAC\xEE0\x93\xF0rw\xD6\xCB\x9A\xB1\xFE\xAE\x0A\x94>zpb\x99\x9D\xDE\xF2\x8Fg\xF7\x0A{;\x90\x08v9\x9C\xDESJ\xC5\xA1\xAA\x88\xEF\xE2U0\x8CF\xC9\x9DXT\xCC\x99\xA7\xE3\x05R!\\x0FT\x0Fg\xD6\x1D\xD8\xA4\xE0\xA4c\xBB\x17\x107r\x82\xEC\x91z-2\x02\xD7\x0F\xFE{\xF80R\x04\xBA\xCD\x98\xBA\xBC2Z\xDFO\x94\x9E\xAA\x83\x05\xD4\x84\xE3\x89Vd\xB1F\x0B\xC6z\xB5\x10\x0D\x06l\xFB!sA&\xE3^'\xEEDw\k8\xB9c\xEE\xAB\x92 \x03\x8A\xD5\x97\x0E\xA9\x9B\xE7\xF2X\xACV\x85\xBF\x05\xEC!l%;\xE1\xC4W;sjH\xA1\x9D"y3\xAB~\xA4\xC6C\x87\x1E\x1F\xA7\xD3\xC8R\x904\x95\xC3d\xDFGV\xDB?\xB4\xC6@\x80\xB74\xD1(y^\xFEW\xD6\x1Du`u\xADg:\x19\x08\xFA\x9D\xDB\xAE\xF5|\xD7DMa\xA4\xA7\xBF\xBD\xC1\x15\xC6\x83\xCDvEB\x85\x0B`hw5M\x0B|\xE3\xC1f\x9A\x0AT\xCFL4)\xB2\xC5\x1B\xCB&$B\xB3`\x15\x00\xD5\xFE\xE9\xA1u\xBC\xCB/E\xDB \x91\xFDX\xA8(\x92\x8E&;+\x1AZt\x0C\xAE\x97<\x860\x14\xB8O\xCE=\x16+\xE1\xDFfX\x04H\x86\xDD( \xCB?\xDC\xC6\xD2\xB1\x11}\x97)\xF1\xD5\x88\xAF\x8E\xA5\x0C\xB9puD\xDAh\xA5zAf\xE6x\xC1\xAB\xDE\xAE$"\x93T&\x06\xBF~C\xDCN.\xFF\x84\x95\x9FW%\x94(2f\x9C^S3\x9F\xE4\-t\xFC\xCA\x1D\xDA\x81\xF5\xB2$\xB7\xC4\xCE\xE6=\x91\xBE\x05\xC6g\xD4\x88e7\x8C\x02\xDA\xAF\x03\x0B\x88\xEB\x94\xE8\xD6\xD9\xE2*\xFE\x17q\xBE\xE3\x7F\x1B\xAEE\xCA{\xC8\x0E\x9E\xCC\xE2\xC2\xD4\x1DY\x0A\xCE\xA80\xE7uL6\xD1?\xDE\x96\xD3*\xBF\xC98\x1E\xFE\x03\xDBcY\xA2\xB4y\xBE.\xA7\xFB\x0E\xD6\xDDP{i\xC8%\x1C,u-$\xD0\xEB\x17\x84\x95\x00\xDE_\x00\x18\x89<\xB4+g\xDFw\xA4T\xF9\xBE\x97-\x1D\xA8\xB7\xAAkz\xBF\xDF\x924\x97N\xCE/\x18\xA1\x05Q\x1B\x03\xF6f\x9A\xB2^<\xEB\x7F\xC6\x1EO"\xEA=\x83\xAE\x9B\x0C\x9F:\x94\x9D\x0C\x8C\x11:rK\x01\xF0\x82un\x12[J\x96\x1F\xD1\xE51\xC1r|\x90\xC8\xBEYis{3\x88;\xE03%\x1F\x93q\x80:\xF5\xAAmB~Q\xA1\xC7Q\x17\x84\xE1>/\x8C\xE6A\xE8\x8D\x11\xAB\x0B"\xDB\x918\x85L\x15WR\xF8\x9C\xF1N\xEBD\x82B\x9F\x88\xBE)\x84H:~\xAE\xA5M\x0C\xF0\xFAZB\xB2\xFE\x93\x97\xFE&=\xBF\xD5\xA3\x874\x19\xA4`D\xA8:\x1F\x08\x05\xF6_\x9A\xAA\xCA\xE9\xDE\x9B+\xEA\x179\xECO\xF8\xA5\x08\x01\x8B\xAA\xBD\x17\x8C\xA4\xC9<\xBD%L'\xB1\xFE\x06,\xA5FTM\xF72r]\x91\xA3\x82\x1E\x0E\xEA\x8F\x0A=\xAA\x9EE\xF6>\x91\x05\xE1\xA8H\x0F\xD9P\x05J<4)\x0E\xC2\xD2\xF7\xAEiF\xCD\x82i\xD3\xA6\x8A\x07C\x80J\xE3\xBB\x10\xEBJ\xF6\xDC\x8A\xAF\xB6\xD9+cF\xF4\xAB\xA0\xEEWyY\x92=\x89\xB0\xB6\xCA\x09\xE8\x01\x9F\xA1v\xD0\x0B\xD1\xE8L[\x89\xFE\x0F8\x00\x8E\xAA\xA5\x84\x0B\xB1"\x127W&\x10\x19\x0F\x8DF\xDBK\xBD\xC4\x83\xA6~\x91\xF2\xD2:\x860:.\xF9\xA42\xEF\xD8Mn^t\x0F\xB0@\xA0\xB3\x95\x14d>\x1D\x9F\xF8\xB5\x86\x17\x0F\x97P\x94i\xA0\x18\x9B\xE2\xB9\x98\xC9\xE0\x0D\\x02\xFB\x81P(\xD5\x08\x89\x9Ah\xB7I\x8D)5\x8E\xB8\x17I\xEB\xA7\xF8\xD45\xB3\x08jB\xEE\xEF\x125|\xEB\xE8\xEA\xDDU\xCBF\xEB\x0B?\xE8\xD6\xD7Y\xDC\xF8\x16\xD6GU\xD6\x899|n&\x0F]\xAA\xFB,,\xD0\x18\x0EC]\xA0\x0F\xE9\xD5%\xB0J\x14B\xE5\xA3\x98\xB0T\xA4\x13\xA8IST\xDC)\xD9H\xD6\x9B\xE7\xA2\xC0(\xA3\xD2@\x0B\x0B\x8D.\x0D\xBE\x8CY\x9E6\x9B\x18\x01>P\x90Nh\x0E\xB8\xABi\xED\xCC\x15u\xC7\xB4W)\xF2ti\xD9\xF4\x17\x9A\x8C\xA8&\x0Ad\xB2\x0BQ\xF2jX\xFD=+\xFC\x1A\xD9\x07X7\x12\xD6\xAECe\x85\xAC\xCAq\xDC/\x82\x10\xB5\xEE@\x93\xF9&\x911\xC2\xDE|*\xEA&v8\xCA\xA8J\xF15L\x9A\xCB\xAB5\xF1\x05}\xC9\x03,"\x03t_\xD6\xE4\xE8\x92\x04\xD5t\xDC\x01\xE0\x88X\xAD=\x0F\xB4\x87U\x9D33T\x1A[(\xB1\xEE\xC4\xCE\xC9\x91\x17\x8B\xE0,N\x91$X\xD2\xB6h\xBDR\x05\xD3X\xF6\xDF\x98\xDAY\x80\xBBDLG\xF7\x82Ce\xD2 ;\x99\x09\x9E\xC4hN\xC6\xDFA\x88z\xFF\xA5!\xEF\xC1\xD1\xE0]^\x07-\x18E\xA8\xAC\x85\x15\xC8\x8A\xA0\x04\xF4\xF05\xF6\xAC\xA8\xF1\xAB\x86.c\x7F\x97\x1D\x14\x18I\xD2\x95ET=\x18\xC9\x1Dj\xBA+\x8Ed>\xDC\x02\x9A;\x0B\xB2\x9B\x122\x1AGz\xB6\xDA\xA6Zo5\xBB\xB3w\xA3\x81J\xECl\xBD1z\x8F}\xF6\xE1sy\x1F\xCB\x9E@\x12C\x99vB\xCA=\xDE\x03-\x04\x9C\x85@\x0A\xA8~\xD9\x8B\xD5\x05|\x81\x1DGg\xDE\x8B\x08&\x9D\x03\xC1\x02O\xBCn\xA7@\x90\xED1\xEB\xF5\xA8O/<\xF5N0\x080\xAD\xA3\x9Avs5\xAE\x0F\xAD\x9A+ f+2\x9E{\x09h8J\x03(|:\x93\x1A8\x1B\xAE\x0A\x1B\x0F|w\x0B@\x0A\xA2\xE1\x17\x99i\x7F\xBC\x09e\xEA:i\xDC0\xBE2ec\xF8h\xD4\x95\xA7%\xF8v\xA6\xA3\xCB~\xBE\x9Egc\xBE\x8E\xD1q"G\xFF\xC4\x1B\xF0\x08\xB2\xC4\xE7\x8C\xCDe\xFE\x85\xD7k\x02\x7F\x9D\xFD\xA2Ia\x0E\xC8\xD7\xFF\x1F\xD7\xDE\xE7\x0D\xA9\xBF\xBE\x19\x12\xE5-\x0A\xA3p\xE4\xC1\xB4\xE1vt\xC9\xCF\x85\xA0\xDEs#\x07\xA1\xA7x^3f\x0E\xC3\x93\xF6Vr[\x8B\xC2/RP\xFB1\x89q\xD0\xE57'\xE1\xA0\x93\xD2q\xB4\x0C@p\xBFZ\x97\xEC\xE2\x90\x03\xE0,\xB5\x82HJz\x97\x9D=-Q\x8Cs\xB1\x0Dz\x12\xE4<\x9E\xD4\x08\x13e.\x1Bp\x1D\xD7%\x8D\xDA\x8B\xB9;\x12a2%\x97P\xAF\xE2\xBD\xE7\xFE\xA5Y\x90\xF3\x86\xDFY\xD0X\x82\xB8\x09Ckh\xFAl\xE6\x9C\x184)\xF3\xED\xA8n<\xB3?\x09\xA0\\xA5\x87\xB6\x13'I\xEA\xCD^}\x10\xC33\x86+O\x8A\x8D\xAE\x0Cr1o\x17\xDE\x91\xB3:is\x0E\xD9\xCEr\xA6\x00\xA4<`^\xD2\xB1\x0B\xBC\xCA\x88\x0C\xC4\x1C\xBA\xD4\xDEI\xC0\xBAz\xB0\xE2\xCE\xFDw`8\x03\x0C1\x85-\xDE\xBELc\xB1\xD2$\xA2\x02\x80\xCBn\x11\x9Fd{\x9F\xDF\xAD\x7F\x93k\x8ASO\xA97\xE9|\xCF\xFB \x86\x8Bp\xA5\xCA\xD0\xF9Kq\xB6{A\x8C6z\x16\x16\xAB\x954\x96\xC0G\xAA\x94\xA0\xB9f\x19\xDC\xB7\xE1Q\xF9B\x07\xF8\x0A\xCC9n\x14\x05\xC1\xBF?v\xE0\xDFp\xB2(\xFE\xF9G\x90\xEDT\x7F\xC3\xBD+\xE9r\xC3\xC1l\x87|w\x03\xA6X\x81\xA3\x0B\x95\xD2y\xCA\x1F\x84\xB8\x16sD5L\xC6\\xDF\xA1\xBC\xA0\xC7`\x92\x87N\x1309\xA8%_\xD4e/\xDE4\xEDZ\x0F\xFBP_\x05\xBA\x9B\x05#\xFEB=P_\x08]\x0A\x87{)c\xFE\xE9\xD8j\x8D\xAF\xD0\x0C\x9A\xFA\x91Z\xE7\x98S\x99\x96j}=\x93\xA7\xF8\x84nl\xEB\xF037L\xA4\x9A\x99+\x10A\xB9 \xA7\xDB\x11\xDEc3\x9FO\x81\xE1vV\xF1\xA2\x1F=w=2\x1E\xC4\xA8\x00D\xD1\x87\xAD%\xA7\\x0E$\xF5\x05e b3\xEA\xA4PU\xF8\xED8BO\xA8\xFE\xE5\x9Fbd\xB3\x022\x1E^\xC1K\xED\xA9\x0DI\xA0\xC9m\xC1\x8A%\xF2T1\xA6\x0A\xC4<\xFA\xF1\x8A O~]{\xFB\xA1r\xFC\xDD\x91\x0F\xD3\xC3kN?\x80d\xD5\xB9P\xA4\x9BFF.t\xB7\x9CR\xB7\xE3\x82\x9B\xD717\xF3O\x0B\xDA\x80\xD0V\x80\xB0y\x08w\xC9PJ-\xDFI\xE6n\xC8=\xB0&\xD6\x9F_\xA4G\xBA\x06\xA3C\x84|*\x14l\x8F-\xB5\x1D$\xA0\xE0L\x10\x08\xF9\xEF\xB2\x84\x9F\x1C\xCE\x0Fp\xC5 \xF4\xD7\x1B\xD9\xF9\x90\x8C\x96\xD6w^Hb,qY\xA0.\\xA7\xDB;\xD8\xE0\xE3`q\xC5**v<:%\w\xFA\x0B\xCB>\xCC\xF8r\xD1\x0C\x18\xB5\x0Fl\x00\xEF\x86\xB0`\xD1/\xC1\x1B:\xA2\x89\xA3\xDB\xAD\xBE\x0DQE \x9Dy\xB5\xD0\x88\x04\xE4\P\xAB\xDDK\xE5\xC7\x8E\xB0\x1A\xC9c\x13\xC4\xDA\xF0\xAE\x8CY\xD6\xB1\xF1\x82\xCB\x94^l\xED\xD0>\xCE\xBF\x1F\x01]!.0\x80\xFD>\x8D6Fh\xB3u\x07\xB3*<;\x886yA\x88\x1F\xA4)[\xD3K\xE1')1Z\xA0w\x1C\x03\xD2\xD2Tz\x1F%\xD4\xF1\xEA\xD8\xB6\xDAU\xC5\x16e\x0F\xE1\xB0\xCA\xD6'\xAA\xF3c\x1DS?\xA8\x17\xB1a\xFFv-\xAE\xC4\xB8\xDE\xC1\x0C\x812\xB2\xA6\x8B\x061]\\xE4u\x02\xBAG\xE0Z\x03i\xCC\xF9\xAD\x16\xCE)\xF8r\xF2)\xF3\xA5F\xC3*\xECO\xAB\xF97D\xAFyT\x00\3\xC5\x1D\xDDY\x9A\xBE\xB4\x9E\xAE\x02\x81N+Cr\xBC\xFAk!f\xE3\x89\xD1\x84k\x0C\x8C\xD8\xAD\xC7X\xDD\xA5\xA0\xDDl\xE6;\xE9\x907\xB6\x92a*\x8Bs\xE0\x96\xC4k\xE0\x18\xB4\x0A&\xCF\x05\x02K\xD6b\xC0%\x80\x0F\x8F\xE2\xCA\x9E\xA0\xEF\xB1\xE8~\x8C\\xAC\xB6\x8E\xD5\x00=\xD5\x1C\xF0\x11\xDB\xAA\xA1oY_\xD4\x0E\x1E\xBE\x1C\x141:\xA0\x0CiT8\xFE!\xE1V\xE3\xDC\xFBS \x97\xEDo\xFE%\x1D\xA6\xFB\xBC\xC8\xA8~\xFD\xED'L%\xE2Y\xCCr\x900\xCD\xE4\xF4\xB8\x94A\x11\x0A[\x0B&\xC6N\x89\xE7\x18N\xE3\x92\xAA>\x9C\xA2\x88\x87^\xC2\xDA\xEB\xC1&\xC5\xBB\x8E\xACQk\x19H\xD0\xC4,|\x9Dc\x10K\x07Jq!\x16b\xFB\xE3$9\xCF\x12H`\xD1Kk\x94K\x7Fp\xAF%\xF6q<\x86\x8Fq\x11\xC7\xF4\xBC\x80\xBCmwM\xBB/5\x0DAz\xC4Ga\xDC\x82J<\xA1+\xFF\x08\x1D\x0C}\xBB\x07#\x8A?\xFA;\xD7O\x89\x9B\xBD\xA1\x09X'\xCE\x94\x97!\xF4\xA1\x01d\xF6-\xD7Q\xCB\x82\xF9\xD5\x02\x03\x81`\x0D\xE6\x07_h\xF0?\x09\x19\x1CW\xACf\xCAO\x88R\xA7\x92^\x02#G\x12YZ\xF9\x8D\xA3\xD4!\xD1K\xD4\x95\xB3{\xACi\xE9\xB0\xE8?&Mu\xD8\xB4\x05\x9D\x9B\xE4[*f0\x04|R\x88|\x13%\xCD\x16\x9F\xF3E\xADF\x8E\xE7\x99\x08\xB2\xC3\x9BX\xBE6\xDDM\xDA\x02\xF34\xEB\xD1\xFE-\xF5\x18\x7F\xF8\xB8|\x0E\x1Bx\xE0Y\x8A\xF8\x8B*\xFD\x84\xED\xBBf\x1C\xDBm#\x8C3.\xE57\xB9\xE1|\xDD\xD21\x0D}\x10\xD9c\x8ET\x8F\x17\x13\x8A\\x90'0\xEC\xD7\xEA\xB0\x8B\xBAQ\x00d\xC9\xA9\x90($8\x82-*\x1C\xC2\x9F8\xEE\xB4\x90\xC5\x82sN\xC5Z\x00\xC3\x90\xAAv\xD4\x87@0df\xE8\x07\xB3\x06\x0Cr\x9F\xC5\xB7\xD5\x8Fh\xD3\xB6S\xD5:\xEE\xC1X*u\xA7\xD8\xA6\x82%\x8C\xD4\xF3\xEC\x11\xFA\x17G7j\x93\xCA\x91\xFEFYO\x06\xD5\x04\xF4\xF4\x04\x9D\xD1D\xABT`Gd#\x19\xB4D2\x9D)\xD2\x0C\x91f\x1A\x82k\x08\x8E\xB3a\xC7\x97\x7F\x0D\xB7\xECl!\x15(Y\x98,\x12\xB4\xA5w\xBB^\xCF\x06\xD5\x0D\xE0Z\xAB\xB3\x98Q\x91\xD5\xC9\xEF\xF4\xD9\xEEP\x85\xDA\xD4?=\x9AW\x10v\x84\xB2\xE7q\x0D\xB0\x0B\xE2\xBB\x996A\xD8Vok\xFC\x13\xD9\x13\xD8\xB8\xFB\xED;\xD4e\x1F\xCE\xD1\xA4\x8C\x82\xBEb$\xD0\xA1\xB0\x15k%\xDD\x8B\x84\xB9W$\xEA\xEA\xDD\xE0v"\x85\xC2\x05\xB4N\x1D\x01\xDE\xEB\x1C`K]\xA9\xABL\xF9\xF2\xD3\xB4\xD4\xA3\xDD\xD8V\xDFd\xE4\x85\xC4b\x8B\xB0\xF8Q\x95\xDC&\x14\x8D\xC0?\x16\xF2-\x02\x96X\xC4\xCA\x91\xAC\xC7\x96\x1CP\x0BH\xB3]\xAE\x82~\xDE\xB7\xE0^\x96k\x9D8\x10\x8D\x8D_\x87\x97\xBC\xFF\xF7g\x06\xA4\x9C\x9A~\x0E\x0C\x04:$hB\xBEbD\x16\x7F\x0E\xD3~9w\xEFf\xCD:P\xC3\x18FBe\x84\xF1\xC8\x18\x8B\x96i\xD9\xB7\x88\xC5S\xDE\xD8\xA5\x06Qh\xF5\xDC\xAB+\x90\x0BnjF\x9Dk@^<\x85\xBFAy\xA4)\xA4\xDBG\xB5\xF4\xA6\x19^\xFE_\x90\x14V~\x82\x85\x0Bw\xE6\xF7l\xC4\x81\xB5|\xAB\x9D;\x8C>\x13P\x94\xB0\xB5\x02N\x04>\xA7~\xB96\xE2\xAC\xEE\xC3\x07U\x0FY\xAB4\x81[\xE2\xA2\xE2\xC2\xF5\xDA2\xE8)\xBEz\x09\xCF/\xE0`\x1A\x7F\x00SCQ\x04\xA6\x0A\xB1\x9Dy\x96\xF0sv\xF8Dv\xCCa\xD6\x82\xB5\xE7\xAFc>\xFB:,\x07QB\xEA\xBF\xCE\x0A\x0F\xBF9{\x90\xC3\x8BZ\xED\xFD\x9B\xB0\x1A\xB7X\xF58\x88N\xB0\xA3\xE3l\x9Fcz\x9C\x87\xEB\xEC\xBDq\xE0\x12\x14=?\x83\xA0'#\xA7cGr\x8A\x94e\x9B\xF77\xBD`\\x8Bx$\xF1|\xED\x9F6m\xDFOgo\x14+\x12\xB2\xAC\xB2\xB2^\x89x\x037\x84.\x8E\x12\xDA\xFE\xE3\xC59\xE8\xE9($\xCB>\xE2\xEE\x1B^\xF0iu\xEB\xDF\x92#\x89\x8C\xEFS\x0CD\xE6]\xC6_\xAE\xBB\xD5\x0B+\xAD\x96\x0B\xF0]\xCF@\x8DK\xEC\x94\xF7\x06\xEB\x0A\x9C\\xACb\x96\x98\x99%\xF1\x0DS4t\xAF\xF7R\xF5\xA2\x80C\xFC(\x17S\x9Ap\xE9*\x1F!\x1FZw\xD6\xE0+\xAE\xBA\x89\xEB\xC4\xFALw0\x0BL }\xE5\x87\x1D\xDF%\xC6\x81.\x837\x90k\xF5~\xD6\x0C\xC3S\xB7r\x13\x8Ec\xC1\x80\x939g\x87\xB5k\xC8\xB3\xA8\xCE\xBBhb\xB4\xA6`\x15t\x0D\x9A\xA0!\xC1\xAF\x1A\xA1\xAC\xC9\x1E8\xEB\xE6\xB9C\xB2c\xF3J\xE5\x1D\xC6\x8D{\xCD\xF9\x97[p\x80\xFB\x86h\x0ED\xEB\x89\x0E\xAA\xBF\x1D\x7FG\xEEVOU\xD0\x06)9<2/W\xE9K\xBBh\xEF\x90KB[\x8D\x01bBFnPh\xF2\xC7\x0A\xF2\xF7\xE4\xAF\xB8\xF0\xB8\x89:\xAC\x95\xB2\xE295\xBD\x86\xE4l\xD7\x80\x86`\xE5\x9F\x9F\x0E\xC1\xCD\x10\x02\xBF4*\xE3\xFAu\xEDu\x8A\x1F\xC4y\xD7x\xB9T\xEE\xBBF\x1E\xED\x88,\xB9v\x02}4T\xDE\x8A\xB7\xDC}\xD5\xC2\xF7\xC1\x17\xC1\xBC\xAA\x7F_\x15\x81\xF0\xDDc\x88F\xBE\xE4\x82\xF7\xF1\xBAk\xA1:\xA7t\xB75S7\xCF8\x181i\xBAx\xEB\xF7\xE9\xDBp\x87\xC8\x8E\xED\xA42\x03$\x86:\xA0\xA6\x1F\xF8q\x9C\xB11|\xF4f@\x064D\xB9H\xCF\xDA)\xF0>+\xAC"\x1B\xD9\x1A_\xAB\x1B\x8C(\xE3\xDEv2M\xD9|/q\xDA\xF52\xCD\xEBT\x0B6\xE9;\x8D_\x0E=`5\x8F\xD2r\x01\x1C\xBA\xD3\xA3\x19\xFA(\x01Q\xC9\xE8F\xDF@v\xC6\x07\xFD\x1Dhz7\x8A\xEFc\xD8\x82\xA6$D\xFCU\x94\x12\x0B\x1B\xE0T^$\x80~1\xA2\x1FO\x09\xEA#"\x12Q\xF7l\xDF\xCB\xE5 \xA3v,\x8B\x14j\xAF\x8E0\xC1\x98\x90\xAET\x92\x9D\xC0\x96\xB6\xDEe!0\xEE\xAE\xEF]\xF4$\xE4Q\xAB\xA0}\xECf\xA9\xC7A\x933\x9Ew\xE3\x11\xD1\xF6\xB5\x02M\xB4X\xD4c\x03\x8DA\x02\xBE\x8B\xE4\x8F\xE7\xBA\xE4b\xE0|\xC2b@A\xCD{\x09\xF7\x9DC\xDE\xE9\xFB'\x9F\xBB\xB2\x0D\xD2\x04~\x14\xBF\xC5\xD8\x0F\xED\x0D\x10G5k<\x84FV\xC6\xF7\xAE~\xF9F\xC2\x02\xB6.\xEEU\xBE\x90\xBB\x9Er\xBA\x1B\x88s\xAD,\xBA\xE5\xA3O\xAB\xE3h\x10\x9D\xE87\x19\x1E<\xA5\xDD\x95\xACx\x8FP\xEAl>\xDFO\xF2\x1E\xDAE\x1Cq\x19\x05gED\x19\xB3\x01\xEE}\xD3\xD2\x9FtS\xAE8\xE9\x18b\x09\x8D\x08\xBD\x0E\x07]*\x03#\xDA\x0D\xC6D\x8C`Mk\xA8\xA0\xBF~`\xB5{O\x9Ay\xC5\xC1\x07\xBB=\xEEM\x03R\x01<5\xF9\x18LV\xA7\xC0\x84\xA0@\xCB7\x15G\xD2\xF4q\xAD\x97\xB1\xC4\xAFj\xD7\xE4\x04\x80\xEB\xBARq\xE8I\x1F\x98?$\x0E\xED\x877\x1DL\xF0\xB0(B\xD6\x0A\xDB\x8BQ\xDAh\xCF\x93\x98\x9AL\xB3\xF3w\x01\xC7\x03TdHT\xE1@\x84\x0BZ\x92cc\xB8\x03\x86X\xCBAbK\xD4b\x0A\x8A\xF9b\xDD\xA3\xAE\xE0\x90\x15P)-I\xDAH\xC58\xA8_\xEAC\xCA\xF8N\x86,\x92\xFEj\xCC\xD9\xDA\xDCEL\xE0 \xC2o)\xC5T\xCC5f\xD15\x8D\x8C\x85\xE4d\x0A\x13\x0A\x80\x93\xAAFu\xCE\xB6\x01\x1E\xA8\x07\xD4)\xA8D\x11\x1Ek*\xD5\xB7\x95\x1A8\xD0\x0A\x9F\xC1[\x98\x18=\x86\xD4U\x84\xD0\xD1(%${5\xADA\xDA\x07\xDE[\xF7n\x88\xAE\xC3\xF19\xF8h\x03\xE3\xD9m\xB2g,pY\xAC\xB0\x14\x9C\xB0\xC8\xD4\x0E\xBE\xC6:%@\x9Dh4\x8D\x85a\xF7\xCA\x17\x90%\x9Fr1\x1A\xA3`\xE3\x01-\xF5\xF92\x09\x1D\xAA\xC6\x1CG\xB1\x96\xB6\x8FV\xEF7~\xE5\xBCN;#\xAF\xC3*-\x8C\xE0\x01|\x13\xFD\xC2(\x8D\xC7\xB8\xE3\xFD\x06*\x0C_C\xB8i\xB5\xD4@Ga\xC0\x97\xF1"zf\xCFwAb\xDEp\xBB\xF5\x0B\xAC\xC8\xD1\xDE\x0D^\xC2xBF\xAB\xDF\xCB\x8A<\x84=\x9D.\x82O.\x91*@\x15]\x83\x11\xAD\xEDQ\xE7\xC6Z\xEA"r'\x0C\x0F\xC6B\x0A\x86\xB3q\x1F\xA1\xC8\x1E\x90\x91\xE0\xEFs\x8C\x9E\x194H\x13\xFAo\xF1l\xCB\xCC&&\xA1@uj\x1C\xD0s\xBE#\x9B\x9EzB\x8B\xE6\x8D\xF1\x85(\x02\xD6\x92Y\x94T\x1A\xEC\x14\xE1>{\xB6Knp\xA8\xCE)\xE0\xFC\xB8\x02\xE8\x8B\xEA\x14\xCF\x97\^u\x01`\x91b\xB0\xBF\xCE\x8C\xA5\x9Bj\x84\xAC\x16X?\xE3\xF2\xA5\x9F\xEE\xBFa\xBB\xB0\x7F\x82\x01V\xEB\xA0ib3\xF7\x8E|_JQ?\xF6s\x03\xC9i\xA1\xEC\x83X\xE4.\xEA\xAAI\xDFt\x92`\xEC;E\x11"'\x90\xE2\x9F\x1EQ\x12\xC4\xAB_\xEC@\xEF\x89RgIs\x1B!:TP\xAF\x0Ak\xEC\x08<\xC5\x1B\x02\xF7\xEA\xDC,\x82C\xA9=JE'j\xD4v\x12\x00\xF6\xECT\xFD\xC8\xBB++(L\xB0c\x09\xE7r\xDA\xBC\x12 \xCAV\x84\xCC+\x84_p\xA7\x84m\xF7\xD6\xC4\xC6\xEAf\x15\xF0\xE6|\x92\x8C\xEE\x1D\xD2\xC2O&\x8Aw\x95\xF8\xA7\xBD\xB3`\xAF\x03\xAC<$\xC2\xA3\xBB;\x10\x8FG\xBB\xEA\x13\xA4\xF9\xF8\x9D\x12\xFD'\xF8\xD1\xD5\x1AhcX\xBD\x8B<\xE9\xFF\xD3'\xF7\x06\xD9\xE3\x94D\xA8k\x85\xF6\x91B\xA3\x09|$\x1033\xF9\xAD\x9F\xDC\x91\xE9\xE9\x06\xCC\x1C\x12\x0Fs\x823\x7Fo\xA3\xC4\xF2\xA8\xE6\x93\x03k2y\xC1QZ"%\xA0[\xA1\xC6\xD5\xEB;\xD7T\xF2\x8A>\x07\xC6\xC2\x1F\x09\x91\xB6\xFC4\xEA\x10Pu\xB3\xA1\x95.\xE8z\xDD\xDB\x89\x03\x0F\x8A\x0D\xE39\xF2s\xE5sN\xEEnh\x16\x7FV\xAAKhe$\xE3\x9D\x0A\x93/\x9D\xD8\xCA\x8A\xF9\xF36\xA1c\x8DiA\xF9\xAEt\xA6\xA7\xB3\xACx\xED\xFA\xB4%\xB9\xD9nT~jM\xC4;\xBB?\x9D\xC3\xEC\xCC\x83\xC5\xC0(\x1E,;>\xA3}{_\xDD\x08\xCA$?`\xCB\xE0\x8B:C\xC7AfQ\xF6\xEDk$\xF5>V\x17:o8\x88}!\xF0\xBF\x9E\x9EB\xDF\xDC\xEDi\x18r\x83!l\xFA\x9C\xE2\x99\x8A\xAAF\x7F\xED\x02\x95y\xE9\x02yg\x15)(o\xA53\xD4j\x0EHuW\xE0\x909QR\xF5\xAA2\xFBK\xF2C\x81\xF1\x8E\xA1\x82{3w\x9C\x9Fv\x9DX1\x10'\xC2Z\xA4\x07'\x9A~k1\xEF\x94\xD4.\x1F\xE8\x8A\x92<\x0CL\xD6K5\xBA\xDD\xCA\x06\xE4\xBB\xDA\xA2YS\xB0\xECP\x0CZ\x02zj\xDE\x99\xC9k]e\x9F\x96\x94\xD2}\xBB\xC3c\xA2V\xA3n\xD1zA$y\xF2&\x82\xC2\x95\xB4 P\xC6\xC0\x09\xA3\xDD\xD4.N\x17\xE7V,\x89,\x913\xBA\xF6\x06|b\xF6\x9Dy"\x17V\xBA\x8D\x1B:\xA1\x82\x083\x14\x15!\xF1l1mxj\x9E\xF5(|qZ5\x99\xE6I\xE6\xB4:\xCA\xE4\xC5\x04\x03\xA6\x0E\xCF6I\x1D\x88s?\xBB\x18\x0A\x1F\xF3\xDA\xF0\x84\x01\x13\xEE\x11\xF8\x9B\x1C\xF3]\xE6@\xCBY\xCDe\xCF\xE0QF\x94\xA1\x0C\xECr\x9C\x90\xF9\xD6\x8C$\x9F\xFD\xE5\xF1\xED\x12\xE1\xBC?\x86p\xA6I\xDF\xB2\xFFY\xAD@\xA1\xE52\x1B_\x81\xEC\x0Fs\xCE\xC3J\xE3\x8C\x07\x7F\x8C\x15\xA8\xA7\xA6e\xD5\x18N\xE7\xC3\x90u\xB5\x09{\xCB\x81\xF9]\xA0y{\xBB/\xC1\x84 \x85\xBE\xEF\xC9\x1C\xD2\xEF\xAD]\xA2\x0F\xA1\x85\x074\xBFN\xC2G\xD3\xD1 8B\xD4r\xEA\xD1EN\xE4\x97\xFB,\x09\xAE\x0AE\xF05\x06|\xE2\x0CF\x89}\x10m\x03\x9D\xAF&\x0Cq\x9Fb\xFB\xF4\x1D\xCB$m\xB8;R]Cv\x16\xFE\x9Ek\x8B`\xADa\x93\xE6\x80\xFA\x08\xEEt3KJ6\x98\xBA'\x80\xEBd>Z\xBD\xC51e\xB2\x17;\x19z\xAC\xEB!\xFB:\xF7\xB7\xDFT\xC1<\xD5\xEDC\x08$)m\xBCb.\xB9.\xFF\xE8\xF4\xAF\xC4\xB5Vl\xC6\xBE\x04m\x0Az\xE1\x01KO\xFA\xAB\xDD&\xFD"\x9B\xD9H\x8A\x02\x7F\xE1\xC2\x01\xA4c\xAA\xE8;\xFA)\x05\xF6"\xFE\xDAu\x81(3KN\x95\x8F6\x12\x14\xF5P\x03y0a\x8C\xA0\xCA1\xFAA\x0C\xE6\x8A\x87\x90\xBA\xF4\xD3\x8A\x15\xB0H\xCC\x9A\xA5\xBE#%\xDD\x11\x0FoH_fj\xB5|\xE1\xFC\x01\xF3S\xC3+&\xE6\x19\xAC$\x90\xE8\xE1\xDD\x12\xB4\xDA\x14HM\xA3d(g\xFA\xBB\xB2\x89\x95\x12\xD4\x8B\xCE\xEC\x93h)C)\xC78L1]L\xC3Ee\x89\xD5\x9C\xB6\xF9\xC2dH;\xA46&U\xE4\xB4}\xFBB\xD6r9&\x9F\xAB\x91\x1A\x0AG\x0B\xD7g\x19\xE0\xBA5@j#L\x16\xEF\x98\xA6\x8Ds\x9B\x97\x96\xBD\xC4\xDD\xD97&2\x07p\xFE\x8A\xB5\x00A\xBF,\xA5\x01\x1B\x9B\xA3\xFCLq8\xE4\xCD\xB2=,\x15\xDC\x98c\x98\x12LH\xF1 \x1E\xF3u\x1Ai\x1CXQ\xE25\xCB\x14\xBE\x0C4\xCF\xB1\xED\x08<\xEE0\xCC\xC1\x0D+\xAF\x01\xA0P\x8D\x87;\x8Ab\xC0]h\x82\x03\xE8\x0E\xB61_\x87\xB8CeJ\xC9\xE1P*\xDDe\x0F\xAB\xFC\xBD\x12\x17\xDD\xE1\x98\xE4>\x91\xBF\xB0P\x0E\x9BG\xBF\x17\xC6\xF9\xF0\xD8\xC4+\x15\x1D\x03ul\xDDT_\x0F#\x91\x15ZO\x8D\xEF\xC8,D\xD6\x19 >L\xC1\xC8\x0AK\xD8w%7\x07&\xAC\xCB#\x91\xD7\x0D\xA93\xFEp\xA3Xg\xC6\x12O\x9F\xB9\xF8n)\xCB\x07-\x1A\xFE\xD1`~\xBDKB\xC6\x1F\xAF\xA9\x10OAL\xD50\xFAo\xDB\xA9\x06\x87\x02SLm"\xB2\xD2\xED8B\x1E4o\xC1\xA3c\xD3kB\x8C\xC7r\x82%\xF0\xF4\xC6\x01\x92\x99\xDF\xAC\x08\x87\xCA$\x1A\xB4\x10\xBE\xBD\xBE8;\x1DCu\xFC\xBF/\x8C\xD2\xCD\xF1\x82\xAD\x88^9\x05|\xAD|\xD0X\xFE\x8C:\x13x.\xA4\xF2\xE6b\x87\x7F\xA9\xC9c-)\xE5Ff\xD4\x15q\xC70Iz\x94G\xBD\x84h\xA5\xF4\xEA)P.\x9A4v\x8A\x1FfH\xE0\xADq\xE2\xA8\xAC\xA4Gn\x90\xE5\xEARc\x98'\xACT\x86\xC7\x8Af\xC1U\xCB#/=\x91=\x80\x15\x9A\x80\x14\xE1.J\x98t\x958\xFE9\xC6Z~)\xFA\x9E\xAAp\xDA'\x04\xAF\xFF\xBA}4W\xFC\xDF\x8C\xBD\x94\x90\xEB'\xEA\xC7\xFF]\xCE\xA7mo\x1Fj\xF8o\x16^\xA1\x89f\x08\xBF\xDEJ6\xC7\x87\xDD\xF2\xDC\x059"\x05\xABW\x1E\xC7\x84g\xA6\xD0\x10\x13\xAD1wE\xF0\xA8\xA5\xA4\x04\x86b\xB4C\xF4\xE0C\x0Ai\xD1\xCE\xE5\xA4\x9F\xE4\xE6\xC0\x8DMnu\x8A\xBBV\xB7\x17\x05\xFE\x1F\xE3"\x94#\xBCM\x90P\xAA\xF7s\xE4\xEDKFB\x93\xE4\xD9\x0D\xBA\x80v ]CU\x94I\x07H=gj\x0B\xAD\x03]\x004\x09\xA4"\x88\xC6\xB8\xBB\x90\xF139\x90D2[:\x80\xF8%\x14fM\xD9~\xED\xC4\xDC\xC9\xB7\xA0<\x9B~\\xE6$\x87\xB4\xD9\x04h\xAB\xFC\x99\xAAJ\xD0\xF3\xD5\xCD\x15\xF0t\xB0}\xE1\xC1\xC2\x0C\xC8Y\xC9L\x88"\x115\x14\x9D\xEF\xAD|\xF6\xB0\x0E\x84&\xE2c\x05\x04\xD7\x11\xB4\x0C[\x88 \x15\xB5\xB6\x1A\x97\xFB\x01\xEC\x1F\x1D\x83I]\xAFn%\xD0\xA5\x98@\xAA\xC9\x10\xB5\x1A\xD1\x07\xBD\x7FN\xEA\xB7\xA54\xA1t\xDDN1b\x8B\xBB+\x06}Oy\xF8\xB8u_:\x98\x02\xA1\x0B?\x99\xD6r\x19\xDC\x98\xA2\x95\x9C\xE2\xF0\xEAP\xBEJ\xEE\x8B\xE9\xF1x\xBC\xA0i\xFD\x0B0\x131C\xE0c\x80\xB1\xCE\x9FA-D\x0F\x8A\x8B\x95\xFB\xE7\x81u\x09\xC7\x12\xDF\x99\xFC\xF7\xCB {\xD9[\x13-w\x9E\xBD\x1C\xBF\xC2\x07v\xBD]\x85\xDFe\x9D\xEC\xDC\xD5\xB6v\xCE7/\x98\xDA\x95\xE4\xD8rUE\@=\x82~\xBA\x0D\xA8\xA0,\xDBn4\xD2\xCFz\x86\xE16\xF0\xCA\x09\xC8%\xE6+B\x15\xBE\x04x\xFC/Yf\xAB\x8A\x89\x09\xC7\x0E\xDB+\xBFg\xF770\xCB8\x00\xE8\x8E\x8F\xF3\xEF\x1A\xBB9X\xE5I=\xEB\xDF?z%\xDF\xD0\xC6{F\x92$KXJI6\xD9\xA7\x83\xD7Zm\xCD\xE4\x98\xF6\xCEU\xB7\xF6(\x924\xE04*\x18)z\x86u\xD7\x93\x0A\xD7[{\x80\xC2\xBA\x85UnK\xCE]\xEBB\xE4\x92hS\xBCT`\xEC\x024\x8D\x87\xFE\xEB\x95\xA5\x16\x87\x89\xE9\x82\x91\x8FV\xBD\x10kBS\x1F\xD7\xACw\xEF\xD8 \x04V\xCF\xB9\x86\xE0\xECHQfL\xCD\xA2\xC2\xB2>\xDB\x9F\xE0\xEBYZ\xBC\xD6\x1BQ\xDF\xA8\x14ut\xB1\x0Bef0\x17\xA3\x82\x9D\x15e\xF4:\xFEm\xC2EC\xCA\xDE\xD9y\x80u4\xCB\x06A\xC4\u\xEF\x16d\xF9\x02eAG\x90\x14\x11\x9E\xFB\x04Fo$\x1F?\o\x15\xB1\xF8\xB0\x95jX\xA7\xE9\x85\xF8\xF7\xC6\xA3?N\x00ACe\x87\xAD-\xEF\x86h\xB8\x0Ag\x96"\xDB\xF4\x8BZ\xBA4\xE5\x0A\x1A"\xD8{6\x82\xE155\xE3\x8A\xDA\x1DPyG\xDC7\xAAm+\x11\xD1\xCF[\x14\x03*\x8DJ\x8C\xC8\xE8\x884\x008\x9A<\xD8\x97\x92B\x104\x8B\xA6v\xE6\"\\xAD\xE6\xC2pA\xA4\x09rra\x93\xE9\x94\x7F\x8Ah\x1B\xECT]\x01\xD4\xC5iL\x1E\x8Bn53=\xC0\xBC?\xFA\xF0\xA1\x15\x03/\xC7\xB2\x92\xCC\xFB\x0C_(\x1C\x07\xD0\x82{\x8D!\x81\xE8a!k\x9C\xAE9\\x82\x87Q\xAF\xC4\x06H\x895^\x06\xBFC\xB9MBT\xFF\xD7\xE9\xCEj\x99g\xE9\x96\x88!\x9Dt\xAA\xDEvvb"\xBC\x84\xA6\xDF\xEA\x07\xCEuM&\x81\x96O^\x97\x83\xC2\x02#\xD8\x0B\xC4\x80@\xA8M\xF9\x98L\xB4\x0C\x8D\xDF3\xDC\xA1\x94\xD2\xAE\x15\xAC\x1A?\x81J|\xC2\x0D,7\xEA9\xC82\xF1\x80\xBD\xE0\xE0\x85\xE9\xBF\xF2\xC2\x16\xB5!\xFB-\xB9\xCF\xCBe\xB3Z\xC95N\x0C\x9F\xE3R\xCCr@\x86cF\xCD/\xEF\x9F+\x91\xFC\xFC)\xAA\x9BL\xE8\x03=\xF6\xFE\xF6\xBC\xDE\xD9]\xAEC\xEC\xF8\xDC\x89%R\x86\xCF}\xF5\x0A\x88qe\xD4\xBD\x87\x0F\xE9w\xB8\xF2h\xDC\x91\x12\xE4h\xB32\xE6\xA9cP\xE1\x19\xBF*\xAC\xF65\xB7\xE9{!\x8Dj\xC62>\x9A\xF9R\xBF\xA4\xF7\xF4\x1Fc%c\xEBu\xDE\x0A\xF9\xD6\x93~bJ\x82\x8F\x18\x97\x9C\xA8\xDDq\x1A\xCA\xCC\xB4\xD3\xA0\xC7\xA9\xCB1r^\x16\xCB(\x1F\x19z\x03\x14\x8D\x99\x0B\xBA\x8E\xCA\xC3)\xD7\xA5Y~\x9C\xF7\xB91\x0E\xE3\xD2\xB65 OH\x01\xD8\xC8\x8C\xE7Q\x97:^#\x84Y\xC0\xEBM\xC4\xFF\x16>IfK{V\xE3\x89\\xBF\xE4n\x1C\xE6\x86\xAF:u\xB6\xBASw\x13\xFF\xFA~gJ"\xB8~l\x91\xE4\x09p{\xAF$}:\x19\xB7H@\xAB\xB3\x08;\xCE?\x9Agl\xE6\x9C\xDD\xEC\xB1U\xD6\xED\x8F\xDF}\xF1\x01iG\xE4=i\xDF\x80\x81\xCD\xA5\x1E\x9A\xE5\\xB9\xFC\xF3y\xCB\xC3|}\xE2.\xFC\x13\xD5\xC0\xD9\x81\xB3=\\xFEP\xD3HO\x11j\xE0\x90\x0C\xBA\xB9\x16O\x070B\xAF8\xB3\xFED\xF34&\x19\xFAxB+\xFF\x13\xF2\x90z\xE8u}\xFD\xA9r\xA7K\xEE<\x84|\x9C\xB0_;l\x96\x87\xA7v\x95\xAA\xB1\x0F.\xC9\x11|\xD7\x8CPo\xCD\xAD\x88\x13\xCE>\x89_LT\xD6\xE6\xA6BN\xDE\x84\xFA\x13\xA3@\xFB\x01m\xDA\xFC\xE8\x93\xFB.\x99t\xACN\xE0\xD3M\x1C%a\xD6\x88\x12G!f\xC6\xAF\xD3C\xB5\xCC\xAB\xF9q\xED\xD8D\xBBs\x97\x82Ok \xE3t\xD1\xCC\x1DO7~_!=`q\x94\x0B\x8ECe<\x91\xFD\x8C\?\xC3Bk\x83\xEB{\xADv\xA3\xE5\xA1j\x0C\x07\xC9\xC0k''\xE0\x97\xCB\x9F\xFB\xF4\xAF3\x0DM\x95\xCA1\x91\xFB\x06\xD7\xD1\xB8\x10\x01\xE4-fS\xF1\xC1`\x91q\x1EF\x10\xA2S\x0A\xB1\x93E\xD67\xA2\x8AV\xEC\xA8.W\xE2\x86\xA2\x9F\xB9\xBC3f\x093\xDB\x96\xE8\x86\x92\x9C\x1C~\xD3b\xBA\xB4\x1D\xAC=\x11\xE6\xB81\xE1Br:\x9A\x15\x19\x95zA\x8C\x85\xF4'\xDB\x9A\xC7\xCEpB\x89\x0A\xB0\x95jC"\x08i\xC6\xB8\x09x\xCF\xF0\xD5\x13Yo\xA5\xF8{\xE5\xE7\x07>\xF3~=\xD3\xCE4\xFF\x94o\xFD\xFD2\x08v\xD0\x8B\xB4\xCF\xC64o9%FJ\x0C\x0B\xFD#\xB8VWv\xE46H\x05\x91At\x11\x83\x05y\x12$\xA27\x1E\x91\xF9\xB8\x10\xB4#_\x82\xBDe4\x1D\xB6\xE14OZ\x850'c\xE9Wz\xF9\xE5\xB1Y\xC5\xC8\xC3\xFC\xBB\xE3G\xF7\xAB\xDDo\xA8\x11\xA9TM:\xBA\xE6>\xC5^\x11\x8C\xBA\xD4\x90\x83\xAF\x05 \xD7\x0B\x1E\x0Bg\x1DL\xFE\xCF\xFA\x9C\xC1}(~\xDDP&\x97\xE8V\xC6\xDA\xA3ON\xA2\xCBxz<\xCE\xEE \x8E\xCA\x0C0J\x9ACZh%y\x1B\xED\xC6je\xE7\x94\x7FqF\xE9\xCF1M,\x9A\x90J\x9B\xE2\xAD\x01\xB9\xAE\xBA\x8E\xC3\x86\xE0U\x17E\x00Wm\xFF\xFC\x83\x8A\xF5S\xC8\xA80\x99\xDA(\x9F3`\x9AZtP\xB2\xA1\xBE\xB1\xDF\xCC\x8C\x00\x06A\xBB\xBD \x1B\xADcC\xC7\xCA\x0E\xF2\xD8\xADK\x8D-+\x00\xEC\xE3v\xBEwQ\xB6\xDF\xCF\xCF\xE3rY\xFF\xA1C%\xEB \xF2\xC4Y\xA9\x02>\xF2rEgb\x0F\xC7\x91m\xB1\xC5\x96\xB9#\x80\x86K\x9C\x18-\xC5\xED\x0C\x06B\xAF\xEC\x04\xE2/\xB8+\xEE\xB9 4Oc\xE1\xC6\xCCa.\x9D\xEDn\xAF\xDC\x82[\x89\xD0\x10\xFE\xECV\x15\xAB\xE6W\xEFQ\x18\xA5\xFF&T\x90x\x7F:\x168\xE0\xB7\xDF\x90\x14\xA6p\xB8\x81>\x0B\x0Ck\x89d\xFFC\xD7\x00\xDEL\xFCk\x9BEj\xD3VL\xAE\xBE\xCD\x07\xD4\xBE^$g\x9F\xB8\x06\x86\xCF\x1C\xE8\xDC\xDD\xBE\xF6R\xC3d\x8E\xB5\xAD\xFF\xAC\xF5w\xD5\xCC\xC7\xF4\x0C/7\x83\xA4\x0FP\xDDMfD\x81X\xF6C5\xB4\x8DR,\x08\xEB;@\xA945\xEB\xD6x\xD68X\xB0>\xA2\xC3\xC7c\xCA\xCA\x9CW5\x0Ag}Rg\xB1\xA9\x1F\xA5$|\x99\xDC8Zd\xAEgdGz\x02px\xB1,k`\x833\xADV0\xAEH2\x01\x09\x8F\x1A\xEC\xC0\x80f\x1F\xEF\xA2\xAF\xA5JW!\x1Ea\x92Nw\xCBD\x82Q]]\xEE\xFE\x04\x8C;\xD0\xEA\xD7\x85\xDF/o\xE5\xBE\xCA\xBAmx7FHT\x05%\xCC\xB4\xEC\xFD\x04\x13#]dY\,e\xC7\x9C\xC9dXB\x93\xCAH\xF1\x12$\xD8B\xCE\x92\x10\xEE3\xD0\x18\xF3\x8E\x04'\xA0\x99\xEE\\x1F\x01\xC3\xFC$\xA2\xA7\x80\xF0\xF2\x85\x0F\xBF$\x9F\xE9\xEA\xEF\xEB\xA98\xCD\x07\xEA\x09U\xF7\xF5N\x8E\x0C\xD7\xC5\x8D\xB3(\xAA:kXp$4\xAB[\xD0\x93\xC4Q\xBF\xE7^\x09\x99\x7F\x83#\xA3|de\xA8]\xCB6k\xB3*dey3\x9C`bw^I!\xF5G\xF1V\xCC\x03V\xDC\xD1G\x04TcA\x09\xD9\xEF\xFA\x8A\xCE\x84\x1C\xE9o:\xA9\x0B\x13\x13\x83C\xD1\xFD&\x0F\xEAyS<\xDC\xD52\x09Db\xE5y\xED.?\xBE\xC2\xDC><\x0E\xE7-.\x1D\xE0mQ\xF8\xD1{[\x84MD\x89A%C\xBB\xF8\xD6\x84\xA1X'\xA7**}yaL\x8Ax\x98\x16\x87\x80\xA7\xE4Y\x81\xB1\x15\x14k\xB5Lj\xB8\x0E\x0B\xB8 \xD1\x94\xAC\xEF\x96o\xD4\xED\x87\x07\xC75\xAAus\xBE\xB4\x1D\xF2j\xE9\xB1\xFD]\x17{\xE3A\xEEs\x074\xF6\x94Ca\xB9\xE1\xF3\xF0PC\x16g\xF8|R\xC1C\x13\xED~\x8B#\x1E\xFD\xF4T\xE1\xDC\xB9\xA6Ap\x86&\xA8\x12\xF2\xF5\x11\\xDD8B\xA9K\xD0\x97\xBD\x15\xFF\x0E\x01\xDCf\xEDJE\xB4I\x03Sp\xEE\x89v\xB9I\xFB\x1A\xAE\x07m\x04\xAF\xEB\xCA\xB0G\xFB\x96)h\x0D\xED\x89Q\xC8\xD4\xA4\x13\x15*\x10\x81\x16\x15\x8E~\xC8\xD5W \xD46Va\x04\xB3\x95\xB2\xF8\x04!\xAB\x18\x81\x8A*n\xAB>#\xD3\x8F19\xC5q\xAA\xC4}\xD2\x0FS\x1B\xA2\xCB\x8DU\x97,\xC2M\xC7u'O\x98\xEB\x1C\x84\xEB\xAB\x17$[\xB1\xE8\x8E\xC8\xC2=\xF2\x19{\xFA\xA0\xFDE\x1B\xFA\x82\x8F?}\xEAp5G\xD5\xA6?\x12\xD6\x0B\xE5>\x09\x894\x05\x17\xBF\e\x1Fn(\xCF\x1E@-\xE2,^\x07O\x1C\x16\xD5\x88\x9C\xBFc\x03y\xD6\xDEk,\xC6\xBCDLtMI\xC3L\xAA5\x12ScQ\x1E\xD0\x01O\x10u\x1A\x0F\xDF5\xF9\xA8\xE7+\x03\x88z\x08pguW \xC5EO\xA4\x04\pu^)usL\xF4\x12\xB8\xCD\xB4\x97"6\x03\xA2\x8E\x87+C2\x10\xFA\xB9\xA33\x09\x83\xF4\x93\xC8\xF3Wv/\x1E\x90\xD8\xF4]\xAC%\xC7;~C\xD3\xD2S\xED\xA7\xDB\x9D\xE3\xE8\xA0\x0C\xA2$1\x0B\xDC\xCC\xEE\x94\xD77\xA8.\xCB\xD1\\x03r\x8BnCMn-\xB8U\x87\x7F\xAF\x0BT\x89\x01U\xC6\x941\xFDvO\x12\x16\xD6\xA3\xD9\xC1\x82\x0C\xD2\x7FM\x1C\x113r\xCB%\xEB\xDEK\x1E\xB4\xBD\xAB\xD1Bf\x0B\xAB\xB8\xEE\xC4\x0E\x99\xE0\x12>\x97\xEB\x1D\x0D\x0D\x0A\xC22\xBA\x0CM8\xF1\xDF\x1F\xFB\x8E\x94\x90\xA3\x94\xC8(\xB8\xF2\x85\x83\xB9\x1Ew\xB6&\xF2\xA0\x05\xA1P\x19\xAF/\x09\x94\xFD\xE8=\xC64\xF3Q\xC0\x07.*\xD0XF7YJk2Y\xA7\xC7\xB8\xBC\x8F=r\xA9\xE1/-\xAF\xC2\x84\xB9\x16U;3>\xD5\x1E\x15!\xF9\x015\x80L1\xBB\x8C2\x1B\x94\xC2i\x9B\x0F\x09\x08!\x96\x0E\x98D\xE2-M\xBAs\xCD\xA4\xAA\x1E\x93\x14\x94<\xCE\xDF\x0CoT4vv\x94T\x9E\xB8\xC1p\x8D\x98\xB4\x99\xF7J\x1Eo\x82\xD2\xAB\x16\xE2>t*\x10\xC5"\x13\x05ZvkG\x11w\xF0\x9Ap\x82\xF3\xC5\xEB\xCD\xDEK\x17\xDFC\x0B\x15b\xF7O#\x9B\xAB\xF9\xE8I\x8E\xE9\\xD2~*\&U32\xDA\x1CW,\x1A\xA7\xE9\x81\xCA\xC3\xE5\x84\xA0\xF4\x14\xB1I\x17\xD4\xE4l]p\xA9H\xAF\x14\x12\xFA\xE7\xB1h\xC2&\xC1Z\xE4\x9C\xC2Wl\xB0\xD6n+a-\x7F\xDF\xE1\xE3\x9B\x12\x8A*G\xF0of1\x1A"\x86u\xF9\x87\x11Y\x8B-\xAD{\xA0\xE9[\xA3\xD7\xD9\xCDV\\x8F\xA1\x13\xB0\xA3\xA5\x93\x9D^\x1A\x7F\xC38\x8B--$Lr\x9A:\xA2a\x01\xD8\xA2\xF8\x96\xDD\xCB\xB6\xB2\xABc\xF6\xC8\x99\xF2\xBC\xB8V\x1F\x00\x9C\xD9\x0CX\xF5f\x89\xD1q\xA5\xB9\x94\xA6F\xDF\xC7\x94\xAA\xD7Q\xEA\x8A\xEF\x12\xA0\x89\xB4Gd\x98(\x81\x17m\x122\x9E\xD3M\x06\x7FwP23F\xC3lb\xF2\xE4\x8E\x12\xFB\xF3\xDAwa\xCC\x89\xF3=\xE4\x11\xEC\x90U\xEE\xC2\xD3\xE6\x85\x05\xA9\x99k4\xF3\x91\xC937\x80\x07\x05R\xEC\xE4b{\xB00\xB1y\x95\x82\x96\xBCl.\xB8\xCE\x87&w\xC88\x05\xD09\xE8\xC3+\xE4\xF6\x0B\xF8\x80\x8Dj\xA4\x91\x81\xBB\xF5U\x85\xED\xEEA\x1F\x8D\xC6\xD3y\xA5\\x04l\xDB\xC2\xF0\xDF\xC2\xB8r(\x1D\xE1\x17\xAA\xC9\xA0\xAE\xF8\xFD\x8D\xF1\x99+\xCD\x1B\x8C\x155a\xEF#\xCEY\xB9Y\xAF\xE5\xA25\x01/\x8Fs\xA7bm\x04^\xFA[\x9Eqr\xA9\\xBD<\xC9\xC9#\x12\xF5\xA3{\xE9\x08\x02\xBC\xB4\xDC\x0C`m\x8Fx&\x0A\xE9A\x94\x87\xC2\x9A\xC9(\xCBd\xC4O\xE5\x1D6=\x87\x8EE\xB5\x94\xEB\x81\x85\xBB<\xF1BdJ\x00\xE33KN\x82\x11\xC0F\x9C\xFEi4\x1D\xC2x\x0D\xCE\x0B0eH\x1C=K\x07Y?.\x13\x11<@\xD4\xC3\x0F\x1AbG4\xC8}\xFDW\x91\x05\x12\xB9\x93\xE3N8%\x0CY\xB6\xA1Fv\x91\x9A\x84\x97U\xCD\xFF?\x1F\xC9\x01\xDC\xEDQ\xB7\xF2\\x85D\xDF\xAF\x15\xFD\xA7<*K\xC6)-6n4\x80\xAEQ\xD0\xAC\x96\xC32\xC1\xBE68S\x14\x1El\xE5\xEDg\xA0-\xC0\x1C3K%n\xF9\xE1\x04$-\xBC\x91\xB8\x9A\x14\x03m\xA1\xDC\x01~3=5\xAD2@(\x0B\x14\xBF\x04\xC0\x88mS\xD7\xF3\xB3$\x94\xDB(\xD6p\x17\x84\xCA\i\xD6\xAF\x07\xC2\x1BT\xB1T\xF2\xA5s\xE3\x1E\x9Agm-\xFE\xE1\xB0\xD0\xAAD"\x1C\x10\xEC\xB4\x0CkJJrW\xBD\xDA\xFA",\x97* ]a\xF2\x8D\xABl$\xDCj\x9C\x95\xD5X\xF3U\x02h\x04\x8B-\xEDf\xFB\x8AE\xE1\x9D\xFAO}\x80\xA3\xF3\x89\xB0\xDFcO\x1E\xDF\xDDL1\x95D\xF0\xAE\xB9\x84\xE3\x1Ee\x1C\x09N \x1D\xC1o\xA1\x92.l\xBD\x19\xB4T\x89\x94\xBF\xD6I\xAE\xB4\x16\x181\x97\x0C\xD4]\xDD\x08\x94\x88\xE0\x97l#\xDC\x82\x8F\x8B\xAF\x1F\xD5\xA3X\xE5\xE3\xB3j\x08\xDB\x0E&\x99~\xAC\xFE\xD7\x02[D\x9B\xF9\xAEk\xBBZ\\xEC\xCA\x10V7\x8D\x06\x15A\xA4\x17\x8A\xC4(K\xC0f\xA9\xB9:\x9C\xBC0\xBA\xFED\x0C\xA10\xBEi\x1B`\xBC\xA9\xC6\xA0+\x0EO\x0F\xA5\x00\xE0\x84|\xD7\xA5-\x90-o\xCD\x10Z\x9B\x03\x10\x81\xD37\xA5\x84\x83\xDB.\x1B\x10\xE8fo \xB5\xB3\x9FD%\x8FaIr\xB3\x0F\x10\xAF\xB0\xA0\xC89\xFC\x8AQpf\xC8\x18U\xF6\xCA\xE5\xD4\xCE\x1A-\x8E=`\xAEN\xC8\xCC\x90\x8Fs\xE4\xDE\xF9\xC0\xC0v\x8C\xFEZF\xBA\xCA\xEE\xD43\xADV[\xC6J`ouH\xD3\xBB\xACx\xB5I\xC2Y\x1D\x095\x81U\xEAv\xAB\x9F\xF3i\x19>\xA6\x87UM\xC5q\xB1\xF5\x10zNp\xD7@\xB6\xFB\xF8\x9B\xD87b\xB8\x81DP\x8DGGzk\xDDj\xBA\xDB\xEB\x0C\xD0\xDFUW\x8A\x01,\xA2\x9B4\xA2\xBDpd\x18\xB1\x08\x84\xF3\x0Ap?\xEA(;\x13\xE6\xC3\x13\x05`\xBA\xF6\xB9h\xEF\x0D\xB1\xD4\xF5\xB7\xE5\xDB\x93\x90Oq\xC8\x9A\x9F,\x8E\xE1\x16\xFE\xCA\x13*\xC7\xB6\xC0\xF0\x18\xAC1\x1F\x84nz\xDD\xCC\xC8\xA3\xE1\x07\xDE \x0F\xF4\x11Q\xC1'|\xFC\xCA\xC5y\xFDpVd\xCFZl\xA4\x17G$\xB4\x0F\xC9\xACG\x88\x0AO\x1F\x1Bc\xE2\xD8\xE8\x05\x02<#\xF2\xD1\xAD\x08(0Eo\xA3(\xDC\xFB (G\xA8\x0E\xA4\xBC\xFB\xF6\xE0j\xF1\x822R\x88\xF5\x7FnK\xAA\x8A\xC2\xEE\xE92\xDE\xF2s\x0D\xDD\xD2\x83U^y\x10\xF3-hwk\xE0\xA6:\x0F\x9F\x06\xAD\x84\xFE\xE5,\xAC\xFC\xB3Z\x01\x85\xA3\xA9P,\xE8\x92\xD3x\x9B>qL7\xED\xA58\xCB^X\x9FA\xC6\x9B\xC1\x88\xE4\xC6\xE0\x13\xBD\x834\x99\x08\x19\xC5\xAE\xB2\xAD\x86\xDD\x8F\x06\xB2\x1D\xC9\xC8a\xAB\xCA\x1F\x94k\x85s\xA8\xFBD\xBB\xD9\xB1\x7Fdq\x08\x8D\x05c6\xC8T\xA1\xA4\x950p\x1F\x17\x10,It*\x92z\xE4]\x7F\x8BXE/H8\x92>\xB8\xCD\xA5\x9C\x0F\x85\x1DT\xDA)\x82\xEE'x?\x06\xECAu\xC4#Q\xCF>\xC4\xAFmLOP\xC1!\x92\xC6\xFD\xCD\xA80\xBEt+\xD4\x1F\x19OJ\x1A\xCA\5\xAE~\x0CU\xE5\xEB\xF4"\x14V\xD7\xDB\xE97~\x8E\x05\xD3m\xB7\xD5\x8B\x19\xAAC\xDF%\x0A\xEA\x98\x1E1\xB8\x1F\x1B\xEB\xDB\x08\x1F\x9Fn\x11\x8E\xB0\xC3Y\xFD\xEF+\x924\xC7a\xCD\xA0\x9B\xBA\x01\xA4(\xFC\xC76\x14)\xC4\x11\xF8\x94\x953\x0A\x82\x1A+\xD8OP3\x98\xD0V\xC0gG\xA1t\xD4g1\x91\xAA!\xDDU)\xCB\xC8\xDC7\x16\xA0\xBF$\xABj\xBC\xE6P\x19S\x94\xC6\xFBe\xCD\xCE\xBB\x14\x18\xBF}\x83\xE7/\x9Bs\xEE\x1E\x1D?\xF4\x0Cej1\x1A/\x8D\x92\xCE;\x9F!\xD8\xE5\x1A\x1B#\xC6<\xC5K\x13\xCD\xA7~\x1E0\x0A\xD5e\xC6\x04C\x00\xE7\x14Q\xEF\xA0(\x93,phC\xCExh\xD6\x96p{*J\xF3\xB1k\x09\x8C\xDCU\xEF0\xEB-\xAD;\x93\xA9\x03\xFD\x1D\xAF\xC2\xF2\x965]\x80\xA7[\xFA\xA63\x8C\x04\x89\x91\xD8\xC0\xC9x9p\xAFZa\x97\x80I\xCD[:\x0B\xF5\xBB\x90\xF4U\x94$\xF5\x8B\x0BU\xFB8]\x86\x02\xAA\xB8\x89\xFE\xD0\x9B\xAC\x1B\x18;x\x05=\x95\x19\xD5{Q5\xF3:\x09\xE9v \x1C\g\x07\xA6w\xF5J\xD0s8\x9D\x84\x04\x09\xB2U\xA3&\xCCa\x13\xA2\x1E\xDC\xDF\xF7\xF2\xEF\x1C'<-\x9CBf\xB6\x1D\x92%\xBF\xFF\x1E\xD7\xCE\xD5\xD6/f\xB2\xC6#>\x1F\x82\xFB\x886\x90}\xF5|\xD8\xE3\xF7,\xF2\xD8\x89Y\xF7,\x91.^\xE7\xB2Vn\xB7\xBDv\x81iV\xFCZ\xCB\xF6\x1F\xD4\xF0\x9AB]\xAB\x02ja\x8F\x7F\xD2<#NK\xCA\x04Kt\x11\xDBF)z\xFB8\xAB\x1C+\xAE\xC3\x879\xD2\xC8z\x1D\xC7\xEAR\x0F,b\xD1\xAA\x81n\xADg\xBD\x8A\x9D%\xF9r\xB9\x87\xE8\x91\xA2$\x9A\xD6\x82\xA2|\x1B\xA9{\x91pc\x06\xAD\x18\xA1\x96x2m]W\xB6\xF6\x1Ei\xB6~?\x87\x96B\x8B\xCB\x0A\xDA\xC3\xA1\xEE<\xC0\xA6\xAF\xF0t\x9E8\xEE\xDE7EO\x9E-]\xC0\x97\x1Br\xD6\xE3\xCBe:\x1CW\x97*r\x011\xDDj\xF0\x12\x096m \x80\xF4\x04\xA6\xB6II\x97\xCC\x81~!\x80\xEF}1bO\xD6T\xDC\xCF\x8E.D\x85}l\xA6X\xE0p3/\xEA\x09\x1B\xFA'\xF9\xBCZauS!\xFC\xBE\x08K\xE5\xE9\xDA4\xEF\x82\x12\xB1\x006^\x16\x8E\x83\xF8\xA69P\xD8\x057.\x02\x8Dw\x1C\xE4\xDB\xB9\xC5\xD2\x98\xA7\x07\x98\xFE\xFE\xDB\x1D\x81Na\xA9\xEAa1\xBA\xD8\x04\x07\xC8\x09_cD\x86\xDA\x1B\xA6\xAD\xB9\x9D\xB7Z?\xB6h\x02J\x8C\xE5\x83\xE3\xB8%\xD0\x1A\xE9\xE6m\xA1\xFF\xD6\xC6v\x81~Y\x85\xB7\x14\xBB\x16>u\xC8W\xB1\x8F\xCC\x96\xED\x16\xB0[\xD0r3\xCD\x15\x96\xDA-\xF3\x08\x90\xCA7V\x82\xD9\xEA\x9D\xB2~\x8B\x15\xAF\x9C\xD4\x86\x0EX\x93KW\xF9\x84\x8C\xBD`\xD5\x83K\x067\x9C\x02\x9B\xD6z\xC6\x19qTh\xB2\xF6^\x85?\x98Y\x9F;Mk^#\x0E\xC5\xB1\x11\xFF\\x8AO\x81?\x86\x9E\xF9\x14A\xEE]\xAA5\x09kJiu\x9D"9\x9D\xF9[>\xE3\x9D\xC0=\xEDy\x15\x14o\xBD\x8B\x1Fz\x02\x91[\xE3E\xB6\xBF\xEA\x8C\xD8\x03\xF8J\xFE\xAE\x12(\xE9:h\x91\x14\xC4Z\xE3B\x9A\x92\xF03sNcN\xD6\xE9\xF6\xC4\xD4UH\xE0\xE1\x85y\x04\xAF\xDF\x8B\x0DQ\x831l\xDC\x8E\x85\xB5\x8D&.\x9Dt)\xB9\xFD\x0A\xD5\xC09\xA8[\xAF\xB0I\0\x1BD\x7F>\x08\x99+\x03U~\x15\x9E\xC9\x1D`\x9C\xD0\x1E\x91\xB6\xB7A\xDDM\xFF\xD1\xA2(\xA0\xF6\xC3q\xB43"\xD2\xE7;\xF9\xA7\x14\x8EO\xF4*M\xB5\x88\xF9\xC2\xFD\xDD\x16I\x1F\x0B\x0B\x1D\xE2\xED\xE2l\x83\x17\xC9\x03)4u\xA7\xACN*\xCD\xEF\xBF\x04Za\x8C\xE1\xEB[\x0C\xDE\x80\x1B!\xB5^j\xDAB\xC9i\xBF\xA2\xED\xAC_\xA8^\xA7\xB3]\x02}\xDF\xD7\xBC\xE3\xC0\x1C\x92\x8B\xD3\xF5-3\xFC\xE6F\x9B\x89\x92\x09\xC7\xC7FB\xF4\xDF\x10\xA0n\xB1}\x07\xD5^qn\x7F\x04\xD8`\xE1\xA4\xCA=2ebWl\xC5\xF5\xCB\xF0[\x94\xCD\x01#\xDC\x1E-a0M\xA6M\xBB\xFA\xBBN{\x17\xA7\xCBU\x96\xC2)\xA3\xF6\xE5DYl\xBF\x90g\x95\x04\x9Cc61\xCBvO\xF4\xE5a#\xE2\x14\x92\xA8\x997[\xAF\xF4T\x1D\xE1\xA4\xBA\xB38\x11\x91S\xEA\xE6\xB5lSl'\xC6g\x97\x02\x87z\x84\xBE\xAB\x92g\x17\xA6x\xBD\xF7\xD9\x11[3\xEA-F\xDA\xC5\x1F\xC0\x95\x84\xC9\xF5\xAD\xD8c\xBA\xE5\xFDj\xF4)&\x146CN\x80s\x81\xB4\x99O\xC4qP\xC4\x88\xA4ia\xAD!\xEE\x86\xF7\x97J\O\xC9\x98\xC9@\x14G\x1FwP\xE3T\xA8\xBA\xC2\xDB\x89\x08=t\xB4\xB9M\xCC\x1Du\x1E\xFC\xED\xC2\xC2\xD2\xE3\xD5a]\x9C\xB2\xE6\xAF]\x03\xD2\xFF\xE1pK\xEB\xF5\x1F\xFFC\xDD}\xCF\xB6\xE9\x15H\xDBL1\xA1C\xE2*\x8CQ:\x1C|fj3Y\xF8k\xFD{\x82n\xD2\x93\xA2g\x13\xFD\x0C\xF8\xEF\xA7\xC8\xB1\xD6>++\x0B\xDC\x07A1\xF48\x84\xEF\xAF)\xE4{U4<~\xC1\x07)\x85\xCCk\xE6 \xB6\x0D=\xE7X\xD9\x96\xC0a'\xD4\xE1,\x0F\x80P\x81\q\xFB!\xAC\xC8_\x15j\x04\x9AH\xA6\xAB\xAC\xA0\x18\xC2\xBFg\xF0\x9B\x0B\xCC\x1A\xF9N\xDCFk\xC5\x88\xC2{\xE99'-\xC5\xE9\xC9\x96\xCF\xE4D\x0A4J\xFB\x87s\x8B\xEAEq\xF1\x92\x8BsP/\xA6\xAE^o\xF5\xEA\xE9\xF8\x10\xB5P\xA4\xF3Mp\x00\xD3\x16}\xEE\x99!g\x90{\xE1\x0F\x00BG\xEA\x8F\xCEQ\x82\xDB2f\x02\x02\xD8"\xA0\x81q\xE6\x87G\xF7\xAB\xE6\xC9\xA7s\x86\x83\x95o\xF7\x1D\xC2\x8D\xE3\x1Dzp\x85bS?\xC0A!\x0A&i\x86o\x97\xBDkyy\x8Bv\xE82\xB7D\x17rb\xC5\xC3\xE2\x06\xC1\x0B\xBD\xC59\x89lA\x95\x0B\x1F\xA8\xBB\x97\xF0\xE8@\xDD\xE5k\xC9\xAE\xE9h\x7F\xA1\x0B\xF4\x88\xADt<:\xAD\xAF\x0Dv\x1C\x0B\xE00\xF2\x1B\x15\x91\xD6?\x9C\xE6\xCB\xBE\xF6\xE1\xDD\xE4\xF2\x8A\xDD\x9A\x01\xEA\x81\x8A\x19\x9FF\xEB!\x16Wq\xCBcZ=\xC4.\xA6j\xD5<\x8A\x96HB \xEF\x94\xFF\x1F\xB4\xE3c,\xFA\xB7\x14\xF4\xDB\x8B\x92\x0A\x88\x9A+V`-}\x8F\xFF\x08\xBB\xA9\xB6'N_\xE4\xFA\xFB\x90\x1F*4\xBD\xFCW\xDF\xA30\xD2hm.\xEB\xF3\xF8b\x7F\x17A\xC8\x9B\x8F\x0C\xEF\xF5\xDFDJ(\x87\xCB\x05\xEE\xC0\xA3\x14Pu\xCF\xAF\x18\xD0\xBDE\xDDg\x07\x97\xC3\xC4\x0D\x8A\xD9\x9Aj\x8C\xB3J\xBFD2Sb\x0A\xAA\xF91V\xDFP\x09\x16\xCC\xD2\xBDm'\xE8}\x04\x0D&jV\xD3\\xD0\x9E\xFA\x93\x82\x9A\x93,Y6\x0B`!@\xD0\x91xD{\x050\xD1Vc\x0A|]\xA1rk\x87\xD5\x1D\x90\xAC\xAE\x85\xC9L\xA9\xA9\xB2\x04Q\x0E$n\xC2U\xBF75`\x02\x8C\xE4\x8Ey*\x1Cb\xA4\xF4 \x84\x0AL\x1C\x83+B\x1F\xBER\xB0%\xF8\x1E\x8FAn|\x17\x99\x9A\xE7F\xA5\xA2\xD6\xAB\xCB\x1Dz\xFBj\x0D/=`|*\x8A\xA5\xFA\xEE\xC5j\xC4\xA1\xB4\x89\xA4\x01\xB2+\xB0\xB7\x13\xAF\x10M^<\xAA\x93.\xB1\x13\x1Cf\x1D2\x85\x9D\xE80\x8F\xB3\xBC\xBA\x89\x84\xCBm\xD3\xB2\xD2u\x06+"W\xC9c\xB5\xB2\xE6\xF4\xAA\xC7\xC3\xE9\x8B\xAC\xA3\x9B\xE5)e\xA0\xCD\x05\xC9\x1C\x18R3\xDB\xE3E\xE1V\x06(\x8D\xABG\x03h\x9F\x1A\xAC\x12\xF71\xB5\xFB\x145#\x97\xE4\xB96\x9F\x03\xA6r.\x0Dhz\xFB\xAE#\xEB!\x0C,\x0FLT\xBC\x19f\xE6o]\x85\x0DjL\xDA\xBF\x16\xC2a\xB6\x91\xFD\xFB96\xF8\xEA\xFD\xC0;\x1B\xB9\x8Em\xD7\xF1\x01\xBAR\x1F}w?).K\xDDX\x16\x7F\xD4\x18\xD9\xBB\xABM\xA1\xA2t\xE1Mf\xA9\xBE\x89W\xBFJ\xCD\x0F\xBB\x80\xE8\x1A\xC440\xB8\x82O\xB3+\x12G7\x83$r\xFD\xE2\xE8\xF7\xEE\xEE\xFBl\xDB+\x1A^d\xEC5E\x8C!\xED{\xAE\x9F\xEBk\x15\xE5\x04\x8C\xF4\xC4rC\xB2%\x90\xAC\x9A\x0At\xDD\xD8\xEB\xDFl\xED\xF7\xC4\x9D*\xAB\x88\xA0b\x02R4H\xB2n~\xB4\xFFf\xCF\xE8]'u\xF5%\xA7\xFB7\xBC\xFA\x0E\xDB.\xDB|\x95\x9B\x1D\xE3\xD8T\xB3s\xEB\xF9\x81\x86\xCAJ\x84z%}l\x92d^1\xBC\x8Fj\xE7\xA9\xD2^\xB3KY\x18\xC0\x0F\xC9\xFEJ\xFB\xBC\x08\x0AN\xA3\xCF>$G\x00\xBB\xA5\xDE\x07Xk\xD8\xE3\xE5\xEA\xC1\xAD\xF6\x83_\x0E\xF6\x80\xDB\xDD\xDC(\xBA\x8D#\xDD_K\x8A$vc\xB8\xAD\xD9'|=\xC9\xB8\xB9&\x0A\x10\xB3g\xE3\xAC\xAB\xEA`\xC2\xCF\xFB\x1E\x1D\x85e\xD5\x8F\xB8\xFC\x86\xA7\x10\xEA\xCE\x17\x1A(\x1A\x0Eh^\xCC\xE4\xC4\xE9CA\xF0\xA5\xD8;\xF0\xFC\xFD\xB8\xCBg\x95\xD4\xD2\xBD\x9E\xA8^/\xF1\x82@\xB6z\xBA\x08\x04\xD6$R\xFC\xC6\xE7\x10\x10\xED\xA5PC\xB0\xEE[`\xFF\xDC3\x10\xE6\xBB\x95\xA8\x1DmEX\x0CT\xB3C\xF5\x17\xA4\xC7\xB3a\xEEnnu\xB4\xD6\xFBz\xB8\x8D\xFC\xB6\xC5\x00\xD0\x9A,/\xADVx\xAB\xF1\x8B\x0E"du\xA1\xED\xBD\xAAX2\x83V\xC55\x9D\xE6\xDB\xC3\xBA\xF1\#\xBB{\x92o\x9Fk}\x8B7\xE8\x86\xA5\x88]\xA8\xE8\x9B\xA8|+\xF0I\xC2.p\x8D\xC2\xB0\xAB\xD6}wyM\xD8\xA9\xCCu\xCB\x08\xF7\x0B\xCA\xCA\xE1\xD1\x09&\x96\x84o\xD5\xD5\xC6\xFB\xBD*\xE1\xED\x98\xFC\xD4\xE4\xAA\xA6\xD24\x02_N/\xAFO\x11Y\x14F]\xC8S\xF5mt\xC9\xFD\xE4`\x9BT\xAFqM\x19\xF6W1\x82\x95YVp\xE8G*\xA8i\x9A\x15\x89K\x93@\xE0\x8DG^\xC4\xB1~\xBFG\x95\x93LD-\x80\xBER\xDC\xF9\x97H^\xFB;D\xBD\x1A"Z\x04\xB2\xF8\xB5\xCC%\xC5\x05g\xC4J\xF6\xC9\xDF\x1Fk$\x02\xF9\x87)n\xDB|\x13\xD3\x82q](\xFBzd\xF9\xC3\xEFHO\xE2{-)\xA0\x94\x80\xC5R<\xF1\xBE\x1BSJG\xF5\x07\xF6\x0DL\xB3}?\xA4\x0A_\xA0\x827\xA2\xBE\x09<]\xA6\xF7\x10\x0D\\x0D\x06\x00\x87U\xD3\xD3t\x0C\xD8m\\xCB|\xB5b\x1D\x86y\xEE\x87\xB8~u\xE2z\x06\xCA\xE07m\xC3K\x9F\x920\x10\x19\x9B\xD9\x15\xD0\xCF\x1A$\xC0\x82\x03\xE0\xE7L:\xAC\x16\x06\xD9\xB6\x87k\x19\x95.\xBC\x14qO8\xFE\x93y=\xF0}\xB0\xEA[o\x0E\xC3z\xE0e\x0680\xBDh\x1E\xC4\xF9\x81CD\x1F\xBE\xE2\x17.\UA$\x99\x7F\xB2\xB8}\xC3\x88}<\x11\x16\xC4\xE8\x97K\x10S\xC7Z\x0Au#\xC4\x8EWJB\x0F\xB8\xC4\xDA\x17P_~\x97\xBF0\xAC\x97\x16\x98\xCB/\xC8\xF4\x80\xCD~.\xE2\xDE$\x93N\x96\x13\x93K\xB2\xDCZ\x99+KLiL\xD78.P]\x91:\x1E\x90\x12\x11\x90"$\x11\x16\xA2\x0D7'\x9F_=\x94\xACL\x05\xDD4\xCD\x8D\xF0aq\xD9W\x81\xE82\xB7\xBDl'\x00{\x9A\xEDC\xB4!\xC2\x91Mnjx\xE0\xEB\xCC\xF8\xFB&\x97\xF9\xEF\x8A\xBA2\xD6:\xD1\xEA\xE0\x14\x9A\xACJbe(U\xB4\x88\xC3\x95\xE9pt\x83\xED\x13\x02Ra\xD9m\x86;e \x14\xB0\x85o \xE1V\xF0V\xF7\x91T5\x13\x11\x15\x8EH\x06\x0Fu\x00\xF5p2[\xB5\xAC\x1D\xF9\xFB>\xD7b\xED\x8B\xB7\xEA\xD7\x8D\xE6\\xF9\xA25\xD7\x87\x09y\xBF.\xCB\xE9\xB3/~T\xEF\xBA\xE2"\x84\x84P Y@\xBEq\9\xDCH\x0A^_\xEC\x96\xC2\x167@\xC2K\xE7\xAD<7\xB9(;\xFD\xF4AS1\xD2\x0CV\x090\x91\xCAzN\xE7\xEF:%i\xF6f\xCE\x0Aa\x15\xCB1B\x03#\x87<\xF5ig\x97]6\x84\x82\xEDj\x824\x81\xCCX\xF01_7\xCC\x88\xE8\xCD9\xD7\xC4\xF6\xA2\x96\x99S\x03\x96J\xF3Q\xDBw\xFA\xCD\xD9\xA9\x86\x8F\x0B\x1B]\x1BXL\xE0\xBC-SWC\x0DVN!\x90\xE7\x04\xA0w\xD3xA}'\x18I0\x0A`\x02\xD3\x99\xB8g\x19R*\xDFi\x82\xD4\xCB\xC0\xD9\x9A\xD0\x9F\x1B\xB45\xC24\xBA\x8C\xBA\xB8\xBB\x7F\xCE\xBF\x9A\xC4<'2\xF0\xDC\x0D\x86\x91c\x0A\xA3\x7F&\xF7\x15O%\x0A\xA1\xEAr\x12\x136F\x04RLi\x8D;\x9E\xEA\xA9\xDF\x17 \xCB\xA0\xA9\x04&\xB1I\xDB2\xE7\x01\xA8\xC9\xC6\xB4G\x06\xB3\xA1(\xC6\xBE\x8D\xF1O\xBE>a\x8A\x82;\x10\x0E\xC7\x13\x0A4n\xAF\x8B[\x8AMi4\x80t+\x1D\xA8\xB8\\x1F\xD5\x81\xA5qd\x05\xCA5\xF4\x81a\x0E\x17\x0C\xC26K\x8A\xE3\x1C\x86\x04\x96j<\x0F\xF8V\xB9r\xD9\x12`\xC6hu\xD3\x14/\x9D\xA2\x9D\xA14\x83[\xE4R\xCB@\xBEpr\x86INC|\xA8'\x11\xD1\x7F\x07\xBBB{q\x03\xCC\xD1\xB6\x1C\x91\x8D\xA0\xA4B3R$\xE1\xB1%OI\xAA\x08\x8A\xF5\xA0\xF9\xB7\x93\x9CL\xFA{\xAD\x8F}\xFEd\xF9\xAE\xC8\x01\xA5]\xFC\xFE%o\xBF9a*\xC7\xE4\x82\x97\xBE\x87\xA7\xDE3\x8C\x8F\xA3\x15\xBF\x8D\xEA\x85\x05\xE4\x0F\x1B\xF4GL\x029\hy\xF7\x1A\x17\x0A\xAF\xECx3E\x03\xF9\xEC\x96e\xF6\x80\xAA;\xF1\x06\xC5x\x1C\x83\x87\xC4\x0C}\x7F\xAE\xC0\x81\xBB\x9CsPL9\xC6\x11&Q\xA8\xDEI\xC7\xC4\x1C?\xFFd\x03|\xB9\xA4\xA4\xB1\x08L\x8Alt\xFD\x94H\x07\x80\x83\xBD\xA0\xB6-\xC7\xCAu\x91i\x90\xDBG\x91T\xC4\x93a2Hn\x1A7\xAAB\x80-\xE9\xB9\x0F\xCFDz\xE8\x1BE\x05f\x1B]h\x19\x00\xFB'vF\x07b\x98nbj\xD6'm\xA9/\xFC\x93\xAFt:\xC9B\x05\xEBd\xE3m\xE3&\xC9\xFA<_'w\xF8\xBD\xBFy\x80\x07\x91\\xE3\x02\xF0\xFD%\xE4\xEA\x84\xE6\x99\xEB\x8D\x12F\x85\x9D8\x93\x05\xD6\xCB\xD8jg\x1E\x7F\xF1\xE8|\x10\xAD\xA0)T\xB7\x08\x93\xB6\x85m@\x9F\x87B\xD7\xA9s\xED#TO\xD6\x1Au\xC2\x0B\x83\xA6\x09b\xFC7\xA6\x8B\xED\xE68\x1BU\x8F\xC1f\x0DDf\x90FG\x82s\x1F\xD8@\x81\xF9\xB6\xD6\x13\x85c\xEC\xC8\x9CFB#\xD4\xD0\x81/\x1D\xDA\xFF=\xE5\xEB\xB9\xD0\xAD?'\xDC\x9E\xE4\xC4Y\x1C_\x94\xF9\x94\x17W6}O/\x93\xBAy)@\xC0\xBAQ!\xB3\xB9&`!\xA3\x9C\xB6\x84\x00g\x8D\x9C\xC4\x18:\xB6\x04\x05"\xC6\xFCh\xF1,..p\xB8m\x01\xD27\xA6\xF3\x85\xF7\x04\xFE\xBC\xAA\xAEV"s\xBD\xA0\xC1\x06LKR\x1E\xECJ\x08\xEF\x81\xE1\xD9\xA58\xB7\xED\x84\xE6\xD7~K \xD4u\x\xA7\xDB\x03\x17_\x0AMs9\xFFjh\xEB\xE4%\x06Tb&pF\xAD\x95\xDE\x08\xD5\x8Fw#\x8F=a\xC4\xF0\xBDtbV)3d\x1D\x19\x83$\xE0\x1B\xB7\x9B>\xA3\xD1r\x16\xB0\xD0z\xDAO\xB4\xA6\xBEp&2b\xB9-\xFFB\xC8\xD78A?\xEF\x04\x1A\xB6)y\xE4\xBD\xB1\x9F\x12\x1CEDZ\xFD\xCB\x1E\xAA\xA7\xF4\x0AM\xDC\x08w9~:/>(.\x80I\x9C\x10{\xDB\xE5\x8A\x01J\x95\xBA\xEA`~R\xC3M\x18!\xF3\x01;\x9E\x0E\xDE\xD5ux\xA0\xEB\x1D3\x82\x82\xED\xFFt9\xBA\x0E\xCC\x07%\xE5\x0A\xCCh\xB1\xA8[\x7F\xA6\xE4\xDA\xAC\x8F\xEC\x92\xBEv\x8F\xC07\xDB\xA4\xF2\xDF\xBA\xB2]<\x034\x94\xCC!\x0F\x81\x10i\xB5\x8D\xB3p:\x92\xE1\xC5$\x84\x82?\x80\xDAO\xD9_\xA3,3}\xFC\xED^\xDDCf\x7F\x19\xBF\xFDN\xF2C\x0E\xB4H\xA3\xD3\x03G\xF6q\x1E\xB89\xB0\xB5\xBF~KE*c\xA0b(_FT\xF5t\xAD)z\x9C@g\xC3,\xD5\x9D \xDA \x11\x9F\x19k\x98O\xBA,\xA1S\xFB'\x96\xCE\x97\xD8\xE8\x87O}\xA6\xAC\xE7\xFC\x92\x8B\xC9\x1Em\xA8\xEF\xBCK\xE2\xE6\xEC\xD1\xC9\xA2OI\xFD\x97\xC7FGy\x1E\xF9\x9A\xDF!\xD5f\xAE\xE6\xD4\xBD\xF9\xAEO+\x88\xEE\xB3f\xE7(QX\xFD7\x16\x0C\xD1\x00\x01<\xD1\xD05w\xBE\x1E\xAA\xCB\x16\x0B\xDE\x10/\xEF\xA5\x88\xB1Yd\x0B\xFE6.e \xC94\x0C\xE7\xDE\x19\x0D\x02\xE5\xC3N\xBB\xD3|\x9C\xE9x\xF4\x83\x96\xD1\xD3~\xDC]+<4\xDC$\xFB%\x10\xA1G\xE9F&fq\xA3\xBBw[I\x8A!\xBAur]\xF9\xA3\xC4\x07P\xA2\x0CT\xF3B\x0F\xB6\xD9\x10\xB1,\x18\xB5\x83\xE2\x840\xA9v7&q\xA2\xF2;EyOEc\xC5\xFB\xB5\xBE\xCF\x17\x1BrCD;\x8D\x04\xBE\x14\xCF\xC1\xDEe\x0E\xD9\xFE\x1D\xB7n\xC7#n\xE7\xDC\xC4#~{\x89*PHu\xF3r\xF6I\xAF\xF9\xF7\x0Cn\xAC\xCC\x1D\xDF\xDF,\xBADvR\x97\x83\xDA\xF4\xB2x\xA9]\xD2\xF0l:\xF0\xDC\xD6ukgn)2\x06\x88\x1A\x9F\x04\xFA\xB7\x93\xE4qY8.\xE6\xBB\x94\\x0C\xFFv\xE1V\xCF9\x9C\xF4l\xC3Y\xA3\x13\x09\x02\\xBB\xAB\xDA\x0EF\xF4\xC6\x9B\x80,\xAC\x8D\x83\xFD\xCBe\x8D\xFA\x86J2yD\x05\x81\x82\xFD\xAD\xCB\xAD\x12F\xFA\xD0\xB2\x98\xAF\\x00\xF8\xEB\x9AN"\x99\xC9G+\x03\x81\x98\xD2b\xF2\x0BF\xEF\x0D\x1E\xBF\x08>\xA9~%\xFCP\x8F\xDB\x9D\x08-\x91\x04\xFB\xF1\xA1\xD7TU.k\x86\xDA\xD4\x16\xCB\xD8S\xF2\\xB9\x84\xDB~m\xE5\x02l">\x08<\xEC\xBBF\xAD\xC5\xDEf\xFD;\x14\xBB\xF2\x90\x10B\x814<\xA7\xAA\x17i8\x0C\xCE\xB1\xC24D\x84\xB5[\xEA\x86\xC5\xEF\xAF\xF0\xF1M\x83Di4\x1A|\x94\xD0%g{\xD0#\x02%\x11\xE4\x16\xB7\xC8\x036\x17\x0AhKrf+\xF9\xF6\xD7\x17\xED\x93\xD5\x12\xB9\xB9\x7F_\xD4[\xEA|2\x83\x13\xC0\xBCj\xBD\xB7Y\xC4QJI E\x89/\x9F/;\xC1\xF8\x15\xE2?\xEB\xF6\x9A\x05\x8A\xE7\xED`Y\xD6\x93b\xF3\x9B\xF8a\xF7\x1B\xC3\x09\xE0\xD7\xAFE\xA1o\xA0\x05{g\xDC"+\xC5H\x13\xC0\x0A\x94\xDA{\xE7\x16@\xBD_k\xF0L\xB9\x89>\xE8\xF9(6\x0B\xB3\x98S\x8F\xF05#\x86\x1E\xD1v\xB3mU\xE3h\x15\xFB~F\xFA[7\x1B`\xA3\x1F\xE9\x9C\x80U\xD9\x9DO\xE5F\x0B\xC5\x81'Vd\xACay\xA7\xEE\x80\xF2p\xBE\x0F\xCF'\x04)\xA6\xBB\x89\x85H\xF3\xC0a\xD2\x17}\\xC7\x945,h[\x0E\x14p\xA5\xBA\xB9V\xBC\xD2\xF29x\xBC\xA2\x09\x0D_\x13\x94l\x84\xA4z\xC79\x15gGrnq(\x8C\x92\xE3vGH\xDC\xD82E\x03M\xD8\xEAh\xD9\xEC\xB2\xAF\xD5\x11\x82\xC4$\xEA\xFF\xE1H\xA8\xF55\xD7\x1E\x8F<\x06\xE5\x82d.\xC6\xA7\xEE\xD6\xA2J\x88rWC\xDA\xB3\xE3\xB2`b\xB1\x9D`\xD1hR\x99\x1D\x1D\xEE6\x07\xD1i\x8FU\x04*."L\x97\x90\xD2N\xB8\xEC\x16e\x1C\x03\xAC\x0E\xC7\xC3\xB7\xD7\xF0'\xFC\xD01_M\x1F\xDAF\xEC\x98r\xED\x90\x95\x96\x8D\xC4\x8D\xDB\xCD\xD7x\xC8\xE6\xC2\x990\x1B\x14\x95W\x8D\xEE\xF0\xF9\x9Dr\xE6k4z\xFD\xF3\xC7%\xA3M\xEF\x9C\xE5\x92\xFB&:VH\xAA\x06\xCB0\xB2H\\x1E\xAC\xDE9\xA6\xCD\xEAaGe\xBB\xCFM\x9E\xBBk\x0A\x82\xD8Y\x08k\xD03\xE7cB\xDA\xFDS9\x92Ox\xCD\x82\x86\xB8A\xDE3\xF6G\xEF\x82]\x01\xB2\x96D\x04\xBC\x19opR\x8B\xBC\xBA\x870\xC4\x99\x9A;\x032\x81\x1D'\xA7\xC4\xEFl\xAC\x05a&n\x900\xC8\xDFCi\xE1\xE4N|(#d\xAB\xB8u\x89 \xDA\x1D\x97\x9F\x8D\x7FP5%l\xA1U\xA6\x9B/\xD7\xFB\x8C\x7F\xC4!8:\x06\xB0H\xC5\x06\x85hE\xE0ghO\x12\x17\xC0i\x06\xCBZ2\xBE\xCF"\xC6ob\xC1s\x0C`YG\xFC\xEB\xC6,\x0A\x9D\x87\xA3\x81\x85\xC7?\xD3+71$\x9FT\xEBs\x04\x9CgA+\x07\x13\xB8\x0A\xD7\xA33\x12\xB0\xEC7\xE7*\x04\xAD\x9A9\xD2\x11H\xEF\x11\x97\xCB\x0A\xB4;\x10\x8Ary\xDA\xD8\x15P\x8D\x08\xAB\x02\x12z\x0F?\xDF|`3NcXQ"\xA6\xE2)\xC8U\xF3S\xF3\xB9a\xA7\x81Y\xDE\xF2^At\xC8\xC0\xC2 \x89\x88\xFC\x0B\x84\xC6\xC2\xBD\xE8!\x92G\xEA\xCE\xBF\xD6\xEB|\xE1\x0C?\x88\xAB\xE8\xD0`\xE7uf\x16\xBD\xD4\xAF0[\xE87z\xDA'\x84%\xF0\x91\xAC`9\xE0\xA9\xB5\x86S\x19\x04(\xA7\xB0\x8C\x86\x98\xC1yY\xB4\x00\x02`m\x85\x90\xB5\xD5\xA4\x99\x13\xD0\x87\xD9)\xEF$\x1Az\xC4\xF1\xA1\xF8\x8Fj\xF3;\x9EB\x1D{\xE4\xFFe\xBB\xB1\xCD\xD1g\x9A\x1B\xDF\xF2\x9DW\x15N\xAEj\xA5m\x13\xE8\x1D\xD6\x8Fn\x0B\x124Uk\xCC\xD6\xE27\xF4\x94\x11(k`\x91\x01j\x8B9$\x17Lz\xABr\x15\x01L\xED\x0B;O(\\xED\x82\x043\x13\xC7\xD8Ex\xAF\xFC=\x02\xBE\xAD\x9A\x12\x0F{\xA7\xCB\x83h\x8C\xA5\xB0,\x1B\xE9+\xC0 \xFE\xC3\xAF\x8F\xB3\xA9\x1D\xA4\xCAV\xDB\xC4=\xD9\xA8n\x08\xACi\xA7\xC4\x03\xA6@ \xA9|\xA5\xA0?\x89\xA9\x02l\xCD\xA1\x12_\x14g\xF7\x0F\x0Abe\xC6=>\x06\x83WGA\xC9g\xC7!$\xA4\xA5\x1F\xE8\xC6\xDDuB\xD4b8\xC2\xA3\x86\x90\x90w\xD4t\x9D\xA6\x86=\xC2\x90\xFF\x15U\xCD\xDB>\xEA\xDB\xE06!)\xB7YU\xF0L`L\xEC\x1EL\xA2\xAD\xFB\xB3am\xC4\x9DBF\x94\x82\xF5n_nvR\x05L\xB3rJ\xB3\xC5\x8B5w'B\xEA\x85\x03\xEA\x81D\x98\xB6/`\x9C\x86\x02\xC2\x80\xD6\xEE\x8D^"G\xDA\xB1FT\x0C\xA4t~\xA1\x10gx\xB9\xD7B/\x98.\xD8\x95\x80K\x956\x82\xDFdu\xDBK}A\xEDI\xB7\xC9\xF0\xDC1N\xB5\x0A.}\x09\xA8\xB8\x05\xF9\xB0v\xEF<\xE4QsbgnS}\x83\x0D\x18\xA8\xE0o\x85r5Y@\xBC\xE0\xF2\xEB\xBD\xF3W\xA0\x02\xD1\xA2?\x97W\xA1\xD6v\x05\x98x\xFB\xFE\xCF\x92\xC0\x81\x94\xAB\xA7W\xF8\x86ux\x8F\x18\xBDP\xCC\xB1!<\xB1\x9D\xD9G\x0B3\xC88\xBFK\xC0\x14\xE94\xFE\x9D\xB0\xC7&\xEFb\xC6\xD4\xF4\xB8\xC1\x19\x1C\x07\xE9\x1C\xC2\xC6\x08\x0Cm\xFD\x8A\xD3\xDC\xF6X\x9E\xB05\x1D\xC1\x19O\xF9\x8F\xD5\xF7\x0C\x7F\xA8\xEE\xBB\x83\xBA\xDB\xF4\x89\xCBR\xC9\x80\x09g\xD6\x09\xC4b\x85G\x1C\x9B\xD5y\xAB\x15\xBD\x01O\xAF(P\xD8d\xEF\xD0h\xB3\xD9T \xF2\xB1Gn\x9E_O"\xFC\xF7\xD5WW\x14-\x8A}\x01\xA1V\x84D\xD6M\x95~{\x9C\xBAN=\xFEs\x86\xB9\x8F\xC2\xF0|\xC7\x88\xFDB\x02\xD4\xD8\xF6k\x83?\x1A\xFB\x0A(\xD3\xB9_6"\xF4)bW\x7F\xFB,\xF2\xA9\x0A?\xDD)O\xED\xF1\xD1\xBD;\x82\xD4\xE8@\x18\xCB\xC5\xAB\xBF\xE6\xE3\xDB\x07\xB8\x8C6\x8BPw\x12O\xF5\xB5}\xB4@Q{#\x9Db\xC0\x92\xB3\xE0\x16\xCCQ\x0C\xF5D\xBB\x7F\x87\x90\xEA&E\x13\xB8\xE9X\xF5j\x8D\xC6\xB4.\x18\xF4\x83\xF2\x97\xF3{SA\x85k\xA3\x94\xD4\xC0\x0C\x9B\xFF\xC7\xE8\xDC3\xFF\xEB:\xFBJ\x99)\x12\x87\xBCZ\x95\x9BA\xAC\xAA\xA9\x97\x95\xCF\xAF\xF9\xF12\xC6A+\xF1\xDA\x9A>\xF7\xB3\xB8\x8F\x0Fz\x88n\xCEH\xA3\x08\x96\\x93$C\x18\x8B\xA7fT`\x9A\xCE\x9D\xC4\x18\xF7\x9C4\x98\xABgw^\xB6\xF3\xAE\xEF\xBD\x09\xA7\x84w\x9A\xD2H\xDA\xD9>^n\x9CqE\xAF\xBFE\xF0\x9C\x03\x86*J\xA6T\xBC\x11\xE9\xF5-\xAFO\x81\x17\xE9\x8E\xA4\xC0\x91\x93\xF8\x08u\xCC"\xB6\x9A[\xCE\x89\xEC\xA8\xDB\xEC!\xCF\xE6\x9C\xD5\xD3\xCD\xE1\xC6\x91\x9B\xE5\xDDR\xD1\xC2\x9C\xFF\xB0q\xFE\xAD\xA0A\x87\xD4\xA2\x8F\xA1Joz\xC5\x97\x14\xFE\x9E\xECR\xC3\x8C\xBC\x99\xF1th<\x99\xFFk\xE2P\xB6\x0B<\xA5\x80A\xF5\x0E\xD1Kh\x0D\xF2\x85K:E\xB3\x81\x82\xA6\xB2\xB4\xF5\xF94m{\xA18\xA7\xFC69f\xFD\xB3\xEBg|\xAE1l\xA9\xCDu\x06\xFB\xC5k{\xE10\xC6\xE4\x1D\x95}\xA7\x01\x8F](mR\x8C\xBD\xEF_\xD1_\xD6\x1A&\xBF\xD7\xBC\x16\xA4\x85A\x9C\xDA"\xF3A\xDC\xEC6\xF0\x93\xB2\x11\xE1[\xF0\xB4\xDC)Z6''\xCF\xD5y\xF4\x96\xFAl\x8D\\xBA\x90\x17>=\xE1\xD1\xD5\xEC\x9Dxm\x8Fd\x13'\x8A\x06\x09\x19U\xD2\xDF(|\x1B/`\x0FN\xACn\xF0\xD7\xFC\x8B\x1DU\x1BU\x12x\x01\xB3\xFA\x97Z%\x86lk\xB6[\xEEE\xAD\xF9#\xF2c>\xE91O\xBD\xC3+\xDD\xBE\xC2\x97\x91\xC1\xD9\x98\x0E\xFB\xBF%\xD0Us`\x14LHBk\xB8J\x81`\x02;\xAD/\xCC\xED\xB0,,A\xEA\xD0}\xFDO"\xDB6P\xD2\x02\x04Sd\xD4\xE5L$\xA2p\xD1\xB3\xBD\x99q\x96e\xAE\xA8`k^\x84HQ\x82W\x17\xB8\xEA\xEA\xC2H\x0Bv\xFDXy\x9F\x13\xFC\x15\x09\x8B\xD3)M\x0BL\xA7\xF3\xCA\xDC\x9A\x80\x15\x7F\xEF\x07ud\xDD\xDAV2\xFB@\xE4\x94\xF17y@\xE1\x90Qzi\x8F4T9\xFB[\x11\xEBLey*z\xA0\xEE\xA3\xC7\xB7\x96I\xFC\x14\xF0\xEA\xAA\x92\\x1C\xB4\xC1\xB9\xA6_\x1Ex\x0E\x86\xB9\xD57%\x19\x03\x00\xB0\x86\xC1\xE7YZ8\xED]\xE3\xBA7\xC6\xEB$6\xD181\x86c\xA6\xA2\x8E\x9C\xAB\x04\xDC]nC\xA0L3\xE4\xE6\xC9\xEDW\xE45\x01V^\x031eA\x1A1u\x7F\xB5EUk}\x91\xCF+~u\x19 \xDDU\xF3\xF2\xBD>\x87\xB0*\xFE\xEE\x1C\xCA\xED\xABr\xE5\x02\x0D]+\xB3\x97\x16\xA2\xD0\x8F\xE8*b,\xF7\xB0\xF7\x0D\xF0x'i\xD6\x85R\xE1\xDD\x82\xE0\xD5\xA3\x8DO\\xC0\xEC\x17VG\xD3o\xE0\xCC\xE0\xFD\x0C\x81B\xE4\x14\xDAX\xE7\xD4_\x10G\xFCDy\xCEg\xD4\xE2\xB7\x0D\x9BY\xD0oyMP\xB3\x03\x7F\xC7;\x7F/\x86J?\xA5{\x84W\xFFK\xE6\xA9\x8E\x01\xF9\xA6*\xC0\xE6\xB7@\xF3=k\xF5\xB6Q\xAF\xA1\x89\x0E\x94\xC1:\x97\xBE\xAD\xD3\x0ER\xF0\x90\x96\x96\xBC\xD9K\xDE\xB0\x03G-f\x19F\xA0\x9C\x17\xBCc\xCCq?\xC9\x06^t\x8E8\xFAo\xE2\xF5\xEFeJg\x1C5\xE8\xE7\x19\xF7\xF0Y\x1F#\xE0UT\xA9\xA8d\xF2f\x09z\x91\xC6\xF9@\x8E\xCA"\xB4}\x886\x80\xEB\x1DR\x19\xCFUA\x9E\xDBj\xB5\xD9\xE2y{|\xF9\xC0\xA6;\xFF\xBD\xDD\x05%_.\x8DP\xD9\x82x\x8E\xBFL\xA6\x92d9\x1E\x03}\xEF\xFA\x89\xCF\xCDlFe\xD2\xD9\x9B)*ho\xEF\xA8\xDDP\xC2\x89\x03w\xB3/\xD8<\xAEB\xF4\xB5\xB4 +\xA9\x1E\x02@\xE8\x89'\xA9\xA8\x88f\x99<\xE45I$\xB2X\xA9+\x95\xF3@\x8E\x85\x9E\x80nk!\x0F+\xD4\xA7:\x8BM\x16Z\x8AY\x00\xA8\xAF\xBB\x8A\x01\xC7e\xF6\x9B\x7F\x0B\xF5\xC6\x8B\xDD\xE0\x9F\xD5D\xD1;\x80\xFD\xA2\xF5\xD6\xED\xB1\x00\xA4\x89^?\x15%\xF5\xB4\xC3}\xC8)\xE9~\xC3\xD6\xCB\xBC\xB1cy\xA3\x7Fs(z\xC4'\xD4\xCF\xAB\x1D\xE4\x7F\x98\xAD\xAA\x95\xF2ZYuc\xC1.\x9A\x82\x198\xD9\x7F*\xC0#\xD9\xC3\xD9O\x1C*\xC9\xA9}\x04*bnV\x07\xD1\xA0}\x7F\xFB\x0Ej\xD0x\x1B\xCB\x81\x15\x84\xB9\x1F\xBB~&eu\xBAuH\x19\xD4\x8D\x0Bj#=\xC7"\xE5\xC5\xA3\xF2\x9D6\xA6Wt\x12\xA2\xA4\x17\x82a&MZ\x86X9\xE0\x1E\x1E\x87MWgLB\x8F\xD5X\xD3]\xEF \xB0w\x1Aq\xCE\xBC\x8D\xEA]\xD8c\x91\xFD\x1BY\x18\xEF'\x9D"_\xCD9\xEE\xDCT\xBBEuh\xBFh\xF4\x11\xC5\x83\xD2B+\x8A+\x946M\x0A\xC0M\xE6K\x06\xDD\xFE\x0A5U\xECh\x7F\xA9\xB2V%\xDFX2q\x03\xCD\xF4[\xAF7\x051\xA5\x8B\xE6\x04\xFC;\xA3\xB5\x0B\xE9\xC5\xBBG\xC7db\xF9\x7Fo\xC0\x02\x0An\xBD\xA3\xCC\x8F\x8B\x9B\x0E\x0C\x1D{\xC5z/\xA3\x86x\x8A\xB7[M\xD8*\xAB8a\x07\x94\xCC\xA0\x8F\xBC\xB6-\x16\xA2YtH{\x01\xD5\xC8U\x00#r\xA2\xB8{UG\xE2\xC22\xCE`\xC6\xB6\x17\x814!\x9B8`\xF3\xDC\xB2\x9Aa\x01)\xA5^\xFEyW\x0FE\x15\x81\xBEj\xE4\xF1"\x1F\x15\xF9\xE9\xC2\xD2M\x05M\xD4Xt\xDD\xCE\x06fR,\xF1V|\x08 \x128sh\xAC;P\xF0\xD6C\xC8E\x099\xF37\xBFX&#\xF6\xC4W\xB2*\xB4\xFB\xE2\x8A,\x8D:\x87c\xF5\xC3A_\xE1Q\xBB\xE7\x17\xDF\x85u\xD8a\x85V(\x08}\xF6o\xBFV\xB7\xE4\xA5\x18\xC0L\x9Eo\xA8ny\x81\xB2\xDB~RZ\x08\x16NH\x06\xFE\xC2\xF2\xD5b-'3\x91\xE4=Y\x00\xE5\x00\x84\xC3>\x8BD\x0B\xD3\xE2\xBC\x8F\xB1}\xA5\x09W\xE2Z>\x95\xC0\x7Fb\xD2\xFE\x18\x00\xA4\xD1 4\x17\xA6 *^\xAE\x0C\xEA\x84\x96Xw\x01\x05c7\x1Br0\xE3O\xDC\xB5tYH\xDB\x0E\xBAJ\xEE\x89\x9A8\x10\xBA\xAB\x1Co\xFDC%!H\x01\x03\xD6f\x16\xD0e\xAD\xF9]\xF4\xA3U\xB2\xC1\xB6\x1E\xC6\x93\xD2\x9D\x07\xD7\xB3\xF6c\x17\x1A\xA6\xE0\x9Ew\x81\xC8\xA1dK; \xE3\xCC\x9B{\xF3{\x1Fu\x9C\x1A\xECNu\x12-aL\x82\x7F\xBEI\xA4\xECW\xA1\xE8\x12\xB2\xE1\xBD%X\x7F\xB6<\xFE\xA3&\x87\xBC\xC0\xD0\x86\xE7W1\xA2?\xBB\x8A\x92\x97\xA1\x1A\xA8\xAAp\xAF\x8A\x1C\x95\xF6\x10\x83\xD4\xDC\x1A\x0FX\xD4e\xC5\x8A\xB2h\x9A\x0A\xF5c\xC3v\xB9r\xA9\xE2F\xA5\\x07\xE4\x91Cp\x83z\xECb\x12\xF6xB\xA6\xBD\xD9\xDB\x08\xA3\x0A'\x9D\xA7\xA8\x95\xB0\x02\xDFFO2\xE0l\xA8b\x14Nu\xD8\x8Fce\xF6\xE9\xE3\xE4\xA6\xA56m\x0C\xB3\xBE-\x1FD\xD2\x83\\xD8\xAC\xBBq\x92P\xB1}z\x07\xE1\xA5\x85\x10\x92\xFE\x9C`wpnfR\x17\x92\x0A\xEBMdw<\xCC\xC6\xCB\xF6\x02t\xAF\xC9hb@a\x7FU\x04\x8C\xCE\xEA!nP\xDD|z\xF8\x09K\xE2\xECX\x93W\x9A\xDD7\xD2:\x1E\xBCM\xBD\xE5\x91\x92O\xBF!\xFA\xF5\xECJy\xA4?o|\x1D/\xECb_\xD2)E\xA6!\xC7\x01\xEC\xF6\xBD\xAE\x86z\xEF\x94\x8B\xCDU\xB6\x96\x9C\x82q\xC2^\x16E\xF3\xFE\x8F~7\x8B\xC1\xE9\xD0\xA1U\x9D\xBF\xE4z\xF4\xF0?F\x8D\x7FB.O\xF7\x16\xB9\xCEXQ\xD6\x93\xFC8\x95\x8C\xCA\xED\x96\x1E7b\xFF\xA1\x1D\x06%6G\xC2^&\xAB\xB2\xAE\x88\xE5\xF1\xD8/_\xE8\xBD{8\xD4\x0E\xA9\xD5'\xF1.<\x84\xA5n\xA5,\xB4#B\xD0\xFA\x0C.\xDE\x06\xD7\xE8\xC9\xC8\xD6\x96\x99\x7F\xE3\xD8J\xE532^\x93\du\xFBG6\x1F\x09|\xA6;\x02pD\x1B\xCD\xE6Dt\xBC)\x9B\x09@\x09I6\x08M\x9A\xF2\x07\\xFF.h\xD5\x87\xE46\x973\x9FR\x88\xD3\xE3'\x16\xCC~\x983\x82\x97\xD8\xFA\x83\xF5+^}\x0D\x90\xD6\xA2\xD0\xBE\xA3R\x98\xD4\xDE\xE1\x83o\x0C\x06\xD8\xE1\xF7\x81\xE7\x15 \x0D\x8C\xD6\x1C\xBBW\x8C\x92\xE4\xDD\xD5\xE6t\x1F1\xA2\x08\x8DHNq\x7F\xE1\xB9\xF8\xC7\xBB\xD1\x0D6g\xC4h\xCE1\xA5L\x85\x92WgA\x1C\x9FF\xB4\xE5\xA7\x1D\xBC\x93\xF9G&\x8C\xD1v\x96p\x1F\xFD`[\x15~@p!\x0A\xA1\x09\xE2/\xC6\x8A\x83~\xE2J\xE9\xDF\xC6B\x84\xA0\xEA\xA3\x99\xC6\x06\xC7\x0F\xD6(^\xAD\xD2$\xAD\xF0\xCE\xDB\xC2\xA8\x0F9a\x0C\xD3\xA1\x96\x83\xE0\x09\xD0\xA9\x08C6\xDA\x85\xC7\xBD\x03\xFA\xD2@I\xF9/\xC6\xC5f\xF4&\xE5\xA31R'\xD5\x04\xE3\xF8\xEB\x84\xF0\xB6/\xB2gb\x96LV\x12XniL\x92'\xC2(\xC4]8\x18\x8AN\x00\xB4J\x06\xFE\xA9\x92\x99\xFB\x0D\x05\x8A\xA4\x80\x1AJ\xC3\x87\xEF\x0B\xE2=\xDC0_\xF5\x86\x85\xF6\x85\xA4\x13\x9E\x07Y\xB7RaA\xE2\xDB\xA2&\x84\x02\x8A\x81\xE2\xC7a"\x95\xC4D\xD40\x99\xDB\xD2\xF4\xE7\xB1n\x9C\xFCj\x7F\x18I\xCA\xE9\xA3\xBD\x80\x9F\x89\xFAZ\xA4\xD9\xE4\xD2\xD7)\xAB\xB1\xE6\xDF\xE2\xDEuE\xCE\xEAa\x94\xE9\x99a'\x19\xF5:\x9C\xFDD\xF6Cs\xCD\xF1^\x89\xC1n0 v/s\xBE\xD6^%,\xBDi'\x99Db\xEBT\xD7i.\xB1\xA0\x8BQ\xCEC\xAB@\xDDH\x80\x81\x84\xA8J\xFD\\xEEc\xE2R~h\xDC\xFC\x90\x0D\x8B\\xC6\x890\x7F\xDAH7K"1\x9A\xE26rY\x85\x01\xB5\xE8\xED%Y8"\xC3\xCB\x8BT\x97S\xB4\x86\x00u\xDBfJ\x9Ei\x9CS_O\x9D\x8D\xD9\xF9\x06a\xBC-R\xD0v[\x82\xE90\xE4\xFA\xE3\x92\xE1\x06$E\x9F\x80\xDF\xD1\x06\xFC\xC3\xF9\xE6\xA6\x05\xAD$\I\x00&\xF9\x16\x10y\xE5\x8E\x19/k\xF7rE\x82\xB6[\xDE\xBA\x9B\x9D\x1Cg\xE4(\x96\x15\x88G\xDB\xBD^\x82\x1F\xC7s\x99(\xCB\x15\xB0G\xC2\xC6\x8Eg\xD3\xA0\xFA\xD0\x12\x12\x1E\x93\xE7)\x06\x8F\xE5\xB4:\x0B:\xECF\x11\x085\xFF\x86U%\x9C\xF5\x88:\xEF\xBB\xB3\xACl\x13\xD0\xF0\x10\x17\xFE\x8D8\xE4#\\xF1\x12\xBB`\x85\x13\x9B\x02L\xF6|*\xE7\x1Dj\xAEU\xBF\xE1\x0B\xBE\xA0\xD7pc\x9DN\x0D\xA1\x93\xF2\x07"H]\xCDh}\xB5P\x9F\xBBT\xD3\xF0{\x93tVb\xE1\xD1\x04\x07\x98\x8C\x1E\xBD=*\x89j$JP\x8E\xA7\xA5\x11\x1D\xD2c\xA0\xA0*\xF1P\xCC?\xAC\x0A.a\x10\xEDXU\xD4\xB4P\x0B\xEE\xB6\x91\x01*\xC8;\xC8>\xBEy\x86\xCF\xC4J\xD4\xAF9Y\x89\xA8g&\xDC\xA6\x84*\x1E\xCC\x9E\xDE\xAC"\xC9\x83`>\xD4w\xF5~c<\xE23\x1D\x86\xA7#w4\xD3<,\xC8\x83o\xD6\xEBj\xFFN\xA6\x9BV\x1DB\xE1n\xD4\x0Dw\x8B\xFD\xF7\xA5\x9D\x06\xA8\x816\x0C=\xF7\xA0\xFB\xC4\xE0~4N\xAA\x19\xF3\xCF8n\x178\xB7dR\x0DH\x03i{\x9C|\xA7\x1C\xEAg\x93%\x14\x12\xFB\x84\xF8\x9A\xE47\xB1o4\xF3\xBE!\x18\x8E\x06\x0F\xF6\x93\x9Aw}y\x8F#8\xC9\xB3F\x1DpgR\x8EK\x85\xBDb\xC3it\x88\x85h|\xC3t\x93$\x8A1\x1A\xEB\xF7)\x8EL\xDB>\xD0\xFA^\x97~&$\x87\xC2\x96s\xF4\x08E\x11\x92\x0A^\x97"\xCC\x98\x10\x18\xC0X5-^\x92\x06@\xE8\xBC0\xBFY\xD7\x12\x9Ea\x08\x07\x0D\x9E\x1F\x0E]-\xFA\xD1}\xD3'\xE7\x89\x80+\xBD<\xEE\xF5zZ{Z\\x86K\xB3\x84\xCA\xB3\xA9\xEA\xAB\x81\xE3\xDB\xD4~W\xA8\xAC7\xD1\xFB7\xD5\xC3\x9BrIZ\xCD\x97\xFE\xB5\xBB\xD3z\x89t\xD7UDL\x1F\x06\x98\x85\xF2T\xD3\xCC\x05mW\x11\x82,\xF6\x8C1\xD9\x09\x7F\x86\xB0C\xA7\xB8\xEC0\xBA\xD0\xB2W\x0C\x95\xCD\xE9\xE4k\xD8\x9CE\x1B\xFB\xC2\x13\xCB\x91\x8C\xF6\xF7\xBA-\xA6\x1D\x9F\x8E\xB4\xC2\xE5\x00'\xF8\x82\x96\xE0\x12V\xA3RYZ6\x93\xD9\x86\xDD|Sw\xC3\xB2\xA7\x8EX&=\xAA\xB2\xC4VCV\xB2\x91\x04fF`\x9E9\xE7\xB0I\xF8&\xF5\x89\xB6\xC8Kf\xCA\xAA\x0Ci\xFCx\xCC#\xE3b\xEF&\x15\xB6X\x0CcELB@K\xB97\x8E) \x95!\xFA\x10~FA\xAC\x85\xF2\x05\xBA\x0C\xE5rX\xEE ;\xB03\xDA\x01\xF9\x0F\xF3\x17\xD6\x\x91\xC2o5/\xC5\x17\xCF\x8C'\xEA\xF7\x0B]\xD4\x92/B\xFD\xE1U\xE0ZO\x1F\x17\xE3\xB0\xC7O\x19\x8A\x89.E\xCCE\xB6\x97tb\xBAl*\x19\xFC\xEDXy\xC5M\xC5\x92\xF2m\xF9\xF2:\x86x6\xF9\xFFj'\x8BT\x07\x90Dr30\xA1v\x90\x13z\x86\xB8t\xB3\x16\xBEr\xFF\xDAA\x86\xB5us\xB2\xD4\x12\x16r\xEFE\xC9\x98;\xAE\x82\xA7oj\x90\xD1k"\xC8x\xCA\x17\xC0\xF7\xFEpGi\x9B\xA2j\x9C\x1A\xFC[\xB8g\7\xF8\xCE\xBA\xC97\xA2\xCDxB\x18\xF3\xB2M*EDAnn]U\xE3\xBFK\x98C8^7\xDF9>8\xADC\xE5X\xF43\xF6&%?3\xBB\xA1\x9C\xC78\_\x89\x9F\xC66\xA9M\xF8W\x17\x11(\xCF\x0D\xC9\xDA\xC9\xA7\xA5Er\x9FY\xF2Q\x1Dg\xAF\xE8LN\xAF\x0A\x07{\xCD\x9A:\xB8\x08\xBB\xD1\x92\x9B_\x96\x05G,S\xC6\x17\xCEk\xA7\xE5\x02\xD5\x03P\x16\xD6D\xB6\x16\xC5\x0B1YW\x08\xCDg\xAC\xCB\x0C5\x12HM\xF7"+\xEF\xB578)\x0C\xD5\xCE\xF3\x8B\xEF\x0EV=\xE6H}j\x7F\x13\x92\xEC\x1Bs\x07\xBEz\x0E\x94F\xC0\x96 \x0EB\x87\x9E\x16+_5\xA1%\xBBf\xE0@\xAF\x9C\x00\xD4T\xF3\x8Ag\x1F\x95U\x0E/\xFC@\xCEx\xD5D\xB0\xEB\x07\x97\xF9\xC3+\xF0\x87p\x11\x8F\xDE\xC3\xB7\x86\x9C}DG)\xCC\x02\xE1\xD2\x1C\x92\xBAa\x18Q/\x0A\xB1\xAAV\xF3\xF2q\xBA,{A\x95~f\x92\xCB\xC1\x95l\xD8\xD4\xB0`\xC5\x0C<\xB3T\x81\x8E\xC0)\xBC\xBF\xEB\xC7\xE4\x86=\x05\xAChz\xFE\x13\xF4P\xDAR\xAC\xD4\xDE)g\xB6s\xC8F\xD9\x88\xAB\x90\x1F\x12\x96\xD5\xA8\x15)\xCE\x1Ea\xA54\xA5\x8DD9\xCF\xD8\x00\x18L;\xC0a%\xF0T\xC1\xBDfP\x0B\xFC}LNP24)D\x8B7\x85\xA6\x0B\xEC4\xF3=\xA2G\x04\xD9\x86\xB2sE\xC4~\xC7rT\x8C"\xFA\xF6{\xF9\x09\x0A\xB9Z7\x88\xF7\xCF\xF6\x98\xAA\xA5\xD5\xB1"\x06\xC09!\xB9\xCBo5\xF4\xFD\x8F}}:\x90\x8F\xFF`\xC6]fZB|~\x0D\x0C\x85ZS\xCC\xF9\xC2\xCF\xEE\x91(\x86p#\xB0\x84O/\xB1\xDF{\x11\xE1\xD6\x14\x05+@\x10\xC4wf\xBE\x08S\xA76\x07\xA3\x13\x8C\xBB/\xA1&\xC3M\x1E\xD5\xB2>\xDF\xFA\xE9e\xFB\xB6H\x01\x8E$\xBC\xD8\xC9Y\xD6\x03\xE6S\x7F\xB3=O.gG\xB4\x8F\x0F\xCB\xD3\x847\xAA\xB6\xF9Mb\x03]0\x17\xB4\x1A\xA7\xC5<\xBDHT.1\xD6uE\xAA\x0C\x99\x82\xD9\xF5z\xF4\x07\xCC\xE5;B\x0A(cO'\x10x\xFBW\x89\xF9]P\x16\xF6\xB6\x14V\xD4\xC5\x01\x8F\xBA\xAA\xC2\xFBT\xCF>\xE8y\x9EBh\xD4\x94/\xBF.\x8C\xDD\xEB\xD6\x9Ci\x12}6\xF9\x9E2\xE4\x88\xF7\xCB\xBB\xE5\x98\x04\xB9\x064C\x0B*\xBDh\xE8rB\x17\xC9\x0D O\xE4\x1C\xD4\xB8\xB1\x0E\xE9\xEC{:\x88\xEAwB\x1C\x88\xD8)\xDA\xD3\x7F\xE3\xFC\xC5yndwIt\x83\x927;\x9FB\xE7\xEAZ`\xAD\xEC5\x8C\x11\x02\x0BX1\x1B\x04DVy\x10\xA3k-\xC1\x18\x1C\xE1\xA3\x01\x15\xCDm\xD8\xC2c5B)\x87\xA0\xEE\xA6\xE3mbA\xA5\xE4\x17D)\xEER\xA2\xE4\xAF\xC8\xB3F\x10\xB4(\x0BG\xDE]\xD2\xD9\x1Bg\xFDe\x8Dv\xBC0\x86[\xAB\xF6\xAF\xE2\x06w1\xE2\xC9}\xD6\xE3\xB8\xC9\xF4\xCE\xCA8\xD8\x8F\x85\xC8\xC5+\xE9\x9C\xAE#\x1A)\x19\xD2\xCB\xBF\xD5\xC7668>@\x88\x99\xEC\x9E1\xC1f\x08@\xF2\x0E\xC6\xF7\xF0_\x7F\x8C\xD7\x0A9 c\xF1,D4.D\xC6o\xD6\xB3\xAD\xE9\x97j"Mty\x98y \x0E\xCE\xA16\xD9\xF4T\xA6\xC0\xD0!\xCA\xFE\xF7\xDE-S\xEFt\xE6\xBE]\xA4efx\x7F\x93P>`\xD9V\xFC\xAE\xA3\xCB\xDF\xB3\x02\xF8\xA4\x03\xCC{B\xC5\x841g\xFA#rJ+\xC8l\xB0r:\x9D\xE8\xBC\xEE\x9CoC"\xC7\xFFHCd&/0r\x95C\xEF\x87zDm\xDA]\xE2p\x9Aj\xF3K\xF1eH\x16\xFF\x92_\xCBy\x17\xAA6\x03|\xBC3\xA0\xB3\x93\x10\xAE\xCC\xAE\xC7\x1D \xB3\xACM\x8F\x06z6\x10\xE2\xF6\x17&X\xBC-\xC24\xFB\x93\x088"m\xFFU\xEB\xE2\xC9%\xAE\xC9+\x8B\xD0\x04\x8Dax\xDD\xFF\x0C\xA9u\xFDS\xCD\x1D:\x85\xB3\x9F6#0\xC9\x92\x0E\xEA\xEB]\xA9\xAF,\xA7\xDC\xB5\xED\xA5\xEF\xFE\xD0\xC1l\xC7P\x1D\xCD\x97:g\x00K4\xC4r%>p\xA5w\\xFF\xD2]\xD5\xFA\x1AG8\x8CN\x9C\xD6\x96L\x0F\xE5\xC0\x15\xCD\x19\x96MJ\x83l\x0D\xD8zT\xE8'\x08&H\x8B\x90&>\x1C~\x9CRXG\xAE\x1A\x91\x0D\x0B\xCF\xDC\x09\xB4\xD6\xBB\xD6\xA1Pv\xE3\x8E\x05pa\xD1J\xDA\x80'F'\xD1\xDD\x80&Ja\xE9p\x06Or\xEB\x83\xD2K \x8E&\x8E\xA1\xF0\xCE\x11\xEF\xC6\xD9(\x9B)\xDB\xB3pC\x8F\x93(\xFA.\xEF6v\x1A\xCB\x18v\x01\x1Fs\x15\xB8\x89Xg\x03\x84F\x01f\xC9\xFA\x86\xAC\x09\xE4\xF9r\xFB\xC0"\x1D\x05\xB0 lx\x16 E\x08?\x08\xAB\xFC\xB1\xB3?\xBB\x82s\x04&\x81\x8D!R,\x1C7Yu{,*^\xE5\xCCn\x0E|\x89\x82\xC2\xF2K\x11g\xF0\x1Au\x13\xC0\x95\xCD\xDF\xAA\x10\x9C\xA03U\x05\xA1\x8D\xC2\x00y\xEBRt\xD9m\xFAM$c\x14\xEB-e#WT\xE4l_\x10"\xDFv@\xCB\x80\x88\xF7\xADFN~\x1D\xF1\xA5\x852\x15\xEB\xB7\xC3^\x89I}\x9D1h!\xEEs;\xE3v'N\x9E\x9F<\xB9\x1C8s\xFFB\xCE\xB1\x9B\xE1]W\x8C\x85\x9D\xD12s\xA1\xB3\xFAU3bn\xEB<(\$r\xD0B\x10N\x8A\x1E\xBD\xFD\xD9g\x11\xA8\xE2\xD3\xD3\x81H\xBC\xA4g\xF8\xC9\xE0\x99\xC7\xEA\x07\xFC\x0A\x98\xD0\xCBs\xACP\x89k\xE0\xADpx\xD7\xF3\xC5+rF\x81\xBB\x94X\xC6\xA8\x0Ap\x9F\x81\x05\xCB_b\x9FO\xD9\xF1gK\xF0\xE3\xEC\xA7\xED\xBF\xE2\x8C\xDF\x91hw$\xD5@\xFD\x17\x87\x10\xF3\xF9\xE2\xEDo3`P\x9C 0\x95\xBBOn$\xDA\xB3\xF7qy\x88aAD\x8A+\x0AX\xB6\x9B\x1E\xBB\x0D\xA6K\xE1\xEB\x15\xE9F\xF7\xA4C|\xB4\xA7\xF6\xA3\xF1\x15\xD8*2\x9D\x12\xB6\xE4\x9EQ\xA4\x84q`\xF0u\xAF\xB89\x1DE\x9E\xDB\x0B\x1E\xFC\xEB\xF3\xD3b\xBDL*\x16\x8C\xB7U\xE1\x1E\xF8\x07_\xEEhb\x1E\xB1\x7F\xA0\xC0\x8F\x02\xC0\x0Bj\xDA\xD6L\x84#r\xD4W]\x981\x13\xD2\x92\xE7\xE1\x9E6\x08~\xC9\xF3~!\xB09P\xAA\xF9Y 99\xDFQ%\x1F\xE1MQ1"'\x80\xA4\xCB~\xCAE@\xC9\x96\x16Cgj<\x8D\xBE-\x04hg\xC5\xCF\xD1s\xDA\x07\x14\x93\x8F\xC7\xC2Dr0\xEF\xB0\xCBn\x1E(,>\x82L&\x90\x01\xDA\xECI\xD1\xD1A\x98\xDA\xD6\x8A\xBCVF\xDD\x95X\xF4\x8B\xDE\xFC\xB1\x800\x9D}j8\x84\x08\x03\xC9#\xA3L\x92\xAF`\xF5b\x0D4\x1Dg")/\x04 A\x14\xFC,\xC4\xCC\xB3\x99}\x1D}Y\x03p:J\x9F\x14\xCE\x7FS\xFAS\x0C\x17\x14\xF2\x01\xF3\x0B\xEF\xFD\xA1\xE48\xA9H\x87\xB5\x90\x18\x0F\x89\xFCC\x08\xEA\x06\xED\x98\x8E\xE2\xBB\x15a\xFE\xB9\x8C\x8D\x86p\xED(\x9A\xD2\xF8'\xD5\xFE6\x08}\x90r]\x0E:\x08\x13j\x84\xE6\x88\xEC\x98\x98\xD8\xD5\xF9\xD7+L\xDC\xD5\xF4I\xC5%\xC2&\xB4}\x12\x06\xDBP\x00\xA3R\x87\xA5\x14M}\x18\x07\xDC}\xD8\xE6\x1C\x9A\x02\x0E\xA4\x00\x8A\xCA\xF7S\xE4\x8E\xE6\xFBK\xFE\xAA\xB4\xF9\x1D\xAA]\xC0\x1A\xF4.\xBA`\xF9B\xD5\xCDe{\x0F\xCB\x0B\x8A\x97\xCB\xB4\x18\xCDq\x1B"\xC21\xBB\x05\xD7\x1Em\x96>\xB6\xAB\xEC\x91\xED\xE5J\x15\xA6\xAC\xF8\x90\xFA`%\xBCI\x0C\xB1\xA2/\xED\x9B\x99\x844\x9C\xA9}\xBA\x0F'\xC9>\xA9\xE3\xF7\xA4\xF55\x90x\xD0\x88\xD0\xAF}\x0F\xB9\x8C0\xEA<\x11\xBF\x84aI\x16\x86W\x18q:0"\xF8\x9B@\xC7\xF8\xA5\x88S\xDE>\x92,\xA9\x96\xFF\x06-\x12\xCB\xD8\xAEOx`c\x07+\xCE\xF1k\xE5m\xBD\xC6\xAF}\xEF'\x8ER\xF3\xBE\xFA\xC2+\xCF?\xE7O\xEA\x00\xEE\xB2U\xCCh\xC9\xC8\x04\xB6\x80_\xF2\xE7\x15\x16\x95!\x8BT\x18\x0C`V\xAF}a+s\xEC\xFC&\xC3O\x96\x09\x131b\xEB\xBBV\xBF\xF22\x8B\x99bxTG\x17\xDEvq\x1A\xC4\xB7\xCD\x8E\xD4H\xAD\xDF\x0C\xCE\xC1qb\xDC\xAF\x94>Y\xEA\xB1\xE73>$z\x19\x070\xECj\x17bPJ\xB8\xD1\x1Au\xB5\x0F\xD8\x88+\xA5/\xCE\xF0n\xEE\xAA9`\x18\k\xF9C\x8A\x8A\xB2\x0B\xBFHG\x13(\xB6@\x83@\xEB\x18\x963#U\x9D\xA7\xCC$\x0D\xDFzv\xC6\x11C%\x89\x09?\x85x<~)(\x197\x1D\xAC\xE7\x08>8\x1FyA\x1A0\xCD\xE98\xA1\xA8\x9C\xEF\x90\xBF\x0D\x17\x15\x86\xE5\xE7\xE2\xCA+\xCB\x88\xF6\x1B?<\xB9(\xC8L|\xBEOC\xD7\xF1\xF8J\x0A2`+\x08\xBAu\x191\xE1\xDE6\xAD\xB5-\x979\xE3k'\xF0c\x90\x0A\xD28`\x1E\x81\xF5Y\xEE\xF6\xCAUhK]\x18\xE9\x9A\xDDX\x94\xB2\xF2Z\xE1\x18\x922\x11\x92\xDF\xD4\xDD7\xAAu\xA6\xB4\xB3\x9Ag\xAF\xAB\xF1\x85\x7F\xC5\x1D\xB9y\x10\xBE\xBFjP,\xB1\xB09~\xF6sp\x1B\xBB\xD6'\xA0\x82\x85l\xE8G\xE3O{\xC6\xA5\xEA\xA0\xC5>\x07*/\xF7\x02N\x87\xF6\\x0F8mN\x04\xCF\xECU\x04#\x84e+\xAB\\xE5r3\x90f\x99\xFF\x9A \x02\xC6\xB6\x81S1\x1Ft6l\x8B\x95\xB2Y9\xEDY\x0F f\xE3J\xFF\xD0s\xC0\xB4\xF7Kf\x8A\x10\xDC\xFC+\x07\xDC\xDD\xF4m^\xBDw\xC6\xC4^\xC4=\xBA\x16\xDD>\x14`\xBF%\xE7\xF7K\xFFJ\xEE\x19^\xB4\xAF@\x12\xC7\xE08(g\x9F\xC4E\xDD+R\xA6\xBE:8\x8C\x8E\x1Dw\x1F\xCD\x0C\x82_\x01E\xFF+\xCB\xC4\xDE\xBD\xB0lk\xEAD\x16\xE8\xF7\xE4s7z\x1C\x89\xEF\xC9-+8\x02P\x81M\x02\x1F\xB8\xFF\xBBP\x14\xAB\xB5H\xB2\xAB\xC1\x0C%\xAC\\xD6\xC5\xAC\xE6\xEA>\xB9\x91\x86\xC2~\xC3KU$\x99\xD6A\x98\x9CB\x1Cb\x08\x90\x8Do(\xA7\xF0\x92\xF8!\xB8\x1A\x02\xB9\x88&Y]\xFA\xE8\xF6\xD9\xBB1u\xA8\xF6O_3\xE7\x96G\x90\x87\x97\xF9K\x9E\x91\xB7Z\xD0\x7Fq\xC6\xC1\xD3#\x1Ep\x7F,\xEB\x93#m]\x8C!\x14\xAEA\xABa3\xF6=\xBBBh~\xF5\x9A\x85\x10|\x84\xB2\x01\x9BV\xF8Y\xF9\xC4\x8E\xDC7\x7F\xBE\xECs\xAF\x84b:\xCA4&%i\xAC.\xBE\xFFl\x0A\xB7\x1A\x83z\xF67\xDF\xF9`|\xA6\xD4\xD3\xDD\xC2\xFF\xCC'0\x13F\x8Al\xAA3\xB2J\xD8T*v\x10C\xE2}2\xC1\x19\xB9{J}\xE4\xA1d\x0C\xCE\xAA6zU\x81.\x09\xEDi\xC2\xA2S\xD0I\xC07"=\xEC\xA1N\xA7\xF3\xC2\x02/\x09xc\xE5\xE1\xA7\x0F}\x00\xD2\xAB\x9F\xC5\x14:\x10\xD3\x06\x01o\xE9K\x80uy\x05{\xC6\xE6\xD2\xFF\xB8\xB1\x1C\x09l\xF8O\x9Fj\x87Y\x16\x1A\x9D\xC9\x1B|s!\xB1\xEC\xD4\xBC\x0F\xB7\x80\x08\xBBl\xB3\xD85\x9E\xDF\xD0\xB0~1\xB2\xF7\x90\xCFPZ\x0FV\x817A\xC4|v\x911\x81\x0E\xEA,W\x1D\xCD?\xEE\x9D\x98N\xDC\x94)-k\x13w\x0Dx\x08\x9D\x17\xDA!\xF6\x9A\xFCm9\xB5\x08+%[\xBC\xFD\xF4\x16\xF8\x8C\x04\x8C&D\x19\xD5\x9C\xFD\x1Eie%\xF1\xED\xC2\xEA\x19\xE0\xCD\x12\xD2\x9A\xD8PP!\xC4\xBE7\xE6\xD5\xBCT\x7F\xDD\x1E\xFA\xD4\xD2{)\x7F\xCF\xCA\xC2H4\xB9\x07\x13\xF5N\x11\x1C8\xBCTC.%Z\xFF"\x1B?\xDDkQ\xC3\x18\xF7_z\xE2\xA7\xB7P|x\xF5?\xC5,\x9Fo\xFD\xEC&\xF6\xBD0\xBF\x01\xDA\x86\x7F?\xB2\xBF\xC7`UVt$\x94\x05\xD9\x06A\x04D\x14\x1B\x14dV\x01\x08 Y=\x8A\x01P\x8F\x95\xAB\xCF\xDE\xE0\xD2d\x81\xB43\x90\x90\xDF\x15C4\xDF\xD2iP\xAD\xBA\xBCs\xC1\xE0\xEA\xA5d\x04\x1C]@6~\x94\xD7z\x07Yq\xBFDA\x97\xE7\xB0T\x9C\xBBs0,v\x9E\x9Fe0\xD7\x8C\x07\x0A\xF1&\xD6D\xE0\xDD\xE2\xB6\xBE\xDB\xBC\xC5v\x08S\x89Z\x85\xE2{\xFD\x9E\x14\x15\xD2VQ)y\xBEZ9\xD3\xF0\x9334\x13\xFF\x05(\xCA\xDBI\x85\xB9(\xC8\xDD\x10\x85\xC6\x1B\x0E\xA9\xCB\xC3m\xFE\xF0;\xB886\xCFe\xC5\x8Fmf\xBC!\xD1.|\x80\xD8\x1E\x18\xBE)!,/\xE0\x0B\xA9\xFD\x84= \xB50-\x91\x81\x84Su\x05MZe\xC5\xAA\xD1\x192+s\xD5\x01\xCAH\x8Dr\xFA\xB3_\xC1p%\xD0\x7F7\x83[\xCB-.\xAE"\x19Gu\xC3\x95\xC2rU#\xE8c\x15\x0B\xF93]\x086\x02F_\x04\xCA\xB4\xF8VY\xA0%\x89J\x12\x87\xD8^\xE3\x87\xD6\x0B\xD4B#\x80\x1D3\x0C\xDA\x92\xB3Z^7\x03\xBF\xB8I\x15\xF5\xA8\x1D\x89\xA1U\xB0d\x8D\xA2A;"\xC5\xAA\xA5\xBB\xDA+\xA1=P\xB8\xA2\xFA\xD8x\x95\xC1\x92\x0B\xE4\xE0'\x94e\xD2\xFB\x99\x9F95,8\x82~\xD8\xB6\xBE"\xA6\xE4\xAD\xF6\xC1\xB1\x82\xBC\xD1dv\x06\x83\xCAP\xA5E\xD1\x1F\x0B\x1BW\x846\xB5N\x16\xCC\xCC\x01,\xE0\x93\xC5_\xC5h\xDBu\xD7d8\xCF\xF6I\xC0\xAF\xE4\xA5j\xAE\x03\x1B\xC1j\xF7uB\xBF\xBAH\x8Ay\x1E\xDD\xC5\xBC\xE4\x07\xBC\xE7j\x0D\xB5\xC1\x07\xE4\xD3\x1Bp\xC9\xFCJ\xB8k\xCC\xBAP<\x80\xA7\xA4\xE3\xA0\x0F\xE7\xC3\xDA\x10\xD6d\x9C\x04i\xFB\x1E\xC5:l\x98\xE8:\xECr\xE0~\x1B\x95\x97I\x9C2\xB6\x15\xA6\xFE\xC9\x8B"\xFD\x0A,$\x81\x87\x03)\xE2Z\x9B\xA9;\x1B\x14:\xD8\x02\xF1\xAC\xF1\xFB\x0D\xA0\xEF\x1D\xC0l\x0Ez\xC18\xB6@\xD3\xEC\xD1C\x8A\x83E\x7F\xFB\\xA4\xEF\xE8B\xDCg\x91P\x97\xE8\xE4\xAB@\xA9\x89\x03\xDB\x99%\xCCX\x0B\x8B\xB8\xEF\xDF\x07\x92\xF7\x14\xB7\xE7a!\x8A\xEB6{\xF5=\xE3#~\xF8d\x89$\xAD\x96\xDC\x7Fg\xB6?\x86aT\xBB\x957\x89\x91\xD8\xFA\x0AM\xBA\xC1\xCD\x8C\xBE\x15UZ\x95\xBE\x07fI\xCF\x00\xF1\xBA\xF6\x03\xC6\xDB\xFE8\x05\xF1~\\xC6\x1E\xA19\x80\xD0\x04\x97{\x9F\xF4\x90\xF8\xA4\xC3x\x09\xBD\xE9\xBBrFM\x9F\x92"\xC4\xD1\xCA\xDAh\xB3v\xEDd\x8E\xC4\x88Z\x00\xC3'_\xCD\xCF<\x06\x81\xD172\xC1\xFB?\xFE.J\xA1\x89f\xBD\x9B\xE048\xC1\xB9\x9Ah\xA9f2\xD6]\xED\x8A\x91\xCA\x9D1.\xC4\xFFY\xAE\xAF\xFAi\xC7\x10\x87A\xB3\xD4\xFF\xAA\xF8\xF5.\x07\x81\x87\xC0\xF0\x99)\xDF\xAAX\xF2\x9A\x06'm\xD3\x1E\xB0\xD4\x0AY\x9A.\xB4\x10'\xDF\xCBJv\xDD\xC49d\x9Bd\x9C\xE3\x8E\xE3j\x1Ewj\x07\xD5Z\x80E\xE48x$?\x16\xFE\xAA,\xCE\x97D7\xEF\x93]\xD1T\xE1c\x1FB\x00\xA3\xAD\xCB\x95\x1Fr\x94%\x14+2yp\x01\xA3WNY\xEDA\xA36\xC0\x96db\xECW\xE3\x08\x08\x84\xC5\x1Bi#\x810M^\xA1\x86U\xBB<`b\xAF\x85vu\xF3\x09\x87S\xC7\xE7\xC4[\xC1\x19n\x96\xEF\xD5\xA6\x14\x88`-\xFF\x9B=0\xC3$\xC0H\xAC7\x0E\x05\xEE\xFD\xA2x\xF7v\xD1\xC47exg\x13G\x0E\xB0\xD9[\x07\xF0+\x0B\x0F\xA8\xFB\xCF]\x9B\xED\x9C\x95`\x0B\xC0\xC1X\xF8U\xE2\xD5\x9A1$6\xD9\xAC\xD2\x8FRl\x9A\x1DCS\xB9\xE1\x83\xE6\xB7&\x82\xF2t\xD6\x8E\xFE\xF4\xA6G\x0B\x95\xC0\xB8S[\xAD\xB6\xC4Az\xFA\xB8\x82\xB3w=\x1E5\xB97\xEA\xB2F\xB4p\x01m\xBAj\w\x16A\x1B\xE4X\x1D\xAD\xD8\xA1%\xE9U^\xA5\xBBI\xC5\xEE\x88\xE8\x82\xEE\xEBNm\x9E$\x12\xE5)\x125M\xE4@\x82\xCF\xB8\x8AF\xF2\x07uRR\xD2p(\x9C\x8A\x8AM)\x99\x1C(5.5\x85\x96\x19\xB1O\xDDC\x1F\xC4\x0D\xD3\x9F-\xDC{3\xE8\xEC\x17\xB9\x9F\x09\xBA\x0Eo\x91=\xBC\x87\xDD\xFC\xE7q\x86a\xD8>\xC4\x02\x81=\xA7\xFC\x0C\x9AxX\xFB{i\xAB\xC1if\xACV\x07\xA3\x0Av\xCBf\xF6\xEE\x8E\x94Z\x7F\x9FW\x08\x14*\xFAU\x8A\x18R\xC3\x05\xDFga\xFF\xA3\x9FF\x86\x17Lw\x0F\xEB\x88H\x90\xA8C\x0F\xB5\x1B\xBC6f\x9D\xA3C\xF8n\xEC\x0A\xB6Lm\xB6\x95\xD9\xB6\xC1%\xBD\xFD\xBE\xFF\xF2,e\x01\xB37L\x9FMqqR\x88\x073\xA2\xDD9Q\x92Vagf\x13A\x99\xC8\xA1+n\xCAf\xF2\xD4/\x8B\xBC@\x1BP\xC3\xF3\x97\x93\xCCne\xE7"\x06\xB7\xE5\x10\x9AK$\xEA\xC93\x06\xD0\xFEn\xFA\xAC\xD9\xE1w?\xAF\xA1\xD9X\xF7\x95L^\x03.s\x042OX\xA9\x95>\xF6\xEE_\x9D{\xE8\x84\x7F\xEA\xE1\xE0X\x10\xD2\xADP\xF0\xA6\xAAe\x06k\xB3{50\x90\xDBHB\x0Bm\xB3\x9FU\xDFV\xF5j\xB0\xDAK\xC6\xDF\xE8\xAC\xF6<\x80yw\xCC\x1Eg\xFC\xE0\xB4jyR\xBCR\xEE~D\xE2\xC1\xB7\xCA|>\xF3\x8AY\xE6\xEEH\xA7\xC8l_q\x99\xC0\x0B\x09+\xAE\xE8k\x9EbK5\xDD\x8E\xC3\xB2Vp_\x86\x8Cn\xE3\xAE\x00\xD09\xC1W\x1E\x95\x81\x04z\xB3\xCC\x7F:e_\x92bZ\xAC\x19\x971\x9B/\x87/ \xCE\xE4\xCF\xA0\xEA\xEBo\x9B\xCD;\x0Cq\x9BI\x16oc}Eh%\xB7\x9AZ\x11U\xF2?\xF02\xEA\xDBd\#\xBA\x11,\xEC\xFD\xD9\x1E3]\xB6\xB0>v\xAB\xE9\x85\x19\x8F\xBA\xDFHv\xE5P\xD52\xDC\x1DL\xA7\x1AE:\xCE\x19\xB6P\xD3\x05m5\xF9r\xC1\xA6\xEE\xBCP\xFBhn\xC8a\xE7\x9A\x95\xA5F\xE6\xB5\x8D\xFDC\xB8\x94\x85\xA5\xBA"g\xDC\xA3;z\x9C\xD4\x8D\xE94\xD0\x0By\x82\xDE\xF7(\xD1\x03\x8D>a\xE8\xBA\x0D\xB3\xA7\xED\x9C\xBF\xAE\xA6\xDA9\xBB\x878\xB6)\xF8\xF2\w:Lz\x92<\xED\xBEl\x7FO\x7F\x09v\xF8\xD8\x7F\xA0;-\xD01\xDB\xB6\x1F\x86\xE2\xA2Dz\x80eV\xEC\xA0\xFB\xEB\xCA,\x88\xE2\x01\x7F\xE7\xDBc\xA5\xB8H\xBD\xDDB\x82\xBE\xDE\xFC/w\xEC\xDD\xFD\xEC\xBA\xB7\xFBz\xA1\x8F\xDC\x1C\x0F\x13}\xAB\xA1?\xFE\xAD\x1FO\xE2\x85\xB6n\x0Fk\x141\xC7\xED\xF6\x16<\xE7"7\x97\xB0\xEE`\xE2\x12ca\x10\xAC\xA9\x87\x07\x80\x02\xFB}\xEF\xE2\xBCK\xFA\xE4\x9C\xC2P\x85c\xB6LEc\x91Oz\xC0\x0Fq\xA7p*FE \xBD\x8D\xF5\xB4\xAF'l\xBFoQ\x03\xB6\xF6\\x04\x81\xBD\xBD\x7FK\x8C\x8C1{\x9Ba\xA3\xE2\xACN\xCD\x96\x8E\x8A9+:\x09\x1A\x84F\xFA\x0C\xE8\xA9\x9F \xE1\x9F!\xD5\x86\xD0\x8FwJ\xD5\xED\x8E\xF0\xDC\xAD\x83\x90,\xAFD\x12I\xAA\x15\x82\xB4\xA4\xBA\xC1U\xFFlz9$\xD2\xA1|\xF5o\xE9\xB8\x86\xCBj\xD2\xE1!o\xA19o<%\xD0[\xA9\xB0\xA0\xA0g!3Y\x97\xA5\xB4\x81\xB4iO\x19\x99a\x81,\xC7\xC4|\xB7\x88\xCB\xEA\xAFJ\x8Eu\xFF\xFD\x03d\x7FnBEx\x1D\xD6\x85q\x12\x9C\xA17\x1DO\x94\xCF\x7F\xD3\xA4\xD8\x0Cz\x87h\x08\xCEHY\x02\xFE\xC6=\xCE@\x03\x926\xBC\x05a\x027c\xF6\xFE\xB2m\xEA\x0C\x052\xB4\xBD\x02\xDE\xA5;B\xBC\x1Ee%\x1Ce\xA7\xCC\x0E\x82\x15\xACl,ou\x03\x8A\xF3\x8A\xCBs\x82 \xDFl/P\xF1\xA9\x93\xC1\xCD;\x95\x19\x91\x1BG\x80\xB6\x06\xF9k\x91\xE5\xBF0\xB0\xBD\xF5\xA3`\x9B\x9B\xF2\xA6\xE8\xD3\xE4\xB1\xCF\x0E\xC7\xB8\xB0\x95\xB4+\x9Bw\xAB\xB5\xD6'qI\xD60\x85i\x84#\xA7\xE1\xA5\x07Gx\x1Fs\xF5\x01{>\xF2]\x83\x1C\xF86\xD3\xD3\x0AdI}\xF7E!\xA0\xD7k\x14\xFA\xFE\xF6\xC9\x1D\x86\x91\xEE\x8F?\xD5'\x1F3\xEF=o\xC7\xEB\xE5\xA9\x05\xCF\xE0\xD9\xD9:8t\x10\xE5iz\x02\xD0\xB5g\xDE\x92\x93`(\xED\xE1\xE6<\xF2kOP\xFF\xA9\xAD\xD5\xA6\xBC#\xD8\x10c\xD2\xDC\xB6\xC2]\xB0\xAD\x09\xFC$'5W\x92\xBF\xCA#\x148\x1E\xF7\xF4\xD7({\x02\xC5#\xD7lm=%pb"Z\xEC \xDA\xA8v\xB5Z:\xAB\x12\x98*\xD2\xF3l%\xC9\xB1"\xE9\xDA\x94\xFF&\x94<7\xF3\x7F\x8F\xD1vp\x840\xEE\xE3\x04n\xCD4\x1E\x14\xD5\xF7\x83\xEC:\xF4K\x89+\xD6Q^\xAD&S\x14\x05t]\xDAp\xE4N\x87\xC8\xB1\xDAC\x09\x0A\xD1\x9D\x90\xE9\xD2>f\x8A\xD0\x04\xC6\x06\xE3\xF3\xAB\xA9\xB2k\xDC\x04\xD3\x8B/\xCD5RK\xF9b\x8C\xE4\xE2/\xA4\xBCnl\x81\xE0\xAE\x88mN\x09\x16\x93\xDC\xB6q)z\xC2M\xF7HF\xBEs\x0B\xB0\xA2`\xAC\x98\xA0.YN\x87\xDB9\x11\x97S\xFF\x18\x1F\xBA\xD1]\xCE\x0Cu=\xC8w\x96\xB7\xC4\xC5YcI\xBD\xECl[U\x05cK\xF5\xB5\x17cy\x1A4\x8F\x04\xE7 z)`\xCC*%\xD9\xF8\xB8\x93M0\xF8\x03\xE9\x14*\xC7M\xC0\x8D|\xB8H\x97U\x1Bzd\xB4\xC1o\xC1f\x81'\xA0_n\x95\xC8\x1D\x9F\xC2zu\xA4\x8B\x12EK\xC3\x15\xA1A\xC5\x95\x92\xB9-t0a\xC1\xCA\x01\xD8T\x14J\x14"\xF5\x1ARd~\xBCz\xEC\x89%\x91(?\x9Az\xE6\x0D\x8E\xBB\x041\x82\xBF\xAF\xCB\x07s\x9E\x99M\xBE\xD6 10h\x0AcH\xD8Q\xD1k\x81v\x1FRP\xEE\xDD\x98\xAF\xBB\xD9\x01\xB7\xBC\xDD\x17\x8Dl\x92y\xDEo~\x13y\\#'1Fo\xA2\x9E\xED(\x0BG\xC4\xEC\xC2>\x069z\xC6\xBB8!\xB5\x88a\x0F\xF9\x14\x01\x98\xD2y\xA3\xE8N\x96U\xE5\xE6G\x8Ev\xCF\xBF\xB8l\xD2\x00\xB2\xAF]-;\xC4\xF0c\xA4\xFC\xA4u\x13\xD3;\xF4\xBA\xF4\x14f-X\xFBp\x0C'\xAC\xFBv\x9F\x87`\xD6\x16\xC5\x90\x0E\xAC%\x9A\x97\x94F\x1C5\xFF?\xE7\x1E\x8F%q\xD83\xC12\x05\x01\xC1\xDC\xFC\x9C\xC5\xE5\x9C\x19w\x9B\x12\xAB\x9Di\xDC\xBCl\xF3\xAA\xFE\x8D\xD5?\xDF\x1D\x03\xDA3\x03Z\x9E"Ty-\x0B\xD8\xF2\x89\xFB\xCA\xD3M\xA6\xEBM\x94\x9E(\xDDn^' \xD2>\x95~u\xA9\x8A9\xBEn\x06\x1B|\xFCf\x0B@\xB8\x03\x15\xF4+l\x8A\xA5\x94\x08-ZTo\x90\xE6\xA0\x07\xD9\x1Cd#%\x18\xCB.\xC2>\x96\x95\\xA0\xF3\xD8\x10=\xE4F\xA8\x0F\xEE\xD3- h\x9A\xD2\x92\x93\x1F\x1C/\xC9\xF1\xF6Hcu\xA0\xD0>\xAF2{\x9Dt\xC8\x8A\xD63\xF2O\xF6'\x99\x18Q\xBB\xF6)\x9E"\xE5\x06\xB5S\x89\x03\x83$\x9B\x84}\x9E\x7F\xD0*\xD2\x15\xE0\xBC\xEC\xF6\xD5\xF5\xF2!\xDA\xD2\xF0\xF1\x04\xFE\x18\xE6X\xFF=AM\xD9\x04\xCFg\xF6\xE3Z\xA0\x86f"\xA7\xDF?\x07\x88\x1C\xEE\xEA\xA4\xA2'\x19\xDB\x03\xA8d\xE2\xBC\xA9\x81\xCA6\xC3\x0A\xD4+g}K\x1C\xFA\xEE\xC73/\xBEW\x88\xA3\x0E\x9D\x9Fz\xAC\xAA\x93|\xBAg\x98-3\x1B\x19\xCEO\xD2\xEFE\xC5\x83\x9D\xA8\xCE\x0E\xB5cu\xE6\xD9A\x17\xD5\xE7zI1\x89\x91\xD4\x02\xDDPDG\x95QTM\xAF\xBA\xB6\xCCe\x0C\xE9\xE26\x82\xCB9\x09{\x88(\x94\x90t\xF4\x02\x94\xB4\xC1\x0B\x7F%;sx\x03\x14\x01M\xF5\x8B\x9D\xB5\xBBL%\x9C#\x80l\xF0T\xE6$4\x17\xDA\xD5%\xF1\x94\x16\xC4LT\x8Ca\xFC\xAB"\xC3\xCC\xA9~/\x92L\xF0\x0B$\xE5":eK\xE9\xF7\xFCP\xAB\xC43\x8E\x9A\xA2\xB1\xFD\xBEH\x12\xF4L\xB6\xA9\xC1\\x00\x14\x81\x1B\x8A:vUl\x16\xCD\xEB7T\x09\x8C\xAA\xB8n\xB3fQ\\x09;\xCA\x96\x0A?\x9F\xE2RC\xB7\x1D,-\x14\x17\x00\x19\xBA3-\xCE3=\xD9\x12\xD2\x85BQ\xAF\x0B\x9DM\xDFL\xFA\xE9\xE3\xDF\xB8\xB4H1\xEFS$\x8641\x13\x858X\x11\x89\xF6\xECg\xDF\xC2\xD8N\xEA\xFD\xB7\xC1\xEF\xA6\x08P1\xC2Le<\xD2."q\x09\xD5\xDB\xBEYrJT&,p\xC2\x04\x068\xF6}a\x11\_}\xE4c\xE8\xCD\x03\x18H\xBA\x89\x99\xA7\x15?a\x01\xCC\x9F\xC9Z\x92z\x7Fj\xA4z9\xA8j&$8TA\x1A\x03\xFF\xE8+t\x81\x19\x09'\xE9^\xC9\x1E \xB3_\xFD\x09(\x8F\x80\x96\xA5\xC6l\xFB\x8B\x12\xA1\xD6-\x9D/\xA31\xF5\x95mSV.\x14\xCE[{\xEB\x8F\xF1\xEE`\xAE\x00\x0B!O\xC5\x1F'~|8J\x12\xFC\xE9\xA3\xCE\xDC\xEE;\x00\xF9\x85\x99\x18\x7F`2\x1FgB}X8\xE2g\x90\x8E\x9D\x07sd\xC66~\xBD\xF9K\x01^\x1C\xF1\xAB\xAE\x11T7f\x12\xC6\xB3\xEDs\xF2\x01\xFE8\xA9\x86\xD9%I\x90l\x89\xE2\xA4\x1F\x14\xE4\xE3| \xC6"\xEF\xE1\xBB\x1D\xAB\xE9A\x7F\xC0\x1E4\x9C\xDB%\xFD\xD1\xF7\xBF@.\x99?\xAF\xDA\xE8U|\xDF\x8C\x92\x98\xF9pO{/\xB9\x15g\x1B\x81s\x81\xAF\xCB\x89\x80\x17":O^\xE3\x94%\x19\xC8\xF6/5G\xB2\xDC\x06\xBERe\xC4\x07R\x95\x03 \xF1\x0A\xD37\xAE\xDB\x81\xD4\x15\xC3a\x9B\xE1\xC7\x80E\xD8\xBAx1Wm\xE6\xD7\x89\x92\xA9$\x18\xDE\x18U"\xC26G4\x06<;\xF3\xA3/\x9Bb8\xD1B\xD2\xCA\x11T\xF6Zw\xEC\x9D\xE6\xA0\x8E\x18\x97\x1D\xA8a\xB9\x18}/\x03\xFA\xAEM\xD2\xF2HU\xDA\xF3\x0B\xDF\x10\xBA@8\x08\\x1A\xFB\x03\xDC_\x04`;\x09\xE6\xF7Q\xA7\x85\x11nA\x9B\xAE\x88i\xA1\xD8n\xF7\x88\xB8\x03i\xD9w}E\x0C\xC0\x86\xC8\xF1F}\xF9\x99,\xCA\x1C\xEEu\xD3Y!\x0B\x04\xC3\xFAg\xF2\x96;\x96\xD0\xC4\xCE\xAC\x84\xFBl~\xDFt2R\xB5j\x8Alk[\x12xi\xABb\xC5m\xAB\xCB\x95\xA6\xA9@r."e\x80v\x85\x0FO\x97w\x9E\xF2\x89\xE2O\xF7a0\x8EIH/\xE1\xCCD\xE6O\x9B~\xD4\xE7\x03[\xA6\xC3nN\xD9\xA2\xEF\xD3!\xE1\xD3\xE0Q\xB1\x7FFo4n\xCA+(\xE2\x1Fmx\xBF\xD8\x97H\xE6\x84~o\xB6\xEB\xBD\xEC\xD4\xAA\x1Ef\xC6\xE1\x96\xE7N\xA8\xDA\x06\xA6\xD40\xDD.\x9C\x82d\xD8Sgd\xBB\x1E\x9Cna\xFD\x01rw0!\x1F\x0F\xC8\xF5]\xE2\xBD\x07*\xA3S\xF0\xFDMu{\xF6t\xC6\x18\xB0\xE8\x04\x1F'\xEA\xC4\x03G\x02\xFD\xE2\x02\xF4\xC2\xC30\xBE;dj\xAA\xD2\xC9X\xA2\xDAwV\xB1K7\x94\x11\xDF\x1E\xE8c\xA6\xF1\x95\x91\xF0{\x87X\xAB\xB3\xB2\x0FCP\xB4\xC3\x15\x09\x10\xFD\xA8Hn\x1Bf\xE6\xEEaF`_3e\x00\x1B\xC1\xD0\x1D,j \xA4\xEC\x1F\x92\xA9\x9Bz\x99>\x1E\x94\xC2Zn\xA7\xEA[\x8C\xA8z\xBB!W\x0FJ\xAA\x8A\x997\xF1\\xDDn\x17\x96`\xE0\xD4.\x1AS\xCDH\xFF\xCFH\xB4\xA5[\xB5A\xB0)&@\xD9\xA6\xA7t\x9B\xE5\xDC7Z\xA1"\x8A\x91\x91\xBA\xF4\x849=>o\xA24 \xEC\xCB\xA1\xD1@EK:l\xF7\x8D\x10\xC1\w\xB1\x0970g%\xAD\xCB\x05\xF4l\xE1\xBF\xE9\xCB.m\x8An\xFC\xCEH\x88\xCFdi\x06h\xC9\x95\xB0M\x1C\xC6e\x17\x9E\x15c)\xC1\x98\xBA\x02x"\xF1s\xF5\xC3\x05g\xDD{\xBC\xD6:#]Z\x02\xE8\xECpc?M\xE1'\x04l\x1A<\xB519\xF6\xBE\xFC\x080T\xB1\xF7\xF79\xDE\xE9\xAB\xCF%\x19\x85 \xFD\xF6\x16|\xE2N\xD8h\xC6\x89b\x07v\xF9\x85&l3\x05\xA4\x1B\xB4k/,t\xC4\xB4{o@\xA9Dw\x88\xBF\xC0Q\x80&\xAC\x82\xA7G\x1B\x03U\x06\xCD\x003\xA5#\x1B\xA2\x09\x89\x8F*\xE1?\x91H\xDC:\xD0Y,\xAFZ\xD7\xF4\xC3e\xDCP\xB7T\xD7\xF8e\xB9\x1D\xC0\x1A\xE4\x13}\xB2H\x05Sx0\xE5O\xCD2y\x92Oo\xC6\xD6\x98iKh\xC2\x0Ff\xC0\xAA$\xA9\x96\xCD\xD9\xB2Ej\x02\xCA\x99\x13\xED\x0A\x86\x0E\x18\xE7\xF2!\x8Bi\xD1\xAA\x9Cv\xDD^~~\xD1\xDF\x97\xD3\x07\x1E\xB7\x99\xF5s`\xD4\xBE\xC4\x03*\x92\xD2Hk\xB0\xFA\xDDj\x90\x90\x02\xAA;\xB2\xB6\xF5\x96f*\xFE\xCC\xEB\x14\xA7\x1E\xE4\xE3\xAC\xEF\x89\xD1\x97\xD6C\x00\xDD\xF9\xE7E/-\x91cnr;\x06z\x0C\x88\x04\xE1\xA3\xA8=\xD0\x09\x93\x88"\xFEl\xBCy\x89\xD9\xF8\xBA<&Kw\xB9\xBE>\xD8U\x1B\xD6!ES\xB5Q\xCC\x14\xA4\xD7/_\xAEn\xE2\xD3C\xEF8\x9E\xB1\xF2\xAC$\xF6r\xBA\xE0\xF4g\x1E\xED\x9F\x9A\xE7\xCB\xF5\xD1\x8D\x0B\xC5O\xBE?\xF8\xD25a\x9A\xC2A\xC6\xA5G\xBF\x99\xB1c\xA7.v\xFB\xE8.u\x13\xABh3i\xB0_\xC6F\x1B'\x0B\xAC\xB5dk\xB1X\x96ph\xB2\xA7\xAA[n\xDA\xFCP4:\xDB,\xDE\xE1{|\x00\xC8doZ\xB5V\xA7\xC3\xDB\xAD1\x06\x9A\x17\xC5\x02\x11af\xEFj\x9EAe\xCC\xFD\xED\xE3O\xA4q\xCF\xDB\x02\xDC\xC8\xBAQ\xA5\xE7\x01\xA7p%*\xF5\xA6\xF4|Yj\x7F\xE6\xBD)D\x1Fz\xFD\xAE\x99\xC5\xEBs\x1F\xEBhb\x8A\xD4\xD4Jq~,eC\xFD\xDF\x0E\xCC#`f\xCD\xA8\xEC|\x91D"J3hX\xC4 \x17\xC3[\x1C{\xBF:\xD3\x05\xF3\xCB\xACV\xA4\x9C|'\x0Fa\xE4\xE8\x9F\x1F\xDFj_U,\xF9U\xA0\xA3\x0D\x91\x9A\x009R\xAA \x96B-n\x82\xC6,\x1F\xE8\ \xCF\x142\x1F\xEA\xB4\xD3\x7F\x8Eb5h\xDE\xA9\xA39!\x89h\xAFr$\x04\xB7\x96\x8B\x9B\x12\xDB\xB3_\xC9z)P\xD6\x12f\xE4\x0F\x0C\xE1y\x80\xC6\xDD<\x07U\xE3\x03\x04c\xF0\xD7hS\xF9A\xE5\x02\xEE\xD1sX\xB6c\x7F \xA1 ]\xFEp\xC3\xD2l\xC1j\x07\xC2a$\x87\xFCm\xB8\x95U}\xE3\x00\xB9g7\xACgf\xC3\xBA\xB90\xB9Y\xB4l\x01Lj\x81-\xEF\x0F\xC0*\xB9;M\x89f\x89\x98\xCE\x02\xA4x\x02\xF4\x10\xB0\x16\x0Cm\xB6^\x03\x116$]\\xFE\x9E\xAAj\x1E\xC7B\x1F\xC1BT\x1C\xB0\xF2N\xB3\xC9J@\xD0\xB5|\I\x82\xD6\xF0y\x05\xC6|q/\x9B\xD7T2\xBBkHh\x8B\xB2\xD3L^\x8C\xF3\x034x\xAF\xA1=x\x06\x95\x9C\xCC\x158l\xA1\x05\x9AxGJ\xCF!\xA3+y\xBD!\xB3~\xDC&s\xD5\xF6\xF9\x90\x05\xAD\x8E\xBD\x8Ew\xD2Z\xB7\x13\xCANp8\x822\xF1\x80\xFB\xD0\x13\x86\x19\xF3\x9E\xB3\xCC6\xFE\x9A\x13J\x0Ak\xB31\x8C\xF9V\xEDS\xB4x\x19)6C\xA3\xB2\xA6\xA9$\xDB\x87gG\xEA\xD4\xF0=W\xD5\x8B\x8Dwa_\xA84\x87<\xCE-H/\x95\xA2\xC6\xF8\xF2\xD84\x89\xD77\xAC\xA9u\xAD\x81K\x97\x05)\x1B\xA6\xDE\xB0\xEFQz\xA4~\xD9\x83\xAD\xFA0"gC\x1B\xE0\xC9\x97\xCF\xE6\x18\xD4;\xFE\x87V\x85K_\xEE\x00rA"B\xCF\xF4\xA9\x94\x84j\xE4\x87\xC3\x14{k\xB0\xE9v(\xB5\x11\xAF\x86:\xBE\xD2\xB2\xA9\xA5$\x88S\xD2\x9D\xF8\xD0\x92`M\xFA\xF3\x7F](%,\x0Bh#\xEC\xC3\x8BhU\xF8\xC7QAwB&T\xCDc1gy\xAC!\xD8\x87\xEC\x98a\xAA{\x81\x93L\xE2tdj,\x80\xB7\xBE\xCD\xD2j+\xB1\xBA\x05\x04\xDC\xBCm\xF5\xBC@[\xBD\x90\x9E\xA3\xB8\x19u"\xCF\xE6\x97j{BP\x18\xBA\xE2\xA3\xD9\x8D\xC7m3\xCCt9r6A!\xBD\x7F\x0A\xB2'<\x17\xC0\x0D\x9D]X\x03\xF3\xED;\xA4\xA2"!\x179\xC6\x9C\x0BcW\x86E\xA9\xB9\xC4)K\x83k\x19q\xD8C\xF6\xC2\xBD\xFDk\xE0\xA8i\xD1\x9D\x9B;\x82\xC2n\x94\xA3,\xCA\xC58y\xCF\x95N'\xAB\xA6h^\xBC%\xDF\xB2\x01\xE6\xEC\xFC\xCEo?\x10$\x9A\xBF\x87\xA2\x87*\xCB\x8AA\x04\xEDX.\xB5\x07\x1D'\xEE\xCB\xF9\x10\xBA\\x9F\xB5\xF2\xBF\xEC\xD7\xD1\x93/\xE5\x9F\xB0\xDDC\xC6;b\xE3\x0Fu,\x9A\xACHX\x1B\xD6\xEA\xA4\xF8\x00\x95z\x9B\xD0\xF3Q\xD3v\x09i\x16Es=\x18b\x0D\xFC\x868\xAA>\xCA\xE1\xB7\xFB:\xDD\x0BE\xB2-\x9AJ\x14\x8D\x1EB\xDB\xBF\xF5\xD5\xE6\xA8\x0A\xACO.U\x15\xBCNhK\xD8\xE9\xDC\x94\xF1\xD5}9AC\xD1s\xC2c\xC4\x04\xFEc\xD1\x81\x88\x14\xFD$_\x1D\xB3\xE5\xCE\x96\xB8\x97\x1B\xBD\xD1\xDF\x9B$\xBCk\xDDF\x92\xAC;Az\xCB\x03\xBB\xE9\x12\x1F\xA9\xB2\xCB\xF4ef\xF4=I\x8C\x16\xAB8\xAB\xF9\xDEB\xED\xA8\xB3\xC0\x04\xBF\xF4J\xC8WBF\xD1\xEA\xB4\xDB[\xCE1\x03r\xCB\xB8\x13Gzh\x9AqG\xCF?\xB1<\x0F?\x0C\xFAkT\xDC\x8A)'`\xB4\xBC\xF0'O\xDE4\xD1:\xFF\x96\x19\xFD\xD6\x08\xA9\x13\xD3:@\xA75\xD3D#sj\x0CI\xEE\xA2D\x81\x89\x85\xCB\xCDS\xFD\xBB\x1D}\xE5+\xEA\xCF\x09j$\xEB\xEB\xD8\x88\xBE\x91\x0F\xFC\x01K)[<\xA3#\xD9\x89\x0AW\xCB/\xA5\xFB\xD3J\x09\x981\x9E\x0A\x0A\xCCQ\x1A\x7F\x1C\x9B\x12\xAF\xABJ\xE8\xA07\x836I\|A]\xA2\x9D6O\xE1N\x7F4\x91)\xDBS6/%\x0A\xDCQ\xF4s\xA0\xE1\xE9p\xDDD\x10\xE9\xDBF\xC3i\xCD+\xFF\xDFd\x99\xB8.\x1C\xA11P\xF4w\x7F\x83',X\xF9\xB9\xAA)\xE9*\xC9\x05\xEF\x09\x93{\xC7\x15\xAE\x14\xC6Z\xB6\x98u+\x84"\x9E\x08\xE9+\xD5\x095bq\xCE\xE56>Z\xBB\x8F_"\xD6(\x97d\xA3\xCC\x9C\xD9\x9F\xF8\xF3\x00\x00\xAB[\xF6zE\xC8t\xF1\xBD\x01\xDD$\xD2\xEB\x8D\x82NH0\xF3\xE050\xF3B'\xBE-%\x9B\xA7W-\x9E\x94\x93yS\x8E\xAB\x140\x7F.u\xE7\x96\x99\x82@\xD09\x88\xF3\xBF\x9B\xD6\x04w\^=\xDAr\xECz\xA8\xB4\x8A9\xE9\x03\x9A^k\xCF\xC8\xA2^\xC5\x93y\x92\x1D\\x19\xC0\x17\xA9u\xE2\x88Y8\xFB\xBF\x8F\x9F\x87c\xCD\xF7\xC2<\x83X\x1Af+\xDE\x9E\xCC\x8A_^\xA4n@\xE0\xD6$/p\xCB\xBE\xEFfL\xA3zE\x8C\xAB\x04\xA1\\x89\xEE\xE1\x830K\xD1>\x95\xC9y4\x1E\xF8u"q@\xF9\xF0\xAB\x17\xABU\x18\xF4,\xB1"^\xE7\xD6h\xA3\x16W\x1D\xFF\x80\xEB\x87\xBA\x15\x1D\xA7\xBC],\x00\x07\x00,.\xCFl\x9D\xC2\xB5\x88\xCDEhB\xE2ah\x06\xB2o\xB5g\xE6U\xB1\x82\xEE\x92=\x94\xD3\x043J}\xCE\x8A\x07y\xD9\x03\xFC\xF0\xB8\x1B\xFE\x05\xBBi\xDEjR\xE2\x00X\x9A\x89nyA\xF4A\xDF\xF4\xDB\x06\xFF\x03\xCF.\xEDy%\xEE>4\x84\xA4\xB0=\xEB\xCD\x80)\x95|\xE5\x14\xEC\xCD\x16f\x0A3\x0E\x0A\xA5\xF2\xB1\xB9\xBA\x1C%#]\xCA+\x09\x8F}\xDB\xB64\xF8\xEA\x0C+<.%OS\xAC\x88\x90\xF5]\xC7\xF1+(\xD2a\x17<;q\x16\x88\x97)\xCA\xD7v\x8E\x076E\xD1B\xB8R\x87\x95\xBB\x85\x04\x18Zm*\xA9m\xA1\xF7V\x9F\x88\xC4\xA1'\xD4\xAF\xD4c\xD2Ms\x1D\xD2\xD7C\xA8\xC8\xE7G\xAC\x0B(B\x19\x84\x10\x83\xDAo\xC9\x96E\xB6\xFEN\xB9\xC9\xAA0\x0F\xA3\xF1\xCA\x1D\xE7\xD38\xCD\xD2\xF2%l\x1D'"\xCBV#\x85\x0F\xF9\x08\xDB\x98\xD7D:\xB2\x15\xDF\xC3\xC6\xC7N\x98\x95i\x92\xA9\xDAd\x9Atq\x94\x0Eh_r\x14\xB69\xF0f56\xDE\x01>\x05h\xABr\x1A\x9F\xCC\xAAjs\xDA\x0F(\x93\x10;'\x9B\x92I\xDB,L\xCA\xDDx}\x92\x96#?\x18\xBE\x09\xB7\x89o\x90\xB1\xDDQ\xD5\xFF\x00\xEF\x1B(\x95\xCC3%Hh\x1C~\xB2\xD8\xA9\x0A\xDAJ\xE2\x8C\xB2}Q\xF0>\xDC\x82\x7F\xAB\xC7\x90E\x07\xCD\xD8D\xC1\xDA\xAD\3\x04\x9BM\xB8\xF6\x11\xFB\xEB\xB4\xBBzNC.\xDB\xE3\xD9d` \x80[\x10UAM\xDC\xCB\x172\xAA\xA1\xFFI\x02\xDB~1DD\x0E3\xA0\x98\xE4\xA1/\xA3T\xA6\xA2\xFD\x94!\xE9\xBB\xF9 \x86\xFA\x95>`Y%\x8AL^T\xFB\x8EO\x1C25\xE4\x14@\xC8\xE3\xE0\xBDE \x01\x81O\x91\x05\x9B\x9CX\x02!\x09dz\x03\x1A\xBD\xDC[\xB2\xBA)\x84:\x11\xE2\xB5\xE0\xAA\x07\xA2\x96|\x08M\kp-m\x07\xCF}\x0D\xC6\x03"zr\xAC\xAB\xFDF\xBBX2\xDF\x1B<\xA4\x97\xACS\xDC@\x04\x0B4\xDFY\xE7\xF83\xF8\xCB\xAA\x14\xE4\x94\x92J\x19\xCC\xF1\xA8`\x0E\x87\x9B!\xBF\x8DT\xFFo\xF7\xEAR;\x8E\xE6=\xC5H\x91\x83\x1D\x97`+\xD4\x0By$V\xD3\x90\xDB\x1B\xCC+\xCB\xBC\x17\xEBE\xBE\x94\x88\xDA\x1Aj\x06\xF5\xEF\xE2\xE13\xC3*\x98m\xF1\x9Ee6\x03\xCD\xCD(\xEF\x03\xC5^9\x030\xA1@g\x8F;x2^\xC6+3\x84\x9B\xE0\x19\xDD\xBB\xE1\x0F\xDF\x16\8\x94\xE8\xAA\x1E\x0Dj\xA9k\xBF\x9D{c\x11<\xCE\xA3\xC8\xC9?-\x8F>\x8EJ\x9C\xA9c\xFE\xEB\xCF\x8D\x16\xEFRHO\xF1\x84\xD6\x1A\xC2w\xBE\xC9~E\x9E\xCDT\xF0\x1EFP\xE4\x05s\xC4\xC1w;yK\x12\x93\x92\xADU\x10\x01\xC6\xFB\xB4\x8F\xA2E\x89\x9A\xE6 G3~\x0EvW\x17\x07\x9BO\xFF*,\xCC\xDC\xE8\x02\x00\xD9\x04\x92$L\xF2\x9B\x9AE-\xF5\x09Q\x86\x19\x06\x8B\x1C\xE9i\xA6K\xB5`T1\xCBa\xB4^bX\xC7\x89k\x14\xB7m[\xDF\xBA35\xCA\xDB\xC6\x81~\x81\xE6\xD7\x04%\x0CC\xBA$PS\x81lg\x93\x18\xFC\xC8\xA9\x19\xAEH\xB0\xB9\x10L\x1C\xF9\x7F\x03\xEC\xB5\xA2\xAFB\x0Fl\x943?\xC7\x98\xDC\xE0\x81\x85\xDE`\x13V\x95\xA6Y\xE1|q\x8A\x00O\xAA[v\xCA9\x7F\xC7\x88\xB6\x14\xE8qc\x0Bsvy\xD2BxW8\xC2\xC9I\xE4\x85<\x0A\x1E\xA5\xE3\xF40\xF3)T\x82@\x167\xFDv\xD2\xED\xB0w\x88\x0F$9\x0D\xAC\xAD:xV\x02\xF1\xC7\xDF\xF7Y\xE6\x00\xE6\xF7%\xB5e\xF6\xA1\x7F\xCB\xE1R1\xEB\x1A\x84\x03\x9E\xAA\x96@Hw\xEF]g\xD6|c\xF4\xDDj\x9F\x06M\x9EC\xB9\xE4\xB52d\xCE\xDD\xEF\xE4&1\xB6M\xAA\xF9\x81\xF3\xF8\xC2?M\x7F\x1A\xDD&1\x16\xE3>6\xD0\x85a\xCD{\x87s\xCC\x04m8\x06\x1F+\xA1\xD42\x09,\x98+'\xF0v\xE5jV\x07JB\xE12\xB5\xC4\x14/\x08\xF0\xE9Ib\xD3w\xDE\x04\x9B\xEE\x97\x10\xB4\x82c{E\x12G\xE4\x9C|\x0A\\x07dNI\xC7\xDE\x8B\x9D8v\x97\x95\xF3\xA7z\x1AW\xEC\x0C\xBE\x82\x1E\xCE\xBEzxDG\xEFI\xED\x826\xE2\x00\x1B\xC5\x9F\xFF\xA1\x08\x14\xFD\x0A\x90\xBF\x05\xB4\xB58_\xA0-7.\xE5fjkM\x18\x9EMc\x9C\x99\x9F\xC6\xF9\x8A&AK}\xDE\x01\xDD-\x95\xAA\xBF\xD1\xC5H\x95\x9D\x8B\x0A\x8F7L8\x96\x13gfkk]?\x15\xA8S\xF4\x0A\xB0\xEF\x82\x98Q\x83[\xFD\x9B\x0B}\xE4/\xBE\xBC[\xAF\x07!*q\x95D\xA9^\xDB\x07\x9FS\x17k\xB8py8"\xFF\x99H\x11\xDF\xA7\x98ze\xDCU\xB6\xA7[\xC0\xF48\xA7m\xB1\x1CI\xBCD\xBB\x15\x8E\xAA\xC4\xADZG\x01\x0D\xA3\xC5\xC9f\xC8z\xC7\xF9\xC5\xF4y\xBF{\xBA\x1A\x009s\xFE~\xC1\xEC\xDC\xD3Bz,]\xF3\x80\x00\x98\xACm\x9D\x173Y\xFF\xF8(\xAC\x05E\xEC+\xBE\xE8\xD4d\xE9\xECY\x9D\xBC\xF3\xA1>v\x10\x80d\xBD\xB1\xE4\x1FR\x08\x89\xF6\x89gc\x96\x89sG\x9D@\x19D\xB6\xC2&Bv\xD6\x1Ee\xFCW\x90=\x1A\xAE\x08\xDB\x06\x12\xAD\xAA}rX=5\x97\xC2\xC4`\x96\xD2r\xBD\xBF\xEF\xF6F-\x07*\x98w\x10\xF48\xF3\xB4}O\xDD\xC1\x15\xD4\xBD\xE7{1\xAET\x0Aq\xB0\xBB]\xCEK\x7F\x11p\xE5\x90\x02\x88\xD1u!\x1Cm\xC7\xD8v'\x06;6\xD3\xE1fU\xE6>\x0D\xCC\x83\xBC\xFF\x8B\x84S\x86\xCA\xC9rS\xC86\xAD\xF6 E\x1E\xAB\x9BZ\xB7\xC7\x90\x00\xEC \x83g\xC7\xFD\xE0\x89\x9A\x0F\x94\xBD\xD3\xFBg\xC8f\xB6d\xC9Q9\xDCfI\x11\xA9R\xDB\xB3\xDA\xF3<\xAC\x91\xF0\xF3\x0C\xFF>\xA5$\x85\xFD\xC2b)s\xEA\xC1\x1B\x82\xA3C\xC3\xFE~\xF8\x80\xDFZ\xDF\xD5B\xE5\x9D\xE3Qh\xE5h\xA4r\x14\xFF\x7F\x82:\xE4\x81\x8F\xD8\xDE\xAB\xCD\x9C\x0F\x01\xA0K\xB1F\xECG\xCB\xE4\xA7\xC1(\xF1\x94\xF1\x91\xC0\xAB\x9B\xA50$+\xB2L\xDCa1f}\xE3Y\xA6L\x0C\xEB\xC0\xCD!\xAF\xB5b0\xE2H5\xC9\xD3\x1A\xE9\xA3]5M\xDF\x11R\xBC\x0E\xB5$\xC8\x04\x86\xE8\x08\xCAf\xFAO]\x98\xF5\x06\x9B\xEEf\x1E`\x9BA\x9F\xB8\xF5b\xE8G\xB3\xB4\x80\x0B\x83/b\xF9\x1F\x06q)\x9E\x940c\x9E\xC9!\xCC\x9Ak]\xD0\xA6E\x1B}*\xC3\xA8\xB3$\xBApAL!%\x835\x03~mF\xA2\xC4\x11\xFF\xB9\xF4\xA1p\x0C\xA6\xD9m;\x8F5\x80\x17\d\x19L\xEA\x09\x9Dk\xE6\xA4\x0E&\xDA4D.\xF3D\xE60\x1E\x03E\x15\x11p8\xBD.\xB5\xBAP\x0D\x8C\xAD{\x12\xF5\x0A\xCF\x9D\xCE\xE3{E\xDDd\xB3\xFFrO\x00\xD2\x8F\xD3\xE1*\xF4\xB7g[C\xD5\x14\xF7\xDB\xDE\xF6\x15\x86\x85\xE7\xDB\xF7\xD5Q\x0A?\x06\xA4$(A\xDB\xA1\x11\x8D\xE4Q\xEE0[\xE1IT\xA4w\x0F\x9D\xAEt\xD6<\x1B\xE3\xA4%\x1D\x13\xA2\xFE\x82x\xB3\xFEq\x8F\xCC\x0D\xB1z\x8A\x9D\xD1\xBC\x803\x18Y\xF8b\x10\xAA|\xE31z\xF2r\xE6\x0F@\x94\x99<\x1Bk\xA8\xDBA\xFD\xBD\xCDo\x9B\x9B!\x8D\xB6\x10\xC6\x83\xC5U\xDA3\xE6\x11Nz\xCE\xCB@\xC0k\xB7\xB4\xF4{\xF9\x02\xBDa\xF9&\xFA,N\xCD3`\x89q9\x19=\x99"@\x02\xB1~\xA4\x9F\xA1&k\x15b\xA6\xB2\xD5\x83\x02\xE8t\xB2\x9C\xF7\xBE\xF2(F\x94\x14\xCB\xF0\x07\x09:\x18~;;\xDCX\xCA\x9C\x99=\x99\x12\xA1mO\xDD*\xB3\x91U\x89$\x7F\xC18\xD8\x9C\xFFH\xF8\xA6\x1F\x9E\xB5\xDE+{\x8F\xCFS\x8D\x91\x18w\x989\xDE\x88\xC7/\x96C>\x9A\x82B\xF7\x0E\xABe|\xDB'\xD4\xC8\x08\xC73\x02\x03\xB3\x91\xD2\xC3\xEE8SsT\x99X\xD4\xCBHL\xA2(\x85\xDA\x84agR|d\xA9\xEB\x8E\x0E\xCE\xD2\x16d\xCCO[\xB1\xD6L\x9C\xB6\x13\xC3\x84\xD3\x83\xBB\xA0@\xF1\x15\x9B\x82\x99\x96,VYV\x92?\xB2\xC5NP\xF4\x845\x03{\xE8\xF7-\xA8E\x92\x0D\xAAa[V\x10\xEDI\xDF_\xA6@#P=\x12\xA7\x96\x1F\xD5\x83Pf\x00k\xE9[\x09]@\x06H\x94\x8C\xED\x80Z;\x02\x98\x15AL\x92;{\xF7Bw\xFA;\xFAY\x8E}\xC0y\xBF\x91\x1F\xC4Sna\x06R\xAF\x1F\xDB$1%\x9F\x83\x11\xFE\x84/7\x07\xBA!\x99\xAE\xBD\xE6\xEDLAD\xDB\xC85\xB4\x82\x8F!/\x11,\xCCA>\xA2/\xEE\xE7\xE6\x97\xF8C}\x13\xADk\x08\xFAz\xF2\xD0\x1A@WW[\xC4\x87\xF6,\xA8\xA3\xFF\xDFR\x02Tc\xC5\xAE\xAF\x0BccrTw\x83\xC2\x1AKpM\xBD\x96hbIJ\xAF\xAF3\xA57\xD5o\x90\x9F\x95\xBD`\x9FB\xD3\x13\x8F\xE8\xDC\xA2\x16\xB9\xDCg?\x14\xA4\x9DtF$PAF\x0F\xE3\xBFM\xF4:\xBCS\xF7\xF0\x1E\x8C\xA9\xBEN\x97\xCE\x00\xFBp.B\xE1O\xC5hf\xA0\xD4\xC4\xAD=B\x8B\x9A\xEB\x0D\x92\xB4\x8F\x9DQ\xCC\xFE\x8D\xCD\x0Ch\x0F<\xF1\x8E@:tx\x98\x87!\xD5\xCB\xCE8\x87\xA2\xFCr\x98\x1Dt4\xE0\xFF\xFF\xE1\x0DQ\xCB\x84\xFB\x1Br\xE8[&\xD0\xD6\xE0l\xEC#\x8B\xD8\x02\x80\x0D\xD4\x0E# m(\xAF\xEEn\x91-\xB30\xE3\xFA"\xAA#\x8CG\x06\x18\x17*\x10\xF8\x13.\x0B\xF1\xEA-\x93Z\xDA\xB2\xE7\x15\xBA\xF7\xCAB\xEF\xEC\x84\x07\xC4d\x1B\xA7\x01d\xDAS}\xCD\xC4\xE3\xDCl\xAA\xB955\xCFPYdbheLb{\xED;|\x91F{\xBF\x86u\xE7\xC0\xD4\xBA\x95\x88\x03I\xB97\x9C\xA8\xED\x94*=\xADt\xE6K\xD5\x1F]\xE9"\xE8k\x03\xD6\xE6t\xFC\xAB\xDC\x85\x08"\xAB\x9A\xBE\xCC\x83\xB2;\x0A\xC9\xFB0\xE9\xE0y9\x89\x09\xBCj\xAD\x19\x1Bh\x18\xC5\xBFV\xAD\xC5\xC2Jg\xB4<\xE1 \xD3I\xDA\xBC\xB2rW\xD9\x8C,\xF6\xF7\x0E\x17\x8B\xE8\xCD3"\x97#oX\x91\x89[\xA2,\x9B\xF4^t\x12\x8C5!V\x0Eh \x0A\x9C\xF9\xC1'l\x00d*\x13m\xDE\xE3u\x13\x1B<\xE8,\x8DK\xAC\x1DL\x1Bk\x1A\xCF\x9E\xD5\xC9\xC7\xAE%\x89\x1B\xC2\x01*\xB6\xC9\xE9Z+R\xA1d\xB7\x17\xCE\x18z}\x8ERm\x08\x00\x0BNZ\xD9l\xB9=M\x09P\x81\x7FJ\xF8\xD7kj\xF1G0/\xF3-\x98\x9B5\xDB\\xCAd\x9A\xD0\xEF\x9B\x02\x0BCH\x1F \x19=L\xF0kG?\xB8\xD2W\x1E\xBE!\xB1\x9F\x0F\xCE\xD0\x97&\xD3\xCE\xF6\xE3c\xB8E\x0D\xD63^\xD0&XZ\xF5xpL\x15M\x7F\xC9\x98\xBBp\xC0\xAEQ\x9Fybm2\x8E\xA6;8\xDB$7\xB3o!]\x9A\x0ED\\xAA\xA7\x8Fh(\xE643\xDBGt\x98yy/5\xE3Z\xB15\xC8\xFB\xE7\xEA\x9D\xC6\xF3\x1F"U\x7Fj\xBD\xFE\xE6W\x12\x06=!\x1DL\x94\x06\xAA\x96\x9F\x051(\x17\x0F`\x95a\x0F\xFF\xE5S\xD0 r\xA1\x9F]\x01\xB9\xCA\xE1\x10\x90\xB09\x92eQ\x16qP69\xFC\x103\xC3\xB3\xEE\x96y\xE0\xB0\xAET}\x98\x95\x1A\x83\xC0\xE0\xF9\xF2\x85\x0D\x85\x98}qU\x9D%s6\xA8\xA3y\x8FO\x8D\xD6 Ek\xA2G\xF9I `6\xDBF\xB0N\xED\x09\x8C\x9F\xA6\x1Fh\x82"\xF6\x08\xDF+\x98\xC4s\x01\xD8\xFCDY\xA2\xCC\xD4\xFB\xDF\x87c\x82\x88lf\x9E4\xE0\xA5`'\xD5h\xF2\xA7d$\xD8\xF7\x9A{R\xAE:\xCAB\xAF~\x9C\xDB\xE9\xF8\xFE=\xCE\x85O\xF0\xF5\xA8\xE7^\x89\x0Dqd\xD0rz/\xDC\xEE\xFAJ\xDAb0c\x9E4ny\x00d\x07+\xEC\xA9B@\xBC\x8B\x0F\x05nB\x04\xE9V\xC92\x86\xD9yQ\xF9\xBEG\xD2\xED\xB33\x0AI\\x1E\xBD|\xC0\xA7\x93p8\xBD\xA6\xF0\xE7\x16\xCE\x18\x93\xD9A\x89\x9BT\xF62&\x9E\xC6\x83\x0D+M$\x04\xDD\xA1\xF7\xE1\xB6{e\xAAMzn\x86\xD7\xF0+\xAD8v\xB8\xFBz\xFE\x0C\xD5q\x90\xC0\xDCA\xF5\xC4\xB5R\x16u\x9E\x96j\x88=\x02\x9C\x02\xB8!\xF1\x7F\x8Ec\xFF\xE6gL>a0\xE8<\xAFq\xC2\xD3K^r\xD9dI\x1E\x04FuM]\xE2\xFC$\xC9\x18b\xE0\xC1\xBB\x98B\xABR\xF1\x02dQ\x15,t\xBD"X\xA3E\xDA\x18I\x90\xA98#z\xE9\xE7\xAE\x1A\xA5\xDF\x103\x98XP\xC1\xE9T\xC6\x1B\xB4\xB5\xD0\x81\xF8\x1A\x94-\xDB\x85\xAB\\x93P:\xE6\xF8:\Q\xC7\xBE\x87\x1E\x18\xDC<\xD5\xD8\xDA\xCDuX\x8B\xE3\xE4\xCD\x085H\xA7\x99\xF7"\xE9\xE6\xE1{/C\x12\xAA[\x0E\xE8\x9E\x18\xA3RzOj\x0C\x8D\xC6%\xB8\xD8\xFD\x12\xAB\xDE\xDF\xBD\xDE\xA4h\xEE@\x00\xB1\x80*\xF0R?\x1C\xCA\xDBU\x15\xC1[\x81kP\xA4\x9C0\xE9No\x92:\x0D.\xF5\xFA\xBB<\xC7\\x0B*\x9AB7\xF9\x0D\x7F\xBB\xE3I\x04\xD4\x82\xF0\x07#HmL2Or\x1E\xAD\x9C\xF7R(\xB5\x08\x16}1\xC2\xE0X;\x9Eh\x00\xB1\x84\xDEt.\xEFu\xFE\xD2\xEDF\xB03\xBE\x84\xD3\x8B\xDD\xB1\x8A\xF4\xB1i\xDC\xF0\xE0\xA4\xAB7\xDE6`\x0C\xCE\xF8\xABXHH\xEF\xEDv\xD8\xF1T\xC6\xA36\xE2L\xB4\x83\x86\xC2\xAC\x92J\x86\x07\xC8\x8D\xD4\xD2U)\xF7\x14G\xB0\x8A;\x80\x07\xFF\x8C\xAA\xF74#'\x96\xF9\xC5*q\x802/\x87\xB3\xC3l\xE1\xEC\x91o\xB5:\x9F\xF9\x82|\x91\xAFU\xF2\x17?\xFB\x82\x15G\xB3t?B\xE9\xD4"\x0A\xEE\xF3\xB7(T\x0CG\xA2\x8F\xC2\xD2I)\xCB\xB9\x1C'\xC0\x89\xE8H\xB0KR\xDFc3\xD8\x8D\xE9\xBCv\xDBG^q\xCB&\xEA\x9E\xC2R81\xD3\xBC\xE5\xF9\x93\xA6gu)'\xFF\xDE\xA8\xF6I\xCF\x88\xE0FC5\x8E\xE8\xB4\xEBT\x14\xB3\x0AF1\xB3;\xF3\x8D ,\xB0+\x04\xCF\x0BK\xC6\xBAo8]U\xC5\x89\x95\x95\xFC\xB6\xC0\xAF\x9DWL\x83\xB0\x0D\xAF\x94\xACU\xAF\x95\xBB\x91\x88\x06AE\x095\x94luN\xE2\xEE\x90\xA2\xEF\xDFT\x9A\xD6\xDF\xD28\xD0\xF8\xBAR\xFF\xB7\x9B[\xDD\xB9\xE4)\x91\x85S\xB2%XI\x03v)\xE64H\x12\xE86\xEF\x11\x08\xF7\x0B*D2:\xCC\xAB\x827\x01\xBD\xB3\x9CK$\xB6\xC8n\xA6N\x14\xC8\x88B\xA9\xC4\xC5\xA8\xA2\xA2\xCAU\x08$\xB2\x10\xB3\xBCZ\x04(\x07\x9B\xCA\x90\x19\x8B\xBF\xD226\x8BA\xCE\xDA?[f\x9E\xCA<\x7F]\x01\xEE\x8B\xCEp\xC6\x02E\xA1(0\xB1\xBF\xE7\xE2\x8A\xC7T\x8E\x82\xAA\xEC\xCF\xA0\xA8*n\x13\x9D\x1BE:\x07^\xABeO\xEF\xEF~\x9C\xF2#\xAF\x89\xAD\x90\x94x\x84L\x1E\xE3\x01v@\x8A\xAA\xD4SJ\xD6\xC7\xB3\xFA\x92\xF1v\xBB\x9B&;\x1BuJ\xA6\x15\xD4\x7F\xD1\xEA\xF5\x9D]\xCB\xD8\x01O\xA7-\x96\xC8P\xA1\x8Ch\x1Bdp\xF5\x13\x9D\x1E\xC1b\x90T\xFE\x1F\xD6\xFF=\xAFC\x95\x9E\xE2(\xC0o\x0E\x124\xD1\xA6'O\x85\xE7\x9A]\x18\x0DM\xA4\xB3n\xD5\xB6y\x87K\xD5\x933\xF2\xAC!\xCB\xCD\x99\x82>\xDC4\x90\xE9x}\xD7\xC3\xEE\x93;\xDF\xC2V\xA7\x99>%JL\xBE\xBA\x04\xC92>r\xB6\xCA\x87"2h\x9F\xC7\xE8\xDC\xBA\xAF\xA3\x05\x10PA\xBE(\x09R\xF3\x1D5\xAD\x03\xDB\xC4\xD7\xA9\x0C_\xC6\xAA\x16t\xEC'\x82\xC5!U\\x94\xDA\x0Bv\xDC\x10@\xE3T\x15\xAE]\xC8\x14\x99We\x09\x83\xB9\x82d\x92\xE9Ca\x00n`\xFBT\xEE\xC3\x81\xD0\x8B\x8D\xC9"\xA1\x9B+Ii\x9E\xC8\x08\xC5\xFEs\xEDN\\xD2\x135u\xD2\xD6\xF9\x03\xD5\xC1\xAF\x87\x1B\xD7\xB9V.gSZ\xDDK\x07\xB3\x8C&\xAB+\x10\x91\xB7\xF7s\x1FC\xC0\xFCI;\xCD:\x9C\x11V^z\x8F"\xC6S;\xA0\x1D\x0F\xC2\xC7\xAC\x08\x08\xD3\x03\xAED&\x976\xF2\xC0\xADcR\xB7\xD0\xCB:\xC5Q\x0F>\x13\x0E\xF8r\x85\xE25k\xD8\x1D\xFE\xCB\xC2\x8B])G\xB9]2U\x9DH\xDE\xD7\xC6g\x86M'\xF3\x1CS\x83\x1Ec\xF1\xA5\xC2\x92\x9F\xA9fY\x1A\x8E\xDB\xFE\x9F\x8D)\x8AK\xA4\x0D\x85\xAB\xE8}\x03\xDCx\x91%u\xE6:N\xB1\xC8\x08\x11+V>\x0B\x85\x1F\xD7?EF\xA8\x92a\xAA\xE2pr\x99\xCA\xF34\xD7\xBBueZl\xC6\xDE\xD1\x15\x82\x80{a\xADD\x85\x87\xCD\x92\xE1\xD6z\x92\xE5\xB4\xCD\x9CO\x0CN&\xD2\x1E\xCF\xE9@=4\x96\xC4\xF3\xC4Q9\x0B\x01\x0C~\xAAk4~\xC8\x82\xB5DCKGa\x9D=\x8A\xE4;\x19\xB2\xF6dQ\xFD\x05Sz\xC1>\xD4:\xA9\xDB\x9FB\xBE\xF7\xA3\x80l\x1Fa\xA1\xC73\xC7\xA0\x19\xEE\x12\xDE\xF8\xD0q\xB0\x99\x8D\xBF\x8B7\x16\x84\x81\x80\xB7\x8D]\xD5M"]b\x85\xCC\x07I \xD2\x89\x0E%\x91\xCA\xB3\xFE\xEB2\xF7Y\x82\xA3Eg[t\xD6\xCB\xD7.\xE8\x97F\x98\xD9\xC6\x8E\xBAx\x9F-\xBF\x96\xA9\xEE2T/4\x8F\x9Ec\xB5\xB1\x9B\xE0\x19\xA2\xEA\xBB;\x07w\x87\x9E\xC1\x8A\x10W}B\x8E,<\x16%_\x8A\x17!\x1B\xD4[\x88\xDDg\x0C\xBC\xE6\x10\xE2T\x93\xA2\xEC\xBAx\xFF\xD24\xA0\x13\x9D\x9D\xB9\xAF9\x1F\xDD\xEC\xE7x\xF1\xDF\xD4(\x93\xBE\xA1\x0Eo\xB7\x81\x11\x95\x9A\x06c$\x8B2\xFC\xBB\xC6f?\x18\xFB\xD8\xF2b\x98\xCC\x85\x99\xE5or_o\xC1V\x01\x03\xB9j\xEA\xEF\xCD\xFC{3\x1B\x97\x0F\xE3Q\xA2>\xB6\xA9\x8C\x97n\xEA\xD1\xF6\xED\x89\x8F\xF9za\xFA)U\xFC\xBE\x9A\x86\x1F"\xB3\xD8\x0E\x0B\xE6<\xE1\x8E\x95\xAB\xC1]\xD0u\x14\xA3\xF1S\xFD7|\xA3L\xA7X\x82o\xDA\x18\xA7\xC4\xB2\x9D\xF0\x0D\xB5>\xA4t7\xF3Y\xE9+MX\xEC\xCC&F\xF8[\x01\xF0v\xC7bS\xE0i8}\x1B\xD8l\x04V;\xE7veMvq\xBE\xA9\xBD\xE4\x92vFI#\xE3N,b{K\x03\x91\xE2\xEF\x9AO\xA5,3p\x88\x01\x0F3\xED~[\xA6\x00t\x8C\xE8\xB5\x16\xB6\x17\xBA\xE4h\x92\xCC\x95\xC4\xD2\xA8\x12p"V#\xAE\x8F\xA9\xCFO\xBF3c\xB2\x90\xB6"\xE5]"\x096&\xA8\xC9t\x12\x0A\x8A:p\x7F\x1E\xD8Cn\x91:@\xAA@\x1D\x9B\x8E\xA5\xC4\x89\x99\xA7*T\xC1TJm\xA7\xE9j\x08\x81C\xFE\xE7\x89\xCE\x8F:;8\xB1d\xC7B\xE0b\x19c\x13\x1D\x9B0\xB9\x0D\xEE\x8F\xC6?\xB9\xB5$Z\x03\x10\x1Cwke\xB4\xDCzz\x81\x85\x93P\x06+\x9Ah\xD6\x87\xC5\xFA\x93.\x1F\xD8P\xDBp\xFA\xC1a\xEE\xA6\x95\xF3L\x87LX(\xE1+o\xE6\x07\x80\xFC\xEE\xDCx\xBB\xB4\x06\xE0\xCC\xAB\xAF\xE5n\xAE\x8F$\xB2\xA3\x01\xDEv\xD3\x0B\xBE\xCB\xB1L\xC5 \xB2\xDADa\xFE\xB7\x180=ai\x11\xF2\xDBUqD\x99u\xEB\xA5+_\xD8QgXn\x18!y\x0A\x17\x13\xCA\x00}M\x08\x87*\x0A\x1Ch\x81\xB8\xC2G\x81\x8D\x9E\x9F\xCB4\xF6\xF7\xBE)\xC8H\xBDI\x04\x9CQu\x90L\x1A\x0BO\xFD?\x16\x8C@*\xA6%<\xD7\x1B\xCEF:\x8Cq\xD8:\x99\xA3}\xDC\x078#[\xC3\x96<\xE6)'\xAE\xE4do^\x15w\xC9\xC3\x1C[\xFAC\x1Bo\x17\x8A,\x9D\xE1!\xF9\x1Cz\xFAWG\xE3\x1B\x02{\x7F\xA5%%\x1E\xBAD\xFB\xCE\x15\x1F\W\xF9<\xC2 \xE5B\x06_\xA5\xBB\x08D\x07-S\xFEd\xEE\xA7y\xC2\xF7p\x18\xF1\x1F\x1B\xA7\x11\x81Z\xE2\xEC\x11\xA28\x14\xE2\xBE\\xCB\x04\xC0\xA4\x88\xD6Tu\xAE\x077\xEDi\xE3x\x7FF\xEE?\x9Cu K\xD8\xFC\xBF0\x00\xEF\xC7\x96\xFC27y\xBB5Z\xB8Z\xA7\x04e\xE5\x08\x84\x15\x993`$Ie{t>\xA41\xAE\x8D$\xF1+\xC8o\xF9\xE7@\xACnQ\xC0#\x87l\x1Fg\x85\x17P\x88\x8A\x89\x1D@\xD0\x12ZO[\xB2\xE75\x09\xEA,\xB2\xF2\x88\xFB.2pC9\x12%\x8E\xC9\x08Z\xB3\x1B\xF5\xB6\xDC\xC7\xF1\xC67\xC0&v\x8C@\xEF8\xF8\xFFClJ\xB4\x8A\x15}k\xF7\xFA\xD9\xE4\x9Bns\x0C\x9F\x1E\x1E\x97\x09\xB4&\x83\xB6s\xEA\x98\x19\xBA\xE0\xFC\xBFC\x9FD\x09\xF5\x92\xE8\x0C"\xDB\x9F+\xB5g\x91\x1A\xF8\xCE\xE7\xC2\xBD8s\xF3J\xE84\xE2\xE3\xFCB#X\xFF\xA8j\x13\xA5\xD5>\x8D!\xA6\x9C\xD5\x08Z"(\xAB\xA9\x97M\xC4N\x96\xC3^\xE6\x05aHK\xCFn\x84i\x0F\xDA`\xABM\xA5o\xCA\xF3\xDB\xF5~JT\xCA\xE89c\xE7[\x1F\xFA\x98e\xE0Y%\xE6\xC9\x97\xDD\x1B\x05iq\xA2K\xF1<98\xABq\x02\xAF\x94\x12\x84Sy\xFF\x1CnA\xD7+/4\xD6C\x03R\xC9\x01{\xCA\x070\xAB\xE31{y\x16\xE0\xE0\xC1\xCF\xBE3\x16\xF50\x15\xEB\x06\xD0\x1Dee\x04\x8D$r\x9F\xF7\xBBkY\x92\xF0\xC6\xADG\xA3\xB2N\xB1\x9An\xDF\xDFUl\xDF\x9Cu\x13+\x06\xD9\xAA;\x0Bi\xBE\xCA\xB2\x07\xE9\x1FmXUD'\x09_\xE7\xD5i\xC2\xD8F'\x0B9\xC6\x87\xD7\x05\xE0XZk\xE1C@EP\xE5\xCA\x17v\x05\xDF;\xE6\xD3\x95\x80<\xF1%\xE0\xF3<\xC7\xADQB\x0Dn\xF1\xEB\x84gT\xD4\xE2#3\xC9L\x811\x87\x02\x0E\xD7\xBA\xD0\x0D\xAF$\xA0\x83\x85|\xDCn\xB2R\xDF\xEC\xB5\xCDTi\xA3j\x13\x093(\xA6\xA4\xBE\xCB\xE3\xEB\xE4\xB2\xB1)\xB4S\x8F"D\x86C\xF2"\xE5\xEF\xF7\x98\xEBf\x8Cp\x9F\xBF\xB2\x1AR\x98G\xB4\xCE}4v}*\x91\xFF~\xAEn\x08)pu\xC9\x14\x0Fz\x80o\xDFQ\xB9\xBF:jv\xAD48\x0D\x97#\x01\x1FA\x91\xA9r\xBB\x98\xF1q\xFC\xAAw\xEC\x8B,X'!\xA0\x1B_\x8FJ\x94\xB2.\xE8\xC9$V\x85\x9C#\x96k\xF5\xAC\xC4\xC8\x85m\x9B\xC6:7F\x14\xE5G\xA8V\xB3?\xA4\xD9%\x8A$\xDAM\xC3\xB9\x96\x03\xCB\xB0\xBC\xA1,!\xF5\xDA\x0B9\xC6E\x0E\xA7\xD2i\x96\xF9\x0F\xC4\xDD\xDB\x93&\xC5\xB3\x95\xA0:\xC3\x83i\x81\x93\xCE\xFA\xFEy\x93\xF5\xA7\x89H\xE3\xF3U0\xA1\x8Bx\x9D`\x99\xAD\xFF5G\x9C\xC6\x9D\x92\xB5y\xB5\xCAr\xC1\xF3\x00\x08@\xAB]:/\xA5\xFC\x92\x92>\xFF\x97_yx[}\x04n!\x8B\xA5\xC5\xECi\x01\x05\xB5\xA7\xA1\xAF8\xC0*\xD0p\x08\xDCS\xF5\xB0c\x92\x03\xF9i\x7FC\xF3\xD9\xBF/~\x1E\x0D\xB0\x14\x1C\xFB7\x98\xBF\x88\xECYq@\x0D5 \xD0\xC5\xFD+\xEA\x9B\x04k\x99\xD3\xD4\x0D\xEA\x19&\xF2=Q\x9A\x09G\xC6\xEB+\xFB\xF0B\xD3\xF3\xA8\xA3\xCC\x97gR \xBA\xCF'\x1F\x11\xE2\x9F\x8D\x0F\x87\xE5\x0C5+\x89~\x84\xE6\xCDg\xE7\x97\xFEy\xEA\x8A=\x7F\xD5\x80m\xC5\x9E\x1B\xC2\x0A\x99l\xE2\gl\xE5\xDFSQ\xDFfSnd\x19\xB0\x8E\x99\xDC\xE5\x0C\xD0\x9C|\xD5\x14\x0E\xC8\xBA\x09\x13\xE4\xFFX\x0F+,\xB0\xDE\x0C\x02\xBF_*\x83\x14\x8B\xDAV\xD6N\xBF*R\xCB\x1D\x069\xE3s\xD2\x9C\x08\xCEI\xBCO\xD53_\x05\x80.\xA5=\xF9\xF2\xD6+?\x02\x87r\x0E6\xE3v\xCB\xA4M\xA18\xA2m\x17\x14\x98b[\xB0\xB3MO'\xA9\xC9\x85\x9B\x0E!\x0C\xCA\x14\x83\xC0\x1F\xE8\xC4M\x0ER$\x98\x1F\x83wU\x9DE\xF0\x83\xB4I<=\x93\xCD\xF0\xF3\x1Ap\xA2d\xCB\xAD\xE2\x03;L\xE0\xC2\xE9\xD3\xFD\x8E\x8F\xBF\xD9;SX\xF0\xAE\xB6\xB9\xB2V7\xB3^\xF4\xC1V\xFB\x0C\xD8Zj\xDA9<\x1A\x8E\xF0X0:\x07\x8E\xCC#\x8A\xD1T\xD5\xE6\x0C6\xA1F=\xCC-\xFE\x82\x9A\x03:6]:ni\xD9*iY\xB6\xCA\xA7\xB8c\xCF\xF9r\x8C\x86\x9E\xB2\x9A,\xA0\x996\xF2\x12\xBC$\xEC\xF02=\xEA\xD8+\xA5W\x82\xC85^\x8F\xBB9\xE3E\xFA\x11b\x7F|S\x89\xCB\x00"\xCF\x9Bi#\x8BB\xB8[\x05\xB0\x91\xB1\x96\x97\x87\x93\x8A\x03d\xEDf\x16\x15\x17\x9E\xE1\x8F\x1FL\x05\xC9p\x03\xDF\xEA:K\xDB\xEE~|5i\x82\xB1\x85M\xF3\xD8k:\xD3E\xC0\x8F3\x86\x92\xA6\xE2\x8E[\x1E@\x00\xF0\x95\xD4\xBB~aJ\x92\xDD>\x8C0\x0Ft\x18D\x1CA[\xD0}\x80\xCF\xF6\xE28\xC4m\xDA\xF1S\xED\xA1\x88\xFB\x0CH\xD3\x8B^\xC5\x89\xDF\xE5P]x\xBE\xEF\xD1r;7qU\xDF\x05k\xEB\x89\xC8\xF1{$J\xB5&\x95zm\x07Ly\x80waFc\xF3\xAB\xB2\xA4\x99\x1E\xDB\xC9\x17\xC8\xBE\xD7N\x89\xF3\x9C\x03\xB4R\xD5\xCDP\xE2\xA6\xE0\x9C\x0BP\xBB|^\x83\x15e]Hx\xF6F\xFD:J`\x92\x18\x94\x0C\xC3\xAF\xE0\x9C+\xF2Z\xC4\x86G\xE2z\xAF\x1D\xD1\x1F8\xF4\xB6\x1E\x99\x85\xA2\xBF:\xE4\x93\x1A\xFA\x0F\xD9\x14\x04\x04\x9D\xB3@7v_%\xA4\x84h\x09\x8C?\xDD2;a6\xFD\xAF\xE6\xF9\xA5b\xE4\x998T\x07\xDA \x8B\x18\xCE\x02\xC3\x8B\xFC\x8B\x14?\x1F\xB6\x8Biz\xE7\xBD\x99\x9Fr\x0E\xEB\xB2W\x07\x13\xF5\x85s\xD5\x82.\xA5.\xA2\xF3\xDF!\x8FV\xB3\xA3\xE9\xFFx7@\x1C\xF0\x88\x8B\xB7T\xBD\xD8\xA8\xE6\x0A\xEC\x8B\x94{+\xFF\xEE\xF3\x06NG\xE9\xE5\xB8\xC7\x92\xB8\xEBXS\xC1\xEF\xFB\xCA\xAB\x17%\xCCB\x8A\xCBFv\x82\xF87\x92Q\xAE,gM\x0C2k\xC9\xB1\xC5\x19\x00\x14\xAD\xCE\x06\xC8\xEFL\xA8al\xFA\xEA;Y\xA1\xDF\x95\xCA\xD3\x99\xCE\xD4\x03\x01]tu3 G~\x84\xBD\xF8{\xD4$\xFC@\xFDMU\x13o\x8Bh\xBF\xB4\xEC\xF87u\xE2\x9B\x06U\xB0\xC9'\xB3\xDE\xF8\xD0\xF2\xBF*4.\x84\xEA\x99\xA0\xA9#\x14\xF9\x9F\xAD\xE5\x12\x7F\x0C\x0E\x1BNbd;\x84o\xE2\xFCV\x0B]\x95d\x00\xDE\x9D\x12&4\xD7\xEA\xD7\xEE\xC79\xF6\xBA\x10\x89Q\x99\7\xC0\x8F\x1E\x82GC\xF2\xAF\x88\x04\x8B1w\x10$\xC6\x10\x11|hT\x89+G$\x96K\xAD\x9A\x0D\x06\x18\x80\xFB\x07\xBBY\xB6FQ\xCB\xC6\xAB\x06TW\\xFA|\x81\xFC\x90\xE3\xD5\x11\x0A\xAD\xEC\xFDK\xBB\x9B\xB2\xD7!m$\xB0N\x96\xF5s\x03\x97\x07\xB7\x9E\x875~4 \xBFC\xAF{\xEE\x9B\x1B\x11\x05$\x0D\x8Ee"U\x1F\x90\x07\xF4\xDC+R\xB4\x82\xF9\x19\x1E$\xB0\x8Bs\x9C\x7F\x01J\x0F\xBF\xAA\x8BAp\xAE\xEEtzI\x82\xB4\x94 \xBEc\x87{5(\x094\xE6\xD1T\xFEkTi\xEF&\xDB- /\x06s^?c\xBE\D\xF9\xC25B\xB4\xCD\xCC3}\x14%\xC7\xDCTA\xC0\xBF\xFA\x97\x1D8\x15\xC2\xCC\xDF\xD4\x90\xE4:\xC4Q\xE9v\x92^\xB9h|\x8C,\xE5{\xFE\xD9\xCB\x86\xDA\x0C\xAA\xFB\xEB\xEAu\xE5\xC1=F8\x7FH\x09\xC6\xFF\xF3\xD5p\x8D\x82\x1C\xD57\xF5\x97J\x81\xF7\x05\xB1+Y=\x10E\xAES\xAF\x9E\xEE\xF6\xD2\xFC\xD6s\xA5n\x9A\x10k\x9A\x9F\xECF\x9E5X\x95\x09@\x86\xD4\xFF\xAA\xDC\xB2\x12l\x08\xD5\xB3a\x93q\x1B\x814\xDDwGu\xDA\x856\x88W\x03\xE7y\x89\x99\x98\xA0i\xBEr\xCE\x9Ei\x8C\xDB\xA3L\xAD\x8F\xE0\x18=\xA6u\x00\x1Ay\xBFa\x11\xD1m!\xDC8\xE6\x0B$\xD6\xC0\xAA\x1A\xB7\xF5\xE4\MX\x1B\xFAp\x14\x1E\x83aN#fZ\xB4\xBB\x1F\x0C \x127_\xDA\xF2\xD2\xB9\xF9i\x80\xE3\xA9'\x8A\xCFN\x80\x06\\xABj\xD1\xE8N{/\x93\xA1\xF4\xF1\xA1\xE7R\xEF;\x80\x8D\xCF\xE4A&sc\xF7\xD3\xAB\x0Dc$\xA3\xF3\xA1\x80(eP]\xB3\x1B\x9E\xAE=o\WP\xE9q\x8B\x0E\xFBM\x0A8\xF4\xF5\xFD\xB8\xC5\xBF\x076\x87U\xC5\x8Cr\xD29\xDE|\xA5\_\xA5Y\z\xE3/\x0B\xC8\xBF>|\x08\xBB\x8D\xF5\x8C0\xA1L:\x91-\xD6\x88\xFC\xCC\x8E\xD4\xB2\x0D\x0B\xD3:\xAEy\xE1\xEES]\xF69ds\x8F\xCFX\xC3g\xFA\xCB\xB3\xBB\x85\x86\x80\xA7*1\xCAk\xDF\xE6\xAA\xBC\xEB:B\xCBN\xCA\x9B\xD9\xE8\x90\x80o\x96;\xDBn\xCB\xBA\xF6\xDC\xF0\xB7\xE5\xFC\\xEB=\xAE\xCC\xAE\x85a\xCA\x9F\x9C\xD5K\x8B\x11s\x08\xEF\xA4\xBB\xEB\xBDV(`\xC4\xE9Q\xE5O\xD5\x9B8x\xCE[?\x02\x02\xAA_\xDB\xE0o\x0A\x8F\xC4\x0B\xE6\x89\xDF|\x1Do\x80\x022\xBC\x96\xE5\xBA\xDD\xD0\x1D\xC4^Uf\x196\x8D\xA7[}\xB1[\xB1\xF50\xADD\xFDm0\xB6\xDE\x98\xCC\xAF\xCFN\xF6\x1C\xE6} \x94!\xC9tL\x02Q\x09\xD6Ny2\xE0\x9Di\xA8\xD1\xFC\x18E\x17\xF4\x84;\x06\xA2\x08\xF4h\xDA\x83\xC5\x07y\x1Ca\x9C\xA8W\xA7\x1E\x92\xF0\xDFu\xA3_\x0E\xA9\xA5\x89\xA3\xE3\xAE\x84ex\xE8=\xE6\-\xF51\x95\xE8n\xBA1A\xE4\xFB\x1D<\x8F!\xA7\x80\x077\xEA\xCB\x90\x1F:\x9A(GH\x09\xE2\xE4\x15\xDFk\x0C&\x01\x99D\xFC\x16\x10\xA2E\xC9[\x0De\xCBo>\\xB6}\x09\xC0|{B/\x7F\xF9\x9E^\x1A\xF3\x05\x84\xE2Vs\xE5=1\xE0\x10\x90\x18\x8B\x13\xC9\xA2\x82"\xFA\x1D\x9F{\x0F\xBD\x9Af\x03\xD0\xD3M\xBD\xB0K\xD5\xCDS\xF4\xD2\xCC)\x1A\x15\xB3k\xD4\x8FRY'\x81h\xC4\x97~\xC5\x19\xF6?\xC0\xC9\xDB4\xE7\x02\x15)\xDB!#ye\x82Y\xA2\x14@\xFA\x86\xC2\x1A\x93\xB1@\xC1\x99`\xEE\x82\xE3M\x0ER\x1E\xDE\xE5n\x1C\x14$\xB9\x95\xFD\xF3\x1D\xCE\xF3\xEDG`\x1C\xE8b\xF1\xC6\x17\x0A\xC3\x89\xBD)Q\x1C~x\x9B\x1B\x1CP\x1C]\xF5q\x90i\xD0gH\xF0\xEB;>\xE07\xCC\xB1\xA2(l$M\x00'\x14y0cb\xA5\xBB\xAEW\xB9\xD9\x8D\x8E\xEC\xAB\x18\xBFz\xF3+\x1E\x16\xB5\x09\x06\xF9\xFD\x87A\xD3\x8C\x88dL\xBF\xDB\x1AHl\x07\x11\x99\x8FK\xBE\xEE\xF3\x11\xCDR\xEF\xF8bKM\xB1ge\xA8\x01\x92\xD4\xB3T]\x019\xE2|c:\x16\x15\x04<2\x83\xF3\x94Z0\x85I\xD9\xBC=\xA0t\x0E\x8F\xF2\xC4\x06$?\x13\x80~\xF0_\xD5\xB8f\xE8.\x86l\xB8\xF3KG\xFBJl\xF2\x9B\xB3\x11nk|]E\xF9{\x09\xC7\x121\xAE#\xCA\x88\x89\xF1\x91\xAF+\xBA\xABY\x99\xCFS\xA1@\x178%\xD9%\x80\xF3<.EGlh\xF07\x97\xBA\xC2\x8A\x05\xFB\xE4\xEC\x8D\x1F\xC6\xB3\x1F\xDD\x85_9\xEA\x19\xBFiN\xE4\xFAr\xB9M\xB2\xCD%\xDF>\x05\xA1\x8B\xE5\x09Sr\xBF\xEFS\xAE4\xE8o\xBD\xD2<\x1E\x87\x87\x83\xC3\xAF\xDD\x82\x12\xF2y\x13}\xCBX\xC1|o5/\xD2\xEB\x04j\xBD8\xC3\xB3\xF0q\xED \xF8gSG\x01s+\xA2\x1C\xA0M"\xFC\xBExZ\xC2\x18.(V\xBA\x1C(\xCC\x1E{\xBDd6\xC6{\x17\xBCO\xFD\xF7\x916=\xF5BRH\xDE\xD6\xF6}j.\x14p{:n\xB4\xD0\x8A)MgR\x16\x04Y\x04{+"\xB2\x96\x8B\x92\xB8\xA0w\xFC\xB7\x0E\xE0\xC9sAIn\x9C\xE2T\x9F\xC6\xD1\x19\xD3(\xBC\x81t\xF5+\xFC\xD6c\xA64\xF0o\xC6P\x9A\xA9`\xB4M\x17\xA2\x0Bm\xD4dw\x92\x13*|Ed:N8\xD9\x85\xF4\x12t\x06\x04|\xCDB\xFD\xD9gq\xB6\x1E\xD2:\xC3\xD5bg.\xBE2\x1Dq\xE5\xFC7e\x84\x1E\x06\xFB0\x01\x17\xAE\xB47\x0A\xDA\xE0M)\xC2\xEC\xF8\x9F\x1E\xD9\xFB_\xBDflIl\x18n\xFB\x04g\xBA\xFE\xADM\x82\x82\xA4,:\x06\xF2\xF6\xAET\xFCd\xA4x\xAD,@F5\x0C\xF6\x82\xFA\x0E\xDE\xF6\xDE\xFC&\x0F\x0AOn\xB2\xFAb\x01\x93H+\x15!\x8B\x14\xA6\x05oV\xC9\x18!\x9DnN4S\x8C9\xD8\xF6\xFE\xB2`\xCA\x14UZ$\x8E\x01\xF4F\xA3\xA6\xDE\xB9\x14\x97\xB0k\xC5VB\xA2\xC8g\x00\xC3\x97\xFBY\xE7n\xB2\x9EB\x88\xDF\x07fc\x16\x08\x19\x07Y\x89F\xD9\x13<]?\x87]ub<&\xA0\x0F\x152\xB9\xF7\xAE\xE2x.\x06\xF7\xCC\x1D\x8APe@\x98\xA8\x13\xCCs\xD6*\xFA\xB3\x16\xD5\x9E\x0A\x1D\xEAx:L\xF8\x94\xF6\x81^\xD6\x8E\xCC\xEE\x0C=_l\xB7RZ\xE1\xE2\xC8\x87OX\x9C8\x8E\x8A\xCF\x12\x0C\xC9Mwf\x990\xA1\xCAP\x8F\x99\x98\xE3\x07E"\x1B\xFC\xB7\xFB\x84\xF5\x7F\x90\x0C\xBD\x1E\xC2r\xAE&\x1B\xC9%U\xB5\xB1\xCA|v\xE3\x91K\xCD\xD9\xF2\x99\xF8\xFD\x97\xED\x88\xC1\xD3\xB1\xFD\xD5\xC3\xD9c\xC6\x8C:\xD5?}U\x98\x85i\xB9\xE2\x01\xC9\x0A_\x8D%D\xCD5\xF7\x86\x89\x9D\x1A\x15$\x9D\x8D\x1C\xBF<\xF5\xFA$O\xE6\x87\x14\xD4\xF3\x80Y\x92_\xD5X\\xADz\xDAU\x07Y)\xF9\x00\xB7\x166,[;\x9A\x97\x0FK\xD1CB\x9D\xD5\x13g\xB8\xEF\xF0\xC9?1\xFA}r\xFDD\x10p\xD3\xC4f\xA20h=W\xC9\xC2\xDB\xCCrK\x17\xAF=\xB9]\xE2\x0F\x0CBC\xA9`\xE0I\xC0@\x0F\x05\xC5'r\x9A5<\xE1\xAFK\xEF\xCEJ\xA6\x0A\x1Dc\xCF\x98\xB9\xCB\x15\xB9\xBCe5\x97^\x925 \x9D #\xEEqPuV\xED\xBDj6E\xA0Q`\x83\xB4\xAD\xA7FR\xC2\xEE\x98\xE8.R\xB92q\x97\xD4%\xDF\xD7\x10T\xD4\xEB[`\xB9\xCD\xE4\xEE\xD8\q\x8A\xC4G\x82\x7F\x01\x82\xB4\xEF\xED+\x08,Ch\x95.#\xB9nz\xB8\xEB \xA0E\xE4\xB3@6\xC2\x8A\xBF\xC9\xF53\xE0\xCF\xBA\xDD\x01@\x02y\x18Q\xE1\x81H^.\x05\x8B=\xC9t\xFD4s\xE2\xB8o\x8Am\x06Nb\x00\xA4\xC2\x00>\xA4y\xCB\xA6\xA1^\x86.\x16\x8C\xAD\x80 \xC0\x86)\x05\xE39\x17|g\xF8\xF2`\x0A\xDF\xAF@E\x16\xBC\x09\x1B\xEE\xDE\xCD\xB4f\xD8j\xAAs_\xE3n\xE9X\x9F\xF7:\xE9\xA21\xAB\xD5\xE7\x19]\x19\xC3G\x8D\xBF\xB0D\xEA\xA4be\x94\xDB:\xE9\xA4u\xF0\xC6\xF5\xDA\xB3u\xFFfD\x1B\xF97Ch0\xAB\x1D\x8BS\xB6\xCF\xBB\x02-\x17\xA8\x1A:\x1C\xB8{j\x8F\xC6\x8F\xCF\xDEI\x9A\x8EP\x98\x0F\x1B\xB3F\xC8\xE8\xC6\xB8\x05\x91\xD1_\xF4\xE6\x96\xBBn\x1BW\xD3\xCE99P\x81\x1B5KV\xD5:"\xE0\xEA\xA7i\xC5\xE4\xA7_\xB9E\xE2"\x13\xEDS\xF4\x99I\x86\xB2X\xB3\xEEw>\xE4\x18\xE0\x84\xA5tQ\x19\xF0\xEA\xD0\xDB\xCBZ0\x17L\x8B\xD73\x93)\xE3\xC6\xB1\xC7\xFAT\xFB\xDE\xB4<\x16\x1E\xB9\xB7\xDA\xB7\xBBJ\xDCV\}X\xB9\x12\xB0"`e\xA2\xE0\xCE\xBDn\xE5|\xD6:\x09^1\x97\xDF\xFES\xCCD!a\xD9D \x0F`^\xBB\xEEp\xC9\xBA6\x04\x0F\x19s\x1F\x9C\x9BT\x95'+\xB3\x073\xA08\x94(\x1B\xB2\x99\x1F\xAEC\x91C\xA5B\xFAF\x88\xF1n\x0D\x0E\x15\xB60\x8E1=v\x07\xD6\xF0I&"\x91\xC0\x17x\xBBI\x02R\xED\x80\x86\xE0i"%\xCD+\xFE\xC6\x82\xF4\x1E\xA4\xAB\x81j\x9C\x92S\x1B\x19\x860\xB6\x1B+3\x02\xB2j\x81"\x08m\xD6\xE9I\x17\x98\xB9"|\x8C\x8A\x12E J\xB2K\x0F\xEA\x98+.\xAD\x18~\xF3on\xA8\x93L\x8ByU\xAE\x07\xBASGH\x89\x15\xB8\x84\x95E\xB1\xB6\xDB\xB8\xB9\xA2\xC4I\xB8\x17,\x19\x18\x1D\x9A\xCB\xB3\x97S\xE6\x85\xD4\xD4vg\xF9_\xE6\x94<\x8D3\x10\x93\\xAA\xCDd\xBBG\xE13P\xA2h\x80\xC7; \x9A\xE3\x04\x08\xA8\xBA\xD7\x0D\xB5\xB0u+\xC3\xCB\x93)\xD3\xA3\xAA3\xA3\xA5I\xA4d\xD2i1p\xF2\xDA\xF2\xF24\xF9\xD3'\xE7\x82\xDF\xA9\x85\xB90)\xEC\xEE\x95\x1B\xAD\xB0:,\x10\xE7q\x18\xB3\xE6%\xA2\x16R\x99T\x811\x08\xE4\xBCf\xB7x\x9D\xF7x\xD7\xE8;@\xF0l\xD4\xF4\\x94\x13-\x9F?\x9E^\x02j\xE2\x1Cr\xD9\x15\xCC\xA3\x1E\xDD$\xC7k\x9C~\xEF\xF8\xFC\xE8\xCA\xC5s\xBA\xB5i\xCB\xB1dyO\xD6\x9B\xDF\x8C\x94\xFD\xC4\xCD\xC8\xC15-\xE8\xA1\xA9\xF9\xE0;\x89\xE9\xA1\x81\x99\xEF\xA5~\xE5\xB3J\xFB9\x9D\xF0\x10\xEF\x92\xAF\xF6sa\xA9\x98\xF7W{\xAF\x9F@\xDF\xB02\xB7S\xFD0*\x16|\x9AY7\xF6\xDDc\xEE\xA3\xA2\xDE.I[y\xA0\xFF;\x82\x872\x94\xA7\xE3|\xD0-:@t\x1D.\xB3\x0Az/\x94\x80\xF6x\xCF-\xDEg\xBBV\xC0\xE2\xD6v\x17j\xDC\x06m\xF5\xA8\x17Uf\xBC\xACtW>\x1D\xD3\xD89\x127\x1Bo\x8E\xE5\xC3,\xAA\x95)\xA4fP\xB7o\xA4VDIR49\xFA\xCB\x12\xB91\xCAFQ\xBC\xD3\xDB\xC7w\xFA6A$|M1?J!\xB52\x1C]\xA1= O\xEC\x8Ep\xD3\xC5\x8F\xAE\xBD\xA9{\x00\x9Bb\xE6\x0A\x08!]}\xA2\x1C\xF3R\xED\x1F\xB5\x92:\xBE\xE6\x11\xE44\xA3=e\xA18\xD3*\x11}\xC8C\xFC\xF0\xF9\xCFdC\x15\xDEO\xC7+\x1C\xC3m"a/\xC1\xBCm<\xEC\xD5\xE9,\x193\xF9\x99\x1E\x0CD\xEE.r\x85\xD3!\x80]\xC2\xFC\xA3\xFAY\x0E\x96\x1D%\xDC]"\x09&\x99\xB3\x14\x92\x0Em\x10\x8FD\xFB*}(-\x10\xA1\xC0\xF7\xD0\xA2\xA7F6\x0C\x87A\x0E\x0E\xDD\x9A.\xCE\xD9G\xC0\xC9\xB8`\x10\x0F\xDB\xDA5\x89\xF3\xB8\xC00\x14}\x86\x1D\xA7\x9AU\xA5\xF0\x94)\xF37a\x81\x15\\x99\x88R\xAD\xA9\x14\x0E\\xB2\xAA\xCF\xF5\xBD\x0Cd{\x9F(\x88\xC18\xD4\xD0\xBA9\x09T\xBD\xDC\x9F\x84\xB7y85\xEE\xBE\xFC\xA2\xF0\xB0\xB5\xEA\x98M!^A|\xAD\xE7\xE8Ju\xBF\x82\x0E\x16\xDC\xDE\xFAe\xB0\x98"\x92\xCB(\x98\x8D\x94^\xF2\x9904\xDC\xB0NT\xA1>-jo\x1E\xEC\xC2\x04\x0B \x13\x13x\xFE\xD4L\xC8j\xABi\xEF\xF1\xD0k+\xA2x\xE1n\xFE\x801\xBB\x08\x83,Y\xBC\xBC\x00y\xF4\x81\x19\xBEy\x82W\x06\xDEu\x98-;\xEB\x92T)\xFC\x87\x95k\xE3Z6\x8B\xEF\xD0\xD5\xB0\xC5\x83C\x14u1\xE3\xB6\x85U\xE6\xB0\xEE\xA0\xB8\x19\xE9'\x92'~Rbv\x1E\xABu\x99\x99Z\xE3%\xDA\x13 \x17\xC7\x15\xD5\xC8Gt\xF9I\x07\xB2\xE5\xA8\xCC!wT\xBF\x16\x95\x9D,\xEDt.\xD47\xF9\xA3\x97\x0D\x1D\xB8\xCA\x9AIE\x86\x12E\xD5\xD8mjN\xDD\xD9)\xEC\x06\x0F\xF4\xCA\xDB$\xE1m\xCC\x1A3\xC0\x00P\x18ld\xC24Yo\x0A\xC2\xFE\x03\x98\xE5"\xF99\xE1-\xAF\x0C\xC7/F\xEC\x9F\x86\x1A\xA2\xCD\x8C\xAC\xFBFHPxR\xED{&\xDC|]yU\xEAz\xDFl*S\x07]1\xDA\xEFCe\x9CL\xAA\x99CQ\xAD8\xCE\x11\xA2\xDA\xB9t\xF4j\xB1g\x9F\x9C\xB6\xDA\xAD\xE2w]\x86e\xC3\x85\x9A6\x04\x0A\xD0\x84l\x95\xAB\x86.\x19\xE7.x0\xDFs\xA7/\x0A~N\xF1\x19\xB6\xCA\x1C\x18\x9F\xC6e!\xBA\xC4\xBC\xEA\x1A\x8A\xC2m\xAF\xF8\xC2)\x81\x87Fe\xCC\x11\x16\xC3\xC7\xE2\x0F9!O\x91k\x0A\xE3V\x8BdE-\xC5\x07\xED\xBAy\x8A\xA6\xA72V\x80\x0C\xC3\xFD0\xC5Z\xE0\xDD\xE5+\xCC\x15,\xDCYJ@?R\x88A\xD3\x16[\xA0%\xC0-\x02\x12\x95\xC1\x9F*\x80\xB6\xC1C$_|"\xE9V\x8BM\x02\x82k\xD8\x09\xAC\xC7\xAB\x03\x0E\xF0\x1D\x90\xD1\xC0\x9C\x0B\x19\x85>%\x90\xF2W>\x86\xF7\xE2\xE2\x09\x0F\xA3\x87\xBF\xED\xA3\x0E\xF3\xC4\x87\xDA\x8B\x04\xE1\xE7\xF6*\xE6\x02H\x8E\x97R\xC6]P\x10\xA1\x97D[T\xEEG\xD9\xD1\x1E$C;\x06\xC4\xE8\xFA\xA8D\xC9\xF4\xBB\xCD\xE3\xD5\xBEC\x0C\xF7{P+\xFE}\xB8yj3\xA6\xBE)\xBC\x91\x1B\x0F\xA2e=\xD3{\xEE\x00\x1B\x18o\xEB\xE2\xE5B\xCF7k[\xD8e\xAF\xBE\x89\xBA\\xB1S\xD3\xD6U\xA0\xBA7\x91\xB9\x0F\xF9\xDB,i\xAE\xAE\xEF\xEC\xE6\x09\xB6\xE5\xB1\x97\xA6T\x80\x19}x`\xE6\x85\x97\x19I\xC9\x0D\\xDC\x12EZl\x1CQ\xBA\xA0P\xC6k\x8F\x87\xBC\x97\\xFD\xF4\x9D\xDD\xB4,\x15\xD9;\xCFg\xF1\xD6E\x03\xEB\x0E$\xEB\x88\xE7^\x80\xE6`\xE0-\xA3h}\x18x\x81\x0DL]\xE6\x0Ep\x91N\x99\xD4\xFE\x94\xDD\xC7M1\xE4\xAD\x13\xE6=d\xF5\xC5\x1A\xF6\x94\xA0\x1F\x86\x94\xFE'\x7F];nf\xAD\xE1ZX\x84\xBEj\xE0\x1CC1\x01[\x97\x82\x96-\x0Br\xCB\x10d\xC07]`\xD7\xCCS\x17\xF0\xACob\xF7$l\xC1\xA1\x8F\xB9\xA9\xE3\xB4\xA0\x1B\xD5\x92\xD1{\xC9G\xD8sS\xFF\x04/RT\xE9\x192S=\x98\x0A\xC6\xF0\xC4\xE1=F+v\xB6\x96\xDE\xA0\x82\x8A\xBB\xE5\x9DB\x0BYp\xBF\x1B0,\x80\xF1\xB9O!E$;!\x00\xCB,*\xC3\xBFW\xE7\x11\x1F5\xE3\xEE\xF1\x8D\xB8\x1E\xF3\xF4E\x9D\x9C\x10\xA8\xFD\x1CjJV\xA7\x14a`\xD9\xFD\x91\x86c\x0E\xAF\xF7E\xCF\xCEsQ\xF97\xEA\xF3?V\x9C\x90e\xA9\xC1\x89\x04\x89\xA4.N\xE9\x7F=\xAA\xEA\x98\xA8&\xFE\xFCf]\x1D*\xC0\\xD1\xCF\xBF#10\xE5\xC0\xFE&\x1D\x81\xD5D\x99[D\xECmWg0\xAC\xC8Z\xA4\x85\x1F\x0AL\x03\x96+\x86\x1C7\x1CkQ\x18\xD5\x8F\xADb\xC7h \xA0\xD2\xBC*\xA9\x80\xAA\x1F\xDB:@\xB1\xC0\xAF\xD6\xAC\x00\x00\x97G\xFA\xE06\xA5_\x90\xB9\xF5\xD3\x1F\xCF\x18QFy\xED\xCEp\xB0\x04\xC3\x8C}\xEB\xA8\x8F\x82\xB3#\x9C-\xEE_JA\xD3\xDBFoI\xF3=\xC4A\x98)P\xFF\x8F\xB6k\x19\xBC/\xBEe@\x0CL\xE1\xDFa5\xE0\xB6\xAC\xF8\x9B\xAFB\x0C>\x1C\xA8\xB2\xC3\xA3U\x9D\xAF\x06\x96\xCA\xE6\x89zC\x1FJ\xEE\x8BZME\xC8\x98\xF2Y\x98\xEB.\x83\xCE\xF0k\x8BC@4z\xC0d\x90\x96\xD4\xA2\x8D\xB4(.s\xE2\x9F\xBFCa\x11q|\xEF\xB7\x05\xF4n\xC5\xAEA\xE9\xEE\x90C\xE1\xEE\x8E\xE5X\x17\x8Bz\xA3gL\x96+w"\xFAIP\xBB\xCA\x09\x90\x9C\xD4\xDA\x89\xBA'\x86\xBD\xF7:\xA6\xEB}0\xBCQ:\xA5Oq8z\x95\xBFZw~\x92\xE7b\\x86\xE6\xBA~\x88I\x04\x19\x9F\xDA\xE5\x89\x08O\x97\x1AAB\xA1\xE0*\x85\x89\xFF\x93\x95\xA6\xFB\xBFDu\x88`\xF7(xM\xAD\xCE]\xBD\xB9g\xC7\xD2\xBE\xBAQ~\xD8\x09\xE7\xEB\x00\xFB\x13\xCEGN\xED\xAB\x97o^\xC4G\x03(\x89\xCC:W\xA9\x1A'\x95\x8E:\ \x89\xD7\x1E \xDBGw\x9A\x98($\xBD\xEE\x99\xB7\xB4\x822\xF9.\xC7\x9F7\xAA`\x06\xAA\xC0Pd@\x9E\xFD=5\x006N\xFF|\xFC\xB1\xF1?\xD6w5k\x0Fy}^d\xB3\xBDz\x9A\x8A\x829x\x93\xE1\xDD*\xAC\xB7\xEAG\xDE"\x13\xEA\xA2\xC8\xB2+P\xAEe\xB1\xBFN\xA0W\xAB\xED\xA3,8K]PR\xF2!8\xEA\xB69\xA3\x11\x87-\x83\x7FGz\x13\xBB\xEE\x86\xC4\x0D\x90\x16 \xBB~e\xDB\xA3\xB3\x16-\xE0\xAFP\x89a\x0Aw\x90\xD8\xBC\x9B\xBF\x0E\xEE\xD5\x16>\xC5\xF6\xDEOq\xF6p/}\xE0N\xE6\x9C!\xA2\xAE\x04\x8F\xBE\x9F\x00i\x12ug&C\xDA\x81\xF9{\xD8\xCC<\xCA\xD5g\xDF\x01\xE2X\xFD:\x1EF\x06\x8F\xE5z-~\xD7\x9F\xD4O\x01\xB37a\xB3\x82>mx\x07\xFA\x07\xD3\xF6\xB0@\xC7C\x95\xFF\xEB\x88\x9D\x99\xDE\xFEP3_v\x17\xAE\xE7\x1A\xAC\xD7,\xAF_\x14\x83HK\x09\xE1\x07!\x80d\xE0\xF8'\xF4%0Y\xA7q\x01\x0F0\xFB\xFAig\x80\x85\xBF\x1C\x99\xF0\xBARo\x1EW{\xD3\x94\xA4R@.:`!\x83\xE4\x85\x0B\x88\xE4i~c\x06\x14\x91z\x8F\x1EJ\x835\xB1q\x04\xA9\x82Y\xFE>\xBE2\x807]/c\xADl\x8EG\xED\xCC\xA9\xBCzV}\x9C\xD1\x10\xF8-[b6JO\xB9i\xC0{\xEB\xE28\x09\x9C0\x81\x94\x89Hx\x1B@\x91E\xA5\xE9\xFE\x8CZ\x98\xC9b\x0F\x98?bdI<\xDBI\xAE\xC6\xA1\xD5\xD3\xBE\xB1\xE8\xB9\xE6qfMS\x9E'\\xAF\xFEe\x9A\xAAKp|%\xE9\xF0=\x9A\xE3\xA4\xF1\xDC\xA2\xE2:\xC9\xE1\x94\x0F\x17mf\xA3I9~\x94\xAEy\xF9\xC30\x1C\x10\xAC\xE0\xCE\x8C\x07\x96\x86\xFA0<\x9B<\x0FAR\x18R\xFB\xE6\xA8\x93\xC9\x91\xD5F\x99\x9ES\x02\x90\x0B\xBC\xB7\xE4n\x0F\xF9\xD3\x9B:\xFF\xF0L\xD1\x12\xD6\xEC\x04|k\x10b\x94tJ\xDA\x80\xCFa\xFB\x09\x9F\xE87\xA2\x0A\xA1\x8F\xCDb\x08?\x81,\xF6\x0F\x09\xC3\xC3\xA7<\x08\xF3\x82\xC0\x18\x95\x83 \x0B\xF97\xD0\xEBy\x81fK\x0DL\x1E$\xF4\xDE\xF2\xC2\xF1h=\xAA\x0E0u\x1D6\xC7T!\x86\xA1[FuW\x13\xE0\x1B\xA3oJL\x13\xEC\xC4\x13/\x1F\xFAx8\xFB\x816!\xBDT\xAD\x004\x975\xCB8\xF2B/\xCF\xF5N\xD9\x1E\xB0\x9Ej\x1CF\x09'\xE9\xA7`\xC1\x15\x91\xC2\x1C\xDF7\x1B\xC2d\xB1\xCF"\x13}\x0A\xAF\xC9\xFB'\xD3ITE\x01\xF6\x14\x1D"\xC6\xA0\xEB\xDD^{8\x19Y\x83\xD1\x8D\x90\xF5\xF6G\x1B)\xAB3\x07j\xD4!\xB68\xC4\xF5\xA5\xB3\xD1w@v\x0C\xF62^A\xEB\xDFH\x19\xD8\x85\xE8\x19\xBB\xD32J\x85T\xC6\xA4\x7F\xA3S\x9A\x11\xBB\xF1\x13\xB7t\x85\xB0\x9B\xEB\xFC\xA5\x9E\xD6\xE1\x8C\x80\xB5N\x9E\xE6\x94G\xB0\x10\xC0\x18OsA*8g\xAA\xB4\x09\xE5\x93U\xEE\xE6m\xFD\xF3|\xDA\xB1\xCD\xE0\xB8\xFC\x03\xFD\x0ALo\xF9\x1Ep[\xF84;?\xADKP\xC1~dF1M\x9B4\xDE\xC78\xB9?2\xC57a\xDD\xB3r\x8A\x17\x85v\xECA\x159TI[oC\xE3\xC0\x8E\xBC7\xDF\x02\xAA\x1Dt\xF7\xB4\xD7=\xA6\xDA9d\xA2\x9A\xD0\xD0\x15Va\xF0\x14\x0E<\xF9\x8B\xC99\x15\x8B\x1F\x0F\xA6\xC0;6\xC5\x9D2\x0B!\xD0\xF8M\xC3,\xA9\x01\x1E,4\x96\xC6\xD8\xCB\x06*\xF8\x1A\xDE\xE4[u\xCA\xE2:\x94'\x94\x11:\x8B\x97/\xFD\x8C\xCD\xD4:\xDCRP\xF3Q\x0CR{3VvR\xDBD\xD4\x89R\x86?\xD1\xA8\x01\xBF?&i\xD1\x98\xD2R%E\xAE\x93\xA6\xFD\x84+\x8C\x9A]\xC8a\x8E\x03\\xB8=2\x0E:\x03\xDB^\xBB9n\x85\x85\xA6\xCAt\x17\x08\x0A\xCE\xC4\xFD\x9F\xFE\x1A\xFEz1gM\xC1\xECK\xC4\x1E\xF4\xDFi\xF7\xB17pq~\x9F\xCAv,\x09\x06\xA8/\xA7\xE9\xCFW5&\xAA%\xCDy\xD5\xC50\x94\xDB<\xED\xE9\xE26\xC3\xF9\x10\x09G\x1A\xF3\xC5\x03\x94\xAA\xAC\xB4\xC7_y\x9F,\xFB\x9CLe\xD3L\x95%\xDF\xE9\xF0\xCD\x0E\xDB]\x8Dp\x81X,\xDD_R\xBC\x9Fz\xD3_\xD7\x9Fe\x95\x7Fsy7R\xFB\xB2\xD7\xE6\x85)$?\xC3Z\x94\x06d\xD55\x0Bmhm\xBB\x95\x8DJbtf\x8Cl\xE9\xBA\x90y\xE0\x9C\x97Y\x9DqK\xC7\xC4\x12\xA6\x06\xD4\xE4\x13\x937\x18/I=E\x10G\x9A\xADYB"\xD4c\xC5\x1D^"\xF2C<\x81\x8D\xE9f\xD7;\x17de{Y\x19\xD8AsyJ\xBA#\x9E\x16\xBB\xA7\xFCG\x9Bfh\xFC\xAA\x8B\xA1\x82\xAE\xF0\x12\x88\xEB\x18\x07\x16\xD3B\xDF\xFDF\x81\x1A\xF9%\x1B\xED\xED\xB9\xE4\x88\xC5\x91\x86RxO\x0E{\x92\xEA\xCC\xCF\x97\x04\xE3\x08\xFDU\xB6\xBF\x18\x03o\xEE}\x11\xFCkp\x93\xA9"_\x18\xDA\xE6ffj\x90v\x1D$F-\xB2,lq7Mi\x96\x12\x8E\x05\xF027\xA3\xC8\xCE\xAA\x91Y\x85\xD4\x81Jd\xBF\xD3=\xE3\xD3\xD0xd\xC9\xCB\xF5%\xF2\xA9T'\xF1>\xB9\xD6\xB2<\xD7\xEE\xFF\x13\x84ly\xC0'43\xAE\xE13f\x0F\x1D\x854\xBB]\x1Dd\x85>\x0D\xEF\xDC\xAF\xB6E>\x82\xE9\xA4F\x83\x88\xE4~M/p\\x140\xA1H'X\x0A\xB7\x0E'\xB8\x9B\x05\x94\xA3)\x1E\x8E<\x14\xC1\xB2\xFA\x9D`n\xC1&\xAE\x8D![\xCE\x91\xFA\x9C\xC1\xFD\x8E\xA5>\xBA\xD5\xDF1'l+j4\xD8k/\xA8En`\xB9\xD2M\xA41x\xE3l3\x1C\x09\x09$'\xE7Q\x08\xF6\x9D\x01\x0BmiO\xCC\xCE\xDD0\xB9+\x84`[n\xA4\xEB\x0F#Q\xAE\x18z\xB6D\x8A\x00\x88N\xC37\x1F\xD7\x87\xEEK\xE2"7C\xD1\x07\xCF1;//!x\x9A\x1EXT\xB3\xB4\xA2c\x15,\xAF\xA5\xC4\xBAb\xA8\xEA\x18'\x0B\xD8\x1C\xE061\x02'.\xA7%\xAD\xBC\xECFp\x1B\x0D0\x1B\x18g\xB9\x81)\x06\xDE\x19\x1A8N\x02\xC4yn\x93\xBE\x80\x84\x7FPI9\x0CBI\x873\x9D\x8An\xC1\xF6\x8D\xF7_\x19\xE4p\x83\xFD\xDF\xA8ej\x09\x8E"\x1B\xC7\xDB\xEEK=\xEC\x08]H\xC2\x90\xD3\xC0\xD1\x9A\xDB\xA6E\x0A\x09\xC1\xC2\xBE\xD2\xBCo\x098\x84\x04\x91\xFEl\xE5\xF5{5\x7FR\x00pK\xF6*)")\xD5\x08\x9B\x0F\xFD\x86(\xD8*v\xA3(=d\xF9@\xCEQO\xB9\xD2\x0C|\xD1\xE2\xC4lL\xBFD\x0C\x13*\xFD\x01\x8C6m{\xE5\x8Ecv\xA3b&\xBB\xA3\x8A\x93\x1E(\x12\xC3+\x0Cl\x05\xE1\xBFM\xBB\xA1\;\xD6\x167H\x0B\x992~\xF5\xCF\xF1\x9D`=z\xCC<*r\x93\x8F\x1D\x9B\x18\x1B[\\xA5I\xD3/E\x0E\x8A\xC2N{\xE2}U\x0A\xC9\xE5\xC0n\x94\xA5\xF9\xCF\x9E\xCE\x16\xD0\xA5\xADHs\xFDv\xA0B\xFC4@u\xA3\x88f\xEE\xBDD1\xBD1>\x8F_{\x87\x13\xA9z\x92U\x0EZ\x9E\xAA\\xE2\xE8\xF0\xFCW{e[\xBC\x8A\xB8\x9F\x11 \x1D-\x0B\x09\x04\x97\xD0\xF2\xC09\x11\x97P4\x97\x97\xB3:\x95\x19I\xC7\x84\xF1\x16\x14\xC2\xBF\xB8\x83\xCC0"s\x0D\xD6\xF0\x8D\x14\xACu5\x8B\xF0\x94L\xFBG\xD8\\x97\xD9\xAB\xE3\x08n.#\xB6\xB2oj`\x9C\x06~"\xB9`2\xEFy\xD9\xDDd\xF4\xF0\xD8\xEA\xA6w\x8B\xDC\x0C\xED\x99\xCAG\xF5\xE4-q\xE9\x8CA\x19\xD0\xD2\xE8\x1Ci\xAF\xAB\xC5\xD0\xC1\xEB\x8FS\xDF\x09\xC9\xA9\xE8N%\xAD\xA8\x98~F\x87\xD3\xC9#\xA7h\x8B[A3eR\xCE\xB4\xCB\xC8k\xC4\xEE\xCFI\xC6\xC4d\x97ImY;\xA0s\x9D\xB8\xE3\xDA\x15\xD1\xD3\xB0\x9Bt\x88aB\xB6\x1E\)\xAEgq\xFF\x1B\xCD\xA6\xA9\xB7\x1D"\xFB\x12\xF71\x13\x88\xB1\xF0\xAAB\x02\xDEP\xE6\xA2\x8F\xD2\x8A\x1F+\x0Ew\x9F\xF3;M\x94v\xAB\xAA\x90^\xDF\xBE\x16G\x8C\x8F \xB4\xCA\x0F|\xCAK&\xF1-Y\xD5a\x99W+\x99\xA7,\xA9\xC8\xB2Hm\x8D\x95\x16\x1E\x04op\x9D\xF3-\xA0\xA5]O\xFEm3\x02\xF2D\x92\xF4H\x9E\xE1\xDF\xC8\xD6d\xECN\x9F\x9Bw\x10T\x18\x07?\xBF\xC0\x93\xB43\xE3\xCE \xDAF\xD7f\xCE\xDC\x08\xA7\xC0\x1B\xCC\x8F*\xDE|\x19/\xDA\xB4\xB8g<\xA4\x19\xDD\xCE\x1D:y\xE0h\x1C}~f\x90\xDA\xFE\x1E\xA6\xE7\xCB\xA1\xE9T\xA3\xAA\x00\xC3\x15\x9F\xDA\x1B\xB8\xC7lk5\xCC\xE4\xC1\xF4'1\xE4\xC47\x04\xD2\x88;X\x14\x88\xF7\x12"/5\x1F\xA9\xD5a\x88\x07\xF2bMMv.\xD3\x13\x16\x0D\xC5\x0C5\x86\x99\x19\xB0\xBB<*ZE$v,)K\xB3\x11\xA8\x97\xF4\xD0p\xBE\x88a\xFEN\xCB\xD7\x80\xE2\xBA^t \x82y!]r\xD8\x01\xF1\xC4\xE4F\xCF\xB5>\x80wa\x0EJ,\xC65& \x18A"\x09\xF4\x9A\xD4\xDC\xD7\xB3Jv\x17\xCE\x19\xE7\x97\xFEWh\x08k\x05\xB5\x02YA\x1E\xD5P:A~\xF3)\x10\x86p\xF7|S\xC2\x9C"\xABs\x84\x09\x0C\x8C\x0E7\x0Ak_\xBC=G\xB1\x91(pH\xBAT\xA1\x9B\xFA\x7F\x082!(7\xEF@\xA07\xF6\xF6TiG\x10\x9C\x15\xEC\xC3\xAB\x19\xE6\xECT\x81\x1EaG\xD4\xBF\xAA\xB1\xB2\x0E-\xFB=?\xC3\xD0\x16\xF4K7\xEB\xC96\xA3\x90\xA3\xF7\x9DM\x8D\x1B\x94\x02k@\xD5\x03\xA0\xD74zY\x07c\xD6u\xA7\xF6\x84\xC9\x95\x8C\xDD\xDE\x12\x87\xAD\x09\xEB\x95\xFF\x941F\xF3Xq\xD3\xFB~\x84\xE3\xC9z\xA2m\xDE\xCA\x1B3\xE5"z\xC2\xD1X\xED\xB6U>\x10\xC8\x1D\xA5\xE4lT\x89E\xE8\x92\x87\x7F\xDD \xD2\xA2\x1B\xED\x8E\xB7\x8A\x92N\xAD[\xBD\xE7\x0C"\x07\xFFr\xA3j\x9CG,9\x8C\xB9\x0F\xB1+\x1A\x05\xD7\x02=\xE0\xFCe@cxf\xCFk\xE8\xD1\xD5\xBF`\xAB>CO\xBBvPg;J\x19\xA6\xEDb\x83\xF1dr%\xE6<\xAB\x0C;\xE4N\x1D,l\xB5\x06\xBF\x9E\xA6\xFB}fN\xC7\x87\x98q)\xD0\x8D\xA5A\x07\x0C&\xC8\xA9\x83\xE73\xF0a\xFD.\x81\xEB\xB3u\xE8p\xA0\xD2d\xAB\xD9"\xE7\x10B6\x92\xD6\xDBo5\x16\xA1\x98\x8Bv\x8Amg\x89\x19p\xDEi\x80\x0D\xCA\xEF\x7F\x02p\xF0\xE0\x18\xC6H\xD1\x8C\x9A\x80\x06\x00$5\x81\xDA\xFC\x7F\x9F\xB3\x02t/Ig8\xAC\xD3C\xE4\xEC{\x1C{\xE4\x02:\xD0eKy\xE9\x1A+\x1A\xA3\xB8\xC7V\xFD\xB9\xE0\x1E\xFDV1\xEA\xD8\x93O\x05\xF4\xDA]\xDA\xB5\xD9`\x9Dc\xA5\xE7\x86\x96O\xEA"\xF6:\x0Be\xF0\xE34\x0C\xC9\x058\xAF8%\x10z2$\x82\xBF_5R\x90\x99S\xA6\x1A\xBE\x16~A\x83.H\xC0g,\xD4\x96\x02\xE1}\x96\x06L%\xC62'\xF2\x09\x10(\x1F\x89 \x8B%\x11Q\x03\xE9\xB5C\xFE\x91\xF8\xA7gG\x1F\x11\xB9\xB8\x86>N\xA5\xD2\xACQlr\xB7u\xB2\xF4\xED\xBD\xD4\xA2>*rQnt\xEF\x8F_*\xFAB\xC9\x1F\xB1+D\xCC)j\x07\xD1\xE4N\x09\xFC\x17\xE7\x003u\x8A\xECN%\xDB6\x1A\xE0\xC4o(\xBD\x14\xDA\xD7\xC6\x04'iMeY\xBA\xFF\x84\xF6\xCE\x03\\x9A*\xA1{\x1DOQ\x84eu\xD3,\x14\xE7E\xE5x\xB2i\xC3\xE9X2\xE7\xB3\xDB\x98L\xA4\xCDJ\x07\x0DLC\xE9\xBF\xCF\x08m\xB8`\xAD\x1Es!\xA8\x9B\x8DN\xA0\xF9\xE63\xFF\xA9\xC7\x10?\xC2\x88\xB5f\xB5\x86\x82\x1A\x1C_!\xA28A\xA8G\xED\xE0U\xE3\x9D\xE1\x92\x84\x18\xADw[[7e\xB5I\x97\x04\xF7;u\xF8;\x990\xB0:\xB20G\xED\xF1_\xB1WI\x13\xAB\xC2\xBE\xEB\x0E\xF5\x08)\x87r\xC0\xA6n>\xFAhs\x8E\xD8\xF7\x18/\x81\xC2 \xE0f'\xF6H\xFBO\xC5\x1DWL\x13\xFD\x9C\xE8\x0C\x1F\x80{E\xA0\xE9\x96\xECLK:)\xA5\xED:\xD2\xD5\x11;\x09]\xA9\x16\xCD\xEA\x06P\xBD\xA8j\xAD\xD8\x1C1\x1F\xF6)>\\xE4\x87\xB2}\xA6\x02\xB5(Hu\xBE]\x8A#\x0A\x85\xE5\x92\xEC\x8C\x1F\xAF\xCA\xD4u\xFBlp\xA9\x06\x97e\x99\xA2\xC5\x8A\xB5q\xEE\\x15\xDB\x88\xE88\x8AM\xF1s\x13\xAE\xE4\xDB\xD0\xC7#\xA3\x031\x14)\x0A\xBF[\xFE\xD5(\xEE\x1Fb\xFFJ&\x19\xF8P\xEFfe\xD2!\x80W\x8EzL\xDB\xE1]\xAE 3e*\xFD7\x03\xAA\xB31\x83\x08\xA0\xC2O\xB3\xE8g\xAE\xEF\xDD8[|\x89\x0Dlg\xB9\xDE\xA9+\x98\xACZ\x01\xF5\xA1\x89\x83\x07\x88\xAA\xD9\xEF5d!G\x9B\x88AFZu\xC3\xF7p\x08\xEC-\xB5\x02\xDD\x8E\xA9\xA4M\x17\xF9%\x11v\xE4\xF0\x12\x9A\xFD\xEER\x9A\xC4<\xDD(\xF1\xD6\xA27r\x0F\xA7\x08\xDD\xDA\xD9I\xB9\xB7p\xA2\xEB\xA0\xDE7\xB9\x8E1\x0AMq$^N\xF7'\x94s2z\xDEPF\xE8\x19^\xCDl\xDE\xE1\x9F\xEF2\xBD\x07\xC5\xF2\xD5#y\xB0\xC8\x00\xED-\xBA\xFF\xE62b A\xF0\x82\xD1\x06?6/\x93\x84N\x1E\xF7\xE3\x9E\xFBt\x90 \xA3qV\xF0s\xF5\xBE\xD1\x0F\xC6\xF41.\x00\x9E\x94\xD1\xDA~\xC4}\x82\xB9\x85.\xD3\xFF\xBA\xDA\xF1d"\x03e\x83\xCF\xDC\xF9\xAA\x0C\xB1\xD9F\x92\xC4VT\xD1\x9B@6\xCB\xBF\x1E2QNw@\xD6O\x12\xA5\xA3\xBB\xE4\xF0\xA5\xEE\xAA\x0A\xF5C\x12\xDC\x11\x1E\xF3\x19\x90\xA0\x9AT\xDBN\x82\x9D\xC1^\xF8\x9F\xA8\xCF\x03-\xCF%@\x0Fz\x0F,\xE0\x94D\xC9\x05d\xE5\x1E>=\xB2L\xA8:\xA7~7\xF8\x97\x12\xB9O\x8D\xC4\x96\x98I\x11\x9A\xC7B\x98Q6\xF6:\x9C\xC8\xF80W{\xE9A;\x97\xCC\x13+\xA0\xD4\xA1\xB7|y\xA9\xA0^\x80\xB2<\xBC\xCEz\xB3\x00\xE0\x05wX>\x17\x91\xF5\xD3d\xBF\x19\x8A\xF8\xC4Am(\xD9?\xF2\xD8\xE3\x03\x9A\xC3F\xB4ySc\xED\xEC\xAC\xBAxy\xD8\xD6\xD9\x01\x18\x03\x1Fe\xB2- +cÎö-b\x18\x1Ck\xCAr\x95'\xFF7\xD2\xC2x\xD5C\xEF\x9A\xA0+"\xB6j\x0Fc[\xBEq\x9E\xA1\xEFE\x15\xCC\xB6)\xAE\x00n\xF7\xFC\xF3\xF98\xA7q\xB0\x81\xAE\x85\xEA\xFB\xCE\x7FhH\xB6\xB8\xCFn'\x8E\xBA\x15\xE5r\x1A\x97~\xD7\x09\xE7\x13\xEE\xD0pw\xB6\x0E\x00\xD2\x12\xFFo \x8C\x1A\xA4\xFE&\xC7k\x03\xED\xE9\x80\xAB,]\xEE\xC9\xC0x\xCD\x8A\xE8j\x1Do\x06\xFA,\x81\xC0B\xD4\xBA\x87\x8BX\xC2+t;\x99\xC2\xD9)E-\xAF\xAC\xB8\x1441\xF5i\xE6B\xC8\x9D\xA2k\xCC\xDA\x13\x87\x0E\xA72~k\x08\xA7\xF50\xE34\xA8\x00\x8D\xBBsh\x97\x7FZq\x1A\x13\xCEtG\xC9\\x1B\xC6K\x9D\x01\xE0\x8C\x8F\xB4\xB0f\xE6l'\xA3\x1F\x11\x98\xBD\x0A\x00\x83Ug\xD2Iy['o\xE1\x17M\x99\x8D\xC2\x1Fs\x92k.8x\xEE3m\xC8\x08\xA0\xF0\xA9\xA7\x8E\xE2\xC2\xF2\x03\x11\x81\xFA\x1B\x16\xBFbv\xAC\xA0\xF5\x16\x1C0\x1E\xBBx\x8Bv0|\xDEVJ\xD9\xFF\xDA\x80J\xF33\x81\xE02\x03\x8C\x7F\x9A\x12[\x0B\xFC)6\xD2\x85\x7F\x14\x09\xE6\x13S\xFA\xF6k\x9FO\x897+!\xCBp\xDE^\x0BU<\xED,D\xF8\xB7]\xC3\xF8\x18\x0D\x07E\x83\x06\x12Op\xD7b\xA5\xF6\x13\x97GwR\x91@\x97\xFC\xAF\xF0k\xF8.\xFA\xBC\x17\x93t\xE0\x08\xF2,\x1B\xFAI\x1B^\xA1aS\xD1l4pprG\xDFw\xF6!\xF0\xAF\x0C\x08F\x10\xFD\x89\xE9\xF5\xE0\xA6\xFD\x84^Mr_\xB8\x1C\x17\xCD(\xD2\xA7;\xC7l\x8A\xA0\x90\xB4\x8B\x01\xDB\xE0pE\x18\x059\x04K\x11\xC0+J\xF0S`\x98mQ\x1C\x04\xCD\xD0\x9B\x88\xEE#\x81\xAF\x9F\x919\xEB\xAEE\x10\x96vj$c\x8D\xD2\xB7\x94\xAA\x81\xE1\x8D\xE5\xD6`\xE2G2\x00\xCB\xDD\x1E\xC8>G\xD7\xCD\x83\xB1A\x97\x8D/&\xFE\x15\xDA`\xE59\x1E\x03M\x82\x90m\xA6\xB9\x96\xFA,\x9B\x00\x06![3\xB7\xED\x96:\x19\x96\x90:;x~u\xEF\xAA\xD0M\xA5ZN\xB0U-\xF2\xAC\xB8s\xB6\x8E\xF9B\x85\x03\x8D\xAE\x86x3P-\x8A\x1D\xF9\x18\xB8\xD7\xAFP\xB3v\x84D\x15\xBD\x04\x05\x9B\xDF{\xE1\x9A'O\xB8\x16;H\x92>)S\xCC9_7\xEE\xFD\xC3\x12\xA0tI\x8B\xE5\xDCKuc\x16I\x9B\x1F\x08V\x7F}C\xA5a\xFE\xF1J\x09\x94B>\x9A\x17/2\x80\xA3h4\x0B\xF1\xCB\x96;\xF1\x9D\xB2\xBEL\xD0a$W\x846mJ\xB2\x19\x1C<\xD1\x16*?\x03\xF9\x98\xCA|\x13 D-\xAC\x92\x9B\x0C8\xE2\xDB\xCF\xB4\xF4\x1C\xEEZ\x15\x05\x8B\xCC\xA6\xFA\\xEA\x10\xFDm\xBF\xA8RP\x06\x1A8\x1B\x8D\x0E\xD7R\xE2\x19\xBC@\xD2\xAA#\x9F\x02\xB9\x11\xFE\xCE8\xF5\xBA\xE0\xAA4\xBC\x80\xAC\xB9\x87\xEEAs]\xADF\x0E\x9F\x15*\xA6\x8C\xD0\xF3I\x97#\xF8p}=\xA8\xDF\xAC\xC3&\xD3\x0C\x0B\xA9\x1Bp\xF4\xAD]\x91vPKt \xB0T%\xD7\xADD\x927P\xDE{m\xB4\xB2\xD4\x80\xB6\x91\xF9\x84Qt\x07\x03&\xAC'\xC4\x09\xA6\x0D\xB2\xDAh\x9F\xA5v\xC4\x0E\xBA\xC8\xD4\x93cx\xA4\x8A\xA9O\x9Dv\xE2\xFD\xFEcI\x18\xB3\xDDg3A\xF4^\xB2\xFDb\x0C\x8AN\xA6\xAE\xAF\xCC\xE4Z\xAD\xCC\xCD\xF5\xFBE*r\xF1.\xC2\xBA\x9Ds\xBD\xA4[\xE0\xDC\x1E\xF2+\xE3r\xF0\xE2\xBA\x18f\xC4.B\xBD\x1Ek\xBE\xB9\x17\xC0R\xF1\xF95\x8D\x8E\x94[\xB5\x98`\xB9\xCDo\x00tP\xFD\xC9H\x80\x98\x82\xAE\xD5a\xEE $~/A\x1F\xE4~\xC8\x12\xE4\xD6\x1C\xA6\xB0M\xA92\xCF\x1C\xDF\xB9\x1E\x18\xB9\x9C\xE0=\x1C,\xDB\xA1\xC6P\xEB\xA9\x04\x14z^(\x04\xA2A\xE0\xD8\x80%\xFE\xA9_\xA8\xF8\x1E\xE9\xC3\x91\xEB\x05<\xD2\xFEp{\x97>\x1Cv\xF34f\x85b\xB0z8\x90H\xF6\xB4J(3\xA8\xBF\x11\x0D\xA4\xCD\xA0\xA1\xC87\x1C\xB4\x0E9\xF6\xFA\xD6\x9C1I\x0B\xE0:~!\xE3n\xE0N Tf&c\xBAP\x9A\xD2\xC8q\xB7v\xCCH3\xCBp\xD2\xC3\xEDR\x020\x9E\xEEc\xE3\x99\x979\x0F\xC7\xD7\xB0`\xB5\x8C\xBEH\xD5\xFCm\x08\x00\xC6J\xF5\\xB2\x88v\xBB\xC3;\x8C\xB0\x1Chp\xF1\x9C\x85o\xBA\xA3\x16\xD8\xAB\x98\xDDOd\xA9\x144\x062\x8B}q\xB4\x11,>i\x07o\xBAJ\x97"0\xB4\x9B\xFC&\x01\x8F\x8B\xE0jsp\xDE\xA4\xAA\xB0\xFF\xC0\xDA\xAC\x83 e\xB7\x93K\x0E$v\xB1\xE0\x8B!J-*ot\x8Bx\x12}qB\xF6\x15g\xDE(\xCF\xD1\x99\x7F\xDA\x80\x869\x8E\x14\x0C2\x0B\x8A\x8D\x90\xEF\x9B\xB8\xABo\x88/\xA36\xF0\x044\xAA\xC5\x8D\xFF\x98\xC8\xDCD[B`\x94\xF8\xD3'O\xB2\xDE\xA3\xCEU\xF0a%\xD5\x11&\x19}Y\xE5t\x1Cy\xC0\xC8\x7F\xF1\x99(\xDB qn\x0Eo\xF3\xC3\x0F4T0[\x04\x8B\xDCI\xE5r\x9F\xD4$\xFEd\x0B\xB8\x1A\x08^\xC7\x85tL\x124q\xB8\xFE6\x98Y\x9D\x94\x90'2\x86\x01X\x1C\xCC\x82\x10\xC77\x0A \xDE\xB7\x0C\xECA\xB4\xE3%%d\xAE|\xFC\xBEk\xA1\xE8\xD5\xCAX\x1A\x8D}a\x88\xF2\xB4\x93\xB7(=\x84\x9B\xBAc4\x82\xDF'\xFD\x98j\x19G\x8B\xC5\xED2\xBF\x11@?S\xF7hb\xAA0K!\xAD\x0B'\xA9,\xFE`\x18\xE9\xF6d\xF1\x7F\xAC\x0A\xC2\xE03fB\x03\xE0W*\x13\\x93\x83\xF06\x03=t\xE5\xC9]T\xC3\x99\xE4\xC93\xB3\xE52\xB2\xBD>Q\xC9-\xEB\xC4\x1F\xF8\xC4'=\xFF|#j\xB8\x1B\x01\xFEw5\x12\x11k\xF5*\xA5\xA1\x8B"b\xD3-\xC0\xA31~h1\x10\x82\xCC\x91d\xC8-\xAC\xEE#\x9F\xE2X>O\xC6skF \xAD=\xCFo\xCF'w\x9Bs \xD8\x18\x10\x192\x08\xAB\xA3\xA6\xC2I\xFE_A\xE7\x07\xFB\x06\x16\xF0\xBC\xC7\xCD\xA9\xF1\xAE\x9A\x85\xA5b\x89\xB9\xDA\x1Fm\x12\xC9\x1Ct\xE3\xCA\xC1\x156,\x10u\xF9R\xC4\xFA\x89\xAC\xE7\xE9K\x1E2\x00\x89\x0A_\x1D2\xEA\xB9!d\xA16\x91\x95\xCDM\xBFi\x17\x9C\xA4\xF8M\x9D\x8B\x81\x1D\xB9_\xB8m\xFB1\x15\x8C\xC2l\x02#|(\x1Eq\xD0\x89s\xAA\x17Y\x0B\xDAO\xED_f9wUw\xBB~\xB6\xF3\x8CA\xF7\xBB}\xC8\x10'\xF5\x04'\x14V\x16%\xE4\xB5\x1A\xB1\x92:\x1BE<\x8D2\xBF\xEF\xB6\x0B+\x0F\xD6\xA7\xBE\x8DE\x17\xE0\x0D\x12:\x08\x97\xC6\xA7R\xD8\xDC\xDC\xF50\xA2\xCE\x0F\xCA-s\xC7%'\xBF\xD2\xDC\xD1\xC2%\xBF\x0BQ\x0E\xBC\x86\xD3\xCA\x1E[\xDF\x87\x93\x05\x9D\xE9+7\xFA_%\xF4\xB5\xEAZ\xC1\xC6\xCCV\xAAO\x0A\xB5\xF7\x05#\xA6\x0C\xA4LZJ\xAC\xDA\xC1\xB1\\x8A\x87U\x8C\xB0s\x9F\x84\xD6B\x9E\xB8\x11ndqZ\xAEl\xC6\xDF\xB5\xAF41O\x87\xAF~]S\x1F\xB6H\xBA\xC3\xE3h\xBC\xB7\xF3\x8D\xBB\x01-W\xF4\xB3\xE5\xA3-\x9A'\x1Bn\x17{\xF33-\x9F{ytsH\xB86\x80\xB5\xE4\xBA}\x82|\x95\x03\x1D\x09\x8EW\xC0C9\x810\x91\xBF\xBD\xF8\xBF\xF2\xA4f\x9E\x17W\x1B\xBB\x8E\x0D\xCBd\xE0\x1A\x04[\xD4\xA3\x87\x08D\xAB\xD5\xFDp,\x96\xA4\x82\xCDC\xFF\xE5\xE5T\xA5g\xE0\x04\xC8i"jI\xA5\xF2\x99.XN\x96\xCF\xDD\xFF\xEE\xF5_\xBD\x98\xC1\xCDH\x91[\xF2.s\xC8\xA4\xEEoGD\xEF\xF0jT4\xDB\x83\xE6\xFB\xB1f\xE7\x15\xD1)\xF6\x9B\xE7p)\x0B*\xE6\xB7A\xBFM\xC9D\xF7T\xA8\xB3\xF9#\xE9\x90\xEB\xC4(\xD5\xAF\x19\x00\xD3\x0As\xC2\x82\x9B\x9C\xCA\xBB\xA7;\xB2P\xB2\x0C\xE1\x0A\xFE\xD7\xB6FI\xCD\x1D\xBC\x07E\x0D\xBB\xA3\x9D\x12\xC3\x95\xC0\xE3\x01\x8DL\x04?\xC9k\x99\x87\xBB\x0E{N\xD8\xE6\xA4\x90\x0DY;\xF0!\x81D\xBF\x82.\xFC\x94\x06\xB4\x9E\xFC\xFA&\xEB@WW\x13\x80\x8A\xD4/~\x836\xD6\x0Fl\xA7\xD0i\x8E'\xA6\xA8\x95\xCE{\x97M\x84\xCA*\x81\xEF\xE0\xB0\x186h\xCC)\x0A>\xEF\xEE\x98\xD3V`n\xF1\xE9\xBF\xB8ip\xBB\x11~B\x07H\x02\x98^~\x8B@\xD76\xD1q\xE9\xB3\xEEZ\xD4\xCBz\x88\xEA\xCE\xFD5\x14\xD3\x06\xC6{\x1E=\xB1\\x09J$\x0C\xEA\xEF\xE8sk$g\x19\x1E\xC9Y \x1Ak\xE1\x8D\xF1<\x96\xB0{A\x8C\xE9\xCE7 tE\xA1\x03#\xDD\x07c\x0Bs\x15\x1A\x94\x19\x9E\xEF\xEA\x91\xE0-\x1FD\xC6Yn\xF6^ZU\x1B\xB6rq\xB9\xCE;\x93R,\xB0*\x94\xFE\xEB\x18O\x19\xFD\xFF\xD0\xE5O\xE32NO\xD7\xFE\xBF\xF9\xCF8l\xAD\x06\x9F\x8B)*2\x1E\x92\x139*\xAFv\xB3\xD6\xCE\xF7\xA9\x02\xBC\xFDvlN2t%\xEA|\x15\xD1|\x94\xBA\x16\xFDh\x87J\x11\x11\x00\xE1.\x86f\xF1\x8C\xDF#T\xFD.T\xDB\xAD\x9F\xCA\xB4\xDD\xB4\x1C\xE8\xAC\xDA\xDC!:\xABL%\xF7\xDB\xD1\x14\xA5\xF4\x86\xA0\xC8q\x96H1\xE3_\x00\xCCE\xD3i:\xF8l\x91\xAF8\xBA\xFE7\x9D\x04\x1BT\x0F\xB0]E\xDE\xC4\xBD\xF6\xDE\xE4\x10\x88\x90\xAB\xC8\x8A\x8D\xAD\x03\x9B\xB1\xE9\xEE\x1C~9\xEA\xA0\x02\x9C\xA6\xFB\xAC-!\xB28\xBD\x00\xEE%\x196\xC9el\x83\xCDn\xF3\xA2P\xC8\xD2\x0F,K\x9CW\xF5\xCCM\x8E\x03\xB2\xC3)\x84\x0DhQm\xFC\xE1\xA8\xCDHz\xEF\xFE\xCCr?\xD9\x02\xCC\xDF?\x01#'\x09\x82\x83'F\xBBs\xA7\xC9\x84#\xD3\x92G\xB5\x0E\x01%@!\x8A\xE3\x05\xD4p9~IUC\x0E\xC6\x84\xF2\xEB\xC6\xE5\xB9j\x8F\x81\xBF%1a$\x99\x06\xE8\x89\xF7?b\xC2\\x9F}X<\x98\x96\x06 Pb@B/\xC2\xB7\x95\x94!\x82_DC\x80\xD5\x9D\x97\x99IZ|\xDA\xC9 \x1F3Vg\xCB2\xFE\xECr5\x7F\xE6\x04\xACZ\x7F\x11\xAF\x19b\x84A\x1038G\xAF\xBBO\x9Ac\x88\xAA%\x03\xD9\xE2\xD2\x18\xCE\xD8\xE9n\xD6\x97_\xE7~.\x91\xD7\x81\xD4\xFF\x95\x94\x87\xE5*=[\x1A\x0D*#\x88\x0Ebm\xD5\xF5c\x8C\xBA\xE4\x82\xA9a\xC8*H\xF6G\xF0\xC7L\xD1\x9C^\xF9\xAC\x10y\x15\x042C\xFC\xCA{\xDA6\x9A\x17\x92\x18\x0C\xAB\xB9@\xEA\x07\xC1p\x13}\x07L\xAB\xFF\xD6\x8B\x08\xB6\xF0:\xCE\xEA\x81\xE2\x9AB\xB0'\x90\xAF\xB8\xD1z\xBFL\x9BL\x09\xBB\x0F\xC9\x9F\xDA\xD4(\xCDb\xA38l\xF1\xE4\xE7\x89F\xDD}\xE69\xB1V\xAB3\x9Dz\x18$\x03q\x86\x96\xB2\x8E\x9C?\x99x\xF0\x90\xF3\xCF\xA1-\x83\x81WTs\xD9o\x03\xF8\x8Ew\xE2\x8D0\x7F\x05\xAAp\x160\xDD$f6\xD9\xD1v\xD7\x1BO\x19\x1A\xD1W^\xA4t\xDDZ\x95JJ\xE2YW\x8FS\xCAVEV\xB2\x93?\xA4\x8E=\xC3\x12\xD4\xE7*kd$\x8D\xEE\xD9\xD9\xC6\x17\x0F\xF1\xAB\xA2\xAC\x81/\x05\xBE\x943h\xD2li0\xAA\xF6\x09\x99\x1C'U\x83\xB9\xA3\x08\x1A\xC7m\x9E\x8C\x91e\x8A\xCE\xC3\x1D\xD2\x9AL\x00\x0Fq\x1C\xFF\xDA\x99\x0F\x01\x04\x87\x9F~\x8D"\xDC\x1F\xF29\x01s\xBC\x90y?&bG|\x87,\x01\x0Ba\x1AP\xFB\xB0\xA2\xCCy\xAEx\x94\xD5IY\x0B\x89>e\x85\xB7\x8Eqj[\xCC\xBE\x16\xA9ai\xD4\xD0k\x10\xCD\x85#\xC1\xA8,\x94\xAF\xFC?\x98\x12\xB9:\x06\xFFl\xC8\x9Ao(\x0A\xA0'Q\xAD\x10\x12\xCB\xD8\xDB\x85\x0F\xA1a\xA1'\xC6\xAB\x92\xB3\x88\xF6\x87\x90\x97\x8B)\xB27z>CP\xD9E\xEE\xD9\xC4~\xE4\xDA\xBC\xAC<\xBB{\xA0[S\xE8+\x0F\xBD\xBD\xC9\xCC\xAFmJ\x04&\x9B\x88\x90\x80z\xA4\xE6\x9C9\x14Y\xE5\xEE@\xBF\xB0XR\x88\xF9)\xA9\x10\j:\xDF\xEB\x7F\x8E\xAC\x82\xE3iv\xBB\xDF3\xEC\xA2\xD9\xD4({\xEA\xFE\xF3\xD5\x08\xFC\x94\x0FP\xDD$\x0B\xBC\x13f\xF5$d\x82\xB3\xF1\xF1\x05\x1D\x92\xC7\xB2G\x83\xCF\xF9\x85\x1B&\xE6\xD9\xEA\x1AO\x03i\xBEt\xF2a\xDFrX\xD8\xFE\xEF\x96\x99\xA6\xE5\xA3w\x99\xC8\x96\x92\xAAF5|\xFE\x1B\x94\xFE\xD9|\xB4_\xE5\xC5"\xAB\xFE \x97\xC7\xD4\x06\x12i\xFF\x0B\x1B\xD0\xC4\xFE^| \xDD$bOs\x0Fr\x9D\xBF/\x11\x11\xEB\xA6|#|\xA9\xF8!\xA4\x9Cs\xEAI\x90n\xC8a\x1At}\xACd\xA1\xE6\x0Dd\xED}F\xF3h\xA5\xC4"\xA1\xD7\xB6#\x81e\xA5}`F\xA5!F\x0A\xC2\xACL#\xE4;B\x14N2b\xC2P'\xFD%\xD1!`\xF3\xB0|\xBE\xE1,\xA9\xBBj\x83+\xB0Q\xCC:\x02\x09b\xC1\x07/\xE3\xD0+l\x80t\xA7\xBDMw-*\xCE.U\x1E\xF6r\xD5\x9D\xA3!\xC9K\xB2\x9B!7q\xA3\xEE\x0F\xE6\x7F\x1D\xAD\xFCa\xC2\xBA\xE6Q+}\x1C\xAD\xF9f\xBA\x86\x11\x9B\xE9\x9C\xE0\x06c'\x90K\xD8\xB8\x9C\x91\x053\xB4kde\x06\x0E\xF8\xE4+\xC4\xCAf\xABI\xA5\xD8a\x16\xF8g@wS\xE3\x0C\xF775s\x18\xC3\xC4\x01\xC2\x90\x0E}\xD0]\xC9\xD9,\xEFR\x17\x1A\xD9\x7F\xCE3\x9B\x94}\xF6\xD6O"\x80\xB9\x9A\x96\x07\xBF\xA4\x0F\x80'\xF9\xA3\xBA\xD4w\xB0\xB4\x9D\xBELp\x03\xADW\x09\x03\xE4\x1D\xC0\x07X&A\x0D\xC3\xC8H\x15Sg\xA8\xFDm\xA4\xA9\xEA~x\xAFNW\xCC\xA6\x01/3&\xCE\x0B\x9Bt?&T&\xB9\x99b\xC8\xC9:'\xF0I\xDEw!\x7FV\x0DE\x95\xAB>Z\x957c\x09\xE4\xA1\xB4\x97\x1F\xDF\x011\xB7a\x14\xF8D\xBD\x8AB\xA7\xA2\xEC\xC7\xD3\xF2L\xF1%\x9C\xCC\xF1(R\xE8\xA9\x1F\xB9\x90\x10*\x85r\xF9c\xA0TN\xE0\x80\x14>\xE7\xA7\xC1\xE5,y3\x04-w)\x12\xA4\xBE\\xEC\xC9xb\xAC\xE9\x86\xCA&\xBD\x07\x8F\xC2\x82T\x9A\xB7\xB4\xF3z\xE9\x01\xB8O!\xF5\xB7\xDB'P\xA2\x9B1\xE48-\x9B\xAA\xB9;\xF6\xEF\xF95QM:J2\x06+$\xE6\xBDD\xEF\xBF\xDD\xA46\xDF\xCC\xC02\xC7B\xED\xC1\xF1\xC2\xC2\x93\xBC7\x80\xD2~Wk`j`\x84\xF1\x11\x10a\x9B\xAA\xA1E\xC4\xAF\x14\xAF\xC1sw\xE9C&k1\xF6[\x0C\xCF\x0F\xCC{f\xAE\xCE\xE8\xCF\x92E\xCC\x09\xC2\x83\xEDk\x94L\x91\xB2\x15\xEE\x8BGY\x97&\xCB\xB1\xCF\xA0\xB1\x88E4\C\x01H\x7F\x17\x80[\xD1\xB0;F\xC8\x022@\xBE\xC5e\x8C{\xAA\x02\xBC\xCC\xCE\xA4\xB1v\xCE\xF6\x86\x89~Z\\xD7ud\xBCgY\x9C?E\x0B \xE7?N\xF7\xE1\xDD{\x0E\xBE!*}\xA38\xBAp\x02T\x94b\xBC\xB5"\xB7\x13\xF2\xB1\xC0\x02#1\x9AX\xAF0;}6\xFB\xC1\xA3\xD4\xAF\x8F\xF1\x9A\x9AI\xCA8\x17X\x09\x94\xAA\xE3\xCC\x93\xE5\x97$\x8DRf\xC8\x11g\xB7\xD0\x92R\x08q9\x8D#\xECV9\x99\xB3\xE0e\xB0\x11\xB3\xE7vJ\xCB\xF3f\xCC\xA4\x7F\x0F0\xE3\x8Fj\x9B\xF0\xB02\xEF\x94\x01\x17\xC71\x05~q\xEB\xF7\x8F\xC3\x97D\xA3&\x84\xCFC*9\x11e\xC3\x17\x93C\x83\x87@uuB\xCA^\xF85\xE6\x98\xD1CcQ\xEFCu\xC0\x03\x01\x89\x9A=\xA8\xC8\xFBt'%\xA7\x7F\xBBqhA\x9A\x05{\xE6Ic\x8D\x08\x0F\x9C\x04\xDA\xD44\xC6\xEC\xFE\x8F\xAB\xEB\xA1\xB7\xA8\x8AUy\xEF\x13\x02\x19\x87_\x1A\xCE\x0A\xE7}\xC9\x86\x0E\x89a\xEA\x9Fq\xE0\xD4E\xB4\xA5\x09f\xC7\x0B\x07B\xA6\xA8\xE7YD\x9D\xB3#\x94\xBD8\x8D\xAB\xF6\xB0\x0B`\x02\xFBf\xB3;\xACL\x8D\xA8\x1C\xE1`\x9F\xF7\x844\xCFQ\xDC\x87\xDB\xAF1`\xFEFH@B\xBD\xD4`\xA3`a\xF1E5)\xC8\xFD\xA0\x9A\xA3]\x1B\xAE\xD9\xA5`A\xE8s\xA4\x15\xDB\x8E\x09RM\xC0`w\x86\xFB\xF9\x9F\x1A\xCB\xF7\x8DR\xFF$0B\x1EZ]Yj=\xC5+\xEB\x9El\xAC\xE1m\xED6\xC4\xD5\xD6\xBE\x08\xD8\xB4\x07F\xA2\xE8\x8A~\x8CEA\x99`\\x83<\x86\x84|k\x0C\x9D\x9A\x13\xED\xF4\x9C\x19VX\xF6\x98\xC4%n\xBD\x87"\xC7\x1E\x90{Jy\x1C\x93\xFD\xB2\xCA\x96\x10\xF6D\x1F\xED\x85\x1D\xB9V\xE3\xA7\x9F<\xA3\xB7\xAE\xDF\x7F\x1D\xF1\xC2\x04;\xB6\xF7_@\x0C\xA8N\x0E\xF9\xCA\x86\xFCU\x9F\xCA!/\x9Cq\x8B[\x14UaT\x7F\x06~\xB6W\x1Al\xB3\xD0\xE4\xC4\x09\xCD\x9FKH\x1F\x02\xD2\xF6\xE5u3o\xB6\xA9L"@h\xA2FV\xD1\xE7\xF1\x1F\xF0X\xF1\xF44d)\x8Fd\xEDK\xC2\xC4\xC6\x02\xC9\x96 \x83\xD1\xCA7^\x9E\xCD\x14\x93r\xC3;@\xE8\x18\x06\xE5\xAB\xFE\x1D\x99G\xA4VP\xF1S\xBBN\xD4N\xCB\x84\xC9t\x1DJ\xE6\xF9~\xA79`\x81\xEC\x0F\xB5\xD1\x80U\xC1\xB4[\xC6\xCFYQZ\xFC\xF9\x9B ?\xA9\x0C\x0D\xD7\xD4\xFDW)b\xA4\x98Nb\x10;\xC6\xEA\x0Auo/\x9D\xA6:\xBF\xF4\xEE$\xAE@7GD\xF0\xEE\xD6\xB4\x8A\xB1\xBFp\x7F\xFC\xB1\xACD\xF8\xCD\xD4C\xD0\x8DY\x17)\xD6\xC5T,\xBAh`\x92`\xB9P\x01\xCE\x1B(\xFB\x81\x11\xF6;<\xD1\xE1;,\xE6\xDC\xDC\x9FB\x86F\xF2\x9C\x9A\xA1]\x9C\xB4\xBB79\xF9S:\xE9o\xFC\xC7\xDDO\xDDVh\xD0\xD2\xAC\xCD>\xF6\xBE\xBD,\xEC\xED\xE8h\xBF\xF4#\xE5K\x82\x8B\x0D\xB0[\x05\xABl\xEB%\xF1ae\xAB\xE9.\xB5\x07\xA0\x15\xAF\xE1h\x94+B\x16:\xC9\xB8pL\xF7\x89\x08+B\xD6-0+j\xBD\x81\xED\xF8\xE7.\x8Ehk\x06\xA1\x89X\xADS\xB6\xB7\x88\xAC{%\xBE=\x9E\x0A\xABC\xCA\xC44\xF1\xE3I\x80eQ\xE7\xC3W\x99\xF6P\x17\xD4\x8D\x7F\xEAE\xFBJwq)F\x1BOx6'\xD20\xBF\xE9\xFC\xDF\x05\x84\xDBu\x96N\x94\x88U\x10\xA5\xD3\x86\x83d\xD2\x9F\xCC\x01\x93C\xAB\xAF\xE8(\x96\xE4\xB3;\xA3\xD1O&0c4\x0D.*\xB0Q\xAD$\x02oh|\xEC\xB6@x\x91\xCFl\xE9c\xA7\x8Cx\xAD\xE3}\xB7\x92\x7F\x9B\xD4\x06W\xA3}\xEAI\x0B;\xE3&^h\x01'\xE1\x86%j\x84\xB9\xF1\xED\x93\x0CG\xCA\x8A\xB4=\x9A\xA3\xC2\xD4Z\xF8\x86\x99\x11\xE8\x19'\xBBN\xFA\xEB\xD2\xA4\xBFiU\xA4\xF3wP\x8A\xA00"\x9A\x02\xC4\xF5R\xE2\xD9\xAEW\x90J\xEB\xFA\xB3h\xEB\x02v\x94gx\x1Ck\xE1\xAC\xFB\xE8\x08\x9E;m\xCE \x90\x89j=\x8F\x86\xF9L\xBBL{\x9D>B\xAB\xC2\x14\xAB\xBCsw\x91*\xA1\x91\xF9\x9F\xD8\xDA\x8E\xC1V,tldDnt?n\xC8\xEEk|t;I*\xDB\xDC`\x8C\xDF\xD2\xAA\xF8\xF0\xEC\x06\xBC\xA6\xA4\xAAsR\x03\x84\x8C\m\xEBs\x15K\xDCb\xC9;\R\xED\x9Fz>\x80xn\x93\xF5\xE1\xB9\x0C\xDBqK\x1E.d\x85\x18\xF83\x1A\x14"C\x8DM\xA5X\x9C\xCE*\xC8\xA1\x98zy\xA1R(\x96*+\xCBd%\xEA\xCC\xE4\xE7\xDD\xF8^\x18s\xB0WL\xEF\x9E\xB9\x1E\x8B;\xEC6\xF4\x05=\xC9\xED\x9D\xD4\xDA\x95\xF4\x7F\x19j5\xCF\x0F\xB6\xF4\xACH\x95\xEB+k[\xB6P/$\x0C\xF0\xC1h\xD7N\xC3i\xF9k\x0B0UD{0Q\x81\xC5v\x9A\\x9E\xCD\x93\xC4=\x12\x87\x89\xCC8X\x1Ak\xEC%\xDF?\xEF`[D\x96a\x8C\x95\xC9\xB9\xDD\xB5\x9A\x07K%|\xDA\xBD\x9E\x1D\xFFB(\x8D<1\x82\x04\xE2\x05?\xF1\xC6/\xD0\x82\xC1z#\x86:\xDA\xEEy\xFA\xEA{\x1C\x87\xC0i=-Y*\xFD\xFAh\xF8\x05\x03\x06\x9C\xA3\xC1\x89@B\x84I\xD6\x15\xD1?f\x12\xE3\xFDP\xA4?8\xFF#\xF8d\xEC>Zk\xE5\xE5\x0B\xC8\x81\xC1j\xD1\xE57\xBF\xEA\xD1\xF16\x9Fs`\x14V\xEB1\x0E\xEE\xC6\xC2\xD0\x7F=uKa\x01\x9A)\xC5\xEE\xA3\x01\x93Wr\xC8\xD7/\x97=\x14SG\x98\xCF\xA5\x0A~\xB3\xA8\xA6\xB1\xC9 \x92\xBF\xB3+\x09\x8D\xA66\xA8I\xDC\xF0O\x7F {\x91\x87\xB1\xA5\x09h\x1Bk\xE9\xE9\xBB\x90d\xFD'K\x89\xD6+\xE4\x8B\xE2\xEE\x81\xE6\xDE7R3U\xC86UhU\xEEQ\x0B\xEF@\x9D\xD5\x9A\xF1\x15\x0E4\xA9R\xD25\xD4\xFC\x08\x1EK8\xFB\x90\xDDG\x08\xC3T\xEA\xF47\x16\xCB\xDF\xA8\xB9\xF7l\x1F>\xE5\x87\x98\xD9\xBCwMDYj\xE1\xE3\x8Ee_9VBo\xBFf\x8F\xB9\xE8H\x8B\x7F\x7F\x0B\x82ns\xAA\xC0,\xAC\x0F\xC7\x05\xA3\xF1\x97\x0D\xED\x99\x85\xF8\xD3\xA8\x8DA\xD38w\xD8\x95\x80Z\xE1\xD0\xBA\xA4\xCD\x8B\x97\xCE\xF5\xAA~6\xB1\x02*\x0CP\xE1\xBD\xD5\xC7W\x00Rn\xE0A(;2Q\x8E\xBE\xFF\x95-\x8B\x07\xF5\x0F\xD5\x8Ek\xD8j\x97\xCA3\xC2\x89Z-~;\x98\xCB\xC5\xAC\xC0\x92\xEC5\x9C\xD9\x17\xF0\x09VPm\xEE=\x14\xC6x\x17$>\xE0 \xC9\x87a\x9D\xFC5;.\xA1\xEE\x0Bv\xBE\xFC\xAD\x91P\x9D\xDE\xB7\xF3\xC7n\/\xF4k\xF2e\xF3,\x89\xF7\xCD<\xD9\xDC\xBFgf\xB4\xD4\x1Ch\xC5F6Sr\x93\x05\xCE\x93 \x0D\x195o\xE0\xE1\xA7Y(\xF2\xF9"\x05f\xFE\x9A\x84*\xD4~\xE9S\x89\xB7\xD0\x1D\xC6u\xB8PZ\x0B\x09k\xD6\xC3\xC9\xD1y6\x90,\xEF\xA4\x08\x0AmG%ND\x80\x8FxTY\x1D(\xE5x\xE7\x86\xCA\x1CW\x86\xC6,\xC6\xD8A\xF5\x88\x81\xF1A\xA16J\x90^\x89\xEEdN3\x82\x16i\xEE\xA9\xE6\xF7\xE6\xE5l\xBDs\\x1FA\x97\xF9"N3\xFF<[f \xFD*&\xF6&R\x1E\xCE?\xE6=8\x9B\xD2\xA0\xC3\x19\x00\xE0\x7F\xC2eh*\xF2r3\xE3\xAFk\xA9,`\xDFEy\xB6MNk\x08u>\xA9\x8BB\xEBp\xC3\x1D\xF4\xCAo\xE1\xCEb\xB8\xB209\x03w\xDA\xB7J\xAF\xB0\xF4y\xE5\xB8\x1A\x09\xFC\xBC\xC6:\xA3.\x11\x11\x9CHs5v\xC7\x82qQ^*y\xA75\x8E\x93Aa\xAB\xC9\xE9\x0D\x8F\xBEP8\xA7B\xDFf>*\xE4E\xFCW]\xEB\x879\x0C\x97\x0A\xA4\x13L\x01\xD6T>\xA7pa\x8D+\x08\xB0r\xEA\xD1\xBEV\x9B=\xAF\x83\xED\xCBy\x8C\xF5\xD4\x99\xBD\x8F\xEDt\x8D\xA5\xF2s\xB4d1d\xA4\x92\xAB\xC6\x89\xCC(\x86fb\xF9\x82\xF9\xC7\xBBZ5\x90&\xBB|\xF7\x0E.\xE2)\x8A\xBA!\xFF@\xC5Z\x88\xCEI\xD7C\x1D\xE4G}\x15>\x12=\x08\x0E7\xE7\xBB\xDB\xC8\x11\x97\xA1\x0F=\x86\xA9E\xC0\xC4\x8D\xDBc~\x1F\x1C\xE4\x9A0\xB9Z\xC9\xB4\xF4:\xC2\xC2.\x12@B\xC5\xD0m\xD8\xE0q\x90\x0B'I\G\xA2\xAA*\x17\xB8O\x1C\xFB\x01IS]\x93\xB9\xB1;\xAD\x1B\x07\xD1\xEE\xB0FxMx\x98\xE9!'\x97\x16\x17w(2\xF0\x954\xE9\x02\x95t\x0CUT\xCF\x11j\xCD\x88V\xAE\x06.\x0A\x19\xCFQ\x8F\x0F\x8Cz\xA5\xA3\xFB/|\x85\xFB\x09\xE5\xF2\x0E\xF0\xC1h\xA4\xCC\xC6\xAC\xF5\xDAm\xB4\x00\x04\x91\xA4F\xB1\x9F\xBA\x0C\xFF\xDD\x8A\xCA\xDBs\x1EQ\xD5\x9B#\xDF\x12\x85\x16\x00\x89\xA7\xD5\xC8>\xEF\xC0\xF8\xFDo\xECJu9\x11\xBD\x90t\x0D\x8A-\x03E)dLg\xC6%Q\x9F\xBB\x9D~0\xB5\x95\xF0\xB7~!\xA1\xEC\xEF\x9A+\xC7\xBD\x90B\xA5c\x08\x08\xFB\xF5\x98\xE5\xF1\xFE\xFC\x11~H\xD3\x16{\xDA\xE5U&d\xC9;\xE5(\xE59ZS\xD2pa\xCC\xB5l'T\xE7t\xCF\xF3k\xB0\x1B\x98\xAA\x8D\xC9Y\xD8\xF1\x97\xF0(K9h]q\xAA\xEA r\xAD;`\xD0]\x91\xDB\xE4I\xEE\xCB.H\xF7\xD4u\xB2\xDD<6aQ\xBE\xF4\xE1"\xCB\x8C\x98\x03\xB5\xCD\x0C\x05\x98\xBF\xC2\xC6\x91\x0B\xD8\xA9z\xD5\x0A0\xB7\xC9\xEC\x0D\x84t\xBEI\xE6\xEE\xAFWAi\\xD6\xC3\xB9\x95\xD0\xD3|\x0E\xBA;\x09pxYo\x9B\x1F\xEF\xAD\xC9\x1CE\xAEj"JG\xD5G\x90\x8A\x85\xAC\xEF\x854\x1D\xE8X\xF0\x13\x9E\xF6VBL\x96\x96\x16\xCA\x034@\xBA\xF5\x0F\xDAiyq\x03\xD0\xAF\xD7R\xD0\xD5\x01\xCF\x93\x9BTa\x94\xE3\xC75\xBE\x0F\xBFI\xCA\xCB\x1F\xB3A^3\xA2\x18\xD5\x19J\xDCwu\xBDs\xAB5\x0B\xF4\xFBN\xC3\x8C%\x0Cl\x1A9\xDEQ'X\x93\xCF\xDC|~\xC6\xFE4\x98\x84\xD3\x15\x0B\xF4\xDAA\x81\x8A\x10\xA9\xAB'\x05\xF6\xDE"S\x84\x959KO\xB4\xEC\xB1x\x886\x16\x05ZJ\x99\x15\xEB\x9Fx\xB7\xD9\x19O\xE2hb\x16a6j]\x043\xE0T~\x82\xEF\x8A\xAB\x80\x0C1\x99I\xFAS0O"\xB6\x88\xFD8\xFC\x1F\x9B\x86\xE9\x83\xCBO\xB1\x09\xDB\x88\x95{*\xE8V\xD2\\x95q\xD3\x0Bl\xEF0/\xEDr\xDA>\xA5\xC8\xCB}k<\x1B\xFC\xA2\xCD\xCE\x98E\x15\x19\x1A\xA9\xA6\xCDl\x91\xD0\x1A\xDC\xA3\x9A\xE8_\xF5{\x94\&H\x89\xB2`\xDFa\xDFd\xB24(\x8E\x0E\xA7@\x001\xF2u\x9E\x97\xA1\x80\xC0G3\xECx\x16Lt"r\x0E\xF1\xB28?\xA8\xD9d\x8F\x8A\xBAo\x06%\x1EP\xE9\xB7\xFE\xE7\xFB\x10\x10/\x0C\xDA\x00|\xFEVU$\x8C\xA9\xC8\xC2\xC5\xAE\xF9n\x82\xB8I[\x8B\xBB\xC1\x82!}:3\x06\x89UK\xB2\xCDyY\x9B\xCA\x86\x9D\xA6[L\x89\x01\xBB\xB1[\xED\x02\xD5\xA8\xAF%\xF3\xEA\xCE\x18l\xC4\x1Bb\xCE\xDC\xDC<{O_\x82B\x02\xFE\xA3\x10\xAF\x16k\xFB>\xE8\xF4Pa\x95\xC5r\xCC{t`4\x9D\xACt\xE4\xFF#Yq\xFE\xD7c\xDBFB\x18\xEB\xAF\xCEW+\xD0\xC8\xC4DYO\x85\x14)\x8F\x18\xF3\xC6cO\xAA\xA0oh\xC8\x9E\x8F\xBE\x93\xF2\x99r\x05\xBD\x91\x9F\xBBc\xC2\xF1E5\xC2p\xCE\xFE\x8F\xA2\xC6\xD7\xF5_:\xBA\x8B\xF2\xD2\xA20M\xFBgok[\x81Pm\x8C\xEF\xFF{\x09ss\xD1\xAF\x8CN\xB3B\x87:\xE1\xE31\xCB\xB0\xFEC\xBD\x14\xC7\xCB\xE3\xE2`\xF2\xEE\x9F\xBF\x8A\x94\x06l.\x95\xE9\x8B\x9Ar\xE3U\xCCQ\x19\xB7[\x99L1\xFD\xD2\\x0FY\xF1\x80\x17f\x0D\x94yc\xFD\\xFC\xE7\xE20\xDC\x88\x8D\xF5\xBE\xF3$\xF5\x0E\x8F\xA7MD\xC5}\xF2\xD0I\xEA\xDD\x9C\x91\xF4\xBCb\x1BD4{\xE7]\xB5BA\xCF\x14\x90\x06\x84\x01\x03\xCB\x88\x13\x83\x19H\xEBiO\xBC\xA7\x9B\xD7\x926)4`F`nCQ\xFD\xB68\x8E\xB3\x80\x19\x1B\xF5jm\xF4/\xD8Q\xC5\x1E\x9B\xFAA\xD7\xE6d\xC3\xFD\x8B\xA9\x8AW\xBA\xA6Uu\xF7m cW\xAE[\x08\xEB\xF0^\xFD\xEAw\xD0\x99v\xF0\\xA5\xA8cj\x15\xEAm\x16\xBD\xD7X\x0C\xB3\xCA\x89\xA0\xAFOx`\xA2\xBC+\xE9\x96\xC1\xD6\x83dl>\x86n\x7FQ\x92*\x9B\xFB\xC0%D\x08_\xE5\xE3\x94\\xFB\xA4l\x02\xEE*{\x8B\x15\x9C1\xC2p\x00\xC4\xC31\xD5\x00\x09\xF8\x1D\xB3\xFE\xD5`\xC2\x04\xDE\xA1\x82V~\xFF\xD0\xFE\O\xB1\xE1\x8C\xA5\x08\x17\x90\xF8\xD7\xDF\xFE\xF9m\xDE\xC1\xDF\xF1\x86I\xB5@\xD2\x93_\xD5,\xC5\xBA\x84\xDB\x1F\x16\x9F1\x7F\xDEg\xA5\xFF4\x11,|R\xC6\\xC9\x08\xE8@\xAF\x01\xAC,\x9FTLH.|\xBC\x87\xAER*"f\xD7\xB8\xD8\xD6\x18"&d\xD6\xB6\xAF\xDBX\xAB\xA3j!\xBF)\xC0\x05=\xB0n\x19*\xD7C\xE4a\x820;!\xE7\x97\x82\x88\x98\x03\xDF\x9B\xFE\xC2\x13\x19.\x90\xBDs\x9BWEz\xB9\x0C\xCF\xCA\xFA_\xEAA<\xBB)8\xDC\xA5T\x14\x87\xBCEl\xD6\xD1\xFDX\xDBl\xCF\xA2 \xEC\xC3\xEA\x9D\xE3\xC6\xD5\x87D\x09\x1A\x93]b\x1C2\xC9\x8D\x86u\x84\xD2y\xC1\h\x13\x81\xFC\xF2BW\xA801\xED\xA4\xEE\x84ry\xBE\xC7\x19^>5\xF6\xAF\xF1\xCA\d\xFA`\xD4=N\xAC\xD4s\x89.x\xDA\xE9\x07\xB1R\x1E\xB2\x9FJ\xC56a{{(\x16fA\x8E\xF1\xFB\xED\xC1\xC8P\x80\x15m\xB9\xAB\x9B\xF7s=2\x12\xC4\x8E\x82UF\x8B\xD9;e\xD6\xCE\xB8\xE4\x033\xB5\xF9\xF7\x9C\xF7\xF6\xE1\x09w\xE6\xEC\xAF@\x899%E&\xA0\x9A\xE0\xBF\xB4\x0B\x97@u1v\x80\xDEf\xA8\xA5+l&\x96\xB5\xC3\xF9\xCA\xEC\xD9E\xD8\x0C\xCA\x87x\xF0\x938M\xB1\x90W%"\xDA\xD8v}\xDA\XcT\xA3\x17\xF9\x7Fzi\xBA\xDAj<\xF7\xFB\x03\x0E\xC2\xAFKK`\xA0Z\xA0U\x00\xD2g\x0C\xDE\x91\x00\x8F\x07\x9Eh\xD2`\x85w\x06\xA9@8\xCA\xA3|\x0E\xB2\xFF\xDEY\xC53\xB92\x11]\xB1\xD6>\xE4}\x9ER2\x04\xF9\x0B\x81"\xE0%\x98\xA6r\xF9\x92\xC5\xF5\xBE~\x9D\xD8\xCC\x83\xAF\xD0\x89\xAF\xC0\xAC\xE8-e\xC8\xF4\x8Ei?\xA1J\x86C\xE4l'4;\x80(\x12\x9F\xD4\x05q \xEC\x16b\xA2<\xDA\xB4& $(\x9D\xF7\xAC3[b\q&J\xD4\xED\xB8\xC7\x03\x0Ag\xBDc\x8F\x0B\xA44E6\xD30 \x17\x07\xE2\xFB\xE2\x11\x1D\xD4|\xBA\xE4\xF3\\x9Fr\xAE\xCF\xD0!R\x80O\xE7\xE0o\xFF\xBB\xCA3\x1F\x07\x02"G7\x92\xABm\xD8\xA0\x7F\x9E\xBA\x82\xC6\x82\x8D\xAE`;\x82\xB8\xEF\x999\xD8\xC9)G\xB4\x86UC\xD4\xD1>\xB0\xD4X1\x06\x1F\xE0\xC9\x85\x8D\x82!\xDE\xC7\xB16\x90\xDB\xEBT\xA3-E\x8D5\xBE\xD2\x82\xA3\xF1;[\xBC\xBAG\xADMY\xFA\xDB\x05\xB6s/\x8A\xF6\xDD\xA3\x0B\xAE\xC3\x9E\xF7\\xE1W\xD3\x13\xFE\x06\xD6\x19\xF9 \xC7\xD2\x9Ep\xA4Z\xF6\xBA\xE0U\xF2\x80\xEA\xDE\xD5\xE5<\xF9\x14\xFF\xF9#\xA6\xD0\xE9\xD4\x8B\x07\xE1\xF1\xAD+o\xBEl\xB9#\xB5\xC4\xB7\\xF3N8\xE7F\xF0\x80e\xD8R*\xE4\x05\xE8n\\x96\xC6\xE2\x12\x80#f\x8D\xB2\x16Z\x17\xFE*\x85\xB7\xD1$1z\x96\x0A\xEC\xC1:\x9C?\x05\xC9\x9C\xE5B\xE1\xBA\xED,\xB4\xEF\xFC\x04\xF9\x16n\xE1O\xE0S\x1B_|\x93\x93^95\xDBc\xE2z1\xFB\xBF\x94\x04\xB2\x01\x07\x99\xDB\xAD\xCD"o\x0Bx\x9F\xC4\xB9\xA5K\xC5\xBD\xB8o\xD0\x08\Yj_\x95\xDEj\xC7\x12V\xF9Z\xC8A*\xC7T\xA9\x08\x14\xC3\xB6\xFF\xE6\xA9\x03]s\xCChAM\x83\x01\xBC\NV\xA8'\xC0\x9D\x1C\x18a\x14:\xCB[\x84I\x81!\x8F\xA4>4\xA86\xDC\xD2q\xAC\x83\\x0D\x97I\xD6]\x8D\xE8\x960sVcJ\x85X\xEA\x85\xCA\xD2b\xCC\xDE\x9A\xA1_\x93N\xFF\xB3/\xC2n\x93\x90!\x16\x0E\xB5I\xA8\x0C\xC9\x09\x0EY\xEE\x94;|\xBA\x05\x1BH\xD9E;\xDAjj\x84:\x8B8\x1BJ\x0E#\x0D^\xFDv\xFA2\xE1\xD6\xDD\xCA66\xBAfZ3\x95\xE6Ev\xEB\x15\xE6\x1BH4\xA8@\x81\x89\xCC\xD5\xBE\x0D\x0AM\xB8\x86\xEF\xBDnW\x88\x1AE\x8E\x81\x7F\x0B#\xDA\xDBT0\xE6m%\x16\x0F\xFF\xA3\x12[ak5\xC2-\xE5#\x1B\x95\xF8D\xEEp>\xCB\x16W~\xD8\xCE;\x9F\xEA{,\xA6\xD3n\x93s\xCC\x9D3\x0C\xBA\xD0\xE4\x06t\x02S\xF0}\xD9q'R\x9A\xFE\xC4]`\x1D\x8B\xDAnW^w\x18\xD9\x9BYK\xF7NM$\x9Cw\xE34)\x98\xCC\x9D\xA7\xCA\xF5\x9Cp\xB1\x84Q\x86\x9Ed\xB7dS\x9F\x82\xB7:$q\xDA\x88lq\xE0Q\xFE\xB7n\x88]\xF2\xC66\xECB\x8Camf\xC7|\x83\x07S\x19\xC5\xC7\x02\xE0>\xED$\\x07\xAE\xB5(\xE8\x82Z{\x01t\x17\x0C\xCA\xC6\x93\x17h\xE8X\xBB\x10?\x8C\x8F\xC4%\xECxD\xF3\x1E\x0A\x14\x96\xBB\xFD\x95\x03\x8E\xE5\xA5$l\xDE\x95\xF7\xFA3Q#\xC7\xC5\xBB\xF7\x97g\xC7~\x02\x093\x8BG\xAB\(b'\xEE\x9Ao%#\xE6\xAB\xAD\x8B\xB4\x85*\xEC\xEA\xAE\xA2\x1B\xF8\x9D\xDF\x96\xD8\xC2R\x17\x11\xDB\xC7='.\x19\xF6\x1CUS\xCE\x01\xEA\xB6fu\xB6\x8C\xC3\x11\xCA\xABP\xC2\xB8ZX\xDD\xB8\xD1A\xB5\xA9\x0A\xE4\x9A\x0D@\x82Q~\xFC3\xA2\x0E \xCE\xC2\x8C\x83\xFD\xF2\x0B\x8B{\x07\x18\xC1\xE4\/\xA8\xA7\xF9=\x08\xD4M\xBCdpu\xDFR\x00Y\x0F@\xCF\xB9\x93Re\xE9\xCD\x0E\xE7.\xF3\xD1=\xC6pb\x046ST,O8FQ\xBB\xBB\x9B`\x99\xB7\x85&\x8C@\xBE\xA3\xD8\x0B\xA7"\xD1K\xD1\x1F\xB2\x97\xB1K\x17\x9C_\x1FrF^\x8A\xC5\x0F\xE7\x18<\x01?v\x01\xA1oA\xA4\xB0\x9Ds?\x80;QY\xEF\x7F\xFC\x1B\xD9\xD7\x97\xCF\x06\x02e-\xCCY \xFE\xFC\xC2p\xF0Y\xAF\x97\xB5\xF2[\xF3\xFB\xADh\x1D\x1A\xE4\x00\xF1\x17?\x84\xD7?\x99P4\x00\xE0\x94\xD5\xFDJ\xC0i\xC9\xF5\x11Ez\xC0Ni;\xE4IZ\xF7\x83\x9EY\xB2-\xD8%\xE2\xD1\xA1\xB7>\x13\x03\xC4@#\xB2\xB8\x0B\x83\xEF\x14\xE3<\x9DAB\x18\xD9h\x88p\x1D\xD7\x93\xB6\xAF\xC6\xC1\x03\xC8g\x10m{\x18:'\xBAc\xFA.\xC6YB`\x06\xBFh\xB5:\xE4\xB6$\xBB\x12\xB3\xC8\xC4\x17L\x9C\xC9\xBB\x9Bri\xAA\x0E\xE2C\x8E\x9E1\x05\xEEE\x9A`\x80\x1A@\xCC0i\xBE\x9A\x9A*&\x8B\x0E\xCCo_}`+\x11\x1D\x1AC \xD8\xD3e\xE6\xC7\xEA\x193@\x0F&\x8A\xD5\xEE\x14nf\xEC\xEB\xA0\x17\x87\xC0\xBF\x1FY\xF6\x19\xF8\xC5&c\xBB\x9EpQ(\x1E=\xDB\xF1\xA1IU\xFAc\x01(\xEF0vf\x97\xB4\xD8\ca\xCD\xCF\x81\x874\x8FC\x87f>U\x05u\x96\xBANr\xA7 =E\xE3\xA6\xF0\x84e\xE8\x00\x95\x9A\xF8\xB9=\xDE\xCEp\xADt\xD1\x1D\xB8\x1A\x8Bv\xF8\xF5k7M5\xC7\xC3\xC0O\xA7mp\xC8\xFC\x0D\xBF\xBA\xBE\x84\xF0AT\xA0\x8A\xAB\x15p./xzF&u\xA4\xFD\x9F\xB2\x90\xF9\x1Fc\xAAm\xD3N\xEF7\x0AAJ\xC3\xB2\xF5\xCD\xEB\xC2\x1B\x95\xF7\x18{\xD1x\xB4\xC3}=\x98\xF7\x15\xF10|\xEC\xE2\x91\x98\xAD\xF2\x98\x8Byp\x08\xD1\xC0\xD5\x7F\xA9&\xC3\xA7-lf\xBB\xB7\xD3\x0D\x15M\x14Kf\x9D@\xCC)\xDF\xC6\xBE\x06\x90\xDF\xC7[\xD5\xD8@\xC5\x86\xBF\xEE\xB2\xDD\xF4\x95\xA2"U\xF7\x7F\x9F&\xC4t\\xF5/\x87\xBA\xA9\xE2.\x1A2w\xE6\x8A\x85w\xFF{\x82\xC2\xB7uB\x00\xD9B\xDB\xDA\xF8W6\xF8\x14\xB5\x1D\xA3Qf;\x86\xBC\xC3\x88b\xE3N\xCE\xC4,\xF6\x94\xBDR\xFF\xE5\xA25\xD2\xDFQ\x13M\x04yX\xA4\x11\xDE]\x15U\xED\xF1l\xDF\x8C\xF1\xAC\xCCr\xDDH\x9E\xF2\xE5Y\x9F\xE2\xE7\x87\xFF\x9E\xAF\xDC\xA44\x1B\xC8\xEA`\x0D5D\x82,\x80\x96\x90\xBBm,\x19\xC5wMt\xFE\xF7\xE8\xBD!\xE2}.\xD1@\xFC+\xCB\xAB\x09(N\xCAH\xB0\xEF\xAC\xF2\xA7\xE5h\xB1;\xB7J\xD2\xD1Jvj\xCF\xE5\xA6\xBF\xA6\x94\xCBIy\x00\x99\x8Fp,\xD6\x15\x8E\x80\xD6\x9AE\x84&\xB08)0b\xA34\xA7\x83 \xA3N\xCF\x88\xA7X\x9A\xA6\x9FW\xE5\x8C(\xBCTX\\xA9\x1C=\x9D\xE2\x93\x87\x93\x1B\xB7&o>\xC6\xCB\x88v\xDB`\xE3\xECTT\x80F6\xC9\xC2\xF8#\xBC\x13\xAAf{u\x93WGL\x1E\x8D\xEB\x0C\xA0zo\xBB\x8B\xB6\x86\xEE.\xAC/\xD2\x9A\xF0_\xEF\x12\x91\xF1T\x97MO\xAD)\x0D\x1D\xB5\xF2&\x90\xEEv\x19p\xD6\x1BVn\x04\x1E09\xBAaG~d\x97#\xA6.\xA8\x09Bm_\b\xD6\x12\xC7\x8D\x9C\x9E\xD3\x0Ac\x9AT\x88G.?[\xE2\x14\xB2X\xF4\x18R\xB7\xD5\x86\xB7\x7F%\x12\xFD\xA3\xC1<8\x15\xDE\x9C\x098/\xF6o\xB2>\xBC\x8CP\xF5/lOe\xA5\x0B\xBDw\xE7\xD6\xCF\xA1P>pUxH\xFB\x9E_\xD2]\xAE\x0C\x098`\x9B\x9F\xDA@:\xF4"z\xDA-d\xE4A\xCB\x1Dt\xFD\x80u<\xCBG\xB5\xF63y\xD2\xCD\xE4\xA8b\xCC]SH\xF8$\x8D8\x1C\xCB\x0E\x99\x17\x84]\x91\xF7#\xB9\xF0A\xC9\x8Beb\xF3\xFC.\xE7\x9Dv\x9A\x99\xD5YL\xD1\xB3\xBF\xEE\xD90\xF7\x81\xEE\x8A97n\xE4\xF3kU\x18\xEB\xF7\x834\x8Fq\xBA*\xC2\x16T:\xB4#\xF5\xE2\xD4\x01+\xFA\xA3I\x91\xCDo9\xFB)\xCB\xCC\xD7\xD0GN\xF8\xE4\x17\xF0\x99C}\x1E\x93O<\x0C\x80\xE2\\x00-"\xC4\xB9[\xEF\xF3\xA7{3\xF3\xB2\x0B\\xFE|\x16\x12\xB0\x1A2v\xBE\xD8\xC5\xE3\x1B\x0B\x09M\xAA\xCF\xC9\xE2~\xA5N\xDB\x1D\xD1\x7FV\xB0&\xC3\x13v\x17\xAA\xCE(\x0E\x97\xDC?\xAD\x99\x00R\x03\xEC\xB3T@z\xBE\xEA#T\xA3)*\xE7I\\x97\xA4o\x97\x8C\xFA\x13\x81\xF6\x81\xD0\xDD4\x9C05\x1CPy\xB6\xB2\x16\x93\x95\x9A\xE0\x9C\xB8\xC7\xE0\xB3\xE5)\xA1\xFDP\x93\xB14rA\xE8\xE2\x1B\xBA\xFAO\xEBw$5p\xCBg\xE3\xFE\x97\xBA\x1BMfR\xADMWv\xBC\x11\xA7r\xF8\xE7\xA0V{\xA0I\x81x\xEF9\x8D\x8F\xE47i\xC9\x1B~\xF3\xBA\xD1\x02\xE8j(\xDBT\xB0P\x945\xBF}\xDD\xB9\xC5\xB4R;\xBB\x92\xDDz\x90\xB9\x82p\x8F\xD5\xFCZ[\x10\x03NB!\xF2\x06\xB3\x04\x15\xB6\x1B\x07y\x7F\x00\xC7\xD7W\x84v\xDCe\xE1[\xF8\xA9\xC2\x87\\xF7\xDD:\xEEW\xD0u\xE8/\x92-}\x8A,\x0C!8\xD0\xEB.3\xB8\x14\xA5hcx\x9B\x9D\xAD\x83\x98L(c\xB5\x15\x1Bv\xF8~\x87Jw\xB3\x9BF\xF1%\xF9UR\xA8\xD27\xE11\xC9\x84)\xAE\x8D\x8DI|/\x02\x8C\x19)\x09y\xEF\xF7\xE1\xD0\xB6\x94$\x86`\xC2\xDF\xC0\x0B\x94\x7F\x0C\x89\x996/\xC4\x82^`\x88\x9EvPp\xAD(\p0\xFAV\x971I\xDFxQ\x89\xEEq\x11\xE0Z_\x1C\x09-\x97,"\xB0B+|\x84\x0E\x16a\xFD\x8C\x87\xA4\xC2;\xD7\x0B\x12\xC7\x80\xF4D#P \xEF\xA69\xBC\xCBF%\xFAH\xB3\xD4\xBA\xD5\xB3\x80V@\xF1\xE4o\xB5\x16\xBA\xF4\xCB\xCB\x0D\xE5\xB3_\xEE\aj>\xD2 6\x0D{\xA2\xFF\x1486\x87\xD8;\xFF\xE20\xF1\xC5!LE\xA5O\x80\xC8\xD1\xD3\xBD\x83\x95\xDE\xD1\x13\x03[\xA8.\x96\x1C\x88\xE2\x84\xED\xA4[\xC9\x0A\x97B\x9C}\xA5nC*\xD6+\x8Ca\x9E\xD9\xE1h!\x09os\xA1\x0E*\xD5\xA7\x07\xC6\\xE0\x94\xF1%\xD9\x7F\x1EI\x11\x97K\xDB\xD2>h\x1EZv\x85\xD3o\x84\xFB\xD2\xE3\x0D+\xF0\x04\xDD\xEB-\x84\xD6\xEC{'J\xAD\x81\xC8\x1B%_\xCDZS\xA9\xBD\xC5n*\xC1\x17^\xBA \x8F\x97~\xD4\xFA.\xAFT\xA7\x001\x16Hp\xFE\x8C\x07\x8C\xE9\xF9w\x03:\xAA\x05R\xFAQ\x98\xFFj\x01\xEC\xD9\x9C\xBF\xDC\xF6\xF8\xDE\xA2A\xD0O\xA2\xB2\xD8F\xA0\xF3ox\xB4\xE7\x0Bi\xCB\x0F\xEC\xE5\xA4\xA0h\xBB\xF2\xD20\xA3cRG\x88\xF3\xE1\xA6\x96\x85O\xD3\xFE\xDA\xB8-\xE4\xD3\xA8\x06\x1A~k\xF6\xBE\x18\x0E\x9B8b\xB4nTR\x00\xDA\x04\xDD\xCF\xCA\x7F\xA2.\x93\x90\xE1$\x8C\xBB\xB99\xC6\xB1\xDA\x11\xA0;\x99\xE5A\xC9o\xAB.\x8E\xD1\x07\x9D\x8A4\xA4\xE6\x13\xAE\xD0\xBA7\x94?\x18\xBB\xF3wd\x9Dn\xEF\x0B\xB0\x0Dj\xECaB[]\xE2\xEE\xE0\x1B\x9A\xE3\xE0$+\xE3\xEB:\xAB\x05rp1,\\xA6\xCC\x1E\xD7\xC9\x0A h\xE7\xBBx'\x11\xEA\x17-\x81Fh\x7F\xD4\xEA}\x18j\xD2\xFA\xF8Se\xB8\xBAn\x95\xA1x\xA5;\xC0*\xD3J\xA2N\x0E\xF6\xA1\xFF\xA4{S\xCF\xA0D?\x8D\xB5?o'>b\x0D\x94\x98\x9D\x04\xA7\xED\x1F\xA2\x7FS\xDE\xC4\xD4\xC30E\xB6k\xDF\xCB\xA4v\xB8\xEB\xEB\xFC\x84\x12y7\xE3D\xF5\x9A\xBA%\xEF\xED\xEC\xBB\xCB\x0B\xF3\xD6=\x0Bz\x9Da\xF7\x91\x08\xD7p\xE3\xCD\x1D\xEB%\xC6t\xC6\x9E\x9Ch\x98\x808~\x94\xAE\xC7/Y*F\x185D\xAC\xBDm>\xDA\x0Ef\x971@\xDEd _*\xEA\xF8\xF5\xBB\x0CFX~u\xC5\xBC|\x1CtW,aS\xBAT\xA4!\xE5\xF1O\xE8\xA00g\xED\xBCI\x85\\xB3\x05q\xA9\xDE\xE3\x8Dg\xD5b\xF5C\xBF\xEF<\x1D\xAD\xCB\xC1\x92\xEA\xA1\xFB\xD4'dc\x10\x8Bg\xC4\x8Cw\xB3vs\xB0V8\xDA\xD6\x8A\x93W\xEDS\xB8S\x87\xA4\xED\xC7\xD5\x02\xD9\xC9\xB5\xAF.M4\x8Ck\xDBgZs\xEC\x0A\x17\xBA\xE0\x8B$\x84K\xA8,5\x00\x00\xFACPbV7\x0B \xE81CQ\xBC\xC6\xAA\x1Bg\x90SK\x94\xE8\xA6C\x16\x9C\x80\x97\x91@&\x00\xD4\x04p\x95\xC0\xE6\x1C\xFC\x9E\xE7\x0C\xACr\xA8\x984\x9B\xA4J\x9D#\xDDl>7l\x177~\xA69&L\x0F\xE7?\xEAj\x81\x92\x94\xD1/\x10L\xAC=\xD3\x07\x83!3\xE1\x98\xAAZ\xD5K\xE8;S\xEA)\xDE\x0E0\x16\x9F\x81g#^@\xAB\xFAG\x8C\xB7\xA7\xA7\x95\xB1q\xCF,\xB9S\xD003\x82\x89UO4\x85\xDC\xBF\x0F'\xB6\x1C\xD0!Ml\x87\x13\x98\x09t9\x7Fo\x0A\x19'<-\xF8\xFCe:F,q\xBE5\x0C\x92\xADI\xBE\xF3\xD4>\x19\x1B\x0B\x1C{\xDC\xEAE\xD6\x0B\xE7t9Ug)\xE3\xED\x96Pdl\xBB]\x083\x06\xB8S\x1B\x12\x887o]\xD1a\x95\xBE\xBC\xFC\x8B)\x1F\x8EQ\xED\x0B\x01\xE5\x9D\xB8\xEC\x96]P\xCDv\xDB,24\x14%\xEFC\xE22\x1E\x85P\x96*\xA2S\xA1\x95\x8C\x1DZf\x90\xD3\xE6\x99\xC8\x16\x9AmW\xDCG\x9B\x0D\x079\xB9\xDA>\xC0\xA88\x9Dx\xEB\xF37\x91\x80t\xDB\xF0\x98J\xF1\xC9\xA43)\xFC\x8D#\xD4b\xD4q\x93\xE9\xC6\xED\x841\x99Y2\xE2\x9F\xB0]\xB9\xC7\x9E-9\x0E>\x9F\xBB(\xCDJ\x9B\xE7\xFC \x93\xA6\x02\xFA\x11w\x92\xBD!\xAE\x1E\xD0\\xF9w\xD0h\xA5\xEC\xD9j\xB6\xEF\xBA\xCB\xA5E\x1D\x1B\xC9\xA6\x0B;\xDE%\xFDf\xE3\xEB\xFD\x89JL\x98\x0B\x81\x90\x96\xAD\x99\xBF\xB1\xE3p\x99\xF4\xC8\x80\x91|\x16\x95\xA4\xDA\xA7\xCE\x01l\x10V\xADo\xC6\xF4\xC4\xEC\xC2\x13nG\xAA\xE7=\x80\xD3\x90T\xCD\xAC\x80\x01\xE6\xA2?\xA8\xBA:\xC9\x89`\xC5\xCCl\xF7\xE1\xD4\xA9_\xBA_\x88|\x0C\x15\xA7\xCC\xC8`\x14@\x08S\xEByS\xD2P\xD6\x83\xAA\x9A\x82Hz\xC5b\x10:\x0BW\xD3g\x81\x16\xE7n\xB8\xE2>\x9Bp\x9F\xAD\x07\xE2Y~\xEB87\x88N'\xE2\xB9FJH\x92\x18)Fa\x03\x9C\x90\xD8\x82!\xD3)\xF4?r\x1B\x91~e]\xF0\xAC6\xF1\x171\xC7f?Z\xE0\x92&\x99\xBB\xC8\xE1\x1A:ecH'\xBA&\xF3\x8F\xDBG\xA6\x17\xB8c\x0F\x97\xC5\x858\x9Ai\xBB\xDBUH>`K+\xA0C9g?\xDC\xBECp$]m\xC4\x8F9)\x8DX\xFF\x08]\xF07G\xCB*\x87\x99\x86\xE1\xD7*\x0D\x05p>\xB5(\x87(\x91R\xC4\x1F\x1C\xF0a\xCA\x0EG\x11\xFD\x83X\x17\xF6\xC4\xC7\xFC]\x1DHi\x8AN\xFD\xE5W8\xE1l\x87i\xD81\xCEX\x053z\x85\x897\xEFc\xFD\x99+\x8E\xFB\xE4\x85\xE5\xA2?K\xED.\x96\x18\xCB\xE6\xF4J\xD3\xE5\xB7\xC7\xD3\x0A&\xACw\xDE \x03\x01\x19\x0C\xF0*\x95S\x8B"k\xA9\xFC\x9Fy\x03\\xEB\x86\xDAkd\x81\x8B\x1F\xAB\xCE\x06\xAF\x9BS@7=\xA55\x89Q\x0C\xC1J"P\x8E\xEA\x1E\x80\xB2@\xB1\xD6\x8B\x03G\x86\x88\x8D`\xF5sC0\xC4Oy\xC7|\xCE4\xA19\x8Bk\x19\xC0\xE6\x9B\xDFI\xAC\x04K\xA1\xAB.\x11\xBD\xAC\xDECQa\x82ah\xC6\xCA(\x8E\x01\xB3\x05\x88pX\xF4\x0BA\xA1QX\xFE\xF1gr\x90\xBF\xC6a\x99\xF5\x8A\x05\x97\x13\xF4\xCCeu\xA1`\xF1\xA0\x11\xAA\x14\xC8\x1E:>\xB3v\x80:[d\x05\xC5\xC0n\xC4\x15[9\x870\xB4\xB0w\xB0O\xC8\xAE1\xA3Y\xAD\x80\xD5\x83Z\x15!\xF0Z\xF3\xA7H\xEA\x89\xC7\xE64\x8A^9\xF0\x1C\x0DJ\xD2m\x11\x1E\xA7J`\x1A\xBD\xA0\xA8Ht\x0E\x8F\xDB\x85Dq\xED\x81N\x16\xDE\x15\x87\xC6H\x83\xA0\xD9\xB6\xB2'\xB8\x06w:K\xB3\x04\xC3\xAE\x03\xF4\x08\x05\x19EJ\xAE\xD6\x8A:\x8F"\xC6=\x11\x9B\xB1\xD2]:\xFD\xAE\xFB\xDA \xF0=\xC0\xE9\x1Fcr\xD7\xF3L\xD4F\xA5\xF0\x97X\xA9v\xA9\x0A\x02ESm\x1E-\x95i\x95\xD2\x03B\xD1\xE3\xDBDK\xA7\xEF\xB1V\xA1ks\xFB\xB0\xD3w\xA9\x05\xFE\xC6\xD2P7\x16\xC4@\x18j\xB3\x06RZ6\xF4TW\xC3\xAB,\x0B\xCA\xAB\x0D\xB9v\xAB'\xF1|\xCC\xFF\x1C\xC9\xFC>\xD8W^\x94\x90\xA3\xD9\x03Z\xEC<`\xFBhh\xEE\x87|\xD3\xA8\xB4AL\x98\x95\x1A\xE5\x1A\x80\xAAj\xE0\xE5?\xCE_\x92C\xB9*\xB8\xB2|\x91\xF3\xFD\xA4\xD1\xC2\xAF\xDB\x05\xF3\x0E,M\xBF\xAC\xF5c\xE3[&<\x928b\xEC99\x04c\x17\xBE\x0D\xA5M\xAB\x91W\xB98\xD2'F\x93\x9C\xB0\xB9\x12\x03B\xEDg\xC6\x8A\xF1\xD1\xCB\xA7)i\xDE\x0F\x8B9`\xE4\x83~\xEF\xBC7\x00NKT\x08ED\x94^\x13\x90\x06z\x1CnP\xEEB Q\x80\x15\x8D\xE3\xBED\xAFg\xE5\xC8]\xBC\x86\xFD\x1E\x17\xAB\xCE\xBC{W\xA0`.\xE9\xF5\x07\x85G|\xA7Zm\x15\x09\x04\xDF\x06\xF4\xE66\xBA\xA7\xE1Z\x85\x0F{<\xA16\xD5\xF7\xD9\xCC\xB6(l\xF8\xD6\xE7\xEF\xED$\xE2\xEC\xF8(\xA0W\xA0m'\xCA\xDC{\xA3\xAE\xC0\xAF\x81\xAF\x95?\xED\xB8yrQ\xC5\xA5\xFD\xADoP\x91\xD7aX2\xFA\x07U\xFBV\xD2(>\x9A\xE5\x0D\x04\xC3SbO\x1C\xE1\xBCe\xA4\xE4o~\xCE\x0D\xD2\x8C\x08\x16(yY\x93\xE6\x04\xC3w\xCB\xE8\x0D\x08,YO<\xB5Q\x1AT\x8B\xC1\x01K\xB1\x86QS\xFC>r\xBB\xDBs\x1Fzt\xE0Q\xB3X\xB8\xDD\x83\xC6Q\xF7g\x04\xA3\xB2\xF3\x9B\xC9o\xA7\xAF7\x91\xC6\x1F\xB7\xDAX\xAAq\x1Fl!\xCAH\xEAQ\x0C\x80\xC51c\x8E2\xE3.b\xD4gJ\x99\xF7\xDD<\xBF\xC1\xAEEF\x9E\xF2\x00"C\xB6\x86\xD6\x96\x99\x01\x7F\xF6\x0C\xD8pq\x07~\xDE_\xF2nL8\x12o^\x99\xAC\xEC\x81I%)e\xCD\xB9H\x89\x80\x83\x0B\xF9\x0B\xED\xA4\xF7\x9F%P\x8BG\x83\x19\xFB\xA5\x909\xC5\x12k\xF7\x9B\x9A\xE7|\x19h\xC7\xC3\xD6\x84\x83l\x1F%\xEB\xA8\x07\x1Cv\x1F\x05G\xBC];\x8D\x0Ep\xA1*\x10\xD7g\xD8_-\xE2i.I\x96\xEF\xBC\xCD\xB690\x95\x83r\xF5\x13\x99\xB6\xB4]G\xAB\x0EGp+\x9E\xD6\xFC\xE4\xDD\xB3Y]$`\x84c\xF4\x1A\x98\x18\xD8?\xD5\xBB\xB1\xDC\xCC\xED\x04\x97}\x1E9*\x06\x14x\x165\xE2Q[\x8A\x0B\x14\x8B\xC0R\xA663\xB6\xC5\x97j\x08\xB7\x9D\xD2u\xEB\x9F\xDE\xE6\x90>\x0CN\x9C\x841\xE6B\xEFwV\xD3\xD2O\x07D\x10\x08\xCBB\xC84\xDDl\xA1\x17\x0C\xF6o\x92\xF6\xA8x|\xB4\x0F4\xD3\xBF7\x1A\x93\xE3\xC9?\x98;\xD9$-\xC2\x84\&\xC0v\xC4\xBAt\xD8\x92b\xD2:Q&\xEA2\x8BB\xCB\xC3\x89G\x96R\xA0\xE8B\x9Cx\xCC\xF7p\\xBC\xD4i\xA3\x0D\x1D[\x0F<\xC2\xC0L/\x00\xFC=j\xD6\xA9\xC2p\xDA\xE1\xDA\xEF\xC1*\xA6\xA2G:mp\x88\xE9i\x17\x8E\x8B_\xB3\x91\xF5\xBC\x8DlN\xEEz\x15\xC7\xAB\xDF\xBE\xBA\x91A\xF7t\xB6\x81\xEB\xB1\xF9FO\xFD\xC2\x12\xAF\x98\x92}\xE0[]\x8CP\xEB\x99e'\xB8:\xD8\xDF<\x0D\xD7\x93\x99\x12\xCE\xA9eGAp\xB1\xD2\xED\xD7\x04\x94\xF3\x02/\xAEL\x0F\xB4\xB2a*jY\x93!\x159\x8B#4\x07\x03T\xE5&\xEB\xE1TQ\xCA\xB3\x17\x9F\x94r_;@49\xDBj\xE0\x09\x10\xBF:\xDB\xFF\x9F\x05\xE0\xFE.\x95\xC9\x9E\xD16\xE6\xD8\x81\xF3\xB9\x18\x82\xCE|O\xB0\xA9\xCF\xC6\xC0\xE3\x02;\xFA\x0E\xE6w7\xF5\xF1\xCFp\x10V\x8A\x05\x9A\x815\x1C\xD0$e\x03l\xAF\xEC8?\xA6\xA9d\xEB\x00\x99Z\xD9`#\xDA!\xAA7\x80\xCF\xD0\xA5\x9B\xDB\xE1\x11Y]\x0F\xD2\x01w#HG\x80\x95\xFA\xA0\x1F%\xC9\xE7&\xEB\xFC\xF5\xD7`\xE3&\x01\xE9\xEB,\x8DF\xA9+\xACCY\x8B\xA2\x87n\xA1\xDA\xA3\x05|~\xE1\xE5\x1E\xA1M)X\xB9o6\xC0\x07\xC7xV.Q@9\xBD\xC5\xD2Ri\x81*\xDE\x14x\xF3IP,\xC5p\xA8\x0D\xEE\xB7\x85\xD9Q\xC0\xD7\x9F`9i\xAB\x06^C\xF6(-\xDE8\xC0\xE8\x144w\x1A\xAC\xFD\x8A\xC0\xBE\xE9\xFB*s\xF2\xC0+\xA6\xE5\x08\xFB^\x88\xAB'6[D\x95\x0C^\x93\x81\xF6qIF\x0CI'\xE9\xC1\x883\xAD\x16\x8B\x94\x1B\xE7o\x9CE\x04S_X4\xF8\xAF)\xE9IW\xBBq]\xF4\xE8\xF2\xE4\x8C6\xF6\xE5\xC9\xA1\xDC_\xA4?\x9C4$\xC5\x8D\x1B5g\xB6`j,\xD2\x1C\xFB}\x91#:_\x9E\x12\xEB\xE8\xE0C\x19I\x11\xCF$V\xF3l\xA7\xAA\xEC\x95\xD6\x00\x11\xEE\xF2\x02\xA0\xFC\x1D\x05\xBA2\x8C\xCE\xCD\x97\xF7\xB4\xF2\xAFzNy\x17\xBD\xB84?w+[\xBBE\x7FG\xC3e\xB7E\xD4ya\xFF\x04\x9F\x9D\x95\x9CcB\x02a;\xD02\xF6j\xA4\xCF\xC8x\xE8\x1C\xDCK\xFA<\xCF\x89\xFDZ\x0D\x16N\xD6\xF24y\xBA\x89*\x84\xEEnH\xCD\xBFO\xFC$y\xEC\xA4\xCA\xA9\x9A\xEB/\xB8)\x81\xDAH!a\xB3o$\xA1\xBBT\xB5\xB0\xAC\xD4}\xCAAu\xB7\x0F\x02\x9E\xEE;\xC431S\xD5\xED\x04d\xD3\xEF\xA4\x02\xEDP\x84\x13\x00a\xC5\xE7t\x11\x1C\x02\x03\xD7\xB4pbCO@\xFD$\x82I#.\xC6/\x96\xBC\xF9R\xC5\x1Ddc\x95\xAA\x03\xE0j\x83\xCFj\xBC%#\xB8\xA9\xD2P\x99jW\xE2\x14\xC8U4^J\x91\x15y\xB2\x08\x18U\xFA\xDFm,&\xCB\xC2\xDE\x83a\xB4"\xBD=zg\xD4\x1C\x98u\x84\xCE\xFD\x8Dv\xFF\x01)\x02%y\xB6\xA4z6\x05\xAA$BG\xA1\xD1i\xB7\x9C\xED\x18i\xA2\xECcp}\xD7/\xBB\xC2<[\xB2N2e\x8B\xDF\xE8E:\xF9\xDCB\xDDk\x8E\x1B\xBE\x8A\xB3\xB8n \xC4\xF3\xE8\x0Ci\xC0\x07\x99\xFB\xD5^\x17#\xB6\xE0-RHt\xB5%\xD9}S\x0Ds\xBB]\xAE\xC5\x1F\xA9\x10\x8E\x11Wb-N\x8D\x94\xAFe\xE5\xC2zG\x93\xC1\x97\xF5x\xB8\x10A\xDCw\xA3\x8B[\x0D\xD0\xE7\xF20\x0D\x9Ft\xF4\x86\xD9[n\x83\xB3\xC7\xDD\xE1:\x02_.j73\xBA\xEBL\x93:\x11\x8A\xB0\x86:#\xF3\xF4\xAA\xB9p\x0A\xED\xC5h\x04\x0C\x10\xE6z\x928\xCEg\xFD\xD2]\x02}\x97\x1E#\xF5\xB9\xB7\x13\xDD\x9A\xFD\x04\xD5\xBEwE\xC8\xEC\x146}\xD9f\xAD\x03\x16\xD5e~QT\xCB\xE3\xDF\x9D\xF4I]\xB6H{\xA2X\x81T\x0B?\xFCOm\x06Q\xE6\xFB\x9D\x0B\xA9,\xDC0\x1D\x08\x06\x83\xB8\xFC\xD6Gc\x0B7\x99A\xE9\xEE\xDA\x96A\x11\xE8\xFE@W\xDF\x9F\xBB\xFDt1\xDBsh{\xE8\xB6I\xEB\xFBU\x1B\x93\xF36\xE5\xCB-\x10\xE8\xDAD\xCC\xC5\xBFK%\xE9Zv\xAD\x08\xE1o\xCB\x83\xF2\xCF}h\xA0w\xE8G\x7FO\xA3\x133\x19\xF2\xAC\xCA$`\xB4\x8A\xAC\x111\x09w\x07\xE8\xCD\xCE;\xA214\xC7\x17\xB5\x14$\x05\x01\x8A\xE4|C\xC3,\xB4UzT\xE3\xDF\x07\xBF\x80\xE0\xC2\x1A\xC9\x029\xBC\xEB\x94\x0A\xD2\x95\xA6y\xDD}\xC0\xBBP%&n:\xF7MGA\x91y\x0CY\x05\xCB!(Yq\x1Dn\x81\xD8Q2\x8D\xD5i\xB1t\xFER\xB5\xC7\x06\xC7\xFDV\x89XUZ\xCFc\x0D\xBC\xD6\xDC)o\xDEO\x11\xFE\x088P\xCB_v\x7F\xF8=8\xD2\xAF\x80`9\xA4\x89\xA0\xD1\xD6D\x19\x8A\xEEu\xADG\x0E2\x9D\x8D\x86\xD3p\xE6F\x0A\xE3\xE8(\xC0\x85\xDEd\xDC*\x158\xED\xFE\x8B\x89\x1DD\x87\xBF\xA2 `8\xD5wjj\x97\xF2\x84v\xF5\xF2\xD5\x0A\x04\xF4\xFF#he\x9E\x1C*om\x1E\x90i=\xC77A\x88\x90\x07bYT\xDB\xFA\x0F\xF7\x15\xCE\xF0l\xBCq\xD4*u\xE3C\xC5U\xA7\xF4\xF8\x92\x9D\xE8\xBF\x0F\xB5\x84\xCDV\xCF\xA9\x0A\x08\xED=\x82\xAB\x95)\xDC\xED\xF9\xEC\xD1\xC3\x86ZW\xFB\xC5\xB2\x12<\xE2IB\xBE\x98O\xFC\xA1q\xD2\xBF\x8AX\x1A50\x0B2\xA8&\x9FMwh\x80\x9A\x82B\xCC\xCC)\xCE\xA6'\x92\xF3M\x98\x92RI\xEE\xF2\xC05\x85&zb\x04\xF8\x02\xEF\xEE8s@\x9F\xE9\xE8G|?\xCD\x90\xC9z\xDD CQ\xB5[;\xE0O3\xB3M\x09uX\xEEnE<\x7F\xE4\xFBj\x1A\xD0\xBE\x90f\xB4\xEA};\x17!\xE4\xF6\x9C\xA5\x9A\x81\xC9\xBF\xAC\xB8\xBB\x91/\xDEXc\x99W\xB8W\xDE\x16"$\xE9\xE1&-\x15\x84\xFA\xCAG\xC2\xB8\xBB\x13\x1F\xC1U\xC9\x12b\x91K\x8F\xC5\xA0\xD8\x9E\x12\x17DmN\xDD\xFD\x92\xB6\x18e\x81c&\xEB\xC4H\x8DOo\xB1r<{\xEE\xAD\xB3\x92x^\xC3\xFB\xD5\xA1\xC8\xE0a\xA3V\xB8\x99\xBF\xC6\xF99\xD0\x81\x05\x1A\xE9\x1CHV\x8B\x88\xAB7\xD73\xA7\xA2\xEF\x95\xA9/\xD8\xF9\xA1z\xDB\x11\xFC\xE9\xAF\x96yQ\xFCrr\xF4\xB7\xED\xDE[B\x05n\x8A\xE5\xD9-H\x10\x81\x12\xE2\xEEM\x17[\xD7`\xD2F(\xB6\x8Fr\xDDW\xA4\xE4ZX\x99\x85 ^d\x83\x17z\xAEQ!):X\xFF\x9B5]\xCD\x08(\xF5\xE1\x0A\x1A\x9F\x09\x7Fp\x0B?\x96m\xAE\x0F\x12\x1E\xEB\xBD+lx\xCF'\xF8\xCB\x8D\x9FhH=\xE4`\xD6\x84\xFD\xA1\xE3`lK\xDD\x83\x06\xD3D\xE4\xF6~\x8E\xD5\xC8\x09\x81~\x87\x02\x09\x87y\x0B\xCC\xE5`\xA6\xD0J\xFA\xC8G\xB5V{\xFB\x83\xAAB$S\xB1uM\x94p>v\xCEK\xC8\x96\x1E.q\xA0d\xFE\x85\x82\xB1\xF4\xC4\xAF\xF2\xA6\x1A\x11,\xA8G\xEE\xCB>\x02\xDA\x9B\x06\x9A\xD5\xD4\xE6\x1BS\x85&}\x90\x19\xD5\xDF[Z\xDF\xEC\xC0\xCD|\xEA]N\xCA\x1FE\xD2n\x8C\xE1\x99\xB2Y\xE0/\xC2\xAD\xC7\xA7\xAC\xCB\xED\xEA\x0D%vb4U\x1B\x11*\xF5\xD8\x8C\xFF\xEB\x89\x9Ac\x8A\x9A\x9A^L\x82\xEE\xBAV\xC4\x02qj1\x18d\xE6\xC5\x8Cq|zx\xB7\x00\x15\x07\xD8p\x00\xE1\x16w\xF07:\xC7\x80c\xA02\x08$\x0A!\xCB]\xAC\xB2\x7F\x92\x97\x07\x8F\xA9^\xD1P\xB4\x0Bgz,\xD3\x18\xC8\x1C9\xAA\xE3^\xB8\x8A\x03\x9CmIaKJE\xCA\xCE\xAB\x8E\xA3B\x0C<]5\xF4[\xEC\xEF\xB8\x17\x16\x09\x92t\xCA\xF4;\x90\xFC\xFCx8\x03\xD4\xB9\x04\x18D5y^'\xE5\x08C\xF5\x0F"\x8EH9\xE4\xC1\xA0?i\x1F\xED\xD6\xE6 \x03j6\x10\xCE\x05\xD1\xC1\xAA\xC3\xEA2,\xBF\xA5\xD2\xA2\x7F\xD1hh\x9F\xED\x8E\xD4\x81\xC3\xDA3(\xFFM(h\x07\xD5NQ"\xBD\xD1g\xBFR\x01\xA5\xA8\x87h\x8AXt\x17\x84(\x86\xA1Z\xFB\xC7%GA\x9A\xB5\xFA\x03"\x8CQw\x87\x1B5\x983\xC6U"j\xCB\x1B\x9C\xA6\x17X\xE5\x998\x11\x1A\xFFa<\x07\xE9\xDB\x8B\xC1[4\xD0\x13\xA1J\xC7\xF7\xF8\xFE\xC3\xC0\xD7\xC4?(\x96\xA2\xE0\xF6}]\xB2\x1E\x84\xDC\x82g\x13|\xECJ\xC8\xFB,\x0F1"\xB9nU\xBD\x94\xC1^~\xA8p\x92\xA9\xB1(\xEE\xF0\x8Cr\xBEJ\x8B\xCFo\x0E\xD1\xE8\x1At\xD5\xB2\xAC\x98,\xD8\xB4\xAE\xA4\xB4\x14\x12-\xA1S\xFB\xB9\x05\xDD'\xB1m\xBA\xA6;n\xC2\x88Rz\x80!\xD2(\x9C{G\xA6\xC1i\x80\x0E\x13\xD5H\xFE\xA3\xF4\xB7\xEED\xE6y\xEBfrkn\xE08l]\xAE&;z\xD6l\xB1>\x97\xC5\xED\x8A\x03\xFD\x96\xD5\xA4\xEB\xBE\x80\x95\x11\xFF\xEE@\x98g\x01\x90I~\xE7\xB5\xCF\xC0\xDD\xCE\x12\x19g3=__\xE6\xE4[\xFE\x90\x17\xB6K\xF7s\xA2W\x1FCp9o\x0E\xCCm\x9E\xB9 V\xCD.\xAF\xC1\xF8a\x82=|\xD0\xFC\xE9\x1EQ\xDB\xD8\xDF\xF6\x86\xA5\x10\xCB;\xB4\xEBB\x00\xDE\x07S\xB3\xA0,\x0D\xA8YT(\xB5%\xFE\xD0\x82D\xE4\xA9<\x01\xB0\x90\x11\xCE|\xE1q\x15\x95\x1F\xA4\xE6W\xF8\xE1s\xF7l\xBD?\xD8i\x8A\x09\x0DY\x1E%]\x83=\x94V>n \xFDz-QT\x88\xA9\xAF3\xFC\xA9\x0D\x7F\x8D\xAC6]PH>\x03!\x9F\xCEx\x80\x15N1\xC7\x0D:\x9C\x91\x81\xC6Q\x9D\xE2"H\x83\x1B\x12\xC5\x89\xB6o\xFD}i\xBF\x118\xFD\xFF\xCDfQ\x1E\xA6\xD6!\x0Bp\xBE\xF1)\x94\xA7\x8A\xC4\xA28\xDE\xB9\xD2\x8A\x1FW\xFA\xAD\x1CA\xD3\x81\xD2\xD4\xD8\xC6O\xBE., \xEB\xBF\xD5\xF6?\xA2\xB1\xBA\x1B\x1D\x86\xABPW\xA3\xB2p\xDF:\xC4\x12?k\xDC5\xE4\x0C\xC4\x97\xD0?G\xBD(%|g\xB1\x1B\xF4\xAA\x9C*\xD0\x03(X:Dtnw\xD1%U}\xD9\x80n7\xFB:\xBE\x14%q\xAFd\xF4*"\x9Bx)\xBE\xAD\x00{\xF2\x0AZO\xC0\x7F\xEA\xA1\x0D;\xD4\xAB\x02\x83\xA6\x05\xAD\xCA\xCA\xFF\xC5\x03Z\x92\x9Cx'\x1D\xF2:\xE3\xF7\xB9vG\x1C0\xDD\xED%\xB5@\xB9\x065Y\x9B\xC9\xDC\xF0\xAF%\xAC\xA1%\x1627\x9F\xEC!\x80t\xF7\x1DX\xCB\xE6\xB8\xC1\xB0\x12\x97\xDAJ\xC3\xAE\xBCE\x0E\x8C\xD2\x93\xAE\x84\xFB\xC8U\xE0\xE7DN\x17\x1B\xB9\x8C\xA6\x8C\xFA\xFCr\x13@\xFF\xD0\xFC\xBA$\xC2\x83\xF2D\xC3\xFFgi\xA6\xC24&\xF8~\xC3\xBE\xBA\xBFO1?t|:Z\xEE\xA2\x1C\x1F\xBC{\xB8_\xDA\x95L\xFF\xC9\xD4\x9A\x98\x1AC_\xA3Sd\xA6\xC7\xB0\x1F/\x0Et\xD7\xCE\xD6\x1Fm_\xC7\xD3\x9F\xA8\x9E\xC1\xE175\xC8\xCD\x8Bd\x1C\xF2\xFB\x9D\xA2\xF7\xA0\x81HW!\x95w\xCD\xD0\x16\xAA!Yh \xCB\xC9\xEB\x8B\xACO\x17W6\xA6\x9DTn\x17\x0C\x0CM\xAA\xD6u\xBA&Hh\xC80\xFFEe\xEBc%\xB3F\x05a\xA7\x8B\xC8\x15\x96\xD1}C\xED\x90=\x14<1P8A\x9F"\xBAV\xDC\xFA\xDC\x00?\xB9\x88/\x0B\x03\xBDd\xFB\xD8f\xDD\x01\xB8\xDEW`\xBF\xA3\xB1\xE2\x0C\xDD\xCAKi\x83\xC3\xCDvG\x04~\xEA\x81DA\x86\xDF\x17\xF6i\xEA\xB2\xEEX\x0EN\xDA|\xB7\xE4?`e\xA7\xD3\xFD\xEC\xCD0\xDF.\x0F{\xD6\xA3/J\x16,\x8C\xB9\xFD\xDA~_\x04\xDA\xFE\xE3\x0A(\x88o\xAB0Po}5\x96&\xC3\xB6N\xE8k\xEF*\xD2\x91\x94\x81\xF2\x91\xD1\x81i\xD9\x86\xC7\x83\xFE\x92\x7Fs\xB1\x16p\xEE9\xB1\xBAY\x0D\xBE2\xA2\x01_\xB2\xF1\x1E\xCD5l\xEF`\x80\x00\x09\xF9\xF9x\x0F6\x82\x0A\x08\xAC\xF5\xFEU[\xCA/\xF8\xB0\x0FW\xC8\xAAY\xF7dHg\xF0\xE8\x81w\x0E`\x9B\x0D\x0F\x80\xCE\x9C\xF6Z\xB6\x931\xC1\xC5\xC9\xB3fI\x9D_U?D\x96-\x85\xDC\x13\xC3N\x14\x864\xF2\x1B\xFE\xAC4\xAD\x93a\xA2A\x0E\x00\xB6\xB2P\x80\xF8x'\x80\x0C\xAEd\x8Dd\xDF\x12\x19\xB29E\xF2\xF6b\xDB\x88\xB8\xE9\xBD\x80\x81\xB982\x16\xEF[\x19\xB1\xA1%TNc\xAA-4\xBB\xBD\xD0u}\xC7q\xA2\xC4\x19\xE5zV\x08S\x1A\xFC\xA4\x08\x9E\xE3o\xB2q\xFCd\x19(F\x7F\x911Cu\xEF^\xAC\xA8\x82\xE7G\x9A\xAA\xD9QC\x91\x04\xCC\xDB\x9D\x9Bb\x96\x18<\xD0\x9C\xB5'\xCB9pLL7b\x0BC\xF7Sb\x95\xCCc\xE7\x0AS\x15\x9E1Ob\x904C\xF0\x1FJ\xD9\xE7\x8D}-\x7F\xD7-\xBB\x0A\x17\xF5V\xA4,}_\xBA\xD0\x03V\xF1\xE3\xF5\xBE\x8E\xEA\x95\x1E\xB5\x9C\xFA\xB3 \x86y\xB9D\xA8E\x9E\xA3\xA5(\xF3\xE3\x99p\x81\xCA\x04\x95\x1B\xD5\xDF(\xAD\xCE\xFF\xB8\x9F\xF8\xE6S\x1C\xF9N\xF2\xA6\xCE\xDFu\xA0M\xCFyA\xB2\x19\x04\xB1m\xEFj\xEA;g\x9C\xE2\x14\x92?w\xE9\x8B/\xB0\x89\xB2\xAB\xD7e7\xA2\xF0\xD7\x954\x94a"u\x1D\xDF\x16\x04\x97\x1C_i\x03\xCC\x93\xC5\xC9m\x85J\xA4$\x14\x80D\x9955\x89\x15\xF9\xDC|j\xD0\x1F\x97[x5\xEA\x15\x94k3\xD5\x94T:Z\x10\xC2<4\xC7\xDDK:!\x9A\x9C\xD1x\xA9\xFE\xF8\xDA\x05\x10\x9F\x11\xA5WQ|\xBF\xCA\x06>\xEF\xC4\x8F}\x9E\xD5?YEP$\xE1\xC4\x115\xD3\x05\x91\xFD\x98M\xACa\x9FP\x04\x96\xE5J\x1A\x1D\x85\x0Ai\x0A\xC6C{Y\xF7\xCC\xA6\xE98\xA8\x10\xAF\x16\x0E\xF2k\x15\xC2b6\xBB\x05\x1DF\xA72@O\xCF\x0C\xA4*\xE1\x00\x13v\x1D\x9E\xD5\xBF\xFB\xBD\x9E\xB2.\x18\xC9\x91\x9CQ-m\xAD\xE8|@\xEDb\x0C\xFA\x0C\xD4\xBB\xC3\xBB\x84\x13rLv"E\xE0\x82K\xDB\xEA(\x19\xAF\xBF\x8C\xC9\xDAy\xF0\xA3\xE0\x95\x0B\xF5\x12\xF51\xD9\xB85b\xCD\xC4\x99'q\xF9\x98\xF8\xECJ y\x83:\x87*\x09\xA8\xE8j\xFD\x96j\x1E\x1BU\xEBi\xF22\xBB\x94C$\x8A\x17r\x84\xB6$lR\xED\xFBY{o\x85\xB2\x8A\x8Etv\xD3\xAF\xD2^Z\xC8\xB3\x85\xB9\xE5\xF5\x93\x9B\xCE\xBF #\xA2\x8F\xA1\xB7W\xCF\x81c\xD6\x1A\xF1\x09"\x83d<\xA6$\x84\x12\xAF\xBD#\xB8\x10\xC6\xEF\xD5),\x92\xD6\xAF\xC6A*v\xCC%\xD3\xB4\x0DV\xB0\xBD\xDD\xBBk\x1CRgJW&\xCA:\xF4*$\xA0\xF9\x81\x13.\xE1\xD9\xD9\xB9\x15\xFE8\xB0\xD8\xA2hM\x09 \x96\xAC\x1D_A5\xB9\x05\x0E\xEB'\xA9\xB2\xE2\x9Es\x98\xC6r\xE0\xDB^T!\xC9{X\xC5\xC6\xA8\xA6\xB9\x08s\x1F\x93\xFC)\xD2`\x16\x98\xE7\xB1y\x96D\xCBy\xD9\xB7q\xBB\xE8\xF9*!O\xA4\x83\xD5H\xA8nK\x88\xCC\xF8\x98\x06O\xB6f\xD3\x91\x10\xEDuT\xE8\x83t\x18,\x1A\xE3p\xBF\xBBjk\x8F\x01/K\xD5.%\xB2\xDE\xA0\xEBDvyl |\xDEl>:U5@0\x04D!\xBA\x05\xC1\x88\xBE\x8F\xAB\xA6\xDA\xE2t\xA0W\xADA\xC5\x85*\xD5I\x0B\xD6\x08\x16\xC8\x0C\xA2\xAC\xA2<\xF5\x96\xA9\xF0&L\x8B\xFD\xAA\x87=\x0D:\x85\xBC\xFA:\x06\xBD\xF1\xB8\x11\xBB\xFAk\xEF\xABHy\xD3-\x9A\x8ANQU\x14\xC1\x94\xF1\x1E7\x120\x90\xE4&\x0DC\x0Dh\xEDPN\xEB\x8A\x84\xD3\x91t\x93\x0A}s\xB7:'&\x1E\x07\x1A\xBCd}?`\x03\xD9\xF5d\x0EE\xC9\xBC>\x0F\xE0\xE4\x8A\x99;h/4\xC3\x1BU\x15\xD5q\x94k\x85g\xCB\xCE\x01Lx\xB1MC<-\x93*\xF8\xE1A\x1F\x08\xF2\xFFU\xC4\xF34o\x0CW\xBB5\xEE\xB6\xDEX\x9B/g\x91\x9E\xD8\x94~\xBC]p\xA7\x0D\xA7\x9C1\xE7uF\x09\xB3\xD8\x8Ao\xF4@l\x00\xED\x0BT\x80A\x08\xD5d\xE7\xAE\xF6fkl{\x94\xD5\x0A\xDF\xACR\x9A\x0Fup}\x81\xF0\xB7\xBB-d\xA2\xC9\xB8\x19\x80\xD4\x83\x87:e\xE1\xBA\x95\xDF\xC6]F\xBB\xDF\x03a\x00k\x92\x03\x13[T\x14\xF0y9\xC1\x1C\x00\xFD\xC6R\xFC\x8D\xE3\xB3\x89\xABV<\xD5d\x09$\xD4c\xD1\xB5\xFF\x8E\xF01]X\xC3d\x7F\xB1\xE4O\xC7~\x15\x9B\xA0vq~e\xF1\x01l!\xBB\x10\xD1\xDB\x1C[\xA2\x85K\xEB\x12P\xF1!\x1E\xA28\xB7u\xCB\xE0\x07O"\x90\x82\x12\xB0\xF0\x0B(\x97\xAC9\x97s\x9AQ\x8BK*\xEB\x82\x018&\xB4\xF8(#\xBBnR\xF2\xE6\x0A\xB0\xB6\xB4\xE9\xED!\xD8\x16\x1A\xC6I\x01\xEC\x9E\xCD\xB2-z\xFF\xC1ev\x93\xCCL\xF7\x8A7\x81+\xFA3\xB9A\x9CSRdR\xF5\xA3\xB6\x12L\xDDV,\xB0fYi\xE5\xE0\xB2\xA6\x1D1\xA9\xAFN\xB9\xE8BNr\xD8Rv\x00\xF59z\xA4O{\x01\x9Fd\xD8O\xB3\xD4\xA4GYEu\x1CH\x1F\xCB\x03\x96M\x08^\xAC\xF1\xAB\x9C\xB8KLc\xFAR\xD10\xFF\x14$+\xCD_P\xC3\xF4F]\xB2\xDB\xAC\xCFGB\x91\x8B:\xB9\x95+U\x8D\x02\xCAa\xA3\xB8\xDC\xCD1\x7F+\xF8\xA7Vs\xBB\x8BO\xEE\xF8\xCF\xA9\xA01I[\x0F\x0F26\xC2\xF3g\x0CL\x99&\xF0\xC80)\x0E\x19\xFA\x1F\xFB\xA7\x94\xF5?\x93\xBC5P\xA4z\xF6\xB9\x12\xDB\x0DH8\x0F\x9D\x87\xC2"\xCF\xF4\xBB\x95~\xAC\x93\x8C\xF8\x09\xCD7eY\xA9\x03\xAD\xC9\xDB\x01GTc\xF3\x07\x9A\x81\x02\x91\x9E\x0E\x89\xB6\xBE\xD4\x9D\xEATR\x9A*\x81\xBC\x90\xD53\xDB\x81\x97\x96\x09Ii\xB9\xBC~V\xA1uml(\xA5O\x9F\xDA1\xCBM\x09\xC7&\x83q\xDE\x12\x86e\x16#\x1B\xB9\x89\xF6\xCD\xEF\xC4\xF7\xB06\x17\xB1\xE0\xFB\xEBi\x9F20\x08IrQ\xC6\x91\xF5\xAF2\x87\xED\xBA\x85\xF4M\xC2T\xC8\xA5X\xAF\xA6}\xABx\xFC%\x90\xC0\x9AQI f\xA9o$\xE7\xA7\x7F\xE8V\xB3\xB3}\x19}~\xD0\xBE\xA5CHE\xF0\*\x10w\xE7\xAF\x8D\xAB\xD7C\xD0\xEF\xF1}\xA32\xB21\x8D\xAD\xFF\x8E+\xEC\x18|\xEBo\xB4;\x0F\xC9\x0Cy\xA2\x17\x8C\x88\xA7\xB4\x8E\x85\x9CSL#U\xD2\xDA\x8F\x98\x81\xD3u\xBA\x1C\x16\x8F\xAC\x1B\xF4SBEB\xD6t\x17\xC5\x0F5\xD1\xA3^\xA2\x85\xBF\xFB&\xE6\xD4\x87\x8A\xAE\xE3\xA1V`\xB2\xE3d\xE2-0ny\xDC\xF9\x97(\xFB\xFDZh|*\xE4a8\x00_\xE7\xD4"\xF4\x94\x97\xB2sL\xF2v\xEC\xF5[\xC5Z\xB2H]\x90\xF8l~\xA0\xA34\xA9\x87\xECs\xBE,b\x18m\xD2\xED\xDD\x01\x1B\xD8\xF7\xE9\x90\x84\xC1\xDB>\x9C\x84\xC1\x8A\xD9\x92\xB3I\xA5y\x80^\xC5+\xD7\xC7\xC9u\xF9\x8A\x82\x1B\x18n\x8D\xB9\x04\xA6\x0C\xB4\x8CF\xAA \xA8\xA0\xAD%1\x82?\x01\xB7\xFES\xCD\x82\xDEA\x8E[\xF8755\xF9x\xBC0\xA6a\xD8\xC8ix\xCC\xDA,F\x89\x81Wv`:k.\x84\x07T\xB7\xCC\xAD\x86\xBE\x06\xCC\xD5\xC0\x1C\xFB\xE2\x04b\xD3\x92!\xB4\xE1/\xA9n\x9E\x83V!XL|.DO\xE2\xAE\x0B`y\xAF\x02\x9D\x0D\x04\x98\xC5\xB3U\xC5\x14\xC4\x1A\x8D\xC4\xEE\xDEz\x07\xEB\xBFG\xB8X(+\x99\x0B\x0E\x17\xA9n\xFF3*/\xA8\\x9FMJ\x09r\xAE+p\xA4\xA8\x83y\x95[\xA5\x9D\x8Bt\xB9BK\xAF>v\xCDR\xF6l-\xA7\x0FB\x0As\xA5\xDEr\xEE\xF0c\xBC\x05\xEE\xF3\xCB}O\xD8Q{V!\xCEV\xE7Q\xDC\x00\xB7\xF1\x8D\x03%h\xD9\x80\xDB\xD9\x8B<\xBB\xFF\xD0#\xD2\xB7?c\x92\xD8\xBD\xFC\xD5\xF7'D`\xD5\xF4\xF1\x89\xB9\x9C2\x15\x90\x99\xC8\xCCa\x94}\x0C%3A\xA8\x83V\xAEH`\xB2\xDC.\x06\x9B\xC8F\xB3\xC2\x85\x89\xED\x16;\x90\xA0\xA1(\xF42\xCDTCw\x84\xC0\xE9\x8D\xF1\xB7\xD6\x98\xDA\x8BT#\x94`\xB0\xA0\x0A.[m\xF8\x01G"\xB3e\xBD\xDB6\x80\xDB\xDC\x8B0,\xFD\xE7\xCF\x9B\x8E\xD2\x8AK7\xE9\xEE\x12\xD6F\xCF\xE8J\x1E\x08\xEC\xC5*\xE8\x03@8\xF9\x13\x00\x1A\xCA\xB0pQ"\xCC\xB0\xDF\xF9\x9E\xC0g\xB1\x88\x92S\xE8eM\xB9I\x10\xDA\xC0\xBEl\x18\x95\x131\xD1\xFD\x15\x9Bw\xA0\x0B5S97\xF6P\xB3\xC8\x8F\x94+S\x0Co\x90\xA9p\xD7\xD9\x08\x09o\xB4\x14^\x03\x09\xAD\xE5\x16\x8D\xE5\x1C0\xE1\xCD\xA7\x0Dtm\xC6\xA2\xB4\xB0\xE4_\x13\x92\xAB\xD8f*p&7\xFDf\x8D$DXE\xCF\x96\xC6\xE1\x0B7\xCD0\xD5,n\x05\x9C\xD1\x9E\xFF<\xB6\xE1\x19VkKn\xDE~ *uv6r\xA9o i\x190\x89\x86S\xC6\xB1\x0AC\xAE\xF6\xE7E\x1Cx}\x93\xE4\x1EQ\xC2XY\xDA\x8F\xFF\x1A\xFEB\x1D\xCD\xA9\x1D\xA7\xE8\xF2\xDB\x84\xC2\x82\xBB\xBFb\xE1&\xDC\x0C\x0A\x99\xDC\xF5)\xD8\x93\x9D^\xBEWw\xBB\xD2\xBD\x04\xEC\xF8\x7F\x04\xE99-\xE3B\xD4\xCB\xD0k\xEB;\xB3k\x8F\xF5z'\xC9Y\xE9\xBFS\xE4{t\x99_\xC3\\x00\xB4\xD0\xF4\xD5\xDB_\xA45v\x068\xD4\x13\xB7m\xFE\xCE\xEE\xCD\x18`\xA6\xC7\x10.\xC1f\xACtY\x8A6\x8ES2\xC4kC\x04\x8E(\xD3\xAFI\xA4z\x82\x0D\xFDat\x9B!\xF4\x86\x98\xCF\xE6\xBF\x8F\x05\xBA\xEA\x13\x06\xD6\xD3"ATE\xCE#\xA1k\x9EG}ATw\x91\xC7<`H\xCF\xF4\x0D\x81&\xA1\xAC\xD1T\xDFz\xFC\x9E\xC8\x90\x83Jv\xCC\x1B\xB9\xA1\xA9<\xE3:\xE1\xC6F\x16\xA9\xEA\xB8*M\x1A2R\xA4\xC8\x85\x96Q\x9DlC\x7F\x83|\xF1\x83\x91\x1D\x02om\xC8\xEAM(\xC5\xD5\xD4\xAA\x1E\xDF\xD2\xC1\xF12rQ\x9Cf7\x99\xAA&\xB1\xA9J\x03\xA1o\xCD\x7Fv\xFB\xF0\xCEa\xF5\xEAs\xBEw\x1E\x0B\x89\x9Dc\xCC\xF8\x0C\x9D\xB4\x0A\xEF\xDB\xA9&\x9D\xA5CY\xB74\xEF\x1D]\x83\xA4\xF3I\xB2:\xAA(\x9D\xC0\xB28\xFDJ\xFA\x9B\xF1\xB5\xAC\xC3\x14\x97|\x8F\x80\xAB\xAD\x92q\x0B5\x08J\x1B\x8F \xEC\x1B\x17\xE1\xC2\xFE\xC4\xD5'\xF9U-\xE4\x98=\x1C~\x89\xEC\xEAV1\xAC@\xD5\x18\x88B3\x06{y\xBCW\xF4\xF3v\x96\xD5\xDD\xBE\x89\x8A7&=\x85\x97\xD8{\xA6o\xA3u\x98hiW,\x1B\xD0\x1B%\xBD\x1Asu\x10\xEB\x1ER\xA4\x932G\x93K|\x8A\x89\xF3\xA6]\xB4j\x7F\xCD\x83eE\xF8\x14\xD9F\x15\xABQ~\xFE\xCF\x12\xFA\xF0\x19\xE9\x96\x15\K\x02\x9Bz4\xB0"\xDF\xAE\x88jv\xBA\xB1\xD1\xED\xA5\x86\xCAh\x80\xAB\xE2q#i\x0E\xB6\xFB\x81f\xD3\x02\xB6E1\x15(\xE54\xF9\xDA\x1C\x9F\x89\x9E\xBB\xF9\xB5_#\x8E\x1C5\xEF\xAE\x19\xB1\xE7\xD1tq\x8B\x01\xB1\xB1\x09\x1D\xA3X6\xCF\xD8\xBB\x98\x9E\xAA\xF3\xCD\xBB*\xDC3_l\x94\xFC\x133Of\xED\xF5\xEFf\xF7{\xCB\xBB-\x02d'a\i\x93\xD7'\x01\x81\xC2J\x1C\xAB\xBD\x0C\x08\x00@u=m\xD9\x92\xBF\xDDb\xE9\xAD\xE4\xE1\xE5\xB2\u\x9A&P0\xBD\xD1\xF6O\xFFv*\xBEkjW\xB7%G\xDA\x8FU\xD4R\x9Fg\x80\x99\x9C\x16\xB3\xB0\xF8,X\x12\xEFbM,\x02W*08LXI\xBBNm\xAD\x95\xBA\x1E\xB8\x8A\xC4\x1F\x91!\xF4\xE5\xFF5\xAF\xB0\x06\xA3\xB9+<\x82\x05\x9Cw\x19I\xA7\xF3\xB9@[\x08 1&\xFE.\xB6\xE6wl\xF0>\xF8\xA0Cmu\xEB\x9F\xB6\x1D=\xDF)\xF1\xBFK,"x\x0E\xEB\xF7\xD8\xA0s\xEC\xBET\x06\xC4\xF6\x0F\xD2\x05\xEF\x0E\xA2O\x97\xA3\\x89K^\x8A\xB3\x1F\x13\xD2\xC7\x0B\x0E\xBA9\x0D\xDE\xCB\xAC|\x9An\x8C\xE5k\xD2\xB6\x06\xB9\x96i\x07\x85\x13\xED\xF9!\xBD\x88\x04\xB5\xFF\x13\x1B]\xCDo@9:\x93\xDF\xE8F$\x87\xB2\xE00?\xF12\xF4\xF5\xBE\x8A\x9A\xD4j\x8B\xF8P\x18O^\x99YFt\xA1\xF1\xEA\xEC\xB5\x83\xF6|\xFE\xA5\xA9\x91B\xE7z\x07\xC6\xF8-\x99\xB7\x9F\x98\xF2\xB6w\x93bh%'\xBF\x9C\xBB\xD5\xDF\x0E\x13\xBD\x90\xF8\x9A\xD4T\xA7\xD1\x1BPF\x92\xF7\xC5$\xCA\x02z\x08\xE2/\x87\xD9('\x10\xD7>8\xA5o$\xDBW\xCE\xFBA\x19\xFEg\x082b\x1D\x13+\x0E\x1A\x93\xF4\xE8\xBE\xBD'\x08\x8E\x97\xCE.\x99\xE0\xA86\xA5J\x0A\x84\xC5\x99_\xA2f%\xF2\x94\xE1O\xB9U`~\xFFYA\x03\x1Ek\xC5W\xD1\xFE\xDBGW\x16k\x07\xB0\xAC\x0A*\x1C\x16\x10\x06\xB9\x12Yc\xCD~\x93\xB5\xEBX\xF79\x03\xC9\x02\xDA\x80\xC1\x8A|\xA4@\xAF\xE7AWo\x156\x11\xAB\xB8\x80\x83\xB2\xFB*qL\xC6C\x84@\xA5\xE3\xEF\xBA7\x85_\x1D\xDD\x953\x8C\x04\xDD\xD0\xAF\xD1M\xB7\xFE\xA2?\xDCQ\xA2W\xB8JK\xFD\x8A\xCFx^.)Vr\xE9\x82\xA2X\x16\x82\xB2\xCA5\x16\xF6d\x97\xD7n\xE2ZJn\x7F]\xF0\xEC7\xF9,\x0Fl\x91\xCE\x1A$8\x99:\xAF=\xF6\x09_\x81\x06ZA2\x87\x06\xE7\xE9\xE9\x86MU\xC2\xF1\xAB\xD03pDW\xED\xAF\xBC\xF3\xB6r\xBF\xBD\xB0\xFF\xEF\x0Au\x83\xA5\xC5c\xA1\xAA8-vb~\xEC^*=\x93' \xDD\x0C\xD9v\xCD#r\x8B\xE6[\x0Dg$me\xB8\x03E\xE0\xBC\xA5HKRX\xBB\xA8\xD0\x9FQk\xCD\x8AvW\xBEL\x9C\x84\x9F'\x08j/\xDD\x8Cn6/\x0A\xFA\xC9\xB0 \x8DT\xEE!\xF3\xD1\x1DB\x92S\xE4\xBB^@l\xD1\xB4\xBE\x1E\xAB\xD2\x82\xC2\x82\xE7E\xCE\x12\xF8\xED\x09\xD1\xFC\x0F\xEC5\xE2\xF7\xD9\x94\xDA\x1E\xF7.\x19\xE6g\xE76\x98\x84\x9D\xE2V\xD4\x95\xA1\x08\xC7\xC3\x02\x83|)(,v\xB1\xFA<\x02E\x80n\xCDe<\xEB\x88\xF7\xA2\xCFA\x18\xFCl\xCC\x1F\xF5DB\x06\xBE\xBC\xE3+\xCC\x92+s\x92"\xE5\xAA#\xFFo\xBD\xAD\x82q\x8E\xFF\xE15\xBE\xC0FC\x0F\x10\xC0!\xC8\xB5\xA2\x0F\x8D\x07\x8B\xA7\xFCP\xA4T\xEA\x7F+C\xD46\xBBe,\x9C\xB1 \x13\x1A\x015d\x94#1{\xDA;\x019]\x18\xF8\xF4?\xEB\xB6\x81q\xFD9\x0DJ\x96S\xC5\xBB\xC2\xAE\xFE\xD1W\xE6\xB6\x86\x88y\x92\x0D\xFD,\xD0\x86G\xBF\xA4k"G\xBEL\xE9n\x0F\xD7\x82\xE8C\x0Fs\xDFL\xBBS0\xAD\x8C\x01I\x08\xBE\xCC\x82"\x17S!z\x13\x0F3E\x84-/F/\xAE\xD6\x01\x00\xB6\xDB-je\xC7\x87{\xBE\x90\xDA\x94-\xD3\xB7\xEC\xC94\x89jNt\x8D\x9F\x10ka\xFA\xDC\x88Q\xCA\x1F\xDB\xB5|\xEE(\x966\xA35\x881b\xC9It!e\x06\xE8Z~b\x81w\xCA\xD2:\xBE\xE7\xF8gI\xE4\s{x\xC0\xDDk\xD0\x98\xF6\x9B\x1AH\xBB]\x1B\xCC'\xBB\x1Cd\xFE\x8DZQb\xEA\x7F\xADJ\xD7\x0C\x7F\x190\xBC\xFEK\xB8#\x13\xE6\x86\xBAUR\xB9\x0B\xD9Z\xFC&\x87\xC3{\xE6Zv\x00L\x9D\xE6\xAC\\xDD}(\x96\xDD\xE5\x98?\x07\x8E\xC4\xDD\xC7\xFFv\xBA\xCFGZ\x02\x92\x8C_\x92\xAAD\x93\xA2\xEA\x0C\x17\x9F\x1A{\xD0\xCE\x00\xB8v\xE3\x03\x05(S)BG%t\xDB6C\xA0\xAA\x0A=\xC5\xA7\xD8K'\x16\xF7;?\xD0s\xC2\x9B\xE5p0\x9E\xF6\xC4D\xBA\xA2\xEB\x012I\xC3"\xA1\xDA6\x82s\xDBL\x8F\xDE\xDC8\xAA8\xC9\x88\x0A\xFAf\x89'\xF0\xBF#\xC2\xEB\xD7\x01\xAE\x97\xBB|\xE7\xDAk0\xF4?\xE1\xBB\x1D\x0A\x88\x1D,Uww\x89\xF8\x17;\xC0\x16\x9C,\x8D\xE5\xB7 \xBF\xD6\x94^\xD1a\xB6.I\xF7\xF4b\x18\x9D%%M\xC9y\xDFU\x88\x16S\x9D\xB3\xE0\x9B\x83\x00\xFB\xB0\x1DE?\xEC\x94\xA2\xE1\xD4\xC5/\x11\x1C\x1A\xFB\x14\xA1\x08.V\x9E\xE00q'\x87jJ\x11\xA7M\xCE+\xB8\xDD\x8Dt\xF2\xDD\xFA\x94#\xBE\x83\xC5\x13}A9\x97\xFF`\x18\x17\x89%\x85\xDBeY\x0C6\x0E6\xA9'\xBD\xAC0\x81\xA5[\xEF\x8E>\x92W\x01\xF0,\xEE\xA0\x1D6\x861\xC1n\xEF\x14\xD1\xBDg\x808@\xE8\x11\xA7\xA1 Xb`\xC8\x1E\x90.Z\xF9\x13\xCAa\xF8K\xC1HS\x18d\x0Ad_\xD4%"\xF8\x06;\xB0\x82\\xC7\xD8\xD0nNSV\xBB\xAC\xDC\x1C'q\x13\xB2\xD6\x85!f\xE7J\x17\xC52\xA0\x17+\x83\x00\xA6\xD6W(\x82~L*\xC0x\xE0\xD1\xF84\xE8h,^[\x8F\xFA\x94\xE3E6;Dl\xAE\xE4.\x96\x9Dy;__\xA5\xE7\x7F\x84\x94d\x05\x84\xDB\xC4\x12\xF9\xC4\xBE-\xFD\xC3\xADD0\x0E\xD4\xEA\x9F\xEB>\xB3\xB4!\x97,\x9B\x17\xA0\xF2\xB0\x88\x1B\xA5\xED\x16\xC7\x9B\xE8:\xF8\xF5\xE3\x92\x05~,\xA0\x7F3\xBDGd\x98\x85I\xC3\xD2\x0FVXl\x01\xDC6:\xEE\x84\x13\xDB\xE3\x13\x05\x1E\x9A\x9F\x1EJ\x1A\xBB\x9A<\x04r\xA5J>\x14\xDF\x8DJ\xE0\xED*w\x06\xD6 \xD2\x1Ep\xA3\x95\xFBO\x85",\xFC\x83\x16k\xA4\x0F\xBE\xFA\xD8J\x91X\x8F\xD5\xD8\xD7\xE3\xD3\x00K\xF7\xD7\x04%\xFBB\x82\x93\xF0\x8CA]}\x90,\xD2\x93'\x0E\xEE\xED\xBB/\x1F\x81\xDCf\x81\xF3\xFDSH\xFEf~\x9Ao\x94\xD0\xF0\xD5\xFC\xC2\xB9u +\xA6F\x18\x81e\xF8\xF3\xD1*\xBC\x8D<\xC9,,\xCBl\x8A}\xDC\xC6yDU\x1A\xC1sv\xADU\xED\xA8\xB1?E\xE6\xF7Mr\xB7i\xC5\xF1\x1C\xBB\xA6\xDC.{\x9DG\xE6\xB4\x1B\xBD\xCC\x8E\x0F\xEC\xFA\x09c2\xA8P\xB5A\xE9B\xB2\xCC\x9F\x84\x91%_\x0B\xC0\x8C\xC2\x0C\x120_\xB2!i\x8C\xBDU\x1F9\x81\x81\xE4\x9D\xF5\xEF\xB3\x18f\x93e\x1EUGM\x13\x8F\xEF\xD4h\x0Cb\x0B\x9A\xD4\xA6A\x98\x8B\xC9\xD2\xDB-\x8B\xEA\x7F\xA5\xF8\xD5)\x8AV\xFD\xD2l\xD2,)\xC1$\xFE3:\xBDd3q\xA9\xD7\xF5\xD0|V,\x099\xD8\xE3{\x97\xEDPU\xB4p\x81\x8AEP\xD9>\xB8\xB2B\xA8o\xE7\xB6\xA4\xAFKJ\xDAg\xC1xv\x9B\xED%#\xA2Uxu%6;&\x0D\xEE\x04I\xEC\xACZ@\x98\x1E\xB9\xCC{\xE5L\xE9C\xB4\x90\xB7"]\x06`\x9A\xF2\xF8\x1C_l\xCD\xEB\xF1\xEC\xDBH\xFD\x84M=/\x05\x1C\x0C\xD1=\\xB25\xAD\xF4u7\x1A)\x86\x9C,8}\xDF\x8Bn8\xEB\xB7\xDBF\xC2\x00\xD6\xAE\ \xCA\xCCG,\x90\xDDG6\x0B>\xE7\xE9%L\xEA\xCDR\xEB((c]\x9D\xBB\x05\xF5\xD6\xCF\xCFb+Z\xF5\x144\xCD\xD1\xAA\xFF\xB2m`\xDA=\xC9\xF8\xC2!s\xE0\xB11\xE7\xC3\xEF\xBDhu\x8Fl!M\x0A\x01)2\x02\x9F\x98\xF1\x92\xC3+\x8C\xAC\xEB\xD5\xA0\x8A|R\xD2S\xAA\x05O\x8C]\xBC}\x0D\xD6\x18\x87\xFA\xDE\xA5\x9Dn\x83K\xF4\xE8\x96c-eHF7\x17\xA3\x0E\xE1\xBC\x8B\xB9\xAA\x11\xF2\x08\xF0\xDE\x0D=\x04\x99\x1A*\xCCy);\xD7\x8C\xB1\xB9\xDF\xB1\x9C\x0E$\xA4Ej|\xEB\xDC\x0A\xC1\x98T\xE0I\xC4C:.\x0A\x03\x03\xDDZ\x93\x02(\xBA`\xF0JS\xA4\xE7e\xD4p\x05\xB6 <\x1D\x7F\xD6a\x8A\x92z_\xD4H\xF6\x8CM\x07P\x9A\xFDT\xB91\w\x0E\x10\xE92\xBA\x1A&r\xD8[\x8E\xBDrzA2\x9F{\xA9q\xB2\xCA\xC6>*i\x0F-\x9Exh\x8C\x93\x06\xF4!g\x99\x10\xB9\x8E\x80$f\xB7\x03\x7F\xC4\xFBg\xC4\xE5\xFFx,rM\x00\xB9!c\xCC++7\x9D\xED&\x1F+\xF0\xAA\xFF\x03\xCD0D\xE6W7x#\xFFv\x96t-\x05\xE9\xB2\x7FE9\x88\x0C\xD7\x0Fc\xC9\xEB\x87pO\xD8\xFD\xD4\xEA\x91\xE4\x11\xE9\xC9\xA9h5[\xA2?\xEAg>\xA7\xA3@*Ku\x1E\x05\xD8cP\x15\xEA \x01\xF1\xF3\xF4\xB3\xFE\xF3\xD3\xBBu G\xBFx\x81\x05\xEE\xE5[&\xB6\xD6x\x99u\xA2\xF0,\x1B\x83\x84W|\x8D\xF5d\x96S\x03\xCB\xBF\x86\xEA\xEA\xC7\x09\x84DG$\x1D!\xD30\xB7I\xF5\x0B\x95\xA2$c\x08\x0F\xCAZ\x86\xF5\xAB\xF19.\x83d\x97P\xEA\x01\xB4\xBF;\x8D\x91k\x02\x90r\xD8oG#\x9B\x87\xA6\xA7D\x12.\xE10\x92L\x93\xB7\xDC\xD4\xB0\x93\xC6\x1F%\xA3\x8Db/\x92\xFE_Y\x0E\x8E(\xEB_\xA0\x8Fv\x1F\x92\xD3ZO\xBCe\x927t\xCE\xED\xFD\xED\xFE\x0D\x7F"X\xC1\x1C\xBC\xFA\xDF.\xE6\x92\xB0\x97\xE4\xA9\xEB\xC89\xC0\xD5e+\xD3\xBAa\xF5\xAC\xBF\x19?{E(\xD6\xA8\xE9$\xE6\xF1\xBA\x0C?q,\x01\xDE;d\xD5\xFC\xCAK\xE4\x8D:\x15\xA9\x1F\x87\xC7\x94\xC1\xDB\xCC(\x99\xB1\x98<\xE7)g.q\xB5\x8C\xFD\xD1&\xA0<\x97\x9BLd`\x88\xB1,E\x7F]\xF2+'D\xC0\xBC\x9A\x98\xA4\xB8\xAD\xA3\x02\x98\xF0\xF0\xEA\xDFNC\xE2\xC8\xB2x\xC7\xE9\xC3\x1D\xB4\x0A\xA7\x0A\x0E}_st\x8E\xF1\x04\xD3\xF1\x0F\xF3$\x85\x97\xEDN\xA0uW\xAEI\xAE\x05\xA6,\xE2\xF0\xBBz\x97\x0EnS\xE5\xC41\xA5v\xCBI\xD2\x82\x1D\xB2\xA7\xD3\x0A\xD1\x8E\xE8\xC65\xF8\xB0<\x0D(cB\x92\xBD.\xDBe\xEC\xEE\xC3\xFB\x81\xCF0\xBD?\x8E\xAD\xAC\xD9\xD4F\x05\xC9\x83\xE1\xF2\x04\xA6\xFC\x8D\x01\xD61\x83\x08\xFD\x97\x08\xF5\xD1\xA5-f\xBB/\xF3\x8AI;\xBE\xA4\xB3\xBFF\xF8f\xEA|Q\x15J\\xEF<\x7F\xFA\xC3#;\xFA\xB1\xC0\x8A\xB9\x7F2\x92\x1AR\xD3\xE9q0`\x7F#\xED\x15\x00;\xA7ht\xBE\x02\x82W@A5d\xB0j\xE5\xCDM\x1B\x86Wq\xDFP\xD0\xB1\x9A\xA7tPo4\xFFL\x9Bl\x19\|1\x9A\xCC\xCB\xA3\x13|\xD3W)V\xBC\xC0\x1EK\xDD\x96\x093\xB1\x91\xF8\xBA\x8F\xEF\xD4A\xBA\xB9L\x8C\xA5\x9C\xCD/\xB1:\xAF\x1EIX\x87\xCF\xE3h\x14\x1D\xE2\x96\xC0\x05%\xCF%\x14\xA2\x0A\x09\x1F\x16\x8Fx\x05\xD2\xD1\x97\x8E\x83\xC8C]S\x98ne\xFB\x89\xCD\x02Q\xDB\xA7\x06!+\xFAWQs\xC6\xDD\x00J\xF5c\xC8%\xBC#\x98\x83B\x80\x81\xAB\x8D\xFC7\xDDR7\xCAnCi0)s<\xC4\x93e\xE8\x96*a\xA7\xBAQ\xBC\xBC\xD5\x0F\x1E\xD6V\x07,*L<2\xA0+\x11\xF16u\x09!\xC4\xD1\x14\x0C\xA2\x19/\x87\xB4\xCE'\xA5;\xD3\xFF{.Gd]\xBB\xEA\xC7GB!\xDCt\xC9.\xAD\x18\xB1E\x02\xFA\xDE\x19\x10\xF3\xD36 \xCD\x14F\xEB\xB0_\xC3\x91\xDC+\x19l\xF3\xC7E\xB9\xB2Q\x90\x15\x02\x0A5\x83hfr\xA7G0\xDA@\x11\xD2\xC0t&\xC2U\x0FC/R\xAC\x9A\xFD\xD2K'R\xE7v>\x9Bb\x98rv\x12L\x0CZ\x8D!k\x92\xC1\xD8\x1B\xB3\xCE\xFC\xEA,x\xE1\xA9W\xE2/\xA5$\x12\x1A\xC6r\xB3\x92\>\x98\xEC\xEC\xC7\xDA\x0E\x91\x86\x10\xE0\xEA\x13\x813)\xBE\x97S\xC3j=\xB1\xD5qF\x86kc\xB33\xB3c\xBB\xF2WN[\x8D\xAFsnO\x9C\xC9\x8E\x9A\xB53z\xD9mq\xBE[\xFE\xBB'\xAD\xA6\x85)\xAA'~\x879\xFC\xAB\x9E\xBF13\x93. \xD5x\xFC\xE0\x15\xEDp\xFAzd\x94\x0C&\xEB\xF4\xE5\x01Lg\xD6\xCE\xB9\x86\x1B\xF2"\xAD\xB8\x90\xE7\x0F\x8B\xE88\xA5:In\xB6\x0F\xD4\xF8\xC7\xA2\xD0W\xCF\xAC\x1D\xD1\xD2\x18\x19\x8A\x8E\xB4\xB8\xD3\xC7\x87?\xD16\xB5f\x08\xF3\#h\xAE\xDE\xBD\xE8\x1B?x\x14\x9D \xAF\U\xD4\x83y\x1A\xBA\x9C\x9F\xB5m\xD2\x1C\x05\xB0@\x09"g\xAF\xCA\xDE\x8C\xF9\x9A\x09^*$z\xD42\xB9\x99\xEA\xDD6r\x91\xFCq\xA84\xE5\x9EA\xB7\x1FmyR\xA2\xED\x8E\x98 \xEF\xB0\xCC4tb~\x18\x88\xCA1\xDB.[VJ\xE8&\x19\x9A\xF60O\xDB7r#\xD0`\x07\xE7\x1D\x04WE\xAB`\x83}E\xACR\x08\x95\xE4\xB4\xD1\x8C\x00!\xD8\x15\xDA*\xB6\x05\xD2\x03\xEF\xB3L\xCB\xDF\xB0N\x87\x89\xE4H\x89r\x92\x84P\xC7\x08\xDA\x17\xA9\xDB\x17|\x10\x01s\xDC\xD1^k\x00\xC5\xEBbm\x04\xEC\xFF\xD0\x0D\xFB3[\x07K\xF6E\x09\x93\x089O\xE48\xB0\x11\x09\xCB\xC9\xDA^-\xAB\x03\xB9^\xE2\x06\xB9\xBBZ\x10O\x85\xF6\x7F\xB2G\xCF!z\xE9\x13\xB3j\xBAP\x0A`H\xE0\x08\xAE=\xF23\x82\x15s\xFAS\x9F\xC6 \x03\xC1\rz\xCAj2g\x0E\x1D\xAA\xC2-\x9AJ::,L\xAE\x90\xF6PR\x17\xB0\xDD\xC9\x97 \xB5\x7F`\xC5\x0FLV\x9B\xFF\xE4I\xFF\x97U\x9D_\xF8Pu\x03\xAD\xF0\x8B\xCBHV\xDF\x08f\x7F\x08\xD1d\xEE\xB6\x85\xBDE\x93\xEF\x08\xE2g\xA5\xE4!\x1B\xF1"`\x007G\xBBx\x98\x97a\x94\xE8\xA7\xAC\xC1\xCD\xC7\xBE\xE5`Xv\x14\xB8m5v\x92g9\x9F\xD5\x9E\xAB\xD0\x1D\xF4\x89\xC6\x85\x19hYz\xF0\xDDF\x83\xC5"\xE11acBv\xD7\x15\x9D\xCA\x0D@6rrv\x96\x8A\x9F\x89\x1D \x93\x06.w\xE8pe0T\x93\x84!~\x85\x15N\xFA\x9E\x87\xCE\xA5\xF2\x7F\xF8\xE5\x89\x99\xFE\xF3\x1DA\x1B\xFB\xF9^\x9F\xE1\x1A\x1B\xAEFK\xB7\xDA/\xC8\xA0\x04;Q\k\xEB\x9C}6z\xB3\xA5\xAB\x82]\xC2\x9EC\xA3\x86\xC1\x02b\xCC\xDD\xCB\xC8\xA0nV\x0DlU\xB1\x91Ea\xA3\x9F\xB0!#C\x07\x17\xCC\x93\x82\x86<\x89\x1Dq\xE0#\xCB7\xB0P\xED\xDA%\xA9\x9E\xA8\x0C'\x8A"\xD5\xF1\x887$\x91\x97o\x96\xBD\x05A+\xD8\x9A\xCE\xF2\x0E-4Gg"dv\xE4\xF9s\xD8\xBF5-\xF7\x9B#\x0D\xD6s\xD9\xE8\xCE\x0F\x955\xE0\xDB$\x03C&\xF2\x87\x1FZ\x036\xF1|\xA3\xD0P\xECrFi\x9AYX\xC6\x85\xACm\xC7\x84?\xA2\xC5\xD4\xA0\x01\x04\xF3\xD2\x94\x1E\xCC\xA3\xF10o\xD41\x12\xB8\xD4@\x17T\xE1\x14\xB5\xAF\xA1Enz'S\xE7\xDDEE\xA6~C<\xA0-{u\x8F\xAE\x8B\x80\xE3\x15\xDF\xCA\x0B\xB2\xDF\x8Et\x8BC\x9C_\uG6x\xA0\xB4-Q\x15\xCEN g\xE9\x85a^\xFF\xD8T\xE8\xB0Z\xC6\x04g\xA5m\x1F\\xC4\xAB*T\x09a\xD7$\xEF\xA3\xF1\xA2tp\x94\xB9\xF1\xFB\xD0sj9D\xED\x07\x0A#y\xBC9?\xB3\xAF\xECKgH\x06\xF2v\xBFN\xE6\xF3\xCA\xBDax\x7F3\x17\x1B[|\xFE\x96K\xD9\x97\x10Y\xE9\xA7F?'\xBD\x1B\x04\x0A\xBB\xA7\x9BO\xD6\x1C\x1C\xFAE;(\x838O\x0FKe\xFD\x0D\xF3C\x11\x89\x0B(\xE7\x85k.<4\xC2r\x09mIz\x8C4\xEF\x06>\xDE\xACD\xFC\xEE\xC6c\xBA\x86\xFD\x13\x17o@v\xA1qH\x18\x07F\xBBQ\x11w\x03\xF1\x83\x94\xB8?F\x8D0\x98\xD7\xF8\x82\xAC\xC5\xB8\xFE\x18\xCE|\xBF\x9FC_S\xC8E\xAB2\xDBb\x7F\xE6\xDF\x07\xB7D7\x81\xE8\xD70\x8Bv\x07\xB4\xD2\xFC\xE40\x05\xBA\xCF\xC6\xB1v\xA5}\x88\xEB\x9A\xFF\x02l\x80#\xA5,\xD7\x06\xD6<+\x12G\xD6R{\x83\xEA\xFD>=_P1\xA4<\\x95\x19\xD1\x1A\x0F\xDD\xE6\x03\x10\xEB:\x88\x10\xE6\xA3\xFB\xB9j\x0AT*:\xB8~\xF4\xB6`3\xA7\xA8\xFF\x19\xC7y+\x0C|\x03\x91\xC6A\xBD+\xC4\xC55\x81\xDC\xA48tpz\x93\x98\x00)Ae\xFD \x81\xE7\x81qwI\x80mVs\xC3\xFD\xDE\xF9\xC9\xBD7(\xA3\xE2\xC5J\x01\xF1\xD3\xB3\xFD\xC2I\x0AI\xC69w\xBC\xF62\xBD\xB6!z\xA5\x18"Z\x92,\x1C4\xE7\xEC\xBA\x97\xA3\xD2\xE9\xD1\x1AX0\xF3DC<\x90C\xF9(\xA24\xA8 G\x97\x86\xA6\xA3tSGFx\x97a\xA1\xBE\xA4q&x\xD2n0&-D\x86x\xE8\xC6d1~>\x1E\x04\xF5\xAC\x9F\x15\xFC\xEE\xEA\x06E\xBB\x93\xFB\xAB\xF0\xAES\x96\xA4)F\xDD\xA99\x8A>\x08\xFC2\x17n\xCAZ\xEE!\xE7\x0B\xB5b\xD8\x8D\xDF1\xB1\xEA\x11\xA5\xA9s\xAEHk\xA1=\x82[\x165:\xB7v\x87c\xDAO\x1F\xED\xF0\xB5a8\x1BN\x10\x99\x97?r\xED\xF6E\x8B\xDB\xA1\xC0\xCA\xB9\xE0\x8C\x09l\xE7\xC8\x93\x06\x9Cc\xDB\xB1\x00\xBD\xB9B\xB1\x85\xC6"\xB2\x08_cIC\x81/\xE4\x99\x16\xF3\xC5\xAF|+,\x037\xB5#`\x97\x1F\xFD\x91\xC8\xD7\x1CY\xB5cEr\xDB\xC5N\xEDHA\xCE\xB8G\xB5\x00[RQ\xEB\xBB V\x097n\xD2\x8F\xC3ng\xAA\x18\xD3gG\x88\xE1\xB3\x1B`|\xA0\xEE\xE0\x95\xEA\xF7N\xD6\xDDE[3;\xC51\x9E\xC30\xD7\xDFab\xA7\xDD\xD6u\xDE\xDC6dn\x1EhH\x8C\xCF\xAE\x1D\xE9T\xE5\x1BB\x04\xD4\xD6\x1A\x09J\xFF !n\xE1\xCE\xD1(\\xC2,\x1DK\xE7\x12\xC7\xEB]\xD7m\x84\xCF\x9D\x8C\xF1\xEF`0\x1F\xE1\xB5\xAA\x8A\xF0\x91\xF0\x90\xB8r\xEA;\x9F\xA8$\xD2\xF3\x9F\x18\xE7\xDE!R\x89\x95\x86\x15\xC7\x1C\xC3R\x19:L9\xECJ_\xE1\xF9\x99\xC8\x11\x09\x88\x17\xF54q\xF2\x8C\x12\xA29\x03\xEEHh\xFB5\x8C\xE2R\xDA\xF2\x9D\x08\xD5T\x0D\xF3+\xDF\x9Db\xECo\xB6\xEA\xB8\xCC\x9Bax9:\xB4\xFB\xA7\xA2\x1Fe\xF7#P\x03\xF3\x19+q\x81\xF4\x08s\xC3\x00\xE3\xFDu\xB5\xB0\xBB,\x0D\xAA[>W\x82\x89z\x13\x06\xA6\xCB 4\x0FpW\x83B\x95\xBE\xFD\xD4U\xC6_)\xCD\xB9\xAB\x0A\xA2"\xA8\x1F\x0BU#\x00)\xA0!\xCD\xA3(E\xA6r\x90$U\x8E\xED\xB9\x11\\x04\x01o5\4\xCD\xB3\x96\xB4\x91\xAC\x0F\xE4\xB45\xB40\x97R\xBE\x88\xE1\x9A#Co\x8DS\x9A\x1Fd\x96\xEE\xF1\xAF\xA9\xA1\x8B\xD7\x87\xB7W\xFE\xF1\xF65\xAE\xBB\xA9\xAD\x0C\x18\xF6\xA7\x03\x13\xB5\x1E\xEE\x98&^\x99\x9C\x04\x87\x13\xA0#\x1DN\xFC0\x85\xDC~\x12b\x03\xA67\x1C\xC1\xA1x\x8F@\x84\x02\xC6\xD5\xB8\x17\xF9\x9F\xF8\x97\xB5k\xB8m\x86m[\xD1\x98\xD2\xCB_e\xF8jFI\xF7w\xC2\xEB\xB4A\x06\x0B\xA4\x82\xAE5\xCE\xD1J\\x98X1\x13\x97\xF0\xA1d\xB6\x01\xB9\xF5\x81\x80\x9F\xC3\x99\xED\xEE\xF4\xED9\x1EI\xD9\x1AZ\xA4\x98\x12\xF1kx\h4\xF8m\xBD\xA2+\xDE7h\x80g\x16w\xED\x0B\xF5/=\xFE\xEB\xE89w\xAEp\xEB\xEB\x84j\x06\x96o\xED\xBBd\x988#5\x14z8\x1EE\x1A\x95\x09\xEA\x82\x8BD\xA5\xBF/\xE6\xAAIxO+\xB01K\xF1\xD9\x81\xCF\xD9j\x07i\xD2\xE6O\xAAX\xE7\xE8\xD8\x13\x9F@h\xF4\xD7\xAC\x85P\x9C\xB5uH\x90\xEB\xB2\x9F\x16\xC7\x89\xC3\x83l\xF6\xC1%\xDC\x96\xED\xF1\x1A\x99\xCB\xAA%\xE7hF\x1D\xC9\x88\x1AiX\xA4\xE0\xD3y\xBF\x96l\xD3*\xAE\xCB\xE9\xCB\xE8\xC2n\xFC\xAB\x98#0U]\xE2w\xEBG\xF8[\xC8\x1C7\x9F\x90,?\x82\xB0\xAD\xD0\x00\x07\x04c\x916EC\xD6k\xDA\x81\xA8\xBD\xE6\xA1\x0CEX\xB0w\x09\xCB\x15vB@\x1B1\xEA\xA8\x08k'\x1C\x19\xDA9\x0F*1\x05Zr6\xD9\xA3\x0C\xA9\xB1\xAD^\x05ic:\x97\x184\x14'R\x14\xE9k\xA9\x04\xD7R \x90\xBDD\xC7\xB9\xE8\x98?\x874\x16\xC7v\xC8\xD0\x15\x87\xB0\x06)Q\xA6\x9B\xEB\xD5A\x1Bi\xEA\xF8\x9B\xA2\xAE\x98\xF6q=\x89>\x8A`\xC8\xA4\x9E\x91\x84\xBEL\x01\xC6\xD2H.C=\xFA\xFF\xC6n\x84\xFD\xF0\xA7\x0F(\xDD\x16\xF4\x961\x08\xAF\xB9\xA0\xFD8\xA4~\x92+\x0D\x91\x98!\xC7\xD0\x9B6 \x8E\x92[p\xC3i\xF5\x08\xB1\xAC\x04\xB1n\xDB\x00[6\x82[\xE2v\x06\xA6of\x18\xC3y$c5\xE8\x97\xD1\x13\xD8\x8B\xD3\xC0\xB7\xBCR\xE9\x91\x03\x05\xC0V(=\x89\x80\x7F0\x97\xC9b\xDA"\x18\x8Ce\x8B\xF4@\x0E_\x06\xF5$\xEF\xFA\xAD\xA3\xFB\xA8ekd\xF0\xB8b\xF9e\x829)K\xE2\xE2;\xB7Jvx\xDF\xCE\xCA\x89\xEA\xC4\x89\xAA=\xB4\xB6\xBF\xD9A\x91\x0BOLa\xADI\xB9c\x0D\x1F\x0Bw\xC0\xA9\x11\x14#\xDB\xE8\xC1\x11\x06M\x08\xEC\x16\x06\xAC\x9D_\xF4g\xB4\xAD\xEE\x81\x08\x094a>yC\xF1\x8F \x8B\xE3\xAE\xC6\x1C\x0FG\x87\xFA\xBF|\xC0]I\x905\x11\xF22\xA7\xCC\x18\x8B\xB0W\xFAF2\xB6\xA5b?\xD3\xF9\xB7\x10X\xE7\xB9*\xC7wp\xBCu\xA6Z\x05\xDF\xB5\x05O\xB9E\x93aZ\x04G=\xD2\xD6]\x10\xFB\xF6\xFC\xC0q\xE1v\x9A\xC8|\xF3`\x90\xE9\x16\xC2\xD9\xFFv\x03\xABDE\xFA\xC8\xA70\x14\xCB\xB9\x81\xA5\x88\xF0A\xB2\x9F\xCES \xA1\xD0\x85c\xF3\x130\xFA,\xF5\xB3H;N\xFD&\x00\xF7\xF7j\x18\x8B#\xE3\xF1+\xB6\\xFF"\xCF&\x0C\xA8\xFD\xC5g\xDE\x18\x9DP\xCB\x14%12FC}m\xC5-\x938\xEE\xFD\xB3\xD5\x9B\xC9\xEF\x01\xF5\xAA/\xBBA\xA2K\x96G\xAA\xDB\xEA\x0DC\x8E\xD3\x85\x08\xBAs\xF4d\x10\xC4{$8\x0A:\xF1\xCDi\xB3\x8C\xA2 \xB0?L&\xB9L$ak\x10\xFF\xD1$9\x8B|\x0BN\xDB"\xAC\xFF\xB9O\xB1\xA7\xE4\xB5W\xFE\x11@\x87xk\x1E\x93?\x82\xB1x\xA3r\x8D\xBA\x03\x1ET\xE7=\xE1\xD0\x8B\xB3t\x04(C\xCA\xABIE.K \xB2\xC4\xF4tQ\xFA\xBB\xCA\xB6\x18\xF5\xABd}\x08n\xC9\xFA\x11\x9DY\xE7\xB4b\x01<\xC1\x18\xBB\x0E\x95\x8F\xD6Nd\x0C\x84\xA0\x9A\xBC&RI\x0A\xB1\xF8\x8F[N\x90\xE2\xF8}\xDF\\xA4\x82\x96<\x15N\x80\xA8\x19\xD1HsX\x90\xCA\xD8\xC4v1\xFB\x00\x11\xDAeMiN\xA8J\xA0S\xCF\x00I\xDE\xBB"\xFF\xA3i\xFE\x14\xB6*y^\x12n\x86M\x8B\xCB\xE2\xFFl\x97w\x7F\xEA\x94\x98\xB8\x0DO\x91?Xdte\xDD\\xF2\x14\xEB\x10\xEB\x8E('\xC4\xF3\x96\x8B\x08\xCBT\xFB\x826\xF7\xECV\xAB%\xA220\xB2<\xE9'\x11m\xC7\xCB)\xB9\x1D\xF2vf\xC8\xD8\x1E!\xDE\x1A3\x8D\x91\xFA\xC8\xA4\x18\xD7K*SL\xBBsM\x863\xCB\xD75N\xFA,\x11\x93ff\x0EA\xB0\xACb\x9E'Kyj\x05L\x8D\xE3\xCB\xDE\xA7\xAC\x95\xDB\xD0&\xC1\xBE\xD4\x8A\x9E$\xA5\x80hu\xCA\xBF\x0C\xEBoh\x16"(\xA1K\xD6\x91\xED\xAD\x85\xB9\x01\xF2\xF6\xEE\xE9\x91\xCC-5\x9E\x9E\x1D\xC4w\x89\xE7\xE1\xD4\x1F\xE14;\xB4\xBB\x01s\x0D\x9C\xC2\x1Cr\xDE\xE0\xB3>\xD7\x16\xC1kI\xA27\xBC\x1CE\xAE\xB8b\xE3\xD7\xAA\xAB_\xBEJ\xB0\x14\x9F\x83\xDA\x9D\x19\x01\xD6\x13o\xC7\x1A\xB1[_5\x13vr\xF8\x00"o\xDF\xF5\xA9\x1D\x963\x86\xFF\xC5\x8A\xD4Sm\xF7`8F\x90#\x7FYD\x1C[\x82\xB1\xF9\xE2<\x8D\xE6\xAE"\xD1\x87%\xBCp\xEE\xFC~\x81\xF4#\xE8\xAE\xF1\x836\x90\xF9}\xC8R\x84\xF7\xC5\x9B\x12\x02&j\xCC\x9C\x97\xD3\xEBj\x0D#z\xA1\xA1\xD7+\xDC\xD4\x05_\xBC\x92:8L\xB2\x13Em\x18\x02\x81\x1B)%\xC8\xE5\xCC\xB2v5\xCD\xC8y\x0E\xB9\x91H(.jw\x96\xA9\xDB8\xF4\xF4\x81\x91\xD4\x97Rl\xDFmK+\\xF1\xBB\x0D\x15\x14\xC9\xDF\xCD\x96N\xA73\xE7\x10\x0Ad\xB1\xADX\x0D\x80\xBA3\xDE\xE5uc\x81J,\x19'_ÿÿ›Åï \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/resources/META-INF/services/org.apache.hadoop.mapred.nativetask.Platform b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/resources/META-INF/services/org.apache.hadoop.mapred.nativetask.Platform new file mode 100644 index 00000000000..eef215d774b --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/main/resources/META-INF/services/org.apache.hadoop.mapred.nativetask.Platform @@ -0,0 +1,14 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +org.apache.hadoop.mapred.nativetask.HadoopPlatform diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/TestTaskContext.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/TestTaskContext.java new file mode 100644 index 00000000000..508ded38d30 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/TestTaskContext.java @@ -0,0 +1,44 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask; + +import org.apache.hadoop.io.FloatWritable; +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.Text; + +import junit.framework.TestCase; + +public class TestTaskContext extends TestCase { + + public void testTaskContext() { + TaskContext context = new TaskContext(null, null, null, null, null, null, null); + + context.setInputKeyClass(IntWritable.class); + assertEquals(IntWritable.class.getName(), context.getInputKeyClass().getName()); + + context.setInputValueClass(Text.class); + assertEquals(Text.class.getName(), context.getInputValueClass().getName()); + + context.setOutputKeyClass(LongWritable.class); + assertEquals(LongWritable.class.getName(), context.getOutputKeyClass().getName()); + + context.setOutputValueClass(FloatWritable.class); + assertEquals(FloatWritable.class.getName(), context.getOutputValueClass().getName()); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/buffer/TestBufferPushPull.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/buffer/TestBufferPushPull.java new file mode 100644 index 00000000000..48c32c0239f --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/buffer/TestBufferPushPull.java @@ -0,0 +1,279 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.mapred.nativetask.buffer; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.hadoop.io.BytesWritable; +import org.apache.hadoop.io.DataInputBuffer; +import org.apache.hadoop.mapred.RawKeyValueIterator; +import org.apache.hadoop.mapred.RecordWriter; +import org.apache.hadoop.mapred.Reporter; +import org.apache.hadoop.mapred.nativetask.DataReceiver; +import org.apache.hadoop.mapred.nativetask.NativeDataSource; +import org.apache.hadoop.mapred.nativetask.NativeDataTarget; +import org.apache.hadoop.mapred.nativetask.handlers.BufferPullee; +import org.apache.hadoop.mapred.nativetask.handlers.BufferPuller; +import org.apache.hadoop.mapred.nativetask.handlers.BufferPushee; +import org.apache.hadoop.mapred.nativetask.handlers.BufferPusher; +import org.apache.hadoop.mapred.nativetask.handlers.IDataLoader; +import org.apache.hadoop.mapred.nativetask.testutil.TestInput; +import org.apache.hadoop.mapred.nativetask.testutil.TestInput.KV; +import org.apache.hadoop.mapred.nativetask.util.ReadWriteBuffer; +import org.apache.hadoop.util.Progress; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +@SuppressWarnings({ "rawtypes", "unchecked"}) +public class TestBufferPushPull { + + public static int BUFFER_LENGTH = 100; // 100 bytes + public static int INPUT_KV_COUNT = 1000; + private KV[] dataInput; + + @Before + public void setUp() { + this.dataInput = TestInput.getMapInputs(INPUT_KV_COUNT); + } + + @Test + public void testPush() throws Exception { + final byte[] buff = new byte[BUFFER_LENGTH]; + + final InputBuffer input = new InputBuffer(buff); + + final OutputBuffer out = new OutputBuffer(buff); + + final Class iKClass = BytesWritable.class; + final Class iVClass = BytesWritable.class; + + final RecordWriterForPush writer = new RecordWriterForPush() { + @Override + public void write(BytesWritable key, BytesWritable value) throws IOException { + final KV expect = dataInput[count++]; + Assert.assertEquals(expect.key.toString(), key.toString()); + Assert.assertEquals(expect.value.toString(), value.toString()); + } + }; + + final BufferPushee pushee = new BufferPushee(iKClass, iVClass, writer); + + final PushTarget handler = new PushTarget(out) { + + @Override + public void sendData() throws IOException { + final int outputLength = out.length(); + input.rewind(0, outputLength); + out.rewind(); + pushee.collect(input); + } + }; + + final BufferPusher pusher = new BufferPusher(iKClass, iVClass, handler); + + writer.reset(); + for (int i = 0; i < INPUT_KV_COUNT; i++) { + pusher.collect(dataInput[i].key, dataInput[i].value); + } + pusher.close(); + pushee.close(); + } + + @Test + public void testPull() throws Exception { + final byte[] buff = new byte[BUFFER_LENGTH]; + + final InputBuffer input = new InputBuffer(buff); + + final OutputBuffer out = new OutputBuffer(buff); + + final Class iKClass = BytesWritable.class; + final Class iVClass = BytesWritable.class; + + final NativeHandlerForPull handler = new NativeHandlerForPull(input, out); + + final KeyValueIterator iter = new KeyValueIterator(); + final BufferPullee pullee = new BufferPullee(iKClass, iVClass, iter, handler); + handler.setDataLoader(pullee); + + final BufferPuller puller = new BufferPuller(handler); + handler.setDataReceiver(puller); + + int count = 0; + + while (puller.next()) { + final DataInputBuffer key = puller.getKey(); + final DataInputBuffer value = puller.getValue(); + + final BytesWritable keyBytes = new BytesWritable(); + final BytesWritable valueBytes = new BytesWritable(); + + keyBytes.readFields(key); + valueBytes.readFields(value); + + Assert.assertEquals(dataInput[count].key.toString(), keyBytes.toString()); + Assert.assertEquals(dataInput[count].value.toString(), valueBytes.toString()); + + count++; + } + + puller.close(); + pullee.close(); + } + + public abstract class PushTarget implements NativeDataTarget { + OutputBuffer out; + + PushTarget(OutputBuffer out) { + this.out = out; + } + + @Override + public abstract void sendData() throws IOException; + + @Override + public void finishSendData() throws IOException { + sendData(); + } + + @Override + public OutputBuffer getOutputBuffer() { + return out; + } + } + + public abstract class RecordWriterForPush implements RecordWriter { + + protected int count = 0; + + RecordWriterForPush() { + } + + @Override + public abstract void write(BytesWritable key, BytesWritable value) throws IOException; + + @Override + public void close(Reporter reporter) throws IOException { + } + + public void reset() { + count = 0; + } + }; + + public static class NativeHandlerForPull implements NativeDataSource, NativeDataTarget { + + InputBuffer in; + private final OutputBuffer out; + + private IDataLoader dataLoader; + private DataReceiver dataReceiver; + + public NativeHandlerForPull(InputBuffer input, OutputBuffer out) { + this.in = input; + this.out = out; + } + + @Override + public InputBuffer getInputBuffer() { + return in; + } + + @Override + public void setDataReceiver(DataReceiver handler) { + this.dataReceiver = handler; + } + + @Override + public void loadData() throws IOException { + final int size = dataLoader.load(); + } + + public void setDataLoader(IDataLoader dataLoader) { + this.dataLoader = dataLoader; + } + + @Override + public void sendData() throws IOException { + final int len = out.length(); + out.rewind(); + in.rewind(0, len); + dataReceiver.receiveData(); + } + + @Override + public void finishSendData() throws IOException { + dataReceiver.receiveData(); + } + + @Override + public OutputBuffer getOutputBuffer() { + return this.out; + } + } + + public class KeyValueIterator implements RawKeyValueIterator { + int count = 0; + BytesWritable key; + BytesWritable value; + + @Override + public DataInputBuffer getKey() throws IOException { + return convert(key); + } + + @Override + public DataInputBuffer getValue() throws IOException { + return convert(value); + } + + private DataInputBuffer convert(BytesWritable b) throws IOException { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + b.write(new DataOutputStream(out)); + final byte[] array = out.toByteArray(); + final DataInputBuffer result = new DataInputBuffer(); + result.reset(array, array.length); + return result; + } + + @Override + public boolean next() throws IOException { + if (count < INPUT_KV_COUNT) { + key = dataInput[count].key; + value = dataInput[count].key; + count++; + return true; + } + return false; + } + + @Override + public void close() throws IOException { + } + + @Override + public Progress getProgress() { + return null; + } + }; +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/buffer/TestByteBufferReadWrite.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/buffer/TestByteBufferReadWrite.java new file mode 100644 index 00000000000..106fdcb4994 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/buffer/TestByteBufferReadWrite.java @@ -0,0 +1,168 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.buffer; + +import java.io.*; + +import com.google.common.base.Charsets; +import com.google.common.primitives.Shorts; +import org.apache.hadoop.mapred.nativetask.NativeDataTarget; + +import org.junit.Assert; +import org.junit.Test; + +import org.mockito.Mockito; + +public class TestByteBufferReadWrite { + @Test + public void testReadWrite() throws IOException { + byte[] buff = new byte[10000]; + + InputBuffer input = new InputBuffer(buff); + MockDataTarget target = new MockDataTarget(buff); + ByteBufferDataWriter writer = new ByteBufferDataWriter(target); + + writer.write(1); + writer.write(new byte[] {2, 2}, 0, 2); + writer.writeBoolean(true); + writer.writeByte(4); + writer.writeShort(5); + writer.writeChar(6); + writer.writeInt(7); + writer.writeLong(8); + writer.writeFloat(9); + writer.writeDouble(10); + writer.writeBytes("goodboy"); + writer.writeChars("hello"); + writer.writeUTF("native task"); + + int length = target.getOutputBuffer().length(); + input.rewind(0, length); + ByteBufferDataReader reader = new ByteBufferDataReader(input); + + Assert.assertEquals(1, reader.read()); + byte[] two = new byte[2]; + reader.read(two); + Assert.assertTrue(two[0] == two[1] && two[0] == 2); + + + Assert.assertEquals(true, reader.readBoolean()); + Assert.assertEquals(4, reader.readByte()); + Assert.assertEquals(5, reader.readShort()); + Assert.assertEquals(6, reader.readChar()); + Assert.assertEquals(7, reader.readInt()); + Assert.assertEquals(8, reader.readLong()); + Assert.assertTrue(reader.readFloat() - 9 < 0.0001); + Assert.assertTrue(reader.readDouble() - 10 < 0.0001); + + byte[] goodboy = new byte["goodboy".length()]; + reader.read(goodboy); + Assert.assertEquals("goodboy", toString(goodboy)); + + char[] hello = new char["hello".length()]; + for (int i = 0; i < hello.length; i++) { + hello[i] = reader.readChar(); + } + + String helloString = new String(hello); + Assert.assertEquals("hello", helloString); + + Assert.assertEquals("native task", reader.readUTF()); + + Assert.assertEquals(0, input.remaining()); + } + + /** + * Test that Unicode characters outside the basic multilingual plane, + * such as this cat face, are properly encoded. + */ + @Test + public void testCatFace() throws IOException { + byte[] buff = new byte[10]; + MockDataTarget target = new MockDataTarget(buff); + ByteBufferDataWriter writer = new ByteBufferDataWriter(target); + String catFace = "\uD83D\uDE38"; + writer.writeUTF(catFace); + + // Check that our own decoder can read it + InputBuffer input = new InputBuffer(buff); + input.rewind(0, buff.length); + ByteBufferDataReader reader = new ByteBufferDataReader(input); + Assert.assertEquals(catFace, reader.readUTF()); + + // Check that the standard Java one can read it too + String fromJava = new java.io.DataInputStream(new ByteArrayInputStream(buff)).readUTF(); + Assert.assertEquals(catFace, fromJava); + } + + @Test + public void testShortOfSpace() throws IOException { + byte[] buff = new byte[10]; + MockDataTarget target = new MockDataTarget(buff); + ByteBufferDataWriter writer = new ByteBufferDataWriter(target); + Assert.assertEquals(false, writer.hasUnFlushedData()); + + writer.write(1); + writer.write(new byte[] {2, 2}, 0, 2); + Assert.assertEquals(true, writer.hasUnFlushedData()); + + Assert.assertEquals(true, writer.shortOfSpace(100)); + } + + + @Test + public void testFlush() throws IOException { + byte[] buff = new byte[10]; + MockDataTarget target = Mockito.spy(new MockDataTarget(buff)); + + ByteBufferDataWriter writer = new ByteBufferDataWriter(target); + Assert.assertEquals(false, writer.hasUnFlushedData()); + + writer.write(1); + writer.write(new byte[100]); + + Assert.assertEquals(true, writer.hasUnFlushedData()); + writer.close(); + Mockito.verify(target, Mockito.times(11)).sendData(); + Mockito.verify(target).finishSendData(); + } + + private static String toString(byte[] str) throws UnsupportedEncodingException { + return new String(str, 0, str.length, "UTF-8"); + } + + private static class MockDataTarget implements NativeDataTarget { + + private OutputBuffer out; + + MockDataTarget(byte[] buffer) { + this.out = new OutputBuffer(buffer); + } + + @Override + public void sendData() throws IOException {} + + @Override + public void finishSendData() throws IOException {} + + @Override + public OutputBuffer getOutputBuffer() { + return out; + } + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/buffer/TestInputBuffer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/buffer/TestInputBuffer.java new file mode 100644 index 00000000000..7eb6467e95f --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/buffer/TestInputBuffer.java @@ -0,0 +1,53 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.buffer; + +import java.io.IOException; + +import junit.framework.TestCase; + +import org.junit.Assert; + +public class TestInputBuffer extends TestCase { + public void testInputBuffer() throws IOException { + final int size = 100; + final InputBuffer input1 = new InputBuffer(BufferType.DIRECT_BUFFER, size); + Assert.assertEquals(input1.getType(), BufferType.DIRECT_BUFFER); + + Assert.assertTrue(input1.position() == 0); + Assert.assertTrue(input1.length() == 0); + Assert.assertTrue(input1.remaining() == 0); + Assert.assertTrue(input1.capacity() == size); + + final InputBuffer input2 = new InputBuffer(BufferType.HEAP_BUFFER, size); + Assert.assertEquals(input2.getType(), BufferType.HEAP_BUFFER); + + Assert.assertTrue(input2.position() == 0); + Assert.assertTrue(input2.length() == 0); + Assert.assertTrue(input2.remaining() == 0); + Assert.assertTrue(input2.capacity() == size); + + final InputBuffer input3 = new InputBuffer(new byte[size]); + Assert.assertEquals(input3.getType(), BufferType.HEAP_BUFFER); + + Assert.assertTrue(input3.position() == 0); + Assert.assertTrue(input3.length() == 0); + Assert.assertTrue(input3.remaining() == 0); + Assert.assertEquals(input3.capacity(), size); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/buffer/TestOutputBuffer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/buffer/TestOutputBuffer.java new file mode 100644 index 00000000000..39c25a6b8d5 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/buffer/TestOutputBuffer.java @@ -0,0 +1,45 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.buffer; + +import junit.framework.TestCase; + +import org.junit.Assert; + +public class TestOutputBuffer extends TestCase { + public void testOutputBuffer() { + final int size = 100; + final OutputBuffer output1 = new OutputBuffer(BufferType.DIRECT_BUFFER, size); + Assert.assertEquals(output1.getType(), BufferType.DIRECT_BUFFER); + + Assert.assertTrue(output1.length() == 0); + Assert.assertEquals(output1.limit(), size); + + final OutputBuffer output2 = new OutputBuffer(BufferType.HEAP_BUFFER, size); + Assert.assertEquals(output2.getType(), BufferType.HEAP_BUFFER); + + Assert.assertTrue(output2.length() == 0); + Assert.assertEquals(output2.limit(), size); + + final OutputBuffer output3 = new OutputBuffer(new byte[size]); + Assert.assertEquals(output3.getType(), BufferType.HEAP_BUFFER); + + Assert.assertTrue(output3.length() == 0); + Assert.assertEquals(output3.limit(), size); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/CombinerTest.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/CombinerTest.java new file mode 100644 index 00000000000..cf6e286af81 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/CombinerTest.java @@ -0,0 +1,124 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.combinertest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapred.Task; +import org.apache.hadoop.mapred.nativetask.NativeRuntime; +import org.apache.hadoop.mapred.nativetask.combinertest.WordCount.IntSumReducer; +import org.apache.hadoop.mapred.nativetask.combinertest.WordCount.TokenizerMapper; +import org.apache.hadoop.mapred.nativetask.kvtest.TestInputFile; +import org.apache.hadoop.mapred.nativetask.testutil.ResultVerifier; +import org.apache.hadoop.mapred.nativetask.testutil.ScenarioConfiguration; +import org.apache.hadoop.mapred.nativetask.testutil.TestConstants; +import org.apache.hadoop.mapreduce.Counter; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; +import org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat; +import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; +import org.junit.AfterClass; +import org.apache.hadoop.util.NativeCodeLoader; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; + +public class CombinerTest { + private FileSystem fs; + private String inputpath; + private String nativeoutputpath; + private String hadoopoutputpath; + + @Test + public void testWordCountCombiner() throws Exception { + final Configuration nativeConf = ScenarioConfiguration.getNativeConfiguration(); + nativeConf.addResource(TestConstants.COMBINER_CONF_PATH); + final Job nativejob = getJob("nativewordcount", nativeConf, inputpath, nativeoutputpath); + + final Configuration commonConf = ScenarioConfiguration.getNormalConfiguration(); + commonConf.addResource(TestConstants.COMBINER_CONF_PATH); + final Job normaljob = getJob("normalwordcount", commonConf, inputpath, hadoopoutputpath); + + assertTrue(nativejob.waitForCompletion(true)); + assertTrue(normaljob.waitForCompletion(true)); + assertEquals(true, ResultVerifier.verify(nativeoutputpath, hadoopoutputpath)); + ResultVerifier.verifyCounters(normaljob, nativejob, true); + } + + @Before + public void startUp() throws Exception { + Assume.assumeTrue(NativeCodeLoader.isNativeCodeLoaded()); + Assume.assumeTrue(NativeRuntime.isNativeLibraryLoaded()); + final ScenarioConfiguration conf = new ScenarioConfiguration(); + conf.addcombinerConf(); + + this.fs = FileSystem.get(conf); + + this.inputpath = TestConstants.NATIVETASK_COMBINER_TEST_INPUTDIR + "/wordcount"; + + if (!fs.exists(new Path(inputpath))) { + new TestInputFile( + conf.getInt(TestConstants.NATIVETASK_COMBINER_WORDCOUNT_FILESIZE, 1000000), + Text.class.getName(), + Text.class.getName(), conf).createSequenceTestFile(inputpath, 1, (byte)('a')); + } + + this.nativeoutputpath = TestConstants.NATIVETASK_COMBINER_TEST_NATIVE_OUTPUTDIR + + "/nativewordcount"; + this.hadoopoutputpath = TestConstants.NATIVETASK_COMBINER_TEST_NORMAL_OUTPUTDIR + + "/normalwordcount"; + } + + @AfterClass + public static void cleanUp() throws IOException { + final FileSystem fs = FileSystem.get(new ScenarioConfiguration()); + fs.delete(new Path(TestConstants.NATIVETASK_COMBINER_TEST_DIR), true); + fs.close(); + } + + protected static Job getJob(String jobname, Configuration inputConf, + String inputpath, String outputpath) + throws Exception { + final Configuration conf = new Configuration(inputConf); + conf.set("fileoutputpath", outputpath); + final FileSystem fs = FileSystem.get(conf); + if (fs.exists(new Path(outputpath))) { + fs.delete(new Path(outputpath), true); + } + fs.close(); + final Job job = Job.getInstance(conf, jobname); + job.setJarByClass(WordCount.class); + job.setMapperClass(TokenizerMapper.class); + job.setCombinerClass(IntSumReducer.class); + job.setReducerClass(IntSumReducer.class); + job.setOutputKeyClass(Text.class); + job.setOutputValueClass(IntWritable.class); + job.setInputFormatClass(SequenceFileInputFormat.class); + FileInputFormat.addInputPath(job, new Path(inputpath)); + FileOutputFormat.setOutputPath(job, new Path(outputpath)); + return job; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/LargeKVCombinerTest.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/LargeKVCombinerTest.java new file mode 100644 index 00000000000..a4eecbe1830 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/LargeKVCombinerTest.java @@ -0,0 +1,115 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.combinertest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapred.Task; +import org.apache.hadoop.mapred.nativetask.NativeRuntime; +import org.apache.hadoop.mapred.nativetask.kvtest.TestInputFile; +import org.apache.hadoop.mapred.nativetask.testutil.ResultVerifier; +import org.apache.hadoop.mapred.nativetask.testutil.ScenarioConfiguration; +import org.apache.hadoop.mapred.nativetask.testutil.TestConstants; +import org.apache.hadoop.mapreduce.Counter; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.TaskCounter; +import org.junit.AfterClass; +import org.apache.hadoop.util.NativeCodeLoader; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; + +public class LargeKVCombinerTest { + private static final Log LOG = LogFactory.getLog(LargeKVCombinerTest.class); + + @Before + public void startUp() throws Exception { + Assume.assumeTrue(NativeCodeLoader.isNativeCodeLoaded()); + Assume.assumeTrue(NativeRuntime.isNativeLibraryLoaded()); + } + + @Test + public void testLargeValueCombiner() throws Exception { + final Configuration normalConf = ScenarioConfiguration.getNormalConfiguration(); + final Configuration nativeConf = ScenarioConfiguration.getNativeConfiguration(); + normalConf.addResource(TestConstants.COMBINER_CONF_PATH); + nativeConf.addResource(TestConstants.COMBINER_CONF_PATH); + final int deafult_KVSize_Maximum = 1 << 22; // 4M + final int KVSize_Maximum = normalConf.getInt(TestConstants.NATIVETASK_KVSIZE_MAX_LARGEKV_TEST, + deafult_KVSize_Maximum); + final String inputPath = TestConstants.NATIVETASK_COMBINER_TEST_INPUTDIR + "/largeKV"; + final String nativeOutputPath = TestConstants.NATIVETASK_COMBINER_TEST_NATIVE_OUTPUTDIR + + "/nativeLargeKV"; + final String hadoopOutputPath = TestConstants.NATIVETASK_COMBINER_TEST_NORMAL_OUTPUTDIR + + "/normalLargeKV"; + final FileSystem fs = FileSystem.get(normalConf); + for (int i = 65536; i <= KVSize_Maximum; i *= 4) { + + int max = i; + int min = Math.max(i / 4, max - 10); + + LOG.info("===KV Size Test: min size: " + min + ", max size: " + max); + + normalConf.set(TestConstants.NATIVETASK_KVSIZE_MIN, String.valueOf(min)); + normalConf.set(TestConstants.NATIVETASK_KVSIZE_MAX, String.valueOf(max)); + nativeConf.set(TestConstants.NATIVETASK_KVSIZE_MIN, String.valueOf(min)); + nativeConf.set(TestConstants.NATIVETASK_KVSIZE_MAX, String.valueOf(max)); + fs.delete(new Path(inputPath), true); + new TestInputFile(normalConf.getInt(TestConstants.NATIVETASK_COMBINER_WORDCOUNT_FILESIZE, + 1000000), IntWritable.class.getName(), + Text.class.getName(), normalConf).createSequenceTestFile(inputPath, 1); + + final Job normaljob = CombinerTest.getJob("normalwordcount", normalConf, + inputPath, hadoopOutputPath); + final Job nativejob = CombinerTest.getJob("nativewordcount", nativeConf, + inputPath, nativeOutputPath); + + assertTrue(nativejob.waitForCompletion(true)); + + assertTrue(normaljob.waitForCompletion(true)); + + final boolean compareRet = ResultVerifier.verify(nativeOutputPath, hadoopOutputPath); + + final String reason = "LargeKVCombinerTest failed with, min size: " + min + + ", max size: " + max + ", normal out: " + hadoopOutputPath + + ", native Out: " + nativeOutputPath; + + assertEquals(reason, true, compareRet); + ResultVerifier.verifyCounters(normaljob, nativejob, true); + } + fs.close(); + } + + @AfterClass + public static void cleanUp() throws IOException { + final FileSystem fs = FileSystem.get(new ScenarioConfiguration()); + fs.delete(new Path(TestConstants.NATIVETASK_COMBINER_TEST_DIR), true); + fs.close(); + } + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/OldAPICombinerTest.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/OldAPICombinerTest.java new file mode 100644 index 00000000000..8954b52d1fa --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/OldAPICombinerTest.java @@ -0,0 +1,129 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.combinertest; + +import static org.junit.Assert.assertEquals; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapred.FileInputFormat; +import org.apache.hadoop.mapred.FileOutputFormat; +import org.apache.hadoop.mapred.JobClient; +import org.apache.hadoop.mapred.JobConf; +import org.apache.hadoop.mapred.RunningJob; +import org.apache.hadoop.mapred.SequenceFileInputFormat; +import org.apache.hadoop.mapred.Task; +import org.apache.hadoop.mapred.TextOutputFormat; +import org.apache.hadoop.mapred.nativetask.NativeRuntime; +import org.apache.hadoop.mapred.nativetask.kvtest.TestInputFile; +import org.apache.hadoop.mapred.nativetask.testutil.ResultVerifier; +import org.apache.hadoop.mapred.nativetask.testutil.ScenarioConfiguration; +import org.apache.hadoop.mapred.nativetask.testutil.TestConstants; +import org.apache.hadoop.mapreduce.Counter; +import org.apache.hadoop.mapreduce.TaskCounter; +import org.junit.AfterClass; +import org.apache.hadoop.util.NativeCodeLoader; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; + +public class OldAPICombinerTest { + private FileSystem fs; + private String inputpath; + + @Test + public void testWordCountCombinerWithOldAPI() throws Exception { + final Configuration nativeConf = ScenarioConfiguration.getNativeConfiguration(); + nativeConf.addResource(TestConstants.COMBINER_CONF_PATH); + final String nativeoutput = TestConstants.NATIVETASK_OLDAPI_COMBINER_TEST_NATIVE_OUTPUTPATH; + final JobConf nativeJob = getOldAPIJobconf(nativeConf, "nativeCombinerWithOldAPI", + inputpath, nativeoutput); + RunningJob nativeRunning = JobClient.runJob(nativeJob); + + Counter nativeReduceGroups = nativeRunning.getCounters().findCounter( + TaskCounter.REDUCE_INPUT_RECORDS); + + final Configuration normalConf = ScenarioConfiguration.getNormalConfiguration(); + normalConf.addResource(TestConstants.COMBINER_CONF_PATH); + final String normaloutput = TestConstants.NATIVETASK_OLDAPI_COMBINER_TEST_NORMAL_OUTPUTPATH; + final JobConf normalJob = getOldAPIJobconf(normalConf, "normalCombinerWithOldAPI", + inputpath, normaloutput); + + RunningJob normalRunning = JobClient.runJob(normalJob); + Counter normalReduceGroups = normalRunning.getCounters().findCounter( + TaskCounter.REDUCE_INPUT_RECORDS); + + final boolean compareRet = ResultVerifier.verify(nativeoutput, normaloutput); + assertEquals("file compare result: if they are the same ,then return true", true, compareRet); + + assertEquals("The input reduce record count must be same", + nativeReduceGroups.getValue(), normalReduceGroups.getValue()); + } + + @Before + public void startUp() throws Exception { + Assume.assumeTrue(NativeCodeLoader.isNativeCodeLoaded()); + Assume.assumeTrue(NativeRuntime.isNativeLibraryLoaded()); + final ScenarioConfiguration conf = new ScenarioConfiguration(); + conf.addcombinerConf(); + this.fs = FileSystem.get(conf); + this.inputpath = TestConstants.NATIVETASK_COMBINER_TEST_INPUTDIR + "/wordcount"; + + if (!fs.exists(new Path(inputpath))) { + new TestInputFile(conf.getInt(TestConstants.NATIVETASK_COMBINER_WORDCOUNT_FILESIZE, 1000000), + Text.class.getName(), + Text.class.getName(), conf).createSequenceTestFile(inputpath, 1, (byte)('a')); + } + } + + @AfterClass + public static void cleanUp() throws IOException { + final FileSystem fs = FileSystem.get(new ScenarioConfiguration()); + fs.delete(new Path(TestConstants.NATIVETASK_COMBINER_TEST_DIR), true); + fs.close(); + } + + private static JobConf getOldAPIJobconf(Configuration configuration, String name, + String input, String output) + throws Exception { + final JobConf jobConf = new JobConf(configuration); + final FileSystem fs = FileSystem.get(configuration); + if (fs.exists(new Path(output))) { + fs.delete(new Path(output), true); + } + fs.close(); + jobConf.setJobName(name); + jobConf.setOutputKeyClass(Text.class); + jobConf.setOutputValueClass(IntWritable.class); + jobConf.setMapperClass(WordCountWithOldAPI.TokenizerMapperWithOldAPI.class); + jobConf.setCombinerClass(WordCountWithOldAPI.IntSumReducerWithOldAPI.class); + jobConf.setReducerClass(WordCountWithOldAPI.IntSumReducerWithOldAPI.class); + + jobConf.setInputFormat(SequenceFileInputFormat.class); + jobConf.setOutputFormat(TextOutputFormat.class); + + FileInputFormat.setInputPaths(jobConf, new Path(input)); + FileOutputFormat.setOutputPath(jobConf, new Path(output)); + return jobConf; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/WordCount.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/WordCount.java new file mode 100644 index 00000000000..c02284825b2 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/WordCount.java @@ -0,0 +1,91 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.combinertest; + +import java.io.IOException; +import java.util.StringTokenizer; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.MRJobConfig; +import org.apache.hadoop.mapreduce.Mapper; +import org.apache.hadoop.mapreduce.Reducer; +import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; +import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; +import org.apache.hadoop.util.GenericOptionsParser; + +public class WordCount { + + private static Log LOG = LogFactory.getLog(WordCount.class); + + public static class TokenizerMapper extends Mapper { + + private final static IntWritable one = new IntWritable(1); + private final Text word = new Text(); + + @Override + public void map(Object key, Text value, Context context) + throws IOException, InterruptedException { + final StringTokenizer itr = new StringTokenizer(value.toString()); + while (itr.hasMoreTokens()) { + word.set(itr.nextToken()); + context.write(word, one); + } + } + } + + public static class IntSumReducer extends Reducer { + private final IntWritable result = new IntWritable(); + + @Override + public void reduce(Text key, Iterable values, Context context) throws IOException, + InterruptedException { + int sum = 0; + for (final IntWritable val : values) { + sum += val.get(); + } + result.set(sum); + context.write(key, result); + } + } + + public static void main(String[] args) throws Exception { + final Configuration conf = new Configuration(); + final String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs(); + if (otherArgs.length != 2) { + System.err.println("Usage: wordcount "); + System.exit(2); + } + final Job job = Job.getInstance(conf, + conf.get(MRJobConfig.JOB_NAME, "word count")); + job.setJarByClass(WordCount.class); + job.setMapperClass(TokenizerMapper.class); + job.setCombinerClass(IntSumReducer.class); + job.setReducerClass(IntSumReducer.class); + job.setOutputKeyClass(Text.class); + job.setOutputValueClass(IntWritable.class); + FileInputFormat.addInputPath(job, new Path(otherArgs[0])); + FileOutputFormat.setOutputPath(job, new Path(otherArgs[1])); + System.exit(job.waitForCompletion(true) ? 0 : 1); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/WordCountWithOldAPI.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/WordCountWithOldAPI.java new file mode 100644 index 00000000000..00547b62053 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/combinertest/WordCountWithOldAPI.java @@ -0,0 +1,68 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.combinertest; + +import java.io.IOException; +import java.util.Iterator; +import java.util.StringTokenizer; + +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapred.MapReduceBase; +import org.apache.hadoop.mapred.Mapper; +import org.apache.hadoop.mapred.OutputCollector; +import org.apache.hadoop.mapred.Reducer; +import org.apache.hadoop.mapred.Reporter; + +public class WordCountWithOldAPI { + + public static class TokenizerMapperWithOldAPI extends MapReduceBase implements + Mapper { + private final static IntWritable one = new IntWritable(1); + private final Text word = new Text(); + + @Override + public void map(Object key, Text value, + OutputCollector output, + Reporter reporter) + throws IOException { + final StringTokenizer itr = new StringTokenizer(value.toString()); + while (itr.hasMoreTokens()) { + word.set(itr.nextToken()); + output.collect(word, one); + } + } + } + + public static class IntSumReducerWithOldAPI extends MapReduceBase implements + Reducer { + private final IntWritable result = new IntWritable(); + + @Override + public void reduce(Text key, Iterator values, + OutputCollector output, + Reporter reporter) throws IOException { + int sum = 0; + while (values.hasNext()) { + sum += values.next().get(); + } + result.set(sum); + output.collect(key, result); + } + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/compresstest/CompressMapper.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/compresstest/CompressMapper.java new file mode 100644 index 00000000000..a0de94928fa --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/compresstest/CompressMapper.java @@ -0,0 +1,63 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.compresstest; + +import java.io.IOException; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapred.nativetask.testutil.ScenarioConfiguration; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.Mapper; +import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; +import org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat; +import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; + +public class CompressMapper { + + public static class TextCompressMapper extends Mapper { + + @Override + protected void map(Text key, Text value, Context context) + throws IOException, InterruptedException { + context.write(key, value); + } + } + + public static Job getCompressJob(String jobname, Configuration conf, + String inputpath, String outputpath) + throws Exception { + Job job = Job.getInstance(conf, jobname + "-CompressMapperJob"); + job.setJarByClass(CompressMapper.class); + job.setMapperClass(TextCompressMapper.class); + job.setOutputKeyClass(Text.class); + job.setMapOutputValueClass(Text.class); + // if output file exists ,delete it + final FileSystem hdfs = FileSystem.get(new ScenarioConfiguration()); + if (hdfs.exists(new Path(outputpath))) { + hdfs.delete(new Path(outputpath), true); + } + hdfs.close(); + job.setInputFormatClass(SequenceFileInputFormat.class); + FileInputFormat.addInputPath(job, new Path(inputpath)); + FileOutputFormat.setOutputPath(job, new Path(outputpath)); + return job; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/compresstest/CompressTest.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/compresstest/CompressTest.java new file mode 100644 index 00000000000..ca39fa5f86e --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/compresstest/CompressTest.java @@ -0,0 +1,144 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.compresstest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapred.nativetask.NativeRuntime; +import org.apache.hadoop.mapred.nativetask.kvtest.TestInputFile; +import org.apache.hadoop.mapred.nativetask.testutil.ResultVerifier; +import org.apache.hadoop.mapred.nativetask.testutil.ScenarioConfiguration; +import org.apache.hadoop.mapred.nativetask.testutil.TestConstants; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.MRJobConfig; +import org.junit.AfterClass; +import org.apache.hadoop.util.NativeCodeLoader; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; + +public class CompressTest { + + private static final Configuration nativeConf = ScenarioConfiguration.getNativeConfiguration(); + private static final Configuration hadoopConf = ScenarioConfiguration.getNormalConfiguration(); + + static { + nativeConf.addResource(TestConstants.COMPRESS_TEST_CONF_PATH); + hadoopConf.addResource(TestConstants.COMPRESS_TEST_CONF_PATH); + } + + @Test + public void testSnappyCompress() throws Exception { + final String snappyCodec = "org.apache.hadoop.io.compress.SnappyCodec"; + + nativeConf.set(MRJobConfig.MAP_OUTPUT_COMPRESS_CODEC, snappyCodec); + final String nativeOutputPath = + TestConstants.NATIVETASK_COMPRESS_TEST_NATIVE_OUTPUTDIR + "/snappy"; + final Job job = CompressMapper.getCompressJob("nativesnappy", nativeConf, + TestConstants.NATIVETASK_COMPRESS_TEST_INPUTDIR, nativeOutputPath); + assertTrue(job.waitForCompletion(true)); + + hadoopConf.set(MRJobConfig.MAP_OUTPUT_COMPRESS_CODEC, snappyCodec); + final String hadoopOutputPath = + TestConstants.NATIVETASK_COMPRESS_TEST_NORMAL_OUTPUTDIR + "/snappy"; + final Job hadoopjob = CompressMapper.getCompressJob("hadoopsnappy", hadoopConf, + TestConstants.NATIVETASK_COMPRESS_TEST_INPUTDIR, hadoopOutputPath); + assertTrue(hadoopjob.waitForCompletion(true)); + + final boolean compareRet = ResultVerifier.verify(nativeOutputPath, hadoopOutputPath); + assertEquals("file compare result: if they are the same ,then return true", true, compareRet); + ResultVerifier.verifyCounters(hadoopjob, job); + } + + @Test + public void testGzipCompress() throws Exception { + final String gzipCodec = "org.apache.hadoop.io.compress.GzipCodec"; + + nativeConf.set(MRJobConfig.MAP_OUTPUT_COMPRESS_CODEC, gzipCodec); + final String nativeOutputPath = + TestConstants.NATIVETASK_COMPRESS_TEST_NATIVE_OUTPUTDIR + "/gzip"; + final Job job = CompressMapper.getCompressJob("nativegzip", nativeConf, + TestConstants.NATIVETASK_COMPRESS_TEST_INPUTDIR, nativeOutputPath); + assertTrue(job.waitForCompletion(true)); + + hadoopConf.set(MRJobConfig.MAP_OUTPUT_COMPRESS_CODEC, gzipCodec); + final String hadoopOutputPath = + TestConstants.NATIVETASK_COMPRESS_TEST_NORMAL_OUTPUTDIR + "/gzip"; + final Job hadoopjob = CompressMapper.getCompressJob("hadoopgzip", hadoopConf, + TestConstants.NATIVETASK_COMPRESS_TEST_INPUTDIR, hadoopOutputPath); + assertTrue(hadoopjob.waitForCompletion(true)); + + final boolean compareRet = ResultVerifier.verify(nativeOutputPath, hadoopOutputPath); + assertEquals("file compare result: if they are the same ,then return true", true, compareRet); + ResultVerifier.verifyCounters(hadoopjob, job); + } + + @Test + public void testLz4Compress() throws Exception { + final String lz4Codec = "org.apache.hadoop.io.compress.Lz4Codec"; + + nativeConf.set(MRJobConfig.MAP_OUTPUT_COMPRESS_CODEC, lz4Codec); + final String nativeOutputPath = + TestConstants.NATIVETASK_COMPRESS_TEST_NATIVE_OUTPUTDIR + "/lz4"; + final Job nativeJob = CompressMapper.getCompressJob("nativelz4", nativeConf, + TestConstants.NATIVETASK_COMPRESS_TEST_INPUTDIR, nativeOutputPath); + assertTrue(nativeJob.waitForCompletion(true)); + + hadoopConf.set(MRJobConfig.MAP_OUTPUT_COMPRESS_CODEC, lz4Codec); + final String hadoopOutputPath = + TestConstants.NATIVETASK_COMPRESS_TEST_NORMAL_OUTPUTDIR + "/lz4"; + final Job hadoopJob = CompressMapper.getCompressJob("hadooplz4", hadoopConf, + TestConstants.NATIVETASK_COMPRESS_TEST_INPUTDIR, hadoopOutputPath); + assertTrue(hadoopJob.waitForCompletion(true)); + final boolean compareRet = ResultVerifier.verify(nativeOutputPath, hadoopOutputPath); + assertEquals("file compare result: if they are the same ,then return true", true, compareRet); + ResultVerifier.verifyCounters(hadoopJob, nativeJob); + } + + @Before + public void startUp() throws Exception { + Assume.assumeTrue(NativeCodeLoader.isNativeCodeLoaded()); + Assume.assumeTrue(NativeRuntime.isNativeLibraryLoaded()); + final ScenarioConfiguration conf = new ScenarioConfiguration(); + final FileSystem fs = FileSystem.get(conf); + final Path path = new Path(TestConstants.NATIVETASK_COMPRESS_TEST_INPUTDIR); + fs.delete(path, true); + if (!fs.exists(path)) { + new TestInputFile(hadoopConf.getInt( + TestConstants.NATIVETASK_COMPRESS_FILESIZE, 100000), + Text.class.getName(), Text.class.getName(), conf) + .createSequenceTestFile(TestConstants.NATIVETASK_COMPRESS_TEST_INPUTDIR); + } + fs.close(); + } + + @AfterClass + public static void cleanUp() throws IOException { + final FileSystem fs = FileSystem.get(new ScenarioConfiguration()); + fs.delete(new Path(TestConstants.NATIVETASK_COMPRESS_TEST_DIR), true); + fs.close(); + } + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/handlers/TestCombineHandler.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/handlers/TestCombineHandler.java new file mode 100644 index 00000000000..68499a79bd7 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/handlers/TestCombineHandler.java @@ -0,0 +1,80 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.handlers; + +import java.io.IOException; + +import org.apache.hadoop.mapred.Task.CombinerRunner; +import org.apache.hadoop.mapred.nativetask.Command; +import org.apache.hadoop.mapred.nativetask.INativeHandler; +import org.apache.hadoop.mapred.nativetask.buffer.BufferType; +import org.apache.hadoop.mapred.nativetask.buffer.InputBuffer; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Matchers; +import org.mockito.Mockito; + +@SuppressWarnings({ "rawtypes", "unchecked", "deprecation" }) +public class TestCombineHandler { + + private CombinerHandler handler; + private INativeHandler nativeHandler; + private BufferPusher pusher; + private BufferPuller puller; + private CombinerRunner combinerRunner; + + @Before + public void setUp() throws IOException { + this.nativeHandler = Mockito.mock(INativeHandler.class); + this.pusher = Mockito.mock(BufferPusher.class); + this.puller = Mockito.mock(BufferPuller.class); + this.combinerRunner = Mockito.mock(CombinerRunner.class); + + Mockito.when(nativeHandler.getInputBuffer()).thenReturn( + new InputBuffer(BufferType.HEAP_BUFFER, 100)); + } + + @Test + public void testCommandDispatcherSetting() throws IOException { + this.handler = new CombinerHandler(nativeHandler, combinerRunner, puller, pusher); + Mockito.verify(nativeHandler, Mockito.times(1)).setCommandDispatcher(Matchers.eq(handler)); + Mockito.verify(nativeHandler, Mockito.times(1)).setDataReceiver(Matchers.eq(puller)); + } + + @Test + public void testCombine() throws IOException, InterruptedException, ClassNotFoundException { + this.handler = new CombinerHandler(nativeHandler, combinerRunner, puller, pusher); + Assert.assertEquals(null, handler.onCall(CombinerHandler.COMBINE, null)); + handler.close(); + handler.close(); + + Mockito.verify(combinerRunner, Mockito.times(1)) + .combine(Matchers.eq(puller), Matchers.eq(pusher)); + + Mockito.verify(pusher, Mockito.times(1)).close(); + Mockito.verify(puller, Mockito.times(1)).close(); + Mockito.verify(nativeHandler, Mockito.times(1)).close(); + } + + @Test + public void testOnCall() throws IOException { + this.handler = new CombinerHandler(nativeHandler, combinerRunner, puller, pusher); + Assert.assertEquals(null, handler.onCall(new Command(-1), null)); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/handlers/TestNativeCollectorOnlyHandler.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/handlers/TestNativeCollectorOnlyHandler.java new file mode 100644 index 00000000000..1c8bf7a3664 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/handlers/TestNativeCollectorOnlyHandler.java @@ -0,0 +1,129 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.handlers; + +import java.io.IOException; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.BytesWritable; +import org.apache.hadoop.mapred.JobConf; +import org.apache.hadoop.mapred.nativetask.Command; +import org.apache.hadoop.mapred.nativetask.ICombineHandler; +import org.apache.hadoop.mapred.nativetask.INativeHandler; +import org.apache.hadoop.mapred.nativetask.TaskContext; +import org.apache.hadoop.mapred.nativetask.buffer.BufferType; +import org.apache.hadoop.mapred.nativetask.buffer.InputBuffer; +import org.apache.hadoop.mapred.nativetask.testutil.TestConstants; +import org.apache.hadoop.mapred.nativetask.util.OutputUtil; +import org.apache.hadoop.mapred.nativetask.util.ReadWriteBuffer; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Matchers; +import org.mockito.Mockito; + +@SuppressWarnings({ "rawtypes", "unchecked", "deprecation" }) +public class TestNativeCollectorOnlyHandler { + + private NativeCollectorOnlyHandler handler; + private INativeHandler nativeHandler; + private BufferPusher pusher; + private ICombineHandler combiner; + private TaskContext taskContext; + private static final String LOCAL_DIR = TestConstants.NATIVETASK_TEST_DIR + "/local"; + + @Before + public void setUp() throws IOException { + this.nativeHandler = Mockito.mock(INativeHandler.class); + this.pusher = Mockito.mock(BufferPusher.class); + this.combiner = Mockito.mock(ICombineHandler.class); + JobConf jobConf = new JobConf(); + jobConf.set(OutputUtil.NATIVE_TASK_OUTPUT_MANAGER, + "org.apache.hadoop.mapred.nativetask.util.LocalJobOutputFiles"); + jobConf.set("mapred.local.dir", LOCAL_DIR); + this.taskContext = new TaskContext(jobConf, + BytesWritable.class, BytesWritable.class, + BytesWritable.class, + BytesWritable.class, + null, + null); + + Mockito.when(nativeHandler.getInputBuffer()).thenReturn( + new InputBuffer(BufferType.HEAP_BUFFER, 100)); + } + + @After + public void tearDown() throws IOException { + FileSystem.getLocal(new Configuration()).delete(new Path(LOCAL_DIR)); + } + + @Test + public void testCollect() throws IOException { + this.handler = new NativeCollectorOnlyHandler(taskContext, nativeHandler, pusher, combiner); + handler.collect(new BytesWritable(), new BytesWritable(), 100); + handler.close(); + handler.close(); + + Mockito.verify(pusher, Mockito.times(1)).collect(Matchers.any(BytesWritable.class), + Matchers.any(BytesWritable.class), Matchers.anyInt()); + + Mockito.verify(pusher, Mockito.times(1)).close(); + Mockito.verify(combiner, Mockito.times(1)).close(); + Mockito.verify(nativeHandler, Mockito.times(1)).close(); + } + + @Test + public void testGetCombiner() throws IOException { + this.handler = new NativeCollectorOnlyHandler(taskContext, nativeHandler, pusher, combiner); + Mockito.when(combiner.getId()).thenReturn(100L); + final ReadWriteBuffer result = handler.onCall( + NativeCollectorOnlyHandler.GET_COMBINE_HANDLER, null); + Assert.assertEquals(100L, result.readLong()); + } + + @Test + public void testOnCall() throws IOException { + this.handler = new NativeCollectorOnlyHandler(taskContext, nativeHandler, pusher, combiner); + boolean thrown = false; + try { + handler.onCall(new Command(-1), null); + } catch(final IOException e) { + thrown = true; + } + Assert.assertTrue("exception thrown", thrown); + + final String expectedOutputPath = LOCAL_DIR + "/output/file.out"; + final String expectedOutputIndexPath = LOCAL_DIR + "/output/file.out.index"; + final String expectedSpillPath = LOCAL_DIR + "/output/spill0.out"; + + final String outputPath = handler.onCall( + NativeCollectorOnlyHandler.GET_OUTPUT_PATH, null).readString(); + Assert.assertEquals(expectedOutputPath, outputPath); + + final String outputIndexPath = handler.onCall( + NativeCollectorOnlyHandler.GET_OUTPUT_INDEX_PATH, null).readString(); + Assert.assertEquals(expectedOutputIndexPath, outputIndexPath); + + final String spillPath = handler.onCall( + NativeCollectorOnlyHandler.GET_SPILL_PATH, null).readString(); + Assert.assertEquals(expectedSpillPath, spillPath); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/HashSumReducer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/HashSumReducer.java new file mode 100644 index 00000000000..2a72d056489 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/HashSumReducer.java @@ -0,0 +1,49 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.kvtest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Arrays; + +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapreduce.Reducer; + +public class HashSumReducer extends Reducer { + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(os); + + @Override + public void reduce(KTYPE key, Iterable values, Context context) + throws IOException, InterruptedException { + int hashSum = 0; + for (final VTYPE val : values) { + if (val instanceof Writable) { + os.reset(); + ((Writable) val).write(dos); + final int hash = Arrays.hashCode(os.toByteArray()); + hashSum += hash; + } + } + + context.write(key, new IntWritable(hashSum)); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/KVJob.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/KVJob.java new file mode 100644 index 00000000000..2d4515f6366 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/KVJob.java @@ -0,0 +1,108 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.kvtest; + +import java.io.IOException; +import java.util.zip.CRC32; + +import com.google.common.base.Stopwatch; +import com.google.common.primitives.Longs; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.mapred.nativetask.testutil.BytesFactory; +import org.apache.hadoop.mapred.nativetask.testutil.TestConstants; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.Mapper; +import org.apache.hadoop.mapreduce.Reducer; +import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; +import org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat; +import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; + +public class KVJob { + public static final String INPUTPATH = "nativetask.kvtest.inputfile.path"; + public static final String OUTPUTPATH = "nativetask.kvtest.outputfile.path"; + private static final Log LOG = LogFactory.getLog(KVJob.class); + Job job = null; + + public static class ValueMapper extends Mapper { + @Override + public void map(KTYPE key, VTYPE value, Context context) + throws IOException, InterruptedException { + context.write(key, value); + } + } + + public static class KVMReducer extends Reducer { + public void reduce(KTYPE key, VTYPE value, Context context) + throws IOException, InterruptedException { + context.write(key, value); + } + } + + public static class KVReducer extends Reducer { + + @Override + @SuppressWarnings({"unchecked"}) + public void reduce(KTYPE key, Iterable values, Context context) + throws IOException, InterruptedException { + long resultlong = 0;// 8 bytes match BytesFactory.fromBytes function + final CRC32 crc32 = new CRC32(); + for (final VTYPE val : values) { + crc32.reset(); + crc32.update(BytesFactory.toBytes(val)); + resultlong += crc32.getValue(); + } + final VTYPE V = null; + context.write(key, (VTYPE) BytesFactory.newObject(Longs.toByteArray(resultlong), + V.getClass().getName())); + } + } + + public KVJob(String jobname, Configuration conf, + Class keyclass, Class valueclass, + String inputpath, String outputpath) throws Exception { + job = Job.getInstance(conf, jobname); + job.setJarByClass(KVJob.class); + job.setMapperClass(KVJob.ValueMapper.class); + job.setOutputKeyClass(keyclass); + job.setMapOutputValueClass(valueclass); + + if (conf.get(TestConstants.NATIVETASK_KVTEST_CREATEFILE).equals("true")) { + final FileSystem fs = FileSystem.get(conf); + fs.delete(new Path(inputpath), true); + fs.close(); + final TestInputFile testfile = new TestInputFile(Integer.valueOf(conf.get( + TestConstants.FILESIZE_KEY, "1000")), + keyclass.getName(), valueclass.getName(), conf); + Stopwatch sw = new Stopwatch().start(); + testfile.createSequenceTestFile(inputpath); + LOG.info("Created test file " + inputpath + " in " + sw.elapsedMillis() + "ms"); + } + job.setInputFormatClass(SequenceFileInputFormat.class); + FileInputFormat.addInputPath(job, new Path(inputpath)); + FileOutputFormat.setOutputPath(job, new Path(outputpath)); + } + + public boolean runJob() throws Exception { + return job.waitForCompletion(true); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/KVTest.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/KVTest.java new file mode 100644 index 00000000000..6b658ac56e5 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/KVTest.java @@ -0,0 +1,153 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.kvtest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.mapred.nativetask.NativeRuntime; +import org.apache.hadoop.mapred.nativetask.testutil.ResultVerifier; +import org.apache.hadoop.mapred.nativetask.testutil.ScenarioConfiguration; +import org.apache.hadoop.mapred.nativetask.testutil.TestConstants; +import org.junit.AfterClass; +import org.apache.hadoop.util.NativeCodeLoader; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import com.google.common.base.Splitter; +import com.google.common.collect.Lists; + +@RunWith(Parameterized.class) +public class KVTest { + private static final Log LOG = LogFactory.getLog(KVTest.class); + + private static Configuration nativekvtestconf = ScenarioConfiguration.getNativeConfiguration(); + private static Configuration hadoopkvtestconf = ScenarioConfiguration.getNormalConfiguration(); + static { + nativekvtestconf.addResource(TestConstants.KVTEST_CONF_PATH); + hadoopkvtestconf.addResource(TestConstants.KVTEST_CONF_PATH); + } + + private static List> parseClassNames(String spec) { + List> ret = Lists.newArrayList(); + Iterable classNames = Splitter.on(';').trimResults() + .omitEmptyStrings().split(spec); + for (String className : classNames) { + try { + ret.add(Class.forName(className)); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + return ret; + } + + /** + * Parameterize the test with the specified key and value types. + */ + @Parameters(name = "key:{0}\nvalue:{1}") + public static Iterable[]> data() throws Exception { + // Parse the config. + final String valueClassesStr = nativekvtestconf + .get(TestConstants.NATIVETASK_KVTEST_VALUECLASSES); + LOG.info("Parameterizing with value classes: " + valueClassesStr); + List> valueClasses = parseClassNames(valueClassesStr); + + final String keyClassesStr = nativekvtestconf.get( + TestConstants.NATIVETASK_KVTEST_KEYCLASSES); + LOG.info("Parameterizing with key classes: " + keyClassesStr); + List> keyClasses = parseClassNames(keyClassesStr); + + // Generate an entry for each key type. + List[]> pairs = Lists.newArrayList(); + for (Class keyClass : keyClasses) { + pairs.add(new Class[]{ keyClass, LongWritable.class }); + } + // ...and for each value type. + for (Class valueClass : valueClasses) { + pairs.add(new Class[]{ LongWritable.class, valueClass }); + } + return pairs; + } + + private final Class keyclass; + private final Class valueclass; + + public KVTest(Class keyclass, Class valueclass) { + this.keyclass = keyclass; + this.valueclass = valueclass; + } + + @Before + public void startUp() throws Exception { + Assume.assumeTrue(NativeCodeLoader.isNativeCodeLoaded()); + Assume.assumeTrue(NativeRuntime.isNativeLibraryLoaded()); + } + + @Test + public void testKVCompability() throws Exception { + final FileSystem fs = FileSystem.get(nativekvtestconf); + final String jobName = "Test:" + keyclass.getSimpleName() + "--" + + valueclass.getSimpleName(); + final String inputPath = TestConstants.NATIVETASK_KVTEST_INPUTDIR + "/" + + keyclass.getName() + "/" + valueclass.getName(); + final String nativeOutputPath = TestConstants.NATIVETASK_KVTEST_NATIVE_OUTPUTDIR + + "/" + keyclass.getName() + "/" + valueclass.getName(); + // if output file exists ,then delete it + fs.delete(new Path(nativeOutputPath), true); + nativekvtestconf.set(TestConstants.NATIVETASK_KVTEST_CREATEFILE, "true"); + final KVJob nativeJob = new KVJob(jobName, nativekvtestconf, keyclass, + valueclass, inputPath, nativeOutputPath); + assertTrue("job should complete successfully", nativeJob.runJob()); + + final String normalOutputPath = TestConstants.NATIVETASK_KVTEST_NORMAL_OUTPUTDIR + + "/" + keyclass.getName() + "/" + valueclass.getName(); + // if output file exists ,then delete it + fs.delete(new Path(normalOutputPath), true); + hadoopkvtestconf.set(TestConstants.NATIVETASK_KVTEST_CREATEFILE, "false"); + final KVJob normalJob = new KVJob(jobName, hadoopkvtestconf, keyclass, + valueclass, inputPath, normalOutputPath); + assertTrue("job should complete successfully", normalJob.runJob()); + + final boolean compareRet = ResultVerifier.verify(normalOutputPath, + nativeOutputPath); + assertEquals("job output not the same", true, compareRet); + ResultVerifier.verifyCounters(normalJob.job, nativeJob.job); + fs.close(); + } + + @AfterClass + public static void cleanUp() throws IOException { + final FileSystem fs = FileSystem.get(new ScenarioConfiguration()); + fs.delete(new Path(TestConstants.NATIVETASK_KVTEST_DIR), true); + fs.close(); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/LargeKVTest.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/LargeKVTest.java new file mode 100644 index 00000000000..5f1619e20c5 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/LargeKVTest.java @@ -0,0 +1,131 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.kvtest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapred.nativetask.NativeRuntime; +import org.apache.hadoop.mapred.nativetask.testutil.ResultVerifier; +import org.apache.hadoop.mapred.nativetask.testutil.ScenarioConfiguration; +import org.apache.hadoop.mapred.nativetask.testutil.TestConstants; +import org.junit.AfterClass; +import org.apache.hadoop.util.NativeCodeLoader; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +public class LargeKVTest { + private static final Log LOG = LogFactory.getLog(LargeKVTest.class); + + @Before + public void startUp() throws Exception { + Assume.assumeTrue(NativeCodeLoader.isNativeCodeLoaded()); + Assume.assumeTrue(NativeRuntime.isNativeLibraryLoaded()); + } + + private static Configuration nativeConf = ScenarioConfiguration.getNativeConfiguration(); + private static Configuration normalConf = ScenarioConfiguration.getNormalConfiguration(); + static { + nativeConf.addResource(TestConstants.KVTEST_CONF_PATH); + nativeConf.set(TestConstants.NATIVETASK_KVTEST_CREATEFILE, "true"); + normalConf.addResource(TestConstants.KVTEST_CONF_PATH); + normalConf.set(TestConstants.NATIVETASK_KVTEST_CREATEFILE, "false"); + } + + @Test + public void testKeySize() throws Exception { + runKVSizeTests(Text.class, IntWritable.class); + } + + @Test + public void testValueSize() throws Exception { + runKVSizeTests(IntWritable.class, Text.class); + } + + @AfterClass + public static void cleanUp() throws IOException { + final FileSystem fs = FileSystem.get(new ScenarioConfiguration()); + fs.delete(new Path(TestConstants.NATIVETASK_KVTEST_DIR), true); + fs.close(); + } + + public void runKVSizeTests(Class keyClass, Class valueClass) throws Exception { + if (!keyClass.equals(Text.class) && !valueClass.equals(Text.class)) { + return; + } + final int deafultKVSizeMaximum = 1 << 22; // 4M + final int kvSizeMaximum = normalConf.getInt( + TestConstants.NATIVETASK_KVSIZE_MAX_LARGEKV_TEST, + deafultKVSizeMaximum); + final FileSystem fs = FileSystem.get(normalConf); + + for (int i = 65536; i <= kvSizeMaximum; i *= 4) { + int min = i / 4; + int max = i; + nativeConf.set(TestConstants.NATIVETASK_KVSIZE_MIN, String.valueOf(min)); + nativeConf.set(TestConstants.NATIVETASK_KVSIZE_MAX, String.valueOf(max)); + normalConf.set(TestConstants.NATIVETASK_KVSIZE_MIN, String.valueOf(min)); + normalConf.set(TestConstants.NATIVETASK_KVSIZE_MAX, String.valueOf(max)); + + LOG.info("===KV Size Test: min size: " + min + ", max size: " + max + + ", keyClass: " + keyClass.getName() + ", valueClass: " + + valueClass.getName()); + + final String inputPath = TestConstants.NATIVETASK_KVTEST_INPUTDIR + + "/LargeKV/" + keyClass.getName() + "/" + valueClass.getName(); + + final String nativeOutputPath = TestConstants.NATIVETASK_KVTEST_NATIVE_OUTPUTDIR + + "/LargeKV/" + keyClass.getName() + "/" + valueClass.getName(); + // if output file exists ,then delete it + fs.delete(new Path(nativeOutputPath), true); + final KVJob nativeJob = new KVJob("Test Large Value Size:" + + String.valueOf(i), nativeConf, keyClass, valueClass, inputPath, + nativeOutputPath); + assertTrue("job should complete successfully", nativeJob.runJob()); + + final String normalOutputPath = TestConstants.NATIVETASK_KVTEST_NORMAL_OUTPUTDIR + + "/LargeKV/" + keyClass.getName() + "/" + valueClass.getName(); + // if output file exists ,then delete it + fs.delete(new Path(normalOutputPath), true); + final KVJob normalJob = new KVJob("Test Large Key Size:" + String.valueOf(i), + normalConf, keyClass, valueClass, inputPath, normalOutputPath); + assertTrue("job should complete successfully", normalJob.runJob()); + + final boolean compareRet = ResultVerifier.verify(normalOutputPath, + nativeOutputPath); + final String reason = "keytype: " + keyClass.getName() + ", valuetype: " + + valueClass.getName() + ", failed with " + + (keyClass.equals(Text.class) ? "key" : "value") + ", min size: " + min + + ", max size: " + max + ", normal out: " + normalOutputPath + + ", native Out: " + nativeOutputPath; + assertEquals(reason, true, compareRet); + ResultVerifier.verifyCounters(normalJob.job, nativeJob.job); + } + fs.close(); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/TestInputFile.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/TestInputFile.java new file mode 100644 index 00000000000..04db67abe67 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/kvtest/TestInputFile.java @@ -0,0 +1,227 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.kvtest; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Random; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.BooleanWritable; +import org.apache.hadoop.io.ByteWritable; +import org.apache.hadoop.io.DoubleWritable; +import org.apache.hadoop.io.FloatWritable; +import org.apache.hadoop.io.IOUtils; +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.SequenceFile; +import org.apache.hadoop.io.VIntWritable; +import org.apache.hadoop.io.VLongWritable; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapred.nativetask.testutil.BytesFactory; +import org.apache.hadoop.mapred.nativetask.testutil.ScenarioConfiguration; +import org.apache.hadoop.mapred.nativetask.testutil.TestConstants; + + +public class TestInputFile { + private static Log LOG = LogFactory.getLog(TestInputFile.class); + + public static class KVSizeScope { + private static final int DefaultMinNum = 1; + private static final int DefaultMaxNum = 64; + + public int minBytesNum; + public int maxBytesNum; + + public KVSizeScope() { + this.minBytesNum = DefaultMinNum; + this.maxBytesNum = DefaultMaxNum; + } + + public KVSizeScope(int min, int max) { + this.minBytesNum = min; + this.maxBytesNum = max; + } + } + + private static HashMap map = new HashMap(); + + private byte[] databuf = null; + private final String keyClsName, valueClsName; + private int filesize = 0; + private int keyMaxBytesNum, keyMinBytesNum; + private int valueMaxBytesNum, valueMinBytesNum; + private SequenceFile.Writer writer = null; + Random r = new Random(); + public static final int DATABUFSIZE = 1 << 22; // 4M + + private enum State { + KEY, VALUE + }; + + static { + map.put(BooleanWritable.class.getName(), new KVSizeScope(1, 1)); + map.put(DoubleWritable.class.getName(), new KVSizeScope(8, 8)); + map.put(FloatWritable.class.getName(), new KVSizeScope(4, 4)); + map.put(VLongWritable.class.getName(), new KVSizeScope(8, 8)); + map.put(ByteWritable.class.getName(), new KVSizeScope(1, 1)); + map.put(LongWritable.class.getName(), new KVSizeScope(8, 8)); + map.put(VIntWritable.class.getName(), new KVSizeScope(4, 4)); + map.put(IntWritable.class.getName(), new KVSizeScope(4, 4)); + } + + public TestInputFile(int filesize, String keytype, String valuetype, + Configuration conf) throws Exception { + this.filesize = filesize; + this.databuf = new byte[DATABUFSIZE]; + this.keyClsName = keytype; + this.valueClsName = valuetype; + final int defaultMinBytes = conf.getInt(TestConstants.NATIVETASK_KVSIZE_MIN, 1); + final int defaultMaxBytes = conf.getInt(TestConstants.NATIVETASK_KVSIZE_MAX, 64); + + if (map.get(keytype) != null) { + keyMinBytesNum = map.get(keytype).minBytesNum; + keyMaxBytesNum = map.get(keytype).maxBytesNum; + } else { + keyMinBytesNum = defaultMinBytes; + keyMaxBytesNum = defaultMaxBytes; + } + + if (map.get(valuetype) != null) { + valueMinBytesNum = map.get(valuetype).minBytesNum; + valueMaxBytesNum = map.get(valuetype).maxBytesNum; + } else { + valueMinBytesNum = defaultMinBytes; + valueMaxBytesNum = defaultMaxBytes; + } + } + + public void createSequenceTestFile(String filepath) throws Exception { + int FULL_BYTE_SPACE = 256; + createSequenceTestFile(filepath, FULL_BYTE_SPACE); + } + + public void createSequenceTestFile(String filepath, int base) throws Exception { + createSequenceTestFile(filepath, base, (byte)0); + } + + public void createSequenceTestFile(String filepath, int base, byte start) throws Exception { + LOG.info("creating file " + filepath + "(" + filesize + " bytes)"); + LOG.info(keyClsName + " " + valueClsName); + Class tmpkeycls, tmpvaluecls; + try { + tmpkeycls = Class.forName(keyClsName); + } catch (final ClassNotFoundException e) { + throw new Exception("key class not found: ", e); + } + try { + tmpvaluecls = Class.forName(valueClsName); + } catch (final ClassNotFoundException e) { + throw new Exception("key class not found: ", e); + } + try { + final Path outputfilepath = new Path(filepath); + final ScenarioConfiguration conf= new ScenarioConfiguration(); + writer = SequenceFile.createWriter( + conf, + SequenceFile.Writer.file(outputfilepath), + SequenceFile.Writer.keyClass(tmpkeycls), + SequenceFile.Writer.valueClass(tmpvaluecls)); + } catch (final Exception e) { + e.printStackTrace(); + } + + int tmpfilesize = this.filesize; + while (tmpfilesize > DATABUFSIZE) { + nextRandomBytes(databuf, base, start); + final int size = flushBuf(DATABUFSIZE); + tmpfilesize -= size; + } + nextRandomBytes(databuf, base, start); + flushBuf(tmpfilesize); + + if (writer != null) { + IOUtils.closeStream(writer); + } else { + throw new Exception("no writer to create sequenceTestFile!"); + } + } + + private void nextRandomBytes(byte[] buf, int base) { + nextRandomBytes(buf, base, (byte)0); + } + + private void nextRandomBytes(byte[] buf, int base, byte start) { + r.nextBytes(buf); + for (int i = 0; i < buf.length; i++) { + buf[i] = (byte) ((buf[i] & 0xFF) % base + start); + } + } + + private int flushBuf(int buflen) throws Exception { + final Random r = new Random(); + int keybytesnum = 0; + int valuebytesnum = 0; + int offset = 0; + + Writable keyWritable = BytesFactory.newObject(null, keyClsName); + Writable valWritable = BytesFactory.newObject(null, valueClsName); + + while (offset < buflen) { + final int remains = buflen - offset; + keybytesnum = keyMaxBytesNum; + if (keyMaxBytesNum != keyMinBytesNum) { + keybytesnum = keyMinBytesNum + r.nextInt(keyMaxBytesNum - keyMinBytesNum); + } + + valuebytesnum = valueMaxBytesNum; + if (valueMaxBytesNum != valueMinBytesNum) { + valuebytesnum = valueMinBytesNum + r.nextInt(valueMaxBytesNum - valueMinBytesNum); + } + + if (keybytesnum + valuebytesnum > remains) { + break; + } + + final byte[] key = new byte[keybytesnum]; + final byte[] value = new byte[valuebytesnum]; + + System.arraycopy(databuf, offset, key, 0, keybytesnum); + offset += keybytesnum; + + System.arraycopy(databuf, offset, value, 0, valuebytesnum); + offset += valuebytesnum; + + BytesFactory.updateObject(keyWritable, key); + BytesFactory.updateObject(valWritable, value); + + try { + writer.append(keyWritable, valWritable); + } catch (final IOException e) { + e.printStackTrace(); + throw new Exception("sequence file create failed", e); + } + } + return offset; + } + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/nonsorttest/NonSortTest.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/nonsorttest/NonSortTest.java new file mode 100644 index 00000000000..81e1eaed183 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/nonsorttest/NonSortTest.java @@ -0,0 +1,118 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.nonsorttest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapred.nativetask.NativeRuntime; +import org.apache.hadoop.mapred.nativetask.kvtest.TestInputFile; +import org.apache.hadoop.mapred.nativetask.testutil.ResultVerifier; +import org.apache.hadoop.mapred.nativetask.testutil.ScenarioConfiguration; +import org.apache.hadoop.mapred.nativetask.testutil.TestConstants; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.lib.input.FileInputFormat; +import org.apache.hadoop.mapreduce.lib.input.SequenceFileInputFormat; +import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; +import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; +import org.junit.AfterClass; +import org.apache.hadoop.util.NativeCodeLoader; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +public class NonSortTest { + + @Test + public void nonSortTest() throws Exception { + Configuration nativeConf = ScenarioConfiguration.getNativeConfiguration(); + nativeConf.addResource(TestConstants.NONSORT_TEST_CONF); + nativeConf.set(TestConstants.NATIVETASK_MAP_OUTPUT_SORT, "false"); + final Job nativeNonSort = getJob(nativeConf, "NativeNonSort", + TestConstants.NATIVETASK_NONSORT_TEST_INPUTDIR, + TestConstants.NATIVETASK_NONSORT_TEST_NATIVE_OUTPUT); + assertTrue(nativeNonSort.waitForCompletion(true)); + + Configuration normalConf = ScenarioConfiguration.getNormalConfiguration(); + normalConf.addResource(TestConstants.NONSORT_TEST_CONF); + final Job hadoopWithSort = getJob(normalConf, "NormalJob", + TestConstants.NATIVETASK_NONSORT_TEST_INPUTDIR, + TestConstants.NATIVETASK_NONSORT_TEST_NORMAL_OUTPUT); + assertTrue(hadoopWithSort.waitForCompletion(true)); + + final boolean compareRet = ResultVerifier.verify( + TestConstants.NATIVETASK_NONSORT_TEST_NATIVE_OUTPUT, + TestConstants.NATIVETASK_NONSORT_TEST_NORMAL_OUTPUT); + assertEquals("file compare result: if they are the same ,then return true", true, compareRet); + ResultVerifier.verifyCounters(hadoopWithSort, nativeNonSort); + } + + @Before + public void startUp() throws Exception { + Assume.assumeTrue(NativeCodeLoader.isNativeCodeLoaded()); + Assume.assumeTrue(NativeRuntime.isNativeLibraryLoaded()); + final ScenarioConfiguration conf = new ScenarioConfiguration(); + conf.addNonSortTestConf(); + final FileSystem fs = FileSystem.get(conf); + final Path path = new Path(TestConstants.NATIVETASK_NONSORT_TEST_INPUTDIR); + if (!fs.exists(path)) { + int filesize = conf.getInt(TestConstants.NATIVETASK_NONSORTTEST_FILESIZE, 10000000); + new TestInputFile(filesize, Text.class.getName(), + Text.class.getName(), conf).createSequenceTestFile(path.toString()); + } + fs.close(); + } + + @AfterClass + public static void cleanUp() throws IOException { + final FileSystem fs = FileSystem.get(new ScenarioConfiguration()); + fs.delete(new Path(TestConstants.NATIVETASK_NONSORT_TEST_DIR), true); + fs.close(); + } + + + private Job getJob(Configuration conf, String jobName, + String inputpath, String outputpath) throws IOException { + final FileSystem fs = FileSystem.get(conf); + if (fs.exists(new Path(outputpath))) { + fs.delete(new Path(outputpath), true); + } + fs.close(); + final Job job = Job.getInstance(conf, jobName); + job.setJarByClass(NonSortTestMR.class); + job.setMapperClass(NonSortTestMR.Map.class); + job.setReducerClass(NonSortTestMR.KeyHashSumReduce.class); + job.setOutputKeyClass(Text.class); + job.setMapOutputValueClass(IntWritable.class); + job.setOutputValueClass(LongWritable.class); + job.setInputFormatClass(SequenceFileInputFormat.class); + job.setOutputFormatClass(TextOutputFormat.class); + FileInputFormat.addInputPath(job, new Path(inputpath)); + FileOutputFormat.setOutputPath(job, new Path(outputpath)); + return job; + } + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/nonsorttest/NonSortTestMR.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/nonsorttest/NonSortTestMR.java new file mode 100644 index 00000000000..4092e5f284b --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/nonsorttest/NonSortTestMR.java @@ -0,0 +1,72 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.nonsorttest; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.StringTokenizer; + +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.mapreduce.Mapper; +import org.apache.hadoop.mapreduce.Reducer; + +public class NonSortTestMR { + + public static class Map extends Mapper { + private final static IntWritable one = new IntWritable(1); + private final Text word = new Text(); + + @Override + public void map(Object key, Text value, Context context) + throws IOException, InterruptedException { + final String line = value.toString(); + final StringTokenizer tokenizer = new StringTokenizer(line); + while (tokenizer.hasMoreTokens()) { + word.set(tokenizer.nextToken()); + context.write(word, one); + } + } + } + + public static class KeyHashSumReduce extends Reducer { + long sum = 0; + ByteArrayOutputStream os = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(os); + + @Override + public void reduce(Text key, Iterable values, Context context) throws IOException, + InterruptedException { + for (final IntWritable val : values) { + os.reset(); + key.write(dos); + final int hash = Arrays.hashCode(os.toByteArray()); + sum += hash; + } + } + + @Override + public void cleanup(Context context) throws IOException, InterruptedException { + context.write(new Text("NonSortTest"), new LongWritable(sum)); + } + } + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/serde/TestKVSerializer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/serde/TestKVSerializer.java new file mode 100644 index 00000000000..fd5b100c412 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/serde/TestKVSerializer.java @@ -0,0 +1,148 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import junit.framework.TestCase; + +import org.apache.hadoop.io.BytesWritable; +import org.apache.hadoop.mapred.nativetask.Constants; +import org.apache.hadoop.mapred.nativetask.buffer.DataInputStream; +import org.apache.hadoop.mapred.nativetask.buffer.DataOutputStream; +import org.apache.hadoop.mapred.nativetask.testutil.TestInput; +import org.apache.hadoop.mapred.nativetask.testutil.TestInput.KV; +import org.apache.hadoop.mapred.nativetask.util.SizedWritable; +import org.junit.Assert; +import org.junit.Before; +import org.mockito.Matchers; +import org.mockito.Mockito; + +@SuppressWarnings({ "rawtypes", "unchecked" }) +public class TestKVSerializer extends TestCase { + + int inputArraySize = 1000; // 1000 bytesWriable elements + int bufferSize = 100; // bytes + private KV[] inputArray; + + final ByteArrayOutputStream result = new ByteArrayOutputStream(); + private SizedWritable key; + private SizedWritable value; + private KVSerializer serializer; + + @Override + @Before + public void setUp() throws IOException { + this.inputArray = TestInput.getMapInputs(inputArraySize); + this.key = new SizedWritable(BytesWritable.class); + this.value = new SizedWritable(BytesWritable.class); + + this.serializer = new KVSerializer(BytesWritable.class, BytesWritable.class); + + key.reset(inputArray[4].key); + value.reset(inputArray[4].value); + serializer.updateLength(key, value); + } + + public void testUpdateLength() throws IOException { + Mockito.mock(DataOutputStream.class); + + int kvLength = 0; + for (int i = 0; i < inputArraySize; i++) { + key.reset(inputArray[i].key); + value.reset(inputArray[i].value); + serializer.updateLength(key, value); + + // verify whether the size increase + Assert.assertTrue(key.length + value.length > kvLength); + kvLength = key.length + value.length; + } + } + + public void testSerializeKV() throws IOException { + final DataOutputStream dataOut = Mockito.mock(DataOutputStream.class); + + Mockito.when(dataOut.hasUnFlushedData()).thenReturn(true); + Mockito.when(dataOut.shortOfSpace(key.length + value.length + + Constants.SIZEOF_KV_LENGTH)).thenReturn(true); + final int written = serializer.serializeKV(dataOut, key, value); + + // flush once, write 4 int, and 2 byte array + Mockito.verify(dataOut, Mockito.times(1)).flush(); + Mockito.verify(dataOut, Mockito.times(4)).writeInt(Matchers.anyInt()); + Mockito.verify(dataOut, Mockito.times(2)).write(Matchers.any(byte[].class), + Matchers.anyInt(), Matchers.anyInt()); + + Assert.assertEquals(written, key.length + value.length + Constants.SIZEOF_KV_LENGTH); + } + + public void testSerializeNoFlush() throws IOException { + final DataOutputStream dataOut = Mockito.mock(DataOutputStream.class); + + // suppose there are enough space + Mockito.when(dataOut.hasUnFlushedData()).thenReturn(true); + Mockito.when(dataOut.shortOfSpace(Matchers.anyInt())).thenReturn(false); + final int written = serializer.serializeKV(dataOut, key, value); + + // flush 0, write 4 int, and 2 byte array + Mockito.verify(dataOut, Mockito.times(0)).flush(); + Mockito.verify(dataOut, Mockito.times(4)).writeInt(Matchers.anyInt()); + Mockito.verify(dataOut, Mockito.times(2)).write(Matchers.any(byte[].class), + Matchers.anyInt(), Matchers.anyInt()); + + Assert.assertEquals(written, key.length + value.length + Constants.SIZEOF_KV_LENGTH); + } + + public void testSerializePartitionKV() throws IOException { + final DataOutputStream dataOut = Mockito.mock(DataOutputStream.class); + + Mockito.when(dataOut.hasUnFlushedData()).thenReturn(true); + Mockito.when( + dataOut + .shortOfSpace(key.length + value.length + + Constants.SIZEOF_KV_LENGTH + Constants.SIZEOF_PARTITION_LENGTH)) + .thenReturn(true); + final int written = serializer.serializePartitionKV(dataOut, 100, key, value); + + // flush once, write 4 int, and 2 byte array + Mockito.verify(dataOut, Mockito.times(1)).flush(); + Mockito.verify(dataOut, Mockito.times(5)).writeInt(Matchers.anyInt()); + Mockito.verify(dataOut, Mockito.times(2)).write(Matchers.any(byte[].class), + Matchers.anyInt(), Matchers.anyInt()); + + Assert.assertEquals(written, key.length + value.length + Constants.SIZEOF_KV_LENGTH + + Constants.SIZEOF_PARTITION_LENGTH); + } + + public void testDeserializerNoData() throws IOException { + final DataInputStream in = Mockito.mock(DataInputStream.class); + Mockito.when(in.hasUnReadData()).thenReturn(false); + Assert.assertEquals(0, serializer.deserializeKV(in, key, value)); + } + + public void testDeserializer() throws IOException { + final DataInputStream in = Mockito.mock(DataInputStream.class); + Mockito.when(in.hasUnReadData()).thenReturn(true); + Assert.assertTrue(serializer.deserializeKV(in, key, value) > 0); + + Mockito.verify(in, Mockito.times(4)).readInt(); + Mockito.verify(in, Mockito.times(2)).readFully(Matchers.any(byte[].class), + Matchers.anyInt(), Matchers.anyInt()); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/serde/TestNativeSerialization.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/serde/TestNativeSerialization.java new file mode 100644 index 00000000000..5666cc36c64 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/serde/TestNativeSerialization.java @@ -0,0 +1,114 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.serde; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapred.nativetask.INativeComparable; +import org.junit.Assert; +import org.junit.Test; + +@SuppressWarnings({ "rawtypes" }) +public class TestNativeSerialization { + @Test + public void testRegisterAndGet() throws IOException { + final NativeSerialization serialization = NativeSerialization.getInstance(); + serialization.reset(); + + serialization.register(WritableKey.class.getName(), ComparableKeySerializer.class); + + INativeSerializer serializer = serialization.getSerializer(WritableKey.class); + Assert.assertEquals(ComparableKeySerializer.class.getName(), serializer.getClass().getName()); + + serializer = serialization.getSerializer(WritableValue.class); + Assert.assertEquals(DefaultSerializer.class.getName(), serializer.getClass().getName()); + + boolean ioExceptionThrown = false; + try { + serializer = serialization.getSerializer(NonWritableValue.class); + } catch (final IOException e) { + ioExceptionThrown = true; + } + Assert.assertTrue(ioExceptionThrown); + } + + public static class WritableKey implements Writable { + private int value; + + public WritableKey(int a) { + this.value = a; + } + + public int getLength() { + return 4; + } + + public int getValue() { + return value; + } + + public void setValue(int v) { + this.value = v; + } + + @Override + public void write(DataOutput out) throws IOException { + + } + + @Override + public void readFields(DataInput in) throws IOException { + } + } + + public static class WritableValue implements Writable { + + @Override + public void write(DataOutput out) throws IOException { + } + + @Override + public void readFields(DataInput in) throws IOException { + } + } + + public static class NonWritableValue { + } + + public static class ComparableKeySerializer + implements INativeComparable, INativeSerializer { + + @Override + public int getLength(WritableKey w) throws IOException { + return w.getLength(); + } + + @Override + public void serialize(WritableKey w, DataOutput out) throws IOException { + out.writeInt(w.getValue()); + } + + @Override + public void deserialize(DataInput in, int length, WritableKey w) throws IOException { + w.setValue(in.readInt()); + } + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/BytesFactory.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/BytesFactory.java new file mode 100644 index 00000000000..4df48fc867e --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/BytesFactory.java @@ -0,0 +1,121 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.testutil; + +import java.util.Random; + +import com.google.common.base.Preconditions; +import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; + +import org.apache.hadoop.io.BooleanWritable; +import org.apache.hadoop.io.ByteWritable; +import org.apache.hadoop.io.BytesWritable; +import org.apache.hadoop.io.DoubleWritable; +import org.apache.hadoop.io.FloatWritable; +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.io.UTF8; +import org.apache.hadoop.io.VIntWritable; +import org.apache.hadoop.io.VLongWritable; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapred.nativetask.util.BytesUtil; + +@SuppressWarnings("deprecation") +public class BytesFactory { + public static Random r = new Random(); + + public static void updateObject(Writable obj, byte[] seed) { + if (obj instanceof IntWritable) { + ((IntWritable)obj).set(Ints.fromByteArray(seed)); + } else if (obj instanceof FloatWritable) { + ((FloatWritable)obj).set(r.nextFloat()); + } else if (obj instanceof DoubleWritable) { + ((DoubleWritable)obj).set(r.nextDouble()); + } else if (obj instanceof LongWritable) { + ((LongWritable)obj).set(Longs.fromByteArray(seed)); + } else if (obj instanceof VIntWritable) { + ((VIntWritable)obj).set(Ints.fromByteArray(seed)); + } else if (obj instanceof VLongWritable) { + ((VLongWritable)obj).set(Longs.fromByteArray(seed)); + } else if (obj instanceof BooleanWritable) { + ((BooleanWritable)obj).set(seed[0] % 2 == 1 ? true : false); + } else if (obj instanceof Text) { + ((Text)obj).set(BytesUtil.toStringBinary(seed)); + } else if (obj instanceof ByteWritable) { + ((ByteWritable)obj).set(seed.length > 0 ? seed[0] : 0); + } else if (obj instanceof BytesWritable) { + ((BytesWritable)obj).set(seed, 0, seed.length); + } else if (obj instanceof UTF8) { + ((UTF8)obj).set(BytesUtil.toStringBinary(seed)); + } else if (obj instanceof MockValueClass) { + ((MockValueClass)obj).set(seed); + } else { + throw new IllegalArgumentException("unknown writable: " + + obj.getClass().getName()); + } + } + + public static Writable newObject(byte[] seed, String className) { + Writable ret; + try { + Class clazz = Class.forName(className); + Preconditions.checkArgument(Writable.class.isAssignableFrom(clazz)); + ret = (Writable)clazz.newInstance(); + } catch (Exception e) { + throw new RuntimeException(e); + } + if (seed != null) { + updateObject(ret, seed); + } + return ret; + } + + public static byte[] fromBytes(byte[] bytes) throws Exception { + throw new Exception("Not supported"); + } + + public static byte[] toBytes(VTYPE obj) { + final String className = obj.getClass().getName(); + if (className.equals(IntWritable.class.getName())) { + return Ints.toByteArray(((IntWritable) obj).get()); + } else if (className.equals(FloatWritable.class.getName())) { + return BytesUtil.toBytes(((FloatWritable) obj).get()); + } else if (className.equals(DoubleWritable.class.getName())) { + return BytesUtil.toBytes(((DoubleWritable) obj).get()); + } else if (className.equals(LongWritable.class.getName())) { + return Longs.toByteArray(((LongWritable) obj).get()); + } else if (className.equals(VIntWritable.class.getName())) { + return Ints.toByteArray(((VIntWritable) obj).get()); + } else if (className.equals(VLongWritable.class.getName())) { + return Longs.toByteArray(((VLongWritable) obj).get()); + } else if (className.equals(BooleanWritable.class.getName())) { + return BytesUtil.toBytes(((BooleanWritable) obj).get()); + } else if (className.equals(Text.class.getName())) { + return ((Text)obj).copyBytes(); + } else if (className.equals(ByteWritable.class.getName())) { + return Ints.toByteArray((int) ((ByteWritable) obj).get()); + } else if (className.equals(BytesWritable.class.getName())) { + // TODO: copyBytes instead? + return ((BytesWritable) obj).getBytes(); + } else { + return new byte[0]; + } + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/EnforceNativeOutputCollectorDelegator.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/EnforceNativeOutputCollectorDelegator.java new file mode 100644 index 00000000000..7212236ad6e --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/EnforceNativeOutputCollectorDelegator.java @@ -0,0 +1,51 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.testutil; + +import java.io.IOException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.mapred.nativetask.NativeMapOutputCollectorDelegator; + +public class EnforceNativeOutputCollectorDelegator + extends NativeMapOutputCollectorDelegator { + private static final Log LOG = LogFactory.getLog(EnforceNativeOutputCollectorDelegator.class); + private boolean nativetaskloaded = false; + + @Override + public void init(Context context) + throws IOException, ClassNotFoundException { + try { + super.init(context); + nativetaskloaded = true; + } catch (final Exception e) { + nativetaskloaded = false; + LOG.error("load nativetask lib failed, Native-Task Delegation is disabled", e); + } + } + + @Override + public void collect(K key, V value, int partition) throws IOException, InterruptedException { + if (this.nativetaskloaded) { + super.collect(key, value, partition); + } else { + // nothing to do. + } + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/MockValueClass.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/MockValueClass.java new file mode 100644 index 00000000000..a476a2d06b6 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/MockValueClass.java @@ -0,0 +1,80 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.testutil; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.Random; + +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.Text; +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapred.nativetask.util.BytesUtil; + +public class MockValueClass implements Writable { + private final static int DEFAULT_ARRAY_LENGTH = 16; + private int a = 0; + private byte[] array; + private final LongWritable longWritable; + private final Text txt; + private final Random rand = new Random(); + + public MockValueClass() { + a = rand.nextInt(); + array = new byte[DEFAULT_ARRAY_LENGTH]; + rand.nextBytes(array); + longWritable = new LongWritable(rand.nextLong()); + txt = new Text(BytesUtil.toStringBinary(array)); + } + + public MockValueClass(byte[] seed) { + a = seed.length; + array = new byte[seed.length]; + System.arraycopy(seed, 0, array, 0, seed.length); + longWritable = new LongWritable(a); + txt = new Text(BytesUtil.toStringBinary(array)); + } + + public void set(byte[] seed) { + a = seed.length; + array = new byte[seed.length]; + System.arraycopy(seed, 0, array, 0, seed.length); + longWritable.set(a); + txt.set(BytesUtil.toStringBinary(array)); + } + + @Override + public void write(DataOutput out) throws IOException { + out.writeInt(a); + out.writeInt(array.length); + out.write(array); + longWritable.write(out); + txt.write(out); + } + + @Override + public void readFields(DataInput in) throws IOException { + a = in.readInt(); + final int length = in.readInt(); + array = new byte[length]; + in.readFully(array); + longWritable.readFields(in); + txt.readFields(in); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/ResultVerifier.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/ResultVerifier.java new file mode 100644 index 00000000000..5749691b4b4 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/ResultVerifier.java @@ -0,0 +1,162 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.testutil; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.zip.CRC32; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.FSDataInputStream; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.FileUtil; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.mapreduce.Counters; +import org.apache.hadoop.mapreduce.Job; +import org.apache.hadoop.mapreduce.TaskCounter; + +public class ResultVerifier { + /** + * verify the result + * + * @param sample the path to correct results + * @param source the path to the results from the native implementation + */ + public static boolean verify(String sample, String source) throws Exception { + FSDataInputStream sourcein = null; + FSDataInputStream samplein = null; + + final Configuration conf = new Configuration(); + final FileSystem fs = FileSystem.get(conf); + final Path hdfssource = new Path(source); + final Path[] sourcepaths = FileUtil.stat2Paths(fs.listStatus(hdfssource)); + + final Path hdfssample = new Path(sample); + final Path[] samplepaths = FileUtil.stat2Paths(fs.listStatus(hdfssample)); + if (sourcepaths == null) { + throw new Exception("source file can not be found"); + } + if (samplepaths == null) { + throw new Exception("sample file can not be found"); + } + if (sourcepaths.length != samplepaths.length) { + return false; + } + for (int i = 0; i < sourcepaths.length; i++) { + final Path sourcepath = sourcepaths[i]; + // op result file start with "part-r" like part-r-00000 + + if (!sourcepath.getName().startsWith("part-r")) { + continue; + } + Path samplepath = null; + for (int j = 0; j < samplepaths.length; j++) { + if (samplepaths[i].getName().equals(sourcepath.getName())) { + samplepath = samplepaths[i]; + break; + } + } + if (samplepath == null) { + throw new Exception("cound not find file " + + samplepaths[0].getParent() + "/" + sourcepath.getName() + + " , as sourcepaths has such file"); + } + + // compare + try { + if (fs.exists(sourcepath) && fs.exists(samplepath)) { + sourcein = fs.open(sourcepath); + samplein = fs.open(samplepath); + } else { + System.err.println("result file not found:" + sourcepath + " or " + samplepath); + return false; + } + + CRC32 sourcecrc, samplecrc; + samplecrc = new CRC32(); + sourcecrc = new CRC32(); + final byte[] bufin = new byte[1 << 16]; + int readnum = 0; + int totalRead = 0; + while (samplein.available() > 0) { + readnum = samplein.read(bufin); + totalRead += readnum; + samplecrc.update(bufin, 0, readnum); + } + + if (0 == totalRead) { + throw new Exception("source " + sample + " is empty file"); + } + + totalRead = 0; + while (sourcein.available() > 0) { + readnum = sourcein.read(bufin); + totalRead += readnum; + sourcecrc.update(bufin, 0, readnum); + } + if (0 == totalRead) { + throw new Exception("source " + sample + " is empty file"); + } + + if (samplecrc.getValue() == sourcecrc.getValue()) { + ; + } else { + return false; + } + } catch (final IOException e) { + throw new Exception("verify exception :", e); + } finally { + + try { + if (samplein != null) { + samplein.close(); + } + if (sourcein != null) { + sourcein.close(); + } + } catch (final IOException e) { + e.printStackTrace(); + } + + } + } + return true; + } + + public static void verifyCounters(Job normalJob, Job nativeJob, boolean hasCombiner) + throws IOException { + Counters normalCounters = normalJob.getCounters(); + Counters nativeCounters = nativeJob.getCounters(); + assertEquals("Counter MAP_OUTPUT_RECORDS should be equal", + normalCounters.findCounter(TaskCounter.MAP_OUTPUT_RECORDS).getValue(), + nativeCounters.findCounter(TaskCounter.MAP_OUTPUT_RECORDS).getValue()); + assertEquals("Counter REDUCE_INPUT_GROUPS should be equal", + normalCounters.findCounter(TaskCounter.REDUCE_INPUT_GROUPS).getValue(), + nativeCounters.findCounter(TaskCounter.REDUCE_INPUT_GROUPS).getValue()); + if (!hasCombiner) { + assertEquals("Counter REDUCE_INPUT_RECORDS should be equal", + normalCounters.findCounter(TaskCounter.REDUCE_INPUT_RECORDS).getValue(), + nativeCounters.findCounter(TaskCounter.REDUCE_INPUT_RECORDS).getValue()); + } + } + + public static void verifyCounters(Job normalJob, Job nativeJob) throws IOException { + verifyCounters(normalJob, nativeJob, false); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/ScenarioConfiguration.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/ScenarioConfiguration.java new file mode 100644 index 00000000000..9cc473d8f68 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/ScenarioConfiguration.java @@ -0,0 +1,58 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.testutil; + +import org.apache.hadoop.conf.Configuration; + +public class ScenarioConfiguration extends Configuration { + public ScenarioConfiguration() { + super(); + this.addResource(TestConstants.COMMON_CONF_PATH); + } + + public void addcombinerConf() { + this.addResource(TestConstants.COMBINER_CONF_PATH); + } + + public void addKVTestConf() { + this.addResource(TestConstants.KVTEST_CONF_PATH); + } + + public void addNonSortTestConf() { + this.addResource(TestConstants.NONSORT_TEST_CONF); + } + + public void addNativeConf() { + this.set(TestConstants.NATIVETASK_COLLECTOR_DELEGATOR, + TestConstants.NATIVETASK_COLLECTOR_DELEGATOR_CLASS); + } + + public static Configuration getNormalConfiguration() { + Configuration normalConf = new Configuration(); + normalConf.addResource("common_conf.xml"); + normalConf.addResource("normal_conf.xml"); + return normalConf; + } + + public static Configuration getNativeConfiguration() { + Configuration nativeConf = new Configuration(); + nativeConf.addResource("common_conf.xml"); + nativeConf.addResource("native_conf.xml"); + return nativeConf; + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/TestConstants.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/TestConstants.java new file mode 100644 index 00000000000..0b5a11717cd --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/TestConstants.java @@ -0,0 +1,71 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.testutil; + +public class TestConstants { + // conf path + public static final String COMMON_CONF_PATH = "common_conf.xml"; + public static final String COMBINER_CONF_PATH = "test-combiner-conf.xml"; + public static final String KVTEST_CONF_PATH = "kvtest-conf.xml"; + public static final String NONSORT_TEST_CONF = "test-nonsort-conf.xml"; + public static final String COMPRESS_TEST_CONF_PATH = "test-compress-conf.xml"; + + // common constants + public static final String NATIVETASK_TEST_DIR = System.getProperty("test.build.data", "target/test/data"); + public static final String NATIVETASK_COLLECTOR_DELEGATOR = "mapreduce.map.output.collector.delegator.class"; + public static final String NATIVETASK_COLLECTOR_DELEGATOR_CLASS = "org.apache.hadoop.mapred.nativetask.testutil.EnforceNativeOutputCollectorDelegator"; + public static final String NATIVETASK_KVSIZE_MIN = "nativetask.kvsize.min"; + public static final String NATIVETASK_KVSIZE_MAX = "nativetask.kvsize.max"; + public static final String NATIVETASK_KVSIZE_MAX_LARGEKV_TEST = "nativetask.kvsize.max.largekv"; + + // kv test + public static final String FILESIZE_KEY = "kvtest.file.size"; + public static final String NATIVETASK_KVTEST_DIR = NATIVETASK_TEST_DIR + "/kvtest"; + public static final String NATIVETASK_KVTEST_INPUTDIR = NATIVETASK_KVTEST_DIR + "/input"; + public static final String NATIVETASK_KVTEST_NATIVE_OUTPUTDIR = NATIVETASK_KVTEST_DIR + "/output/native"; + public static final String NATIVETASK_KVTEST_NORMAL_OUTPUTDIR = NATIVETASK_KVTEST_DIR + "/output/normal"; + public static final String NATIVETASK_KVTEST_CREATEFILE = "nativetask.kvtest.createfile"; + public static final String NATIVETASK_KVTEST_FILE_RECORDNUM = "nativetask.kvtest.file.recordnum"; + public static final String NATIVETASK_KVTEST_KEYCLASSES = "nativetask.kvtest.keyclasses"; + public static final String NATIVETASK_KVTEST_VALUECLASSES = "nativetask.kvtest.valueclasses"; + + // compress test + public static final String NATIVETASK_COMPRESS_FILESIZE = "nativetask.compress.filesize"; + public static final String NATIVETASK_COMPRESS_TEST_DIR = NATIVETASK_TEST_DIR + "/compresstest"; + public static final String NATIVETASK_COMPRESS_TEST_INPUTDIR = NATIVETASK_COMPRESS_TEST_DIR + "/input"; + public static final String NATIVETASK_COMPRESS_TEST_NATIVE_OUTPUTDIR = NATIVETASK_COMPRESS_TEST_DIR + "/output/native"; + public static final String NATIVETASK_COMPRESS_TEST_NORMAL_OUTPUTDIR = NATIVETASK_COMPRESS_TEST_DIR + "/output/normal"; + + // combiner test + public static final String NATIVETASK_COMBINER_TEST_DIR = NATIVETASK_TEST_DIR + "/combinertest"; + public static final String NATIVETASK_COMBINER_TEST_INPUTDIR = NATIVETASK_COMBINER_TEST_DIR + "/input"; + public static final String NATIVETASK_COMBINER_TEST_NATIVE_OUTPUTDIR = NATIVETASK_COMBINER_TEST_DIR + "/output/native"; + public static final String NATIVETASK_COMBINER_TEST_NORMAL_OUTPUTDIR = NATIVETASK_COMBINER_TEST_DIR + "/output/normal"; + public static final String NATIVETASK_OLDAPI_COMBINER_TEST_NATIVE_OUTPUTPATH = NATIVETASK_COMBINER_TEST_DIR + "/oldapi/output/native"; + public static final String NATIVETASK_OLDAPI_COMBINER_TEST_NORMAL_OUTPUTPATH = NATIVETASK_COMBINER_TEST_DIR + "/oldapi/output/normal"; + public static final String NATIVETASK_COMBINER_WORDCOUNT_FILESIZE = "nativetask.combiner.wordcount.filesize"; + public static final String NATIVETASK_NONSORTTEST_FILESIZE = "nativetask.nonsorttest.filesize"; + + // nonsort test + public static final String NATIVETASK_MAP_OUTPUT_SORT = "mapreduce.sort.avoidance"; + public static final String NATIVETASK_NONSORT_TEST_DIR = NATIVETASK_TEST_DIR + "/nonsorttest"; + public static final String NATIVETASK_NONSORT_TEST_INPUTDIR = NATIVETASK_NONSORT_TEST_DIR + "/input"; + public static final String NATIVETASK_NONSORT_TEST_NATIVE_OUTPUT = NATIVETASK_NONSORT_TEST_DIR + "/output/native"; + public static final String NATIVETASK_NONSORT_TEST_NORMAL_OUTPUT = NATIVETASK_NONSORT_TEST_DIR + "/output/normal"; + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/TestInput.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/TestInput.java new file mode 100644 index 00000000000..23fb1ef192f --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/testutil/TestInput.java @@ -0,0 +1,61 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.testutil; + +import java.util.Arrays; + +import org.apache.hadoop.io.BytesWritable; + +@SuppressWarnings({ "rawtypes", "unchecked" }) +public class TestInput { + + public static class KV { + public K key; + public V value; + } + + public static char[] CHAR_SET = new char[] { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', + 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', + 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '/' }; + + public static KV[] getMapInputs(int size) { + + final KV[] dataInput = new KV[size]; + + for (int i = 0; i < size; i++) { + dataInput[i] = getSingleMapInput(i); + } + return dataInput; + } + + private static KV getSingleMapInput(int i) { + final char character = CHAR_SET[i % CHAR_SET.length]; + final byte b = (byte) character; + + final byte[] bytes = new byte[i]; + Arrays.fill(bytes, b); + final BytesWritable result = new BytesWritable(bytes); + final KV kv = new KV(); + kv.key = result; + kv.value = result; + return kv; + } + +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/utils/TestBytesUtil.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/utils/TestBytesUtil.java new file mode 100644 index 00000000000..5bafa43c62f --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/utils/TestBytesUtil.java @@ -0,0 +1,69 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.utils; + +import com.google.common.primitives.Ints; +import com.google.common.primitives.Longs; + +import org.junit.Assert; +import org.junit.Test; + +import org.apache.hadoop.mapred.nativetask.util.BytesUtil; + +public class TestBytesUtil { + + @Test + public void testBytesIntConversion() { + final int a = 1000; + final byte[] intBytes = Ints.toByteArray(a); + + Assert.assertEquals(a, BytesUtil.toInt(intBytes, 0)); + } + + @Test + public void testBytesLongConversion() { + final long l = 1000000L; + final byte[] longBytes = Longs.toByteArray(l); + + Assert.assertEquals(l, BytesUtil.toLong(longBytes, 0)); + } + + @Test + public void testBytesFloatConversion() { + final float f = 3.14f; + final byte[] floatBytes = BytesUtil.toBytes(f); + + Assert.assertEquals(f, BytesUtil.toFloat(floatBytes), 0.0f); + } + + @Test + public void testBytesDoubleConversion() { + final double d = 3.14; + final byte[] doubleBytes = BytesUtil.toBytes(d); + + Assert.assertEquals(d, BytesUtil.toDouble(doubleBytes), 0.0); + } + + @Test + public void testToStringBinary() { + Assert.assertEquals("\\x01\\x02ABC", + BytesUtil.toStringBinary(new byte[] { 1, 2, 65, 66, 67 })); + Assert.assertEquals("\\x10\\x11", + BytesUtil.toStringBinary(new byte[] { 16, 17 })); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/utils/TestReadWriteBuffer.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/utils/TestReadWriteBuffer.java new file mode 100644 index 00000000000..6ea809249c5 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/utils/TestReadWriteBuffer.java @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.utils; + +import junit.framework.TestCase; + +import org.apache.hadoop.mapred.nativetask.util.ReadWriteBuffer; +import org.junit.Assert; + +public class TestReadWriteBuffer extends TestCase { + + private static byte[] bytes = new byte[] { '0', 'a', 'b', 'c', 'd', '9' }; + + public void testReadWriteBuffer() { + + final ReadWriteBuffer buffer = new ReadWriteBuffer(); + + Assert.assertFalse(buffer.getBuff() == null); + + Assert.assertEquals(buffer.getWritePoint(), 0); + Assert.assertEquals(buffer.getReadPoint(), 0); + + buffer.writeInt(3); + + buffer.writeString("goodboy"); + + buffer.writeLong(10L); + buffer.writeBytes(bytes, 0, bytes.length); + buffer.writeLong(100L); + + Assert.assertEquals(buffer.getWritePoint(), 41); + Assert.assertEquals(buffer.getReadPoint(), 0); + Assert.assertTrue(buffer.getBuff().length >= 41); + + Assert.assertEquals(buffer.readInt(), 3); + Assert.assertEquals(buffer.readString(), "goodboy"); + Assert.assertEquals(buffer.readLong(), 10L); + + final byte[] read = buffer.readBytes(); + for (int i = 0; i < bytes.length; i++) { + Assert.assertEquals(bytes[i], read[i]); + } + + Assert.assertEquals(100L, buffer.readLong()); + Assert.assertEquals(41, buffer.getReadPoint()); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/utils/TestSizedWritable.java b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/utils/TestSizedWritable.java new file mode 100644 index 00000000000..7b82eff7148 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/java/org/apache/hadoop/mapred/nativetask/utils/TestSizedWritable.java @@ -0,0 +1,34 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.hadoop.mapred.nativetask.utils; + +import junit.framework.TestCase; + +import org.apache.hadoop.io.BytesWritable; +import org.apache.hadoop.mapred.nativetask.util.SizedWritable; +import org.junit.Assert; + +@SuppressWarnings({ "rawtypes", "unchecked" }) +public class TestSizedWritable extends TestCase { + + public void testSizedWritable() { + final SizedWritable w = new SizedWritable(BytesWritable.class); + Assert.assertTrue(w.length == SizedWritable.INVALID_LENGTH); + Assert.assertFalse(w.v == null); + } +} diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/common_conf.xml b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/common_conf.xml new file mode 100644 index 00000000000..d4574d54bd9 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/common_conf.xml @@ -0,0 +1,48 @@ + + + + + + + + mapred.job.tracker + local + + + keep.failed.task.files + true + + + keep.task.files.pattern + .*_m_ + Keep all files from tasks whose task names match the given + regular expression. Defaults to none. + + + nativetask.kvsize.max.largekv + 1048576 + + + native.processor.buffer.kb + 128 + + + nativetask.output.manager + org.apache.hadoop.mapred.nativetask.util.LocalJobOutputFiles + + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/kvtest-conf.xml b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/kvtest-conf.xml new file mode 100644 index 00000000000..eb626d33128 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/kvtest-conf.xml @@ -0,0 +1,85 @@ + + + + + + + + kvtest.file.size + 10485760 + + + mapreduce.reduce.class + org.apache.hadoop.mapred.nativetask.kvtest.HashSumReducer + + + mapred.output.value.class + org.apache.hadoop.io.IntWritable + + + nativetask.kvtest.keyclasses + + org.apache.hadoop.io.BytesWritable; + org.apache.hadoop.io.BooleanWritable; + org.apache.hadoop.io.ByteWritable; + org.apache.hadoop.io.DoubleWritable; + org.apache.hadoop.io.FloatWritable; + org.apache.hadoop.io.IntWritable; + org.apache.hadoop.io.LongWritable; + org.apache.hadoop.io.Text; + org.apache.hadoop.io.VIntWritable; + org.apache.hadoop.io.VLongWritable; + + + + nativetask.kvtest.valueclasses + + org.apache.hadoop.io.BytesWritable; + org.apache.hadoop.io.BooleanWritable; + org.apache.hadoop.io.ByteWritable; + org.apache.hadoop.io.DoubleWritable; + org.apache.hadoop.io.FloatWritable; + org.apache.hadoop.io.IntWritable; + org.apache.hadoop.io.LongWritable; + org.apache.hadoop.io.Text; + org.apache.hadoop.io.VIntWritable; + org.apache.hadoop.io.VLongWritable; + org.apache.hadoop.mapred.nativetask.testutil.MockValueClass; + + + + mapred.output.compress + false + + + mapred.output.compression.type + BLOCK + + + mapred.compress.map.output + true + + + mapred.map.output.compression.codec + org.apache.hadoop.io.compress.SnappyCodec + + + hadoop.native.lib + true + + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/log4j.properties b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/log4j.properties new file mode 100644 index 00000000000..531b68b5a9f --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/log4j.properties @@ -0,0 +1,19 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# log4j configuration used during build and unit tests + +log4j.rootLogger=info,stdout +log4j.threshhold=ALL +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c{2} (%F:%M(%L)) - %m%n diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/native_conf.xml b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/native_conf.xml new file mode 100644 index 00000000000..7d0d01fd380 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/native_conf.xml @@ -0,0 +1,30 @@ + + + + + + + + mapreduce.job.map.output.collector.class + org.apache.hadoop.mapred.nativetask.testutil.EnforceNativeOutputCollectorDelegator + + + io.sort.mb + 5 + + \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/normal_conf.xml b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/normal_conf.xml new file mode 100644 index 00000000000..48fddd9854a --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/normal_conf.xml @@ -0,0 +1,26 @@ + + + + + + + + io.sort.mb + 30 + + \ No newline at end of file diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/test-combiner-conf.xml b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/test-combiner-conf.xml new file mode 100644 index 00000000000..8f9ee4d33e2 --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/test-combiner-conf.xml @@ -0,0 +1,30 @@ + + + + + + + + nativetask.combiner.wordcount.filesize + 20971520 + + + mapred.job.tracker + local + + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/test-compress-conf.xml b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/test-compress-conf.xml new file mode 100644 index 00000000000..88d6cd80cdd --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/test-compress-conf.xml @@ -0,0 +1,50 @@ + + + + + + + + mapred.output.compress + false + + + mapred.output.value.class + org.apache.hadoop.io.IntWritable + + + nativetask.compress.filesize + 100000 + + + mapreduce.reduce.class + org.apache.hadoop.mapred.nativetask.kvtest.HashSumReducer + + + mapred.compress.map.output + true + + + mapred.output.compression.type + BLOCK + + + hadoop.native.lib + true + + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/test-nonsort-conf.xml b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/test-nonsort-conf.xml new file mode 100644 index 00000000000..f1f4c6d5e3b --- /dev/null +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/src/test/resources/test-nonsort-conf.xml @@ -0,0 +1,30 @@ + + + + + + + + nativetask.nonsorttest.filesize + 4194304 + + + mapred.job.tracker + local + + diff --git a/hadoop-mapreduce-project/hadoop-mapreduce-client/pom.xml b/hadoop-mapreduce-project/hadoop-mapreduce-client/pom.xml index 72b9cd43b31..5a16820baf3 100644 --- a/hadoop-mapreduce-project/hadoop-mapreduce-client/pom.xml +++ b/hadoop-mapreduce-project/hadoop-mapreduce-client/pom.xml @@ -187,5 +187,6 @@ hadoop-mapreduce-client-jobclient hadoop-mapreduce-client-hs hadoop-mapreduce-client-hs-plugins + hadoop-mapreduce-client-nativetask diff --git a/hadoop-mapreduce-project/pom.xml b/hadoop-mapreduce-project/pom.xml index 772a2a38763..5cee534057c 100644 --- a/hadoop-mapreduce-project/pom.xml +++ b/hadoop-mapreduce-project/pom.xml @@ -194,7 +194,7 @@ .eclipse.templates/ - CHANGES.txt + CHANGES.*txt lib/jdiff/** @@ -234,6 +234,34 @@ + + org.apache.maven.plugins + maven-antrun-plugin + + + dist + prepare-package + + run + + + + + LIB_DIR="${mr.basedir}/hadoop-mapreduce-client/hadoop-mapreduce-client-nativetask/target/native/target/usr/local/lib" + if [ -d $${LIB_DIR} ] ; then + TARGET_DIR="${project.build.directory}/${project.artifactId}-${project.version}/lib/native" + mkdir -p $${TARGET_DIR} + cp -R $${LIB_DIR}/lib* $${TARGET_DIR} + fi + + + + + + + + + org.apache.maven.plugins maven-assembly-plugin